- New implementation of esp.file_get that also works with binary files
- New communication protocol for downloaded chunks based on queues instead of events.
This commit is contained in:
parent
4b56431e2a
commit
b484fcf9ed
2 changed files with 33 additions and 20 deletions
|
@ -1,4 +1,5 @@
|
|||
import base64
|
||||
import io
|
||||
import os
|
||||
import threading
|
||||
|
||||
|
@ -1532,22 +1533,31 @@ print([b for b in os.urandom({size})])
|
|||
return self.execute(code, **kwargs).output
|
||||
|
||||
@action
|
||||
def file_get(self, file: str, **kwargs) -> str:
|
||||
def file_get(self, file: str, binary: bool = False, timeout: Optional[float] = 60.0, **kwargs) -> str:
|
||||
"""
|
||||
Get the content of a file on the board.
|
||||
NOTE: It only works with non-binary files.
|
||||
|
||||
:param file: File name/path to get from the device.
|
||||
:param kwargs: Parameters to pass to :meth:`platypush.plugins.esp.EspPlugin.execute`.
|
||||
:param binary: If True, then the base64-encoded content of the file will be returned.
|
||||
:param timeout: File transfer timeout (default: one minute).
|
||||
:param kwargs: Parameters to pass to :meth:`platypush.plugins.esp.EspPlugin.connect`.
|
||||
"""
|
||||
file = self.string_quote(file)
|
||||
code = '''
|
||||
import os
|
||||
with open('{file}', 'r') as f:
|
||||
print(f.read())
|
||||
'''.format(file=file)
|
||||
device = self._get_device(**kwargs)
|
||||
host = device['host']
|
||||
port = device['port']
|
||||
self.connect(host=host, port=port, password=device['password'])
|
||||
conn = self._get_connection(host=host, port=port)
|
||||
|
||||
return self.execute(code, **kwargs).output
|
||||
with io.BytesIO() as buffer:
|
||||
conn.file_download(file, buffer, timeout=timeout)
|
||||
data = buffer.getvalue()
|
||||
|
||||
if binary:
|
||||
data = base64.encodebytes(data).decode()
|
||||
else:
|
||||
data = data.decode()
|
||||
|
||||
return data
|
||||
|
||||
@action
|
||||
def file_upload(self, source: str, destination: Optional[str] = None, timeout: Optional[float] = 60.0, **kwargs):
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import enum
|
||||
import logging
|
||||
import queue
|
||||
import os
|
||||
import re
|
||||
import threading
|
||||
|
@ -50,7 +51,7 @@ class Connection:
|
|||
self._file_transfer_ack_received = threading.Event()
|
||||
self._file_transfer_request_successful = True
|
||||
self._file_transfer_successful = True
|
||||
self._downloaded_chunk = None
|
||||
self._downloaded_chunks = queue.Queue()
|
||||
self._password_requested = False
|
||||
self._running_cmd = None
|
||||
self._received_echo = None
|
||||
|
@ -203,7 +204,7 @@ class Connection:
|
|||
def on_file_download_start(self):
|
||||
self.logger.info('Starting file download')
|
||||
self._file_transfer_successful = False
|
||||
self._downloaded_chunk = None
|
||||
self._downloaded_chunks = queue.Queue()
|
||||
self.state = self.State.DOWNLOADING_FILE
|
||||
self._file_transfer_ack_received.clear()
|
||||
self.ws.send(b'\x00', opcode=websocket.ABNF.OPCODE_BINARY)
|
||||
|
@ -218,10 +219,10 @@ class Connection:
|
|||
if size == 0:
|
||||
# End of file
|
||||
self.logger.info('File download completed')
|
||||
self._downloaded_chunk = None
|
||||
self._downloaded_chunks.put(None)
|
||||
self.on_file_download_completed()
|
||||
else:
|
||||
self._downloaded_chunk = data
|
||||
self._downloaded_chunks.put(data)
|
||||
self.ws.send(b'\x00', opcode=websocket.ABNF.OPCODE_BINARY)
|
||||
|
||||
self._download_chunk_ready.set()
|
||||
|
@ -237,15 +238,17 @@ class Connection:
|
|||
self.state = self.State.SENDING_FILE_TRANSFER_RESPONSE
|
||||
|
||||
def get_downloaded_chunks(self, timeout: Optional[float] = None):
|
||||
block_ok = self._download_chunk_ready.wait(timeout=timeout)
|
||||
|
||||
while self._downloaded_chunk and block_ok:
|
||||
yield self._downloaded_chunk
|
||||
block_ok = self._download_chunk_ready.wait(timeout=timeout)
|
||||
|
||||
if not block_ok:
|
||||
while True:
|
||||
try:
|
||||
chunk = self._downloaded_chunks.get(timeout=timeout)
|
||||
except queue.Empty:
|
||||
self.on_timeout('File download timed out')
|
||||
|
||||
if chunk is None:
|
||||
break
|
||||
|
||||
yield chunk
|
||||
|
||||
def wait_ready(self):
|
||||
connected = self._connected.wait(timeout=self.connect_timeout)
|
||||
if not connected:
|
||||
|
|
Loading…
Reference in a new issue