# Send Payload
- @property
- async def payload(self):
+ async def open(self):
# Open the package
p = await self.package.open()
- # Create a helper function to read the entire payload
+ # Create a helper function to return a file-like object
func = lambda: p.read(self.path)
# Read the payload in a separate thread
return await asyncio.to_thread(func)
- async def sendfile(self, f, chunk_size=102400):
+ async def sendfile(self, dst, chunk_size=8192):
"""
Sends the payload of the file into the given file descriptor
"""
- # XXX This should ideally not load the entire payload into memory at once
+ src = await self.open()
+
+ return await asyncio.to_thread(self._sendfile, src, dst, chunk_size=chunk_size)
+
+ def _sendfile(self, src, dst, chunk_size=8192):
+ while True:
+ chunk = src.read(chunk_size)
+ if not chunk:
+ break
- # Fetch the payload
- payload = await self.payload
+ dst.write(chunk)
- # Send the payload in chunks, so that we do not overwhelm Tornado
- for i in range(0, self.size, chunk_size):
- block = payload[i:i+chunk_size]
+ @property
+ async def payload(self):
+ """
+ Returns the entire payload at once
+ """
+ # Open the file
+ f = await self.open()
- f.write(block)
+ # Read everything in a separate thread
+ return await asyncio.to_thread(f.readall)