Files
OSIT-AE-API-FastAPI/app/routers/hosted_file.py
2021-05-28 01:40:18 -04:00

162 lines
5.5 KiB
Python

import datetime, shutil, time
#from datetime import datetime, time, timedelta
from fastapi import APIRouter, Body, Depends, File, Form, Header, HTTPException, Query, Response, status, UploadFile
from pydantic import BaseModel, EmailStr, Field
from typing import Dict, List, Optional, Set, Union
from ..lib_general import *
from ..log import *
from app.config import settings
from app.db_sql import *
from .api_crud import delete_obj_template, get_obj_template, get_obj_li_template, patch_obj_template, post_obj_template
from ..models.hosted_file_models import Hosted_File_Base
from ..models.response_models import *
router = APIRouter()
# This just needs to return the currect model for a hosted_file
# Everything else seems to be workign well
# Should this also do something with meta data and updating the DB?
@router.post('/upload_files/')
async def create_upload_files(
files: List[UploadFile] = File(...),
account_id: str = Form(..., min_length=1, max_length=22),
filename: Optional[str] = Form(...),
object_type: Optional[str] = Form(...),
object_id: Optional[str] = Form(..., min_length=1, max_length=22),
x_account_id: Optional[str] = Header(..., ),
return_obj: Optional[bool] = True,
by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True,
):
data = {}
data['account_id'] = account_id
#data['filename'] = filename
data['object_type'] = object_type
data['object_id'] = object_id
data['file_li'] = []
log.debug(await save_file_li(files))
response_li = []
for file in files:
file_info = {}
file_info['filename'] = file.filename
file_info['content_type'] = file.content_type
file.file.seek(0, os.SEEK_END)
file_size = file.file.tell()
file.file.seek(0) # The file will not properly save if seek is not reset to 0.
file_info['size'] = file_size
log.debug(file_size)
data['file_li'].append(file_info)
return mk_resp(data=data)
#response = { 'response_data': response_data, 'response_li':response_li }
#response['filenames'] = [file.filename for file in files]
#return response
#return {'filenames': [file.filename for file in files]}
# This is not needed. Just for reference of the mk_resp() function
@router.post('/', response_model=Resp_Body_Base)
async def post_upload_file(
account_id: str = Query(..., min_length=1, max_length=22),
):
if return_obj:
if order_cart_obj := load_order_cart_obj(order_cart_id=order_cart_id, inc_order_cart_line_li=inc_order_cart_line_li, inc_order_cart_cfg=inc_order_cart_cfg):
data = order_cart_obj.dict(by_alias=True, exclude_unset=False)
return mk_resp(data=data)
else:
return mk_resp(data=False, status_code=404) # Not Found
else:
return mk_resp(data=True)
async def save_file_li(file_li: List[UploadFile] = File(...)):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
hosted_file_path = '/home/scott/tmp/hosted_file_dev/'
log.debug(shutil.disk_usage(hosted_file_path))
result = []
for file in file_li:
log.debug(f'{file.filename}')
file.file.seek(0, os.SEEK_END)
file_size = file.file.tell()
file.file.seek(0) # The file will not properly save if seek is not reset to 0.
#file_info['size'] = request_file_size
log.debug(file_size)
file_hash = await get_file_object_hash(file.file)
log.debug(file_hash)
# 16384 bytes is the default
# 4096 8192 16384 32768 65536 131072 262144 524288 1048576 bytes
buffer_size = 524288
#file_src = file.filename
#f_src = open(file_src, 'rb')
f_src = file.file # Don't need to do open(file_src, 'rb') since it is already "open"
#file_dest = f'{hosted_file_path}{file.filename}'
file_dest = f'{hosted_file_path}{file_hash}.file'
f_dest = open(file_dest, 'wb')
timer_start = time.process_time()
shutil.copyfileobj(f_src, f_dest, buffer_size)
timer_end = time.process_time()
elapsed_time = timer_end - timer_start
log.debug(f'Elapsed time: {elapsed_time}')
result.append({ 'filename': file.filename })
log.debug(shutil.disk_usage(hosted_file_path))
return result
async def get_file_object_hash(file_object):
#log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
# 4096 bytes is the current block size on my workstation and Linode server
# 4096 8192 16384 32768 65536 131072 262144 524288 1048576 bytes
block_size = 131072
hash_value = hashlib.sha256()
timer_start = time.process_time()
for chunk in iter(lambda: file_object.read(block_size), b""):
hash_value.update(chunk)
file_hash = hash_value.hexdigest()
file_object.seek(0) # The file will not properly save if seek is not reset to 0.
timer_end = time.process_time()
elapsed_time = timer_end - timer_start
#log.debug(f'Elapsed time: {elapsed_time}')
return file_hash
# def allowed_file_extension(filename):
# return False
# return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']
# def guess_file_extension(filename):
# return filename.rsplit('.', 1)[1].lower()
# def copyLargeFile(src, dest, buffer_size=16000):
# with open(src, 'rb') as fsrc:
# with open(dest, 'wb') as fdest:
# shutil.copyfileobj(fsrc, fdest, buffer_size)