2
2
import weakref
3
3
from fastapi import Request
4
4
from dataclasses import dataclass
5
- from fastapi .responses import StreamingResponse
6
5
7
6
8
7
@dataclass
@@ -16,52 +15,71 @@ class Duplex:
16
15
17
16
instances = weakref .WeakValueDictionary ()
18
17
19
- def __init__ (self , stream , identifier : str , file : File , wait_for_client : bool ):
20
- self .stream = stream
18
+ def __init__ (self , identifier : str , file : File , stream = None ):
21
19
self .identifier = identifier
22
20
self .file = file
23
- self .queue = asyncio .Queue (1 if wait_for_client else 0 )
21
+ self .queue = asyncio .Queue (1 )
24
22
self .client_connected = asyncio .Event ()
25
23
26
24
@staticmethod
27
- def get_upload_details (request : Request ):
28
- stream = request .stream
29
- identifier = request .path_params .get ('identifier' )
25
+ def get_file_from_request (request : Request ):
30
26
file = File (
31
27
name = request .path_params .get ('file_name' ),
32
28
size = int (request .headers .get ('content-length' )),
33
29
content_type = request .headers .get ('content-type' )
34
30
)
35
- return stream , identifier , file
31
+ return file
32
+
33
+ @staticmethod
34
+ def get_file_from_header (header : dict ):
35
+ file = File (
36
+ name = header ['file_name' ],
37
+ size = int (header ['file_size' ]),
38
+ content_type = header ['file_type' ]
39
+ )
40
+ return file
41
+
42
+ def get_file_info (self ):
43
+ return self .file .name , self .file .size , self .file .content_type
36
44
37
45
@classmethod
38
- def from_upload (cls , request : Request ):
39
- stream , identifier , file = cls .get_upload_details (request )
40
- duplex = cls (stream , identifier , file , wait_for_client = True )
46
+ def create_duplex (cls , identifier : str , file : File ):
47
+ duplex = cls (identifier , file )
48
+ cls .instances [identifier ] = duplex
49
+ return duplex
50
+
51
+ @classmethod
52
+ def create_duplex_ws (cls , identifier : str , name : str , size : int , type : str ):
53
+ file = File (name = name , size = size , content_type = type )
54
+ duplex = cls (identifier , file )
41
55
cls .instances [identifier ] = duplex
42
56
return duplex
43
57
44
58
@classmethod
45
- def from_identifer (cls , identifier : str ):
59
+ def get (cls , identifier : str ):
46
60
if duplex := cls .instances .get (identifier ):
47
61
return duplex
48
62
else :
49
63
raise KeyError (f"Duplex '{ identifier } ' not found." )
50
64
51
65
def get_file_info (self ):
52
66
return self .file .name , self .file .size , self .file .content_type
67
+
68
+ async def wait_for_empty_queue (self , seconds = 600 ):
69
+ while not self .queue .empty () and seconds > 0 :
70
+ await asyncio .sleep (1 )
71
+ seconds -= 1
53
72
54
- async def transfer (self ):
73
+ async def transfer (self , stream ):
55
74
bytes_read = 0
56
75
57
- async for chunk in self . stream () :
76
+ async for chunk in stream :
58
77
bytes_read += len (chunk )
59
78
await self .queue .put (chunk )
60
79
61
80
await self .queue .put (None )
62
-
63
- while not self .queue .empty ():
64
- await asyncio .sleep (0.5 )
81
+ await self .wait_for_empty_queue ()
82
+ return bytes_read
65
83
66
84
async def receive (self ):
67
85
while True :
0 commit comments