copyparty 1.15.10__py3-none-any.whl → 1.16.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
copyparty/httpcli.py CHANGED
@@ -181,6 +181,7 @@ class HttpCli(object):
181
181
  self.rem = " "
182
182
  self.vpath = " "
183
183
  self.vpaths = " "
184
+ self.dl_id = ""
184
185
  self.gctx = " " # additional context for garda
185
186
  self.trailing_slash = True
186
187
  self.uname = " "
@@ -632,7 +633,7 @@ class HttpCli(object):
632
633
  avn.can_access("", self.uname) if avn else [False] * 8
633
634
  )
634
635
  self.avn = avn
635
- self.vn = vn
636
+ self.vn = vn # note: do not dbv due to walk/zipgen
636
637
  self.rem = rem
637
638
 
638
639
  self.s.settimeout(self.args.s_tbody or None)
@@ -721,6 +722,11 @@ class HttpCli(object):
721
722
  except Pebkac:
722
723
  return False
723
724
 
725
+ finally:
726
+ if self.dl_id:
727
+ self.conn.hsrv.dli.pop(self.dl_id, None)
728
+ self.conn.hsrv.dls.pop(self.dl_id, None)
729
+
724
730
  def dip(self) :
725
731
  if self.args.plain_ip:
726
732
  return self.ip.replace(":", ".")
@@ -1191,6 +1197,9 @@ class HttpCli(object):
1191
1197
  if "move" in self.uparam:
1192
1198
  return self.handle_mv()
1193
1199
 
1200
+ if "copy" in self.uparam:
1201
+ return self.handle_cp()
1202
+
1194
1203
  if not self.vpath and self.ouparam:
1195
1204
  if "reload" in self.uparam:
1196
1205
  return self.handle_reload()
@@ -1210,6 +1219,9 @@ class HttpCli(object):
1210
1219
  if "shares" in self.uparam:
1211
1220
  return self.tx_shares()
1212
1221
 
1222
+ if "dls" in self.uparam:
1223
+ return self.tx_dls()
1224
+
1213
1225
  if "h" in self.uparam:
1214
1226
  return self.tx_mounts()
1215
1227
 
@@ -1445,6 +1457,7 @@ class HttpCli(object):
1445
1457
  not self.args.no_scandir,
1446
1458
  [[True, False]],
1447
1459
  lstat="davrt" not in vn.flags,
1460
+ throw=True,
1448
1461
  )
1449
1462
  if not self.can_read:
1450
1463
  vfs_ls = []
@@ -1782,6 +1795,9 @@ class HttpCli(object):
1782
1795
  if "move" in self.uparam:
1783
1796
  return self.handle_mv()
1784
1797
 
1798
+ if "copy" in self.uparam:
1799
+ return self.handle_cp()
1800
+
1785
1801
  if "delete" in self.uparam:
1786
1802
  return self.handle_rm([])
1787
1803
 
@@ -3665,6 +3681,8 @@ class HttpCli(object):
3665
3681
  self.args.s_wr_sz,
3666
3682
  self.args.s_wr_slp,
3667
3683
  not self.args.no_poll,
3684
+ {},
3685
+ "",
3668
3686
  )
3669
3687
  res.close()
3670
3688
 
@@ -3879,6 +3897,19 @@ class HttpCli(object):
3879
3897
  self.send_headers(length=upper - lower, status=status, mime=mime)
3880
3898
  return True
3881
3899
 
3900
+ dls = self.conn.hsrv.dls
3901
+ if upper - lower > 0x400000: # 4m
3902
+ now = time.time()
3903
+ self.dl_id = "%s:%s" % (self.ip, self.addr[1])
3904
+ dls[self.dl_id] = (now, 0)
3905
+ self.conn.hsrv.dli[self.dl_id] = (
3906
+ now,
3907
+ upper - lower,
3908
+ self.vn,
3909
+ self.vpath,
3910
+ self.uname,
3911
+ )
3912
+
3882
3913
  if ptop is not None:
3883
3914
  return self.tx_pipe(
3884
3915
  ptop, req_path, ap_data, job, lower, upper, status, mime, logmsg
@@ -3898,6 +3929,8 @@ class HttpCli(object):
3898
3929
  self.args.s_wr_sz,
3899
3930
  self.args.s_wr_slp,
3900
3931
  not self.args.no_poll,
3932
+ dls,
3933
+ self.dl_id,
3901
3934
  )
3902
3935
 
3903
3936
  if remains > 0:
@@ -4048,6 +4081,8 @@ class HttpCli(object):
4048
4081
  wr_sz,
4049
4082
  wr_slp,
4050
4083
  not self.args.no_poll,
4084
+ self.conn.hsrv.dls,
4085
+ self.dl_id,
4051
4086
  )
4052
4087
 
4053
4088
  spd = self._spd((upper - lower) - remains)
@@ -4133,6 +4168,18 @@ class HttpCli(object):
4133
4168
  self.log("transcoding to [{}]".format(cfmt))
4134
4169
  fgen = gfilter(fgen, self.thumbcli, self.uname, vpath, cfmt)
4135
4170
 
4171
+ now = time.time()
4172
+ self.dl_id = "%s:%s" % (self.ip, self.addr[1])
4173
+ self.conn.hsrv.dli[self.dl_id] = (
4174
+ now,
4175
+ 0,
4176
+ self.vn,
4177
+ "%s :%s" % (self.vpath, ext),
4178
+ self.uname,
4179
+ )
4180
+ dls = self.conn.hsrv.dls
4181
+ dls[self.dl_id] = (time.time(), 0)
4182
+
4136
4183
  bgen = packer(
4137
4184
  self.log,
4138
4185
  self.asrv,
@@ -4141,6 +4188,7 @@ class HttpCli(object):
4141
4188
  pre_crc="crc" in uarg,
4142
4189
  cmp=uarg if cancmp or uarg == "pax" else "",
4143
4190
  )
4191
+ n = 0
4144
4192
  bsent = 0
4145
4193
  for buf in bgen.gen():
4146
4194
  if not buf:
@@ -4154,6 +4202,11 @@ class HttpCli(object):
4154
4202
  bgen.stop()
4155
4203
  break
4156
4204
 
4205
+ n += 1
4206
+ if n >= 4:
4207
+ n = 0
4208
+ dls[self.dl_id] = (time.time(), bsent)
4209
+
4157
4210
  spd = self._spd(bsent)
4158
4211
  self.log("{}, {}".format(logmsg, spd))
4159
4212
  return True
@@ -4410,6 +4463,32 @@ class HttpCli(object):
4410
4463
  }
4411
4464
 
4412
4465
 
4466
+ dls = dl_list = []
4467
+ if self.conn.hsrv.tdls:
4468
+ zi = self.args.dl_list
4469
+ if zi == 2 or (zi == 1 and self.avol):
4470
+ dl_list = self.get_dls()
4471
+ for t0, t1, sent, sz, vp, dl_id, uname in dl_list:
4472
+ rem = sz - sent
4473
+ td = max(0.1, now - t0)
4474
+ rd, fn = vsplit(vp)
4475
+ if not rd:
4476
+ rd = "/"
4477
+ erd = quotep(rd)
4478
+ rds = rd.replace("/", " / ")
4479
+ spd = humansize(sent / td, True) + "/s"
4480
+ hsent = humansize(sent, True)
4481
+ idle = s2hms(now - t1, True)
4482
+ usr = "%s @%s" % (dl_id, uname) if dl_id else uname
4483
+ if sz and sent and td:
4484
+ eta = s2hms((sz - sent) / (sent / td), True)
4485
+ perc = int(100 * sent / sz)
4486
+ else:
4487
+ eta = perc = "--"
4488
+
4489
+ fn = html_escape(fn) if fn else self.conn.hsrv.iiam
4490
+ dls.append((perc, hsent, spd, eta, idle, usr, erd, rds, fn))
4491
+
4413
4492
  fmt = self.uparam.get("ls", "")
4414
4493
  if not fmt and (self.ua.startswith("curl/") or self.ua.startswith("fetch")):
4415
4494
  fmt = "v"
@@ -4431,6 +4510,12 @@ class HttpCli(object):
4431
4510
  txt += "\n%s" % (", ".join((str(x) for x in zt)),)
4432
4511
  txt += "\n"
4433
4512
 
4513
+ if dls:
4514
+ txt += "\n\nactive downloads:"
4515
+ for zt in dls:
4516
+ txt += "\n%s" % (", ".join((str(x) for x in zt)),)
4517
+ txt += "\n"
4518
+
4434
4519
  if rvol:
4435
4520
  txt += "\nyou can browse:"
4436
4521
  for v in rvol:
@@ -4454,6 +4539,7 @@ class HttpCli(object):
4454
4539
  avol=avol,
4455
4540
  in_shr=self.args.shr and self.vpath.startswith(self.args.shr1),
4456
4541
  vstate=vstate,
4542
+ dls=dls,
4457
4543
  ups=ups,
4458
4544
  scanning=vs["scanning"],
4459
4545
  hashq=vs["hashq"],
@@ -4516,8 +4602,14 @@ class HttpCli(object):
4516
4602
 
4517
4603
  t = t.format(self.args.SR)
4518
4604
  qv = quotep(self.vpaths) + self.ourlq()
4519
- in_shr = self.args.shr and self.vpath.startswith(self.args.shr1)
4520
- html = self.j2s("splash", this=self, qvpath=qv, in_shr=in_shr, msg=t)
4605
+ html = self.j2s(
4606
+ "splash",
4607
+ this=self,
4608
+ qvpath=qv,
4609
+ msg=t,
4610
+ in_shr=self.args.shr and self.vpath.startswith(self.args.shr1),
4611
+ ahttps="" if self.is_https else "https://" + self.host + self.req,
4612
+ )
4521
4613
  self.reply(html.encode("utf-8"), status=rc)
4522
4614
  return True
4523
4615
 
@@ -4565,7 +4657,7 @@ class HttpCli(object):
4565
4657
  if self.args.no_reload:
4566
4658
  raise Pebkac(403, "the reload feature is disabled in server config")
4567
4659
 
4568
- x = self.conn.hsrv.broker.ask("reload")
4660
+ x = self.conn.hsrv.broker.ask("reload", True, True)
4569
4661
  return self.redirect("", "?h", x.get(), "return to", False)
4570
4662
 
4571
4663
  def tx_stack(self) :
@@ -4668,6 +4760,40 @@ class HttpCli(object):
4668
4760
  ret["a"] = dirs
4669
4761
  return ret
4670
4762
 
4763
+ def get_dls(self) :
4764
+ ret = []
4765
+ dls = self.conn.hsrv.tdls
4766
+ for dl_id, (t0, sz, vn, vp, uname) in self.conn.hsrv.tdli.items():
4767
+ t1, sent = dls[dl_id]
4768
+ if sent > 0x100000: # 1m; buffers 2~4
4769
+ sent -= 0x100000
4770
+ if self.uname not in vn.axs.uread:
4771
+ vp = ""
4772
+ elif self.uname not in vn.axs.udot and (vp.startswith(".") or "/." in vp):
4773
+ vp = ""
4774
+ if self.uname not in vn.axs.uadmin:
4775
+ dl_id = uname = ""
4776
+
4777
+ ret.append([t0, t1, sent, sz, vp, dl_id, uname])
4778
+ return ret
4779
+
4780
+ def tx_dls(self) :
4781
+ ret = [
4782
+ {
4783
+ "t0": x[0],
4784
+ "t1": x[1],
4785
+ "sent": x[2],
4786
+ "size": x[3],
4787
+ "path": x[4],
4788
+ "conn": x[5],
4789
+ "uname": x[6],
4790
+ }
4791
+ for x in self.get_dls()
4792
+ ]
4793
+ zs = json.dumps(ret, separators=(",\n", ": "))
4794
+ self.reply(zs.encode("utf-8", "replace"), mime="application/json")
4795
+ return True
4796
+
4671
4797
  def tx_ups(self) :
4672
4798
  idx = self.conn.get_u2idx()
4673
4799
  if not idx or not hasattr(idx, "p_end"):
@@ -4852,7 +4978,7 @@ class HttpCli(object):
4852
4978
 
4853
4979
  cur.connection.commit()
4854
4980
  if reload:
4855
- self.conn.hsrv.broker.ask("_reload_blocking", False, False).get()
4981
+ self.conn.hsrv.broker.ask("reload", False, False).get()
4856
4982
  self.conn.hsrv.broker.ask("up2k.wake_rescanner").get()
4857
4983
 
4858
4984
  self.redirect(self.args.SRS + "?shares")
@@ -4943,7 +5069,7 @@ class HttpCli(object):
4943
5069
  cur.execute(q, (skey, fn))
4944
5070
 
4945
5071
  cur.connection.commit()
4946
- self.conn.hsrv.broker.ask("_reload_blocking", False, False).get()
5072
+ self.conn.hsrv.broker.ask("reload", False, False).get()
4947
5073
  self.conn.hsrv.broker.ask("up2k.wake_rescanner").get()
4948
5074
 
4949
5075
  fn = quotep(fns[0]) if len(fns) == 1 else ""
@@ -4994,16 +5120,39 @@ class HttpCli(object):
4994
5120
  return self._mv(self.vpath, dst.lstrip("/"))
4995
5121
 
4996
5122
  def _mv(self, vsrc , vdst ) :
4997
- if not self.can_move:
4998
- raise Pebkac(403, "not allowed for user " + self.uname)
4999
-
5000
5123
  if self.args.no_mv:
5001
5124
  raise Pebkac(403, "the rename/move feature is disabled in server config")
5002
5125
 
5126
+ self.asrv.vfs.get(vsrc, self.uname, True, False, True)
5127
+ self.asrv.vfs.get(vdst, self.uname, False, True)
5128
+
5003
5129
  x = self.conn.hsrv.broker.ask("up2k.handle_mv", self.uname, self.ip, vsrc, vdst)
5004
5130
  self.loud_reply(x.get(), status=201)
5005
5131
  return True
5006
5132
 
5133
+ def handle_cp(self) :
5134
+ # full path of new loc (incl filename)
5135
+ dst = self.uparam.get("copy")
5136
+
5137
+ if self.is_vproxied and dst and dst.startswith(self.args.SR):
5138
+ dst = dst[len(self.args.RS) :]
5139
+
5140
+ if not dst:
5141
+ raise Pebkac(400, "need dst vpath")
5142
+
5143
+ return self._cp(self.vpath, dst.lstrip("/"))
5144
+
5145
+ def _cp(self, vsrc , vdst ) :
5146
+ if self.args.no_cp:
5147
+ raise Pebkac(403, "the copy feature is disabled in server config")
5148
+
5149
+ self.asrv.vfs.get(vsrc, self.uname, True, False)
5150
+ self.asrv.vfs.get(vdst, self.uname, False, True)
5151
+
5152
+ x = self.conn.hsrv.broker.ask("up2k.handle_cp", self.uname, self.ip, vsrc, vdst)
5153
+ self.loud_reply(x.get(), status=201)
5154
+ return True
5155
+
5007
5156
  def tx_ls(self, ls ) :
5008
5157
  dirs = ls["dirs"]
5009
5158
  files = ls["files"]
@@ -5433,6 +5582,7 @@ class HttpCli(object):
5433
5582
  not self.args.no_scandir,
5434
5583
  [[True, False], [False, True]],
5435
5584
  lstat="lt" in self.uparam,
5585
+ throw=True,
5436
5586
  )
5437
5587
  stats = {k: v for k, v in vfs_ls}
5438
5588
  ls_names = [x[0] for x in vfs_ls]
copyparty/httpsrv.py CHANGED
@@ -81,6 +81,7 @@ from .util import (
81
81
  )
82
82
 
83
83
  if TYPE_CHECKING:
84
+ from .authsrv import VFS
84
85
  from .broker_util import BrokerCli
85
86
  from .ssdp import SSDPr
86
87
 
@@ -127,6 +128,12 @@ class HttpSrv(object):
127
128
  self.bans = {}
128
129
  self.aclose = {}
129
130
 
131
+ dli = {} # info
132
+ dls = {} # state
133
+ self.dli = self.tdli = dli
134
+ self.dls = self.tdls = dls
135
+ self.iiam = '<img src="%s.cpr/iiam.gif" />' % (self.args.SRS,)
136
+
130
137
  self.bound = set()
131
138
  self.name = "hsrv" + nsuf
132
139
  self.mutex = threading.Lock()
@@ -201,6 +208,9 @@ class HttpSrv(object):
201
208
  self.start_threads(4)
202
209
 
203
210
  if nid:
211
+ self.tdli = {}
212
+ self.tdls = {}
213
+
204
214
  if self.args.stackmon:
205
215
  start_stackmon(self.args.stackmon, nid)
206
216
 
@@ -573,3 +583,32 @@ class HttpSrv(object):
573
583
  ident += "a"
574
584
 
575
585
  self.u2idx_free[ident] = u2idx
586
+
587
+ def read_dls(
588
+ self,
589
+ ):
590
+
591
+
592
+ """
593
+ mp-broker asking for local dl-info + dl-state;
594
+ reduce overhead by sending just the vfs vpath
595
+ """
596
+ dli = {k: (a, b, c.vpath, d, e) for k, (a, b, c, d, e) in self.dli.items()}
597
+ return (dli, self.dls)
598
+
599
+ def write_dls(
600
+ self,
601
+ sdli ,
602
+ dls ,
603
+ ) :
604
+ """
605
+ mp-broker pushing total dl-info + dl-state;
606
+ swap out the vfs vpath with the vfs node
607
+ """
608
+ dli = {}
609
+ for k, (a, b, c, d, e) in sdli.items():
610
+ vn = self.asrv.vfs.all_nodes[c]
611
+ dli[k] = (a, b, vn, d, e)
612
+
613
+ self.tdli = dli
614
+ self.tdls = dls
copyparty/metrics.py CHANGED
@@ -72,6 +72,9 @@ class Metrics(object):
72
72
  v = "{:.3f}".format(self.hsrv.t0)
73
73
  addug("cpp_boot_unixtime", "seconds", v, t)
74
74
 
75
+ t = "number of active downloads"
76
+ addg("cpp_active_dl", str(len(self.hsrv.tdls)), t)
77
+
75
78
  t = "number of open http(s) client connections"
76
79
  addg("cpp_http_conns", str(self.hsrv.ncli), t)
77
80
 
copyparty/mtag.py CHANGED
@@ -4,6 +4,7 @@ from __future__ import print_function, unicode_literals
4
4
  import argparse
5
5
  import json
6
6
  import os
7
+ import re
7
8
  import shutil
8
9
  import subprocess as sp
9
10
  import sys
@@ -56,6 +57,9 @@ def have_ff(scmd ) :
56
57
  HAVE_FFMPEG = not os.environ.get("PRTY_NO_FFMPEG") and have_ff("ffmpeg")
57
58
  HAVE_FFPROBE = not os.environ.get("PRTY_NO_FFPROBE") and have_ff("ffprobe")
58
59
 
60
+ CBZ_PICS = set("png jpg jpeg gif bmp tga tif tiff webp avif".split())
61
+ CBZ_01 = re.compile(r"(^|[^0-9v])0+[01]\b")
62
+
59
63
 
60
64
  class MParser(object):
61
65
  def __init__(self, cmdline ) :
@@ -120,6 +124,7 @@ def au_unpk(
120
124
  log , fmt_map , abspath , vn = None
121
125
  ) :
122
126
  ret = ""
127
+ maxsz = 1024 * 1024 * 64
123
128
  try:
124
129
  ext = abspath.split(".")[-1].lower()
125
130
  au, pk = fmt_map[ext].split(".")
@@ -142,17 +147,41 @@ def au_unpk(
142
147
  zf = zipfile.ZipFile(abspath, "r")
143
148
  zil = zf.infolist()
144
149
  zil = [x for x in zil if x.filename.lower().split(".")[-1] == au]
150
+ if not zil:
151
+ raise Exception("no audio inside zip")
145
152
  fi = zf.open(zil[0])
146
153
 
154
+ elif pk == "cbz":
155
+ import zipfile
156
+
157
+ zf = zipfile.ZipFile(abspath, "r")
158
+ znil = [(x.filename.lower(), x) for x in zf.infolist()]
159
+ nf = len(znil)
160
+ znil = [x for x in znil if x[0].split(".")[-1] in CBZ_PICS]
161
+ znil = [x for x in znil if "cover" in x[0]] or znil
162
+ znil = [x for x in znil if CBZ_01.search(x[0])] or znil
163
+ t = "cbz: %d files, %d hits" % (nf, len(znil))
164
+ if znil:
165
+ t += ", using " + znil[0][1].filename
166
+ log(t)
167
+ if not znil:
168
+ raise Exception("no images inside cbz")
169
+ fi = zf.open(znil[0][1])
170
+
147
171
  else:
148
172
  raise Exception("unknown compression %s" % (pk,))
149
173
 
174
+ fsz = 0
150
175
  with os.fdopen(fd, "wb") as fo:
151
176
  while True:
152
177
  buf = fi.read(32768)
153
178
  if not buf:
154
179
  break
155
180
 
181
+ fsz += len(buf)
182
+ if fsz > maxsz:
183
+ raise Exception("zipbomb defused")
184
+
156
185
  fo.write(buf)
157
186
 
158
187
  return ret
copyparty/pwhash.py CHANGED
@@ -24,17 +24,13 @@ class PWHash(object):
24
24
  def __init__(self, args ):
25
25
  self.args = args
26
26
 
27
- try:
28
- alg, ac = args.ah_alg.split(",")
29
- except:
30
- alg = args.ah_alg
31
- ac = {}
32
-
27
+ zsl = args.ah_alg.split(",")
28
+ alg = zsl[0]
33
29
  if alg == "none":
34
30
  alg = ""
35
31
 
36
32
  self.alg = alg
37
- self.ac = ac
33
+ self.ac = zsl[1:]
38
34
  if not alg:
39
35
  self.on = False
40
36
  self.hash = unicode
@@ -90,17 +86,23 @@ class PWHash(object):
90
86
  its = 2
91
87
  blksz = 8
92
88
  para = 4
89
+ ramcap = 0 # openssl 1.1 = 32 MiB
93
90
  try:
94
91
  cost = 2 << int(self.ac[0])
95
92
  its = int(self.ac[1])
96
93
  blksz = int(self.ac[2])
97
94
  para = int(self.ac[3])
95
+ ramcap = int(self.ac[4]) * 1024 * 1024
98
96
  except:
99
97
  pass
100
98
 
99
+ cfg = {"salt": self.salt, "n": cost, "r": blksz, "p": para, "dklen": 24}
100
+ if ramcap:
101
+ cfg["maxmem"] = ramcap
102
+
101
103
  ret = plain.encode("utf-8")
102
104
  for _ in range(its):
103
- ret = hashlib.scrypt(ret, salt=self.salt, n=cost, r=blksz, p=para, dklen=24)
105
+ ret = hashlib.scrypt(ret, **cfg)
104
106
 
105
107
  return "+" + base64.urlsafe_b64encode(ret).decode("utf-8")
106
108
 
copyparty/svchub.py CHANGED
@@ -106,7 +106,7 @@ class SvcHub(object):
106
106
  self.stopping = False
107
107
  self.stopped = False
108
108
  self.reload_req = False
109
- self.reloading = 0
109
+ self.reload_mutex = threading.Lock()
110
110
  self.stop_cond = threading.Condition()
111
111
  self.nsigs = 3
112
112
  self.retcode = 0
@@ -205,6 +205,15 @@ class SvcHub(object):
205
205
  t = "WARNING: --s-rd-sz (%d) is larger than --iobuf (%d); this may lead to reduced performance"
206
206
  self.log("root", t % (args.s_rd_sz, args.iobuf), 3)
207
207
 
208
+ zs = ""
209
+ if args.th_ram_max < 0.22:
210
+ zs = "generate thumbnails"
211
+ elif args.th_ram_max < 1:
212
+ zs = "generate audio waveforms or spectrograms"
213
+ if zs:
214
+ t = "WARNING: --th-ram-max is very small (%.2f GiB); will not be able to %s"
215
+ self.log("root", t % (args.th_ram_max, zs), 3)
216
+
208
217
  if args.chpw and args.idp_h_usr:
209
218
  t = "ERROR: user-changeable passwords is incompatible with IdP/identity-providers; you must disable either --chpw or --idp-h-usr"
210
219
  self.log("root", t, 1)
@@ -994,41 +1003,18 @@ class SvcHub(object):
994
1003
  except:
995
1004
  self.log("root", "ssdp startup failed;\n" + min_ex(), 3)
996
1005
 
997
- def reload(self) :
998
- with self.up2k.mutex:
999
- if self.reloading:
1000
- return "cannot reload; already in progress"
1001
- self.reloading = 1
1002
-
1003
- Daemon(self._reload, "reloading")
1004
- return "reload initiated"
1005
-
1006
- def _reload(self, rescan_all_vols = True, up2k = True) :
1007
- with self.up2k.mutex:
1008
- if self.reloading != 1:
1009
- return
1010
- self.reloading = 2
1006
+ def reload(self, rescan_all_vols , up2k ) :
1007
+ t = "config has been reloaded"
1008
+ with self.reload_mutex:
1011
1009
  self.log("root", "reloading config")
1012
1010
  self.asrv.reload(9 if up2k else 4)
1013
1011
  if up2k:
1014
1012
  self.up2k.reload(rescan_all_vols)
1013
+ t += "; volumes are now reinitializing"
1015
1014
  else:
1016
1015
  self.log("root", "reload done")
1017
1016
  self.broker.reload()
1018
- self.reloading = 0
1019
-
1020
- def _reload_blocking(self, rescan_all_vols = True, up2k = True) :
1021
- while True:
1022
- with self.up2k.mutex:
1023
- if self.reloading < 2:
1024
- self.reloading = 1
1025
- break
1026
- time.sleep(0.05)
1027
-
1028
- # try to handle multiple pending IdP reloads at once:
1029
- time.sleep(0.2)
1030
-
1031
- self._reload(rescan_all_vols=rescan_all_vols, up2k=up2k)
1017
+ return t
1032
1018
 
1033
1019
  def _reload_sessions(self) :
1034
1020
  with self.asrv.mutex:
@@ -1042,7 +1028,7 @@ class SvcHub(object):
1042
1028
 
1043
1029
  if self.reload_req:
1044
1030
  self.reload_req = False
1045
- self.reload()
1031
+ self.reload(True, True)
1046
1032
 
1047
1033
  self.shutdown()
1048
1034
 
copyparty/szip.py CHANGED
@@ -94,7 +94,7 @@ def gen_hdr(
94
94
 
95
95
  # spec says to put zeros when !crc if bit3 (streaming)
96
96
  # however infozip does actual sz and it even works on winxp
97
- # (same reasning for z64 extradata later)
97
+ # (same reasoning for z64 extradata later)
98
98
  vsz = 0xFFFFFFFF if z64 else sz
99
99
  ret += spack(b"<LL", vsz, vsz)
100
100
 
copyparty/tcpsrv.py CHANGED
@@ -368,7 +368,7 @@ class TcpSrv(object):
368
368
  if self.args.q:
369
369
  print(msg)
370
370
 
371
- self.hub.broker.say("listen", srv)
371
+ self.hub.broker.say("httpsrv.listen", srv)
372
372
 
373
373
  self.srv = srvs
374
374
  self.bound = bound
@@ -376,7 +376,7 @@ class TcpSrv(object):
376
376
  self._distribute_netdevs()
377
377
 
378
378
  def _distribute_netdevs(self):
379
- self.hub.broker.say("set_netdevs", self.netdevs)
379
+ self.hub.broker.say("httpsrv.set_netdevs", self.netdevs)
380
380
  self.hub.start_zeroconf()
381
381
  gencert(self.log, self.args, self.netdevs)
382
382
  self.hub.restart_ftpd()
copyparty/tftpd.py CHANGED
@@ -266,6 +266,7 @@ class Tftpd(object):
266
266
  "*",
267
267
  not self.args.no_scandir,
268
268
  [[True, False]],
269
+ throw=True,
269
270
  )
270
271
  dnames = set([x[0] for x in vfs_ls if stat.S_ISDIR(x[1].st_mode)])
271
272
  dirs1 = [(v.st_mtime, v.st_size, k + "/") for k, v in vfs_ls if k in dnames]
copyparty/th_srv.py CHANGED
@@ -20,7 +20,6 @@ from .util import (
20
20
  FFMPEG_URL,
21
21
  Cooldown,
22
22
  Daemon,
23
- Pebkac,
24
23
  afsenc,
25
24
  fsenc,
26
25
  min_ex,
@@ -161,6 +160,7 @@ class ThumbSrv(object):
161
160
  self.ram = {}
162
161
  self.memcond = threading.Condition(self.mutex)
163
162
  self.stopping = False
163
+ self.rm_nullthumbs = True # forget failed conversions on startup
164
164
  self.nthr = max(1, self.args.th_mt)
165
165
 
166
166
  self.q = Queue(self.nthr * 4)
@@ -858,7 +858,6 @@ class ThumbSrv(object):
858
858
  def cleaner(self) :
859
859
  interval = self.args.th_clean
860
860
  while True:
861
- time.sleep(interval)
862
861
  ndirs = 0
863
862
  for vol, histpath in self.asrv.vfs.histtab.items():
864
863
  if histpath.startswith(vol):
@@ -872,6 +871,8 @@ class ThumbSrv(object):
872
871
  self.log("\033[Jcln err in %s: %r" % (histpath, ex), 3)
873
872
 
874
873
  self.log("\033[Jcln ok; rm {} dirs".format(ndirs))
874
+ self.rm_nullthumbs = False
875
+ time.sleep(interval)
875
876
 
876
877
  def clean(self, histpath ) :
877
878
  ret = 0
@@ -892,7 +893,9 @@ class ThumbSrv(object):
892
893
  prev_b64 = None
893
894
  prev_fp = ""
894
895
  try:
895
- t1 = statdir(self.log_func, not self.args.no_scandir, False, thumbpath)
896
+ t1 = statdir(
897
+ self.log_func, not self.args.no_scandir, False, thumbpath, False
898
+ )
896
899
  ents = sorted(list(t1))
897
900
  except:
898
901
  return 0
@@ -933,6 +936,10 @@ class ThumbSrv(object):
933
936
 
934
937
  continue
935
938
 
939
+ if self.rm_nullthumbs and not inf.st_size:
940
+ bos.unlink(fp)
941
+ continue
942
+
936
943
  if b64 == prev_b64:
937
944
  self.log("rm replaced [{}]".format(fp))
938
945
  bos.unlink(prev_fp)