File size: 3,849 Bytes
3205dff
a460fdc
 
3205dff
146248c
 
 
059bbb9
0b67e3c
146248c
 
a71ce8a
146248c
3205dff
146248c
 
 
 
 
 
a71ce8a
146248c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
059bbb9
146248c
33f8f7c
3205dff
 
 
 
 
146248c
 
 
 
 
a71ce8a
 
 
146248c
3205dff
 
 
146248c
3205dff
146248c
 
 
 
3205dff
 
146248c
3205dff
146248c
a71ce8a
146248c
 
 
 
 
 
 
3205dff
 
 
 
 
 
146248c
 
 
 
 
 
a71ce8a
3205dff
 
a71ce8a
3205dff
 
146248c
 
3205dff
a71ce8a
 
 
146248c
a71ce8a
059bbb9
146248c
 
 
 
 
 
 
 
3205dff
0b67e3c
a460fdc
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
from flask import Flask, request, jsonify, Response
import random
import string
import os
import threading
import time
from pathlib import Path

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'temp_uploads'
Path(app.config['UPLOAD_FOLDER']).mkdir(exist_ok=True)

# Конфигурация памяти
MAX_MEMORY = 12 * 1024 * 1024 * 1024  # 12 GB
CHUNK_SIZE = 100 * 1024 * 1024  # 4 MB
MAX_FILE_SIZE = 20 * 1024 * 1024 * 1024  # 20 GB

transfers = {}
active_memory = 0
lock = threading.Lock()

class TransferManager:
    def __init__(self):
        self.transfers = {}
        self.file_locks = {}
    
    def create_transfer(self, filename, filesize):
        if filesize > MAX_FILE_SIZE:
            raise ValueError("File size exceeds maximum limit")
            
        transfer_id = ''.join(random.choices(string.ascii_letters + string.digits, k=16))
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], transfer_id)
        
        with lock:
            self.transfers[transfer_id] = {
                'filename': filename,
                'filesize': filesize,
                'received': 0,
                'file_path': file_path,
                'created_at': time.time(),
                'status': 'uploading'
            }
            self.file_locks[transfer_id] = threading.Lock()
        
        return transfer_id

manager = TransferManager()

@app.route('/init_upload', methods=['POST'])
def init_upload():
    filename = request.json.get('filename')
    filesize = request.json.get('filesize')
    
    try:
        transfer_id = manager.create_transfer(filename, filesize)
        return jsonify({'transfer_id': transfer_id})
    except Exception as e:
        return jsonify({'error': str(e)}), 400

@app.route('/upload/<transfer_id>', methods=['POST'])
def upload_chunk(transfer_id):
    if transfer_id not in manager.transfers:
        return jsonify({'error': 'Invalid transfer ID'}), 404
    
    chunk = request.data
    chunk_size = len(chunk)
    
    with lock:
        transfer = manager.transfers[transfer_id]
        if transfer['status'] != 'uploading':
            return jsonify({'error': 'Transfer completed'}), 400
    
    try:
        with manager.file_locks[transfer_id], open(transfer['file_path'], 'ab') as f:
            f.write(chunk)
            transfer['received'] += chunk_size
        
        if transfer['received'] >= transfer['filesize']:
            transfer['status'] = 'ready'
        
        return jsonify({
            'received': transfer['received'],
            'status': transfer['status']
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/download/<transfer_id>', methods=['GET'])
def download_file(transfer_id):
    def generate():
        file_path = manager.transfers.get(transfer_id, {}).get('file_path')
        if not file_path or not os.path.exists(file_path):
            yield b'File not found'
            return

        with open(file_path, 'rb') as f:
            while True:
                chunk = f.read(CHUNK_SIZE)
                if not chunk:
                    break
                yield chunk
        
        # Автоочистка через 1 час
        threading.Timer(3600, cleanup_transfer, args=[transfer_id]).start()
    
    return Response(
        generate(),
        mimetype='application/octet-stream',
        headers={'Content-Disposition': f'attachment; filename="{manager.transfers[transfer_id]["filename"]}"'}
    )

def cleanup_transfer(transfer_id):
    with lock:
        if transfer_id in manager.transfers:
            try:
                os.remove(manager.transfers[transfer_id]['file_path'])
            except:
                pass
            del manager.transfers[transfer_id]

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, threaded=True)