diff --git a/README.md b/README.md index cc90d0be..73e1a542 100644 --- a/README.md +++ b/README.md @@ -1190,6 +1190,9 @@ upload modifiers: |--|--|--| | `Accept: url` | `want=url` | return just the file URL | | `Rand: 4` | `rand=4` | generate random filename with 4 characters | +| `Life: 30` | `life=30` | delete file after 30 seconds | + +`life` only has an effect if the volume has a lifetime, and the volume lifetime must be greater than the file's server behavior of `msg` can be reconfigured with `--urlform` diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 5238b595..8b98d90f 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -720,6 +720,7 @@ class HttpCli(object): # post_sz, sha_hex, sha_b64, remains, path, url reader, remains = self.get_body_reader() vfs, rem = self.asrv.vfs.get(self.vpath, self.uname, False, True) + rnd, want_url, lifetime = self.upload_flags(vfs) lim = vfs.get_dbv(rem)[0].lim fdir = vfs.canonical(rem) if lim: @@ -794,9 +795,8 @@ class HttpCli(object): params.update(open_ka) - srnd = self.uparam.get("rand", self.headers.get("rand", "")) - if srnd and not self.args.nw: - fn = self.rand_name(fdir, fn, int(srnd)) + if rnd and not self.args.nw: + fn = self.rand_name(fdir, fn, rnd) with ren_open(fn, *open_a, **params) as zfw: f, fn = zfw["orz"] @@ -823,7 +823,7 @@ class HttpCli(object): rem, fn, self.ip, - time.time(), + time.time() - lifetime, ) vsuf = "" @@ -863,7 +863,7 @@ class HttpCli(object): self.reply(t.encode("utf-8")) return True - def rand_name(self, fdir: str, fn: str, rnd: int): + def rand_name(self, fdir: str, fn: str, rnd: int) -> str: ok = False try: ext = "." + fn.rsplit(".", 1)[1] @@ -1281,6 +1281,22 @@ class HttpCli(object): self.redirect(vpath, "?edit") return True + def upload_flags(self, vfs: VFS) -> tuple[int, bool, int]: + srnd = self.uparam.get("rand", self.headers.get("rand", "")) + rnd = int(srnd) if srnd and not self.args.nw else 0 + ac = self.uparam.get( + "want", self.headers.get("accept", "").lower().split(";")[-1] + ) + want_url = ac == "url" + zs = self.uparam.get("life", self.headers.get("life", "")) + if zs: + vlife = int(vfs.flags.get("lifetime") or 0) + lifetime = max(0, int(vlife - int(zs))) + else: + lifetime = 0 + + return rnd, want_url, lifetime + def handle_plain_upload(self) -> bool: assert self.parser nullwrite = self.args.nw @@ -1296,12 +1312,7 @@ class HttpCli(object): if not nullwrite: bos.makedirs(fdir_base) - srnd = self.uparam.get("rand", self.headers.get("rand", "")) - rnd = int(srnd) if srnd and not nullwrite else 0 - ac = self.uparam.get( - "want", self.headers.get("accept", "").lower().split(";")[-1] - ) - want_url = ac == "url" + rnd, want_url, lifetime = self.upload_flags(vfs) files: list[tuple[int, str, str, str, str, str]] = [] # sz, sha_hex, sha_b64, p_file, fname, abspath @@ -1393,7 +1404,7 @@ class HttpCli(object): vrem, fname, self.ip, - time.time(), + time.time() - lifetime, ) self.conn.nbyte += sz diff --git a/copyparty/up2k.py b/copyparty/up2k.py index 69cc6e39..e7e72110 100644 --- a/copyparty/up2k.py +++ b/copyparty/up2k.py @@ -265,22 +265,29 @@ class Up2k(object): def _sched_rescan(self) -> None: volage = {} - cooldown = 0.0 - timeout = time.time() + 3 + cooldown = timeout = time.time() + 3.0 while True: + now = time.time() timeout = max(timeout, cooldown) - wait = max(0.1, timeout + 0.1 - time.time()) + wait = timeout - time.time() + # self.log("SR in {:.2f}".format(wait), 5) with self.rescan_cond: self.rescan_cond.wait(wait) now = time.time() if now < cooldown: + # self.log("SR: cd - now = {:.2f}".format(cooldown - now), 5) + timeout = cooldown # wakeup means stuff to do, forget timeout continue if self.pp: + # self.log("SR: pp; cd := 1", 5) cooldown = now + 1 continue + cooldown = now + 5 + # self.log("SR", 5) + if self.args.no_lifetime: timeout = now + 9001 else: @@ -302,7 +309,7 @@ class Up2k(object): timeout = min(timeout, deadline) - if self.db_act > now - self.args.db_act: + if self.db_act > now - self.args.db_act and self.need_rescan: # recent db activity; defer volume rescan act_timeout = self.db_act + self.args.db_act if self.need_rescan: @@ -3073,6 +3080,10 @@ class Up2k(object): with self.mutex: self.idx_wark(ptop, wark, rd, fn, inf.st_mtime, inf.st_size, ip, at) + if at and time.time() - at > 30: + with self.rescan_cond: + self.rescan_cond.notify_all() + def hash_file( self, ptop: str, flags: dict[str, Any], rd: str, fn: str, ip: str, at: float ) -> None: