hook/reloc: fix up2k jank

* wark landed in the wrong registry when moved to another volume
   (harmless; upload would succeed on the next handshake)

* dedup did not apply correctly when moved into another volume,
   since all the checks were done based on the previous vol;
   fix this by recursing the whole thing

also update the reloc example after some real-world experience

Reported-by: @daniiooo
This commit is contained in:
ed 2024-08-15 19:26:06 +00:00
parent 00da74400c
commit c8f4aeaefa
2 changed files with 66 additions and 17 deletions

View file

@ -2,11 +2,12 @@
import json
import os
import re
import sys
_ = r"""
relocate/redirect incoming uploads according to file extension
relocate/redirect incoming uploads according to file extension or name
example usage as global config:
--xbu j,c1,bin/hooks/reloc-by-ext.py
@ -52,11 +53,19 @@ def main():
try:
fn, ext = fn.rsplit(".", 1)
except:
# no file extension; abort
return
# no file extension; pretend it's "bin"
ext = "bin"
ext = ext.lower()
# this function must end by printing the action to perform;
# that's handled by the print(json.dumps(... at the bottom
#
# the action can contain the following keys:
# "vp" is the folder URL to move the upload to,
# "ap" is the filesystem-path to move it to (but "vp" is safer),
# "fn" overrides the final filename to use
##
## some example actions to take; pick one by
## selecting it inside the print at the end:
@ -80,11 +89,37 @@ def main():
elif ext in MUSIC.split():
by_category = {"vp": "/just/tunes"}
else:
by_category = {}
by_category = {} # no action
# now choose the effect to apply; can be any of these:
# now choose the default effect to apply; can be any of these:
# into_subfolder into_toplevel into_sibling by_category
effect = into_subfolder
effect = {"vp": "/junk"}
##
## but we can keep going, adding more speicifc rules
## which can take precedence, replacing the fallback
## effect we just specified:
##
fn = fn.lower() # lowercase filename to make this easier
if "screenshot" in fn:
effect = {"vp": "/ss"}
if "mpv_" in fn:
effect = {"vp": "/anishots"}
elif "debian" in fn or "biebian" in fn:
effect = {"vp": "/linux-ISOs"}
elif re.search(r"ep(isode |\.)?[0-9]", fn):
effect = {"vp": "/podcasts"}
# regex lets you grab a part of the matching
# text and use that in the upload path:
m = re.search(r"\b(op|ed)([^a-z]|$)", fn)
if m:
# the regex matched; use "anime-op" or "anime-ed"
effect = {"vp": "/anime-" + m[1]}
# aaand DO IT
print(json.dumps({"reloc": effect}))

View file

@ -2564,7 +2564,10 @@ class Up2k(object):
return ret
def _handle_json(self, cj: dict[str, Any]) -> dict[str, Any]:
def _handle_json(self, cj: dict[str, Any], depth: int = 1) -> dict[str, Any]:
if depth > 16:
raise Pebkac(500, "too many xbu relocs, giving up")
ptop = cj["ptop"]
if not self.register_vpath(ptop, cj["vcfg"]):
if ptop not in self.registry:
@ -2794,12 +2797,16 @@ class Up2k(object):
if hr.get("reloc"):
x = pathmod(self.asrv.vfs, dst, vp, hr["reloc"])
if x:
zvfs = vfs
pdir, _, job["name"], (vfs, rem) = x
dst = os.path.join(pdir, job["name"])
job["vcfg"] = vfs.flags
job["ptop"] = vfs.realpath
job["vtop"] = vfs.vpath
job["prel"] = rem
bos.makedirs(pdir)
if zvfs.vpath != vfs.vpath:
self.log("xbu reloc %d..." % (depth,), 6)
return self._handle_json(job, depth + 1)
job["name"] = self._untaken(pdir, job, now)
@ -2880,7 +2887,9 @@ class Up2k(object):
lut.add(k)
try:
self._new_upload(job)
ret = self._new_upload(job, vfs, depth)
if ret:
return ret # xbu recursed
except:
self.registry[job["ptop"]].pop(job["wark"], None)
raise
@ -4176,22 +4185,17 @@ class Up2k(object):
return ret
def _new_upload(self, job: dict[str, Any]) -> None:
def _new_upload(self, job: dict[str, Any], vfs: VFS, depth: int) -> dict[str, str]:
pdir = djoin(job["ptop"], job["prel"])
if not job["size"]:
try:
inf = bos.stat(djoin(pdir, job["name"]))
if stat.S_ISREG(inf.st_mode):
job["lmod"] = inf.st_size
return
return {}
except:
pass
self.registry[job["ptop"]][job["wark"]] = job
job["name"] = self._untaken(pdir, job, job["t0"])
# if len(job["name"].split(".")) > 8:
# raise Exception("aaa")
xbu = self.flags[job["ptop"]].get("xbu")
ap_chk = djoin(pdir, job["name"])
vp_chk = djoin(job["vtop"], job["prel"], job["name"])
@ -4220,10 +4224,18 @@ class Up2k(object):
if hr.get("reloc"):
x = pathmod(self.asrv.vfs, ap_chk, vp_chk, hr["reloc"])
if x:
zvfs = vfs
pdir, _, job["name"], (vfs, rem) = x
job["vcfg"] = vfs.flags
job["ptop"] = vfs.realpath
job["vtop"] = vfs.vpath
job["prel"] = rem
if zvfs.vpath != vfs.vpath:
self.log("xbu reloc %d..." % (depth,), 6)
return self._handle_json(job, depth + 1)
job["name"] = self._untaken(pdir, job, job["t0"])
self.registry[job["ptop"]][job["wark"]] = job
tnam = job["name"] + ".PARTIAL"
if self.args.dotpart:
@ -4233,7 +4245,7 @@ class Up2k(object):
job["tnam"] = tnam
if not job["hash"]:
del self.registry[job["ptop"]][job["wark"]]
return
return {}
if self.args.plain_ip:
dip = job["addr"].replace(":", ".")
@ -4293,6 +4305,8 @@ class Up2k(object):
if not job["hash"]:
self._finish_upload(job["ptop"], job["wark"])
return {}
def _snapshot(self) -> None:
slp = self.args.snap_wri
if not slp or self.args.no_snap: