Starchik1 commited on
Commit
790f271
·
verified ·
1 Parent(s): 488a8ed

Update server.py

Browse files
Files changed (1) hide show
  1. server.py +98 -0
server.py CHANGED
@@ -5,7 +5,105 @@ import threading
5
  import time
6
  from collections import deque
7
  from datetime import datetime, timedelta
 
 
 
 
 
 
8
  import logging
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  app = Flask(__name__)
11
 
 
5
  import time
6
  from collections import deque
7
  from datetime import datetime, timedelta
8
+ import loggingfrom flask import Flask, request, jsonify, Response
9
+ import random
10
+ import string
11
+ import threading
12
+ import time
13
+ from datetime import datetime, timedelta
14
  import logging
15
+ from gevent import sleep
16
+
17
+ app = Flask(__name__)
18
+
19
+ # Конфигурация
20
+ TRANSFER_LIFETIME = timedelta(hours=6)
21
+ CLEANUP_INTERVAL = 300
22
+ MAX_CHUNK_SIZE = 100 * 1024 * 1024
23
+ KEEP_ALIVE_INTERVAL = 25
24
+ TRANSFER_TIMEOUT = 3600 * 3
25
+ BUFFER_FLUSH_SIZE = 100 * 1024 * 1024 # 10MB
26
+
27
+ # Логирование
28
+ logging.basicConfig(
29
+ level=logging.INFO,
30
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
31
+ )
32
+ logger = logging.getLogger('FileTransfer')
33
+
34
+ # Хранилище данных
35
+ transfers = {}
36
+ transfer_data = {}
37
+ transfer_lock = threading.Lock()
38
+
39
+ def cleanup_task():
40
+ """Фоновая очистка старых передач"""
41
+ while True:
42
+ time.sleep(CLEANUP_INTERVAL)
43
+ with transfer_lock:
44
+ now = datetime.now()
45
+ to_delete = [
46
+ tid for tid, info in transfers.items()
47
+ if info['completed'] and (now - info['completed_time']) > TRANSFER_LIFETIME
48
+ ]
49
+ for tid in to_delete:
50
+ del transfers[tid]
51
+ del transfer_data[tid]
52
+ logger.info(f"Cleaned transfer: {tid}")
53
+
54
+ threading.Thread(target=cleanup_task, daemon=True).start()
55
+
56
+ @app.route('/download/<transfer_id>', methods=['GET'])
57
+ def download_file(transfer_id):
58
+ """Потоковая отдача файла с оптимизацией буферизации"""
59
+ def generate():
60
+ buffer = bytearray()
61
+ last_flush = time.time()
62
+
63
+ try:
64
+ while True:
65
+ with transfer_lock:
66
+ transfer = transfers.get(transfer_id)
67
+ if not transfer or (transfer['completed'] and not transfer_data.get(transfer_id)):
68
+ break
69
+
70
+ chunks = transfer_data.get(transfer_id, [])
71
+ while chunks:
72
+ buffer.extend(chunks.pop(0))
73
+
74
+ # Отправляем буфер при достижении размера или таймаута
75
+ if (len(buffer) >= BUFFER_FLUSH_SIZE or
76
+ (time.time() - last_flush) > KEEP_ALIVE_INTERVAL):
77
+ yield bytes(buffer)
78
+ buffer.clear()
79
+ last_flush = time.time()
80
+
81
+ # Асинхронное ожидание новых данных
82
+ sleep(0.1)
83
+
84
+ # Отправить оставшиеся данные
85
+ if buffer:
86
+ yield bytes(buffer)
87
+
88
+ except Exception as e:
89
+ logger.error(f"Download error: {transfer_id} - {str(e)}")
90
+ finally:
91
+ logger.info(f"Download finished: {transfer_id}")
92
+
93
+ return Response(
94
+ generate(),
95
+ mimetype='application/octet-stream',
96
+ headers={
97
+ 'Content-Disposition': f'attachment; filename="{transfers[transfer_id]["filename"]}"',
98
+ 'Cache-Control': 'no-store'
99
+ }
100
+ )
101
+
102
+ if __name__ == '__main__':
103
+ from gevent.pywsgi import WSGIServer
104
+ logger.info("Starting optimized server...")
105
+ http_server = WSGIServer(('0.0.0.0', 5000), app)
106
+ http_server.serve_forever()
107
 
108
  app = Flask(__name__)
109