-
Notifications
You must be signed in to change notification settings - Fork 9
/
server_upload.py
159 lines (135 loc) · 4.45 KB
/
server_upload.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from fastapi import (
FastAPI,
HTTPException,
Request,
Response,
status,
)
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from constants import SERVERS
from c_path import Directories
from logs_upload import (
CurrentUploads,
LogsArchive,
UploadChunk,
)
app = FastAPI()
TEMPLATES = Jinja2Templates(directory="templates")
class CurrentUploadsProgress(dict[str, LogsArchive]):
...
CURRENT_UPLOADS = CurrentUploads()
CURRENT_UPLOADS_PROGRESS = CurrentUploadsProgress()
def real_ip(request: Request):
ip = request.client.host
if not ip:
ip = request.headers.get('x-real-ip')
if not ip:
ip = "0.0.0.0"
return ip
def check_upload_id_header(request: Request):
try:
return request.headers['x-upload-id']
except KeyError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="must include [x-upload-id] header with a non empty value",
)
def check_chunk_header(request: Request):
try:
return int(request.headers.get('x-chunk'))
except (TypeError, ValueError):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="must include [x-upload-id] header with an integer of a chunk",
)
@Directories.top.cache_until_new_self
def get_servers(folder):
print(">>>>>>>>>> get_servers")
s = set((
file_path.stem
for file_path in folder.iterdir()
if file_path.suffix == ".db"
))
servers = s - set(SERVERS.values())
return sorted(servers)
@app.get("/upload", response_class=HTMLResponse)
async def upload_get(request: Request):
return TEMPLATES.TemplateResponse(
request=request,
name="upload.html",
context={
"SERVERS": get_servers(),
}
)
@app.post("/upload")
async def upload_post(request: Request, response: Response):
ip = real_ip(request)
current_upload = CURRENT_UPLOADS[ip]
final_piece = request.headers.get('content-type') == 'application/json'
if not final_piece:
data = await request.body()
upload_id = check_upload_id_header(request)
chunk_id = check_chunk_header(request)
chunk = UploadChunk(
data=data,
chunk_id=chunk_id,
upload_id=upload_id,
)
current_upload.add_chunk(chunk)
return None
try:
file_data = await request.json()
except Exception:
file_data = {}
try:
archive = current_upload.save_uploaded_file(file_data)
except ValueError:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="file was corrupted during upload",
)
except OSError:
raise HTTPException(
status.HTTP_507_INSUFFICIENT_STORAGE,
detail="Couldn't complete upload. No disk space left on the server.",
)
archive.start_processing()
CURRENT_UPLOADS_PROGRESS[ip] = archive
response.status_code = status.HTTP_201_CREATED
return None
@app.get("/upload_progress")
async def upload_progress(request: Request, response: Response):
ip = real_ip(request)
uploads_progress = CURRENT_UPLOADS_PROGRESS.get(ip)
if uploads_progress is None:
response.status_code = status.HTTP_204_NO_CONTENT
return
if not uploads_progress.thread.is_alive():
del CURRENT_UPLOADS_PROGRESS[ip]
return uploads_progress.status_dict
if __name__ == "__main__":
# testing without nginx to prevent cors
from fastapi.responses import RedirectResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from h_other import Ports
app.mount("/static", StaticFiles(directory="static"))
@app.get("/")
def root_path():
return RedirectResponse("/upload")
@app.exception_handler(404)
def not_found_exception_handler(request: Request, exc: HTTPException):
if request.scope["root_path"] in ["/cache", "/static", ]:
return Response(
content="Not Found",
status_code=404,
)
_url = str(request.url).replace(f":{Ports.upload}/", f":{Ports.main}/")
return RedirectResponse(
url=_url,
status_code=status.HTTP_307_TEMPORARY_REDIRECT,
)
print("STARTING UPLOAD SERVER")
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=Ports.upload)