diff --git a/app/routers/event_file.py b/app/routers/event_file.py index 365355a..eebbda9 100644 --- a/app/routers/event_file.py +++ b/app/routers/event_file.py @@ -1,6 +1,6 @@ import datetime, os, pathlib, time from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query, Response, status -from fastapi.responses import FileResponse +from fastapi.responses import FileResponse, StreamingResponse from pydantic import BaseModel, EmailStr, Field from typing import Dict, List, Optional, Set, Union @@ -240,6 +240,7 @@ async def event_file_lookup( async def download_event_file( event_file_id: str = Query(..., min_length=11, max_length=22), filename: str = Query(None, min_length=4, max_length=100), + streaming: bool = False, commons: Common_Route_Params = Depends(common_route_params), ): @@ -280,10 +281,17 @@ async def download_event_file( if os.path.exists(file_path_w_subdir): log.info('Hosted file found on server.') - return FileResponse(file_path_w_subdir, filename=filename) + if streaming: + log.warning('Streaming!!!') + def iterfile(): # + with open(file_path_w_subdir, mode="rb") as file_like: # + yield from file_like # + return StreamingResponse(iterfile(), media_type='video/mp4') + else: + return FileResponse(file_path_w_subdir, filename=filename) else: log.error(f'The hosted file was not found on the server. Hash: {hash_sha256}') - return mk_resp(data=False, status_code=404, response=commons.response, status_message=f'The hosted file was not found on the server. Hash: {hash_sha256}') # Not Found + return mk_resp(data=None, status_code=404, response=commons.response, status_message=f'The hosted file was not found on the server. Hash: {hash_sha256}') # Not Found # ### END ### API Event File ### download_event_file() ### diff --git a/app/routers/hosted_file.py b/app/routers/hosted_file.py index d98b8c2..d7e17a4 100644 --- a/app/routers/hosted_file.py +++ b/app/routers/hosted_file.py @@ -1,6 +1,9 @@ import datetime, hashlib, os, pathlib, shutil, time from fastapi import APIRouter, Body, Depends, File, Form, Header, HTTPException, Query, Response, status, UploadFile -from fastapi.responses import FileResponse +# from fastapi.responses import FileResponse, StreamingResponse +from fastapi.responses import StreamingResponse +from baize.asgi.responses import FileResponse +# from baize.wsgi.responses import FileResponse from pydantic import BaseModel, EmailStr, Field from typing import Dict, List, Optional, Set, Union from pdf2image import convert_from_path @@ -157,6 +160,7 @@ async def directory_check( async def download_hosted_file( hosted_file_id: str = Query(..., min_length=11, max_length=22), filename: str = Query(None, min_length=4, max_length=100), + streaming: bool = False, commons: Common_Route_Params = Depends(common_route_params), ): @@ -198,13 +202,112 @@ async def download_hosted_file( log.info(f'Full file path with subdirectory: {file_path_w_subdir}') if os.path.exists(file_path_w_subdir): - return FileResponse(file_path_w_subdir, filename=filename) + # log.info('Hosted file found on server.') + # return FileResponse(file_path_w_subdir, filename=filename) + + log.info('Hosted file found on server.') + if streaming: + log.warning('Streaming!!!') + def iterfile(): # + with open(file_path_w_subdir, mode="rb") as file_like: # + yield from file_like # + return StreamingResponse(iterfile(), media_type='video/mp4') + else: + return FileResponse(file_path_w_subdir, filename=filename) else: log.error(f'The hosted file was not found on the server. Hash: {hash_sha256}') - return mk_resp(data=False, status_code=400, response=commons.response, status_message='The hosted file was not found on the server.') # Bad Request + return mk_resp(data=None, status_code=404, response=commons.response, status_message=f'The hosted file was not found on the server. Hash: {hash_sha256}') # Not Found # ### END ### API Hosted File ### download_hosted_file() ### +# class ChunkFileResponse(Response): +# def __init__(self, *args, **kwargs) -> None: +# if len(args) == 1: +# kwargs = args[0] +# [kwargs.pop(k) for k in ['status_code', 'cookies', 'stat_result']] +# super().__init__(**kwargs) + +# ### BEGIN ### API Hosted File ### stream_hosted_file() ### +# Updated 2023-08-17 +# @router.get('/{hosted_file_id}/stream', response_model=Resp_Body_Base) +# @router.get('/{hosted_file_id}/stream', response_class=Resp_Body_Base) +# @router.get('/{hosted_file_id}/stream', response_class=FileResponse) +@router.get('/{hosted_file_id}/stream') +# def stream_hosted_file( +async def stream_hosted_file( + hosted_file_id: str = Query(..., min_length=11, max_length=22), + filename: str = Query(None, min_length=4, max_length=100), + streaming: bool = True, + + commons: Common_Route_Params = Depends(common_route_params), + ): + log.setLevel(logging.INFO) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL + log.debug(locals()) + + # ### SECTION ### Secondary data validation + if hosted_file_id := redis_lookup_id_random(record_id_random=hosted_file_id, table_name='hosted_file'): pass + else: return mk_resp(data=None, status_code=404, response=commons.response, status_message='The hosted_file ID was invalid or not found.') + + hosted_files_path = settings.FILES_PATH['hosted_files_root'] + # hosted_files_path = '/home/scott/tmp/hosted_files_dev/' + log.info(f'Hosted Files Path: {hosted_files_path}') + + if hosted_file_obj := load_hosted_file_obj( + hosted_file_id = hosted_file_id, + # inc_hosted_file = True, + inc_hosted_file_link_list = True, + ): + pass + else: + return mk_resp(data=False, status_code=400, response=commons.response) # Bad Request + + if not filename: + filename = hosted_file_obj.filename + log.info(f'Filename: {filename}') + dir_path = hosted_file_obj.directory_path + subdir_path = hosted_file_obj.subdirectory_path + hash_sha256 = hosted_file_obj.hash_sha256 + hash_filename = hash_sha256+'.file' + + if subdir_path: + full_subdirectory_path = os.path.join(hosted_files_path, subdir_path) + else: + full_subdirectory_path = hosted_files_path + log.debug(full_subdirectory_path) + pathlib.Path(full_subdirectory_path).mkdir(parents=True, exist_ok=True) + file_path_w_subdir = os.path.join(full_subdirectory_path, hash_filename) + log.info(f'Full file path with subdirectory: {file_path_w_subdir}') + + if os.path.exists(file_path_w_subdir): + # log.info('Hosted file found on server.') + # return FileResponse(file_path_w_subdir, filename=filename) + + log.info('Hosted file found on server.') + + + # return ChunkFileResponse(filepath=file_path_w_subdir) + + # return FileResponse(file_path_w_subdir, filename=filename) + + + if streaming: + log.warning('Streaming!!!') + return FileResponse(filepath=file_path_w_subdir, content_type='video/mp4', download_name=filename) + + # def iterfile(): # + # with open(file_path_w_subdir, mode="rb") as file_like: # + # yield from file_like # + # return FileResponse(iterfile(), download_name=filename) + + # return StreamingResponse(iterfile(), media_type='video/mp4') + else: + return FileResponse(file_path_w_subdir, filename=filename) + else: + log.error(f'The hosted file was not found on the server. Hash: {hash_sha256}') + return mk_resp(data=None, status_code=404, response=commons.response, status_message=f'The hosted file was not found on the server. Hash: {hash_sha256}') # Not Found +# ### END ### API Hosted File ### stream_hosted_file() ### + + # ### BEGIN ### API Hosted File Route ### upload_files() ### # This just needs to return the correct model for a hosted_file # Everything else seems to be working well