THED2 commited on
Commit
4b737a2
·
verified ·
1 Parent(s): 574870a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +108 -95
app.py CHANGED
@@ -7,6 +7,7 @@ import shutil
7
  import aiohttp
8
  import gc # Memory management ke liye garbage collector
9
  import zipfile # ZIP file handle karne ke liye in-built library
 
10
  from fastapi import FastAPI, BackgroundTasks, Request, File, UploadFile
11
  from fastapi.middleware.cors import CORSMiddleware
12
  from fastapi.responses import FileResponse, StreamingResponse
@@ -57,65 +58,71 @@ async def cleanup_old_files():
57
  async def startup_event():
58
  asyncio.create_task(cleanup_old_files())
59
 
60
- async def download_file(task_id: str, url: str):
 
61
  file_path = tasks[task_id]["file_path"]
62
  try:
63
- # Buffer limit ko strictly small rakha hai taaki RAM leak na ho
64
- connector = aiohttp.TCPConnector(limit=5)
65
- async with aiohttp.ClientSession(connector=connector, read_bufsize=64 * 1024) as session:
66
- async with session.get(url, timeout=None) as response:
67
- response.raise_for_status()
68
- total_size = int(response.headers.get('Content-Length', 0))
69
- tasks[task_id]["total_size"] = total_size
70
-
71
- # Header check for proper filename extraction (.apk, .mp4, etc.)
72
- cd = response.headers.get('Content-Disposition')
73
- if cd and 'filename=' in cd:
74
- fname = re.findall('filename="([^"]+)"', cd)
75
- if not fname:
76
- fname = re.findall('filename=([^;]+)', cd)
77
- if fname:
78
- new_filename = fname[0]
79
- file_path = os.path.join(DATA_DIR, f"{task_id}_{new_filename}")
80
- tasks[task_id]["file_path"] = file_path
81
- tasks[task_id]["original_filename"] = new_filename
82
 
83
- downloaded = 0
84
- start_time = time.time()
85
- last_time = start_time
86
- last_downloaded = 0
87
- chunk_counter = 0
 
 
 
 
 
 
 
 
 
88
 
89
- with open(file_path, 'wb') as f:
90
- async for chunk in response.content.iter_chunked(64 * 1024):
91
- if not chunk:
92
- break
93
- f.write(chunk)
94
- downloaded += len(chunk)
95
- tasks[task_id]["downloaded"] = downloaded
96
-
97
- current_time = time.time()
98
- if current_time - last_time >= 1.0:
99
- speed = (downloaded - last_downloaded) / (current_time - last_time)
100
- tasks[task_id]["speed"] = speed
101
- last_time = current_time
102
- last_downloaded = downloaded
103
-
104
- f.flush()
105
- chunk_counter += 1
106
- if chunk_counter % 10 == 0:
107
- os.fsync(f.fileno())
108
- del chunk
109
- gc.collect() # Strict garbage collection
110
-
111
- tasks[task_id]["status"] = "completed"
112
- tasks[task_id]["speed"] = 0.0
113
  except Exception as e:
114
  tasks[task_id]["status"] = "error"
115
  tasks[task_id]["error"] = str(e)
116
  finally:
117
  gc.collect()
118
 
 
 
 
 
 
119
  @app.post("/start_download")
120
  async def start_download(req: DownloadRequest, background_tasks: BackgroundTasks):
121
  task_id = str(uuid.uuid4())
@@ -171,7 +178,7 @@ async def stream(task_id: str, request: Request):
171
  def file_iterator(start, length):
172
  with open(file_path, "rb") as f:
173
  f.seek(start)
174
- chunk_size = 128 * 1024 # Hugging Face RAM Optimization
175
  while length > 0:
176
  read_size = min(chunk_size, length)
177
  data = f.read(read_size)
@@ -279,54 +286,60 @@ async def file_sender(file_path, chunk_size=64 * 1024):
279
  del chunk
280
  gc.collect()
281
 
282
- async def process_gofile_transfer(task_id: str, url: str):
 
283
  file_path = tasks[task_id]["file_path"]
284
- try:
285
- connector = aiohttp.TCPConnector(limit=5)
286
- async with aiohttp.ClientSession(connector=connector, read_bufsize=64 * 1024) as session:
287
- async with session.get(url, timeout=None) as response:
288
- response.raise_for_status()
289
- total_size = int(response.headers.get('Content-Length', 0))
290
- tasks[task_id]["total_size"] = total_size
291
-
292
- cd = response.headers.get('Content-Disposition')
293
- if cd and 'filename=' in cd:
294
- fname = re.findall('filename="([^"]+)"', cd)
295
- if not fname:
296
- fname = re.findall('filename=([^;]+)', cd)
297
- if fname:
298
- new_filename = fname[0]
299
- file_path = os.path.join(DATA_DIR, f"{task_id}_{new_filename}")
300
- tasks[task_id]["file_path"] = file_path
301
- tasks[task_id]["original_filename"] = new_filename
302
 
303
- downloaded = 0
304
- start_time = time.time()
305
- last_time = start_time
306
- last_downloaded = 0
307
- chunk_counter = 0
308
-
309
- with open(file_path, 'wb') as f:
310
- async for chunk in response.content.iter_chunked(64 * 1024):
311
- if not chunk:
312
- break
313
- f.write(chunk)
314
- downloaded += len(chunk)
315
- tasks[task_id]["downloaded"] = downloaded
316
-
317
- current_time = time.time()
318
- if current_time - last_time >= 1.0:
319
- tasks[task_id]["speed"] = (downloaded - last_downloaded) / (current_time - last_time)
320
- last_time = current_time
321
- last_downloaded = downloaded
322
-
323
- f.flush()
324
- chunk_counter += 1
325
- if chunk_counter % 10 == 0:
326
- os.fsync(f.fileno())
327
- del chunk
328
- gc.collect()
 
 
 
 
 
 
329
 
 
330
  tasks[task_id]["status"] = "uploading_to_gofile"
331
  tasks[task_id]["speed"] = 0.0
332
 
 
7
  import aiohttp
8
  import gc # Memory management ke liye garbage collector
9
  import zipfile # ZIP file handle karne ke liye in-built library
10
+ import urllib3 # Zero-buffer strict low RAM downloding ke liye
11
  from fastapi import FastAPI, BackgroundTasks, Request, File, UploadFile
12
  from fastapi.middleware.cors import CORSMiddleware
13
  from fastapi.responses import FileResponse, StreamingResponse
 
58
  async def startup_event():
59
  asyncio.create_task(cleanup_old_files())
60
 
61
+ def sync_download_worker(task_id: str, url: str):
62
+ """Urllib3 pool se strict raw streaming taaki RAM me cache accumulate na ho"""
63
  file_path = tasks[task_id]["file_path"]
64
  try:
65
+ http = urllib3.PoolManager(block=True, maxsize=1)
66
+ response = http.request('GET', url, preload_content=False, timeout=None)
67
+
68
+ total_size = int(response.headers.get('Content-Length', 0))
69
+ tasks[task_id]["total_size"] = total_size
70
+
71
+ # Proper filename aur extension extraction (.apk wagera)
72
+ cd = response.headers.get('Content-Disposition')
73
+ if cd and 'filename=' in cd:
74
+ fname = re.findall('filename="([^"]+)"', cd)
75
+ if not fname:
76
+ fname = re.findall('filename=([^;]+)', cd)
77
+ if fname:
78
+ new_filename = fname[0]
79
+ file_path = os.path.join(DATA_DIR, f"{task_id}_{new_filename}")
80
+ tasks[task_id]["file_path"] = file_path
81
+ tasks[task_id]["original_filename"] = new_filename
 
 
82
 
83
+ downloaded = 0
84
+ start_time = time.time()
85
+ last_time = start_time
86
+ last_downloaded = 0
87
+ chunk_counter = 0
88
+
89
+ with open(file_path, 'wb') as f:
90
+ # 64KB strict buffer chunking, RAM me data holds hi nahi hoga
91
+ for chunk in response.stream(64 * 1024):
92
+ if not chunk:
93
+ break
94
+ f.write(chunk)
95
+ downloaded += len(chunk)
96
+ tasks[task_id]["downloaded"] = downloaded
97
 
98
+ current_time = time.time()
99
+ if current_time - last_time >= 1.0:
100
+ speed = (downloaded - last_downloaded) / (current_time - last_time)
101
+ tasks[task_id]["speed"] = speed
102
+ last_time = current_time
103
+ last_downloaded = downloaded
104
+
105
+ f.flush()
106
+ chunk_counter += 1
107
+ if chunk_counter % 10 == 0:
108
+ os.fsync(f.fileno())
109
+ del chunk
110
+ gc.collect() # Strict cleanup inside raw sync thread
111
+
112
+ response.release_conn()
113
+ tasks[task_id]["status"] = "completed"
114
+ tasks[task_id]["speed"] = 0.0
 
 
 
 
 
 
 
115
  except Exception as e:
116
  tasks[task_id]["status"] = "error"
117
  tasks[task_id]["error"] = str(e)
118
  finally:
119
  gc.collect()
120
 
121
+ async def download_file(task_id: str, url: str):
122
+ # Loop block bypass karne ke liye execution ko framework thread pool me run karenge
123
+ loop = asyncio.get_event_loop()
124
+ await loop.run_in_executor(None, sync_download_worker, task_id, url)
125
+
126
  @app.post("/start_download")
127
  async def start_download(req: DownloadRequest, background_tasks: BackgroundTasks):
128
  task_id = str(uuid.uuid4())
 
178
  def file_iterator(start, length):
179
  with open(file_path, "rb") as f:
180
  f.seek(start)
181
+ chunk_size = 64 * 1024
182
  while length > 0:
183
  read_size = min(chunk_size, length)
184
  data = f.read(read_size)
 
286
  del chunk
287
  gc.collect()
288
 
289
+ def sync_gofile_download_part(task_id: str, url: str):
290
+ """GoFile processing ke liye bhi same raw low RAM wrapper"""
291
  file_path = tasks[task_id]["file_path"]
292
+ http = urllib3.PoolManager(block=True, maxsize=1)
293
+ response = http.request('GET', url, preload_content=False, timeout=None)
294
+
295
+ total_size = int(response.headers.get('Content-Length', 0))
296
+ tasks[task_id]["total_size"] = total_size
297
+
298
+ cd = response.headers.get('Content-Disposition')
299
+ if cd and 'filename=' in cd:
300
+ fname = re.findall('filename="([^"]+)"', cd)
301
+ if not fname:
302
+ fname = re.findall('filename=([^;]+)', cd)
303
+ if fname:
304
+ new_filename = fname[0]
305
+ file_path = os.path.join(DATA_DIR, f"{task_id}_{new_filename}")
306
+ tasks[task_id]["file_path"] = file_path
307
+ tasks[task_id]["original_filename"] = new_filename
 
 
308
 
309
+ downloaded = 0
310
+ start_time = time.time()
311
+ last_time = start_time
312
+ last_downloaded = 0
313
+ chunk_counter = 0
314
+
315
+ with open(file_path, 'wb') as f:
316
+ for chunk in response.stream(64 * 1024):
317
+ if not chunk:
318
+ break
319
+ f.write(chunk)
320
+ downloaded += len(chunk)
321
+ tasks[task_id]["downloaded"] = downloaded
322
+
323
+ current_time = time.time()
324
+ if current_time - last_time >= 1.0:
325
+ tasks[task_id]["speed"] = (downloaded - last_downloaded) / (current_time - last_time)
326
+ last_time = current_time
327
+ last_downloaded = downloaded
328
+
329
+ f.flush()
330
+ chunk_counter += 1
331
+ if chunk_counter % 10 == 0:
332
+ os.fsync(f.fileno())
333
+ del chunk
334
+ gc.collect()
335
+ response.release_conn()
336
+
337
+ async def process_gofile_transfer(task_id: str, url: str):
338
+ try:
339
+ loop = asyncio.get_event_loop()
340
+ await loop.run_in_executor(None, sync_gofile_download_part, task_id, url)
341
 
342
+ file_path = tasks[task_id]["file_path"]
343
  tasks[task_id]["status"] = "uploading_to_gofile"
344
  tasks[task_id]["speed"] = 0.0
345