11import os
22import asyncio
3+ import time
4+ import uuid
35from datetime import datetime
46from pathlib import Path
57from typing import BinaryIO
1618 import oss2
1719
1820
19- class AliyunFileStorage :
20- def __init__ (self ):
21- auth = oss2 .Auth (settings .KeyId , settings .KeySecret )
22- self .bucket = oss2 .Bucket (auth , settings .OSS_ENDPOINT , settings .BUCKET_NAME )
23-
24- def upload_file (self , upload_filepath , remote_filepath ):
25- self .bucket .put_object_from_file (remote_filepath , upload_filepath )
26-
27- async def get_text (self , file : UploadFile , key : str ):
28- ext = file .filename .split ('.' )[- 1 ]
29- now = datetime .now ()
30- path = f"FileCodeBox/upload/{ now .year } /{ now .month } /{ now .day } "
31- text = f"{ path } /{ f'{ key } .{ ext } ' } "
32- return f"https://{ settings .BUCKET_NAME } .{ settings .OSS_ENDPOINT } /{ text } "
33-
34- async def get_url (self , info : Codes ):
35- text = info .text .strip (f"https://{ settings .BUCKET_NAME } .{ settings .OSS_ENDPOINT } /" )
36- url = self .bucket .sign_url ('GET' , text , settings .ACCESSTIME , slash_safe = True )
37- return url
38-
39- @staticmethod
40- async def get_size (file : UploadFile ):
41- f = file .file
42- f .seek (0 , os .SEEK_END )
43- size = f .tell ()
44- f .seek (0 , os .SEEK_SET )
45- return size
46-
47- @staticmethod
48- def _save (filepath , file : BinaryIO ):
49- with open (filepath , 'wb' ) as f :
50- chunk_size = 256 * 1024
51- chunk = file .read (chunk_size )
52- while chunk :
53- f .write (chunk )
54- chunk = file .read (chunk_size )
55-
56- async def save_file (self , file : UploadFile , remote_filepath : str ):
57- now = int (datetime .now ().timestamp ())
58- upload_filepath = settings .DATA_ROOT + str (now )
59- await asyncio .to_thread (self ._save , upload_filepath , file .file )
60- self .upload_file (upload_filepath , remote_filepath )
61- remote_filepath = remote_filepath .strip (f"https://{ settings .BUCKET_NAME } .{ settings .OSS_ENDPOINT } /" )
62- self .upload_file (upload_filepath , remote_filepath )
63- await asyncio .to_thread (os .remove , upload_filepath )
64-
65- async def delete_files (self , texts ):
66- tasks = [self .delete_file (text ) for text in texts ]
67- await asyncio .gather (* tasks )
68-
69- async def delete_file (self , text : str ):
70- text = text .strip (f"https://{ settings .BUCKET_NAME } .{ settings .OSS_ENDPOINT } /" )
71- self .bucket .delete_object (text )
72-
73-
7421class FileSystemStorage :
7522 def __init__ (self ):
7623 self .DATA_ROOT = Path (settings .DATA_ROOT )
@@ -110,6 +57,38 @@ def _save(filepath, file: BinaryIO):
11057 f .write (chunk )
11158 chunk = file .read (chunk_size )
11259
60+ @staticmethod
61+ def _save_chunk (filepath , file : bytes ):
62+ with open (filepath , 'wb' ) as f :
63+ f .write (file )
64+
65+ async def create_upload_file (self ):
66+ file_key = uuid .uuid4 ().hex
67+ file_path = self .DATA_ROOT / f"temp/{ file_key } "
68+ if not file_path .exists ():
69+ file_path .mkdir (parents = True )
70+ return file_key
71+
72+ async def save_chunk_file (self , file_key , file_chunk , chunk_index , chunk_total ):
73+ file_path = self .DATA_ROOT / f"temp/{ file_key } /"
74+ await asyncio .to_thread (self ._save_chunk , file_path / f"{ chunk_total } -{ chunk_index } .temp" , file_chunk )
75+
76+ async def merge_chunks (self , file_key , file_name , total_chunks : int ):
77+ ext = file_name .split ('.' )[- 1 ]
78+ now = datetime .now ()
79+ path = self .DATA_ROOT / f"upload/{ now .year } /{ now .month } /{ now .day } /"
80+ if not path .exists ():
81+ path .mkdir (parents = True )
82+ text = f"{ self .STATIC_URL } /{ (path / f'{ file_key } .{ ext } ' ).relative_to (self .DATA_ROOT )} "
83+ with open (path / f'{ file_key } .{ ext } ' , 'wb' ) as f :
84+ for i in range (1 , total_chunks + 1 ):
85+ now_temp = self .DATA_ROOT / f'temp/{ file_key } /{ total_chunks } -{ i } .temp'
86+ with open (now_temp , 'rb' ) as r :
87+ f .write (r .read ())
88+ await asyncio .to_thread (os .remove , now_temp )
89+ await asyncio .to_thread (os .rmdir , self .DATA_ROOT / f'temp/{ file_key } /' )
90+ return text
91+
11392 async def save_file (self , file : UploadFile , text : str ):
11493 filepath = await self .get_filepath (text )
11594 await asyncio .to_thread (self ._save , filepath , file .file )
@@ -134,6 +113,61 @@ def judge_delete_folder(self, filepath):
134113 break
135114
136115
116+ class AliyunFileStorage :
117+ def __init__ (self ):
118+ auth = oss2 .Auth (settings .KeyId , settings .KeySecret )
119+ self .bucket = oss2 .Bucket (auth , settings .OSS_ENDPOINT , settings .BUCKET_NAME )
120+
121+ def upload_file (self , upload_filepath , remote_filepath ):
122+ self .bucket .put_object_from_file (remote_filepath , upload_filepath )
123+
124+ async def get_text (self , file : UploadFile , key : str ):
125+ ext = file .filename .split ('.' )[- 1 ]
126+ now = datetime .now ()
127+ path = f"FileCodeBox/upload/{ now .year } /{ now .month } /{ now .day } "
128+ text = f"{ path } /{ f'{ key } .{ ext } ' } "
129+ return f"https://{ settings .BUCKET_NAME } .{ settings .OSS_ENDPOINT } /{ text } "
130+
131+ async def get_url (self , info : Codes ):
132+ text = info .text .strip (f"https://{ settings .BUCKET_NAME } .{ settings .OSS_ENDPOINT } /" )
133+ url = self .bucket .sign_url ('GET' , text , settings .ACCESSTIME , slash_safe = True )
134+ return url
135+
136+ @staticmethod
137+ async def get_size (file : UploadFile ):
138+ f = file .file
139+ f .seek (0 , os .SEEK_END )
140+ size = f .tell ()
141+ f .seek (0 , os .SEEK_SET )
142+ return size
143+
144+ @staticmethod
145+ def _save (filepath , file : BinaryIO ):
146+ with open (filepath , 'wb' ) as f :
147+ chunk_size = 256 * 1024
148+ chunk = file .read (chunk_size )
149+ while chunk :
150+ f .write (chunk )
151+ chunk = file .read (chunk_size )
152+
153+ async def save_file (self , file : UploadFile , remote_filepath : str ):
154+ now = int (datetime .now ().timestamp ())
155+ upload_filepath = settings .DATA_ROOT + str (now )
156+ await asyncio .to_thread (self ._save , upload_filepath , file .file )
157+ self .upload_file (upload_filepath , remote_filepath )
158+ remote_filepath = remote_filepath .strip (f"https://{ settings .BUCKET_NAME } .{ settings .OSS_ENDPOINT } /" )
159+ self .upload_file (upload_filepath , remote_filepath )
160+ await asyncio .to_thread (os .remove , upload_filepath )
161+
162+ async def delete_files (self , texts ):
163+ tasks = [self .delete_file (text ) for text in texts ]
164+ await asyncio .gather (* tasks )
165+
166+ async def delete_file (self , text : str ):
167+ text = text .strip (f"https://{ settings .BUCKET_NAME } .{ settings .OSS_ENDPOINT } /" )
168+ self .bucket .delete_object (text )
169+
170+
137171STORAGE_ENGINE = {
138172 "filesystem" : FileSystemStorage ,
139173 "aliyunsystem" : AliyunFileStorage
0 commit comments