Add file_stream response handler
For streaming large static files Like `file()` but breaks the file into chunks and sends it with a `StreamingHTTPResponse` Chunk size is configurable, but defaults to 4k, this seemed to be the sweet spot in my testing. Also supports ContentRange same as `file()` does.
This commit is contained in:
parent
0e4aaf8856
commit
e155fe403d
|
@ -310,6 +310,55 @@ async def file(location, mime_type=None, headers=None, _range=None):
|
||||||
body_bytes=out_stream)
|
body_bytes=out_stream)
|
||||||
|
|
||||||
|
|
||||||
|
async def file_stream(location, chunk_size=4096, mime_type=None, headers=None,
|
||||||
|
_range=None):
|
||||||
|
"""Return a streaming response object with file data.
|
||||||
|
|
||||||
|
:param location: Location of file on system.
|
||||||
|
:param chunk_size: The size of each chunk in the stream (in bytes)
|
||||||
|
:param mime_type: Specific mime_type.
|
||||||
|
:param headers: Custom Headers.
|
||||||
|
:param _range:
|
||||||
|
"""
|
||||||
|
filename = path.split(location)[-1]
|
||||||
|
|
||||||
|
_file = await open_async(location, mode='rb')
|
||||||
|
|
||||||
|
async def _streaming_fn(response):
|
||||||
|
nonlocal _file, chunk_size
|
||||||
|
try:
|
||||||
|
if _range:
|
||||||
|
chunk_size = min((_range.size, chunk_size))
|
||||||
|
await _file.seek(_range.start)
|
||||||
|
to_send = _range.size
|
||||||
|
while to_send > 0:
|
||||||
|
content = await _file.read(chunk_size)
|
||||||
|
if len(content) < 1:
|
||||||
|
break
|
||||||
|
to_send -= len(content)
|
||||||
|
response.write(content)
|
||||||
|
else:
|
||||||
|
while True:
|
||||||
|
content = await _file.read(chunk_size)
|
||||||
|
if len(content) < 1:
|
||||||
|
break
|
||||||
|
response.write(content)
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
finally:
|
||||||
|
await _file.close()
|
||||||
|
return # Returning from this fn closes the stream
|
||||||
|
|
||||||
|
mime_type = mime_type or guess_type(filename)[0] or 'text/plain'
|
||||||
|
if _range:
|
||||||
|
headers['Content-Range'] = 'bytes %s-%s/%s' % (
|
||||||
|
_range.start, _range.end, _range.total)
|
||||||
|
return StreamingHTTPResponse(streaming_fn=_streaming_fn,
|
||||||
|
status=200,
|
||||||
|
headers=headers,
|
||||||
|
content_type=mime_type)
|
||||||
|
|
||||||
|
|
||||||
def stream(
|
def stream(
|
||||||
streaming_fn, status=200, headers=None,
|
streaming_fn, status=200, headers=None,
|
||||||
content_type="text/plain; charset=utf-8"):
|
content_type="text/plain; charset=utf-8"):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user