Implement PUT chunk uploads, 16MiB chunk size for faster transfers with resilient retries and smoother progress
This commit is contained in:
+38
-4
@@ -1,5 +1,6 @@
|
||||
import asyncio
|
||||
import os
|
||||
import threading
|
||||
|
||||
from cista import config
|
||||
from cista.util import filename
|
||||
@@ -69,6 +70,8 @@ class FileServer:
|
||||
self.alink.to_sync,
|
||||
)
|
||||
self.cache = LRUCache(File, capacity=10, maxage=5.0)
|
||||
self.cache_lock = threading.Lock()
|
||||
self.file_locks: dict[str, threading.Lock] = {}
|
||||
|
||||
async def stop(self):
|
||||
await self.alink.stop()
|
||||
@@ -80,6 +83,8 @@ class FileServer:
|
||||
with req as (command, *args):
|
||||
if command == "upload":
|
||||
req.set_result(self.upload(*args))
|
||||
elif command == "upload_info":
|
||||
req.set_result(self.upload_info(*args))
|
||||
elif command == "download":
|
||||
req.set_result(self.download(*args))
|
||||
else:
|
||||
@@ -87,13 +92,42 @@ class FileServer:
|
||||
finally:
|
||||
self.cache.close()
|
||||
|
||||
@staticmethod
|
||||
def _stat_size(path):
|
||||
try:
|
||||
return os.stat(path).st_size
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
def upload(self, name, pos, data, file_size):
|
||||
name = filename.sanitize(name)
|
||||
f = self.cache[name]
|
||||
f.write(pos, data, file_size=file_size)
|
||||
with self.cache_lock:
|
||||
f = self.cache[name]
|
||||
lock = self.file_locks.setdefault(name, threading.Lock())
|
||||
with lock:
|
||||
f.write(pos, data, file_size=file_size)
|
||||
return len(data)
|
||||
|
||||
def upload_info(self, name, pos, data, file_size):
|
||||
name = filename.sanitize(name)
|
||||
with self.cache_lock:
|
||||
f = self.cache[name]
|
||||
lock = self.file_locks.setdefault(name, threading.Lock())
|
||||
with lock:
|
||||
size_before = self._stat_size(f.path)
|
||||
f.write(pos, data, file_size=file_size)
|
||||
size_after = self._stat_size(f.path)
|
||||
return {
|
||||
"written": len(data),
|
||||
"created": size_before is None,
|
||||
"size_before": size_before,
|
||||
"size_after": size_after,
|
||||
}
|
||||
|
||||
def download(self, name, start, end):
|
||||
name = filename.sanitize(name)
|
||||
f = self.cache[name]
|
||||
return f[start:end]
|
||||
with self.cache_lock:
|
||||
f = self.cache[name]
|
||||
lock = self.file_locks.setdefault(name, threading.Lock())
|
||||
with lock:
|
||||
return f[start:end]
|
||||
|
||||
Reference in New Issue
Block a user