copyparty 1.15.10__py3-none-any.whl → 1.16.0__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/__init__.py +1 -0
- copyparty/__main__.py +11 -1
- copyparty/__version__.py +3 -3
- copyparty/authsrv.py +13 -7
- copyparty/broker_mp.py +40 -5
- copyparty/broker_mpw.py +20 -19
- copyparty/broker_thr.py +2 -2
- copyparty/cfg.py +4 -0
- copyparty/ftpd.py +1 -0
- copyparty/httpcli.py +159 -9
- copyparty/httpsrv.py +39 -0
- copyparty/metrics.py +3 -0
- copyparty/svchub.py +16 -30
- copyparty/szip.py +1 -1
- copyparty/tcpsrv.py +2 -2
- copyparty/tftpd.py +1 -0
- copyparty/th_srv.py +10 -3
- copyparty/up2k.py +333 -64
- copyparty/util.py +45 -5
- copyparty/web/a/partyfuse.py +2 -1
- copyparty/web/a/u2c.py +20 -5
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/shares.js.gz +0 -0
- copyparty/web/splash.css.gz +0 -0
- copyparty/web/splash.html +12 -0
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/ui.css.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.15.10.dist-info → copyparty-1.16.0.dist-info}/METADATA +8 -4
- {copyparty-1.15.10.dist-info → copyparty-1.16.0.dist-info}/RECORD +35 -35
- {copyparty-1.15.10.dist-info → copyparty-1.16.0.dist-info}/WHEEL +1 -1
- {copyparty-1.15.10.dist-info → copyparty-1.16.0.dist-info}/LICENSE +0 -0
- {copyparty-1.15.10.dist-info → copyparty-1.16.0.dist-info}/entry_points.txt +0 -0
- {copyparty-1.15.10.dist-info → copyparty-1.16.0.dist-info}/top_level.txt +0 -0
copyparty/__init__.py
CHANGED
copyparty/__main__.py
CHANGED
@@ -50,6 +50,8 @@ from .util import (
|
|
50
50
|
PARTFTPY_VER,
|
51
51
|
PY_DESC,
|
52
52
|
PYFTPD_VER,
|
53
|
+
RAM_AVAIL,
|
54
|
+
RAM_TOTAL,
|
53
55
|
SQLITE_VER,
|
54
56
|
UNPLICATIONS,
|
55
57
|
Daemon,
|
@@ -676,6 +678,8 @@ def get_sects():
|
|
676
678
|
\033[36mxbu\033[35m executes CMD before a file upload starts
|
677
679
|
\033[36mxau\033[35m executes CMD after a file upload finishes
|
678
680
|
\033[36mxiu\033[35m executes CMD after all uploads finish and volume is idle
|
681
|
+
\033[36mxbc\033[35m executes CMD before a file copy
|
682
|
+
\033[36mxac\033[35m executes CMD after a file copy
|
679
683
|
\033[36mxbr\033[35m executes CMD before a file rename/move
|
680
684
|
\033[36mxar\033[35m executes CMD after a file rename/move
|
681
685
|
\033[36mxbd\033[35m executes CMD before a file delete
|
@@ -1193,6 +1197,8 @@ def add_hooks(ap):
|
|
1193
1197
|
ap2.add_argument("--xbu", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file upload starts")
|
1194
1198
|
ap2.add_argument("--xau", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file upload finishes")
|
1195
1199
|
ap2.add_argument("--xiu", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after all uploads finish and volume is idle")
|
1200
|
+
ap2.add_argument("--xbc", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file copy")
|
1201
|
+
ap2.add_argument("--xac", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file copy")
|
1196
1202
|
ap2.add_argument("--xbr", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file move/rename")
|
1197
1203
|
ap2.add_argument("--xar", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m after a file move/rename")
|
1198
1204
|
ap2.add_argument("--xbd", metavar="CMD", type=u, action="append", help="execute \033[33mCMD\033[0m before a file delete")
|
@@ -1225,6 +1231,7 @@ def add_optouts(ap):
|
|
1225
1231
|
ap2.add_argument("--no-dav", action="store_true", help="disable webdav support")
|
1226
1232
|
ap2.add_argument("--no-del", action="store_true", help="disable delete operations")
|
1227
1233
|
ap2.add_argument("--no-mv", action="store_true", help="disable move/rename operations")
|
1234
|
+
ap2.add_argument("--no-cp", action="store_true", help="disable copy operations")
|
1228
1235
|
ap2.add_argument("-nth", action="store_true", help="no title hostname; don't show \033[33m--name\033[0m in <title>")
|
1229
1236
|
ap2.add_argument("-nih", action="store_true", help="no info hostname -- don't show in UI")
|
1230
1237
|
ap2.add_argument("-nid", action="store_true", help="no info disk-usage -- don't show in UI")
|
@@ -1308,9 +1315,12 @@ def add_admin(ap):
|
|
1308
1315
|
ap2.add_argument("--no-reload", action="store_true", help="disable ?reload=cfg (reload users/volumes/volflags from config file)")
|
1309
1316
|
ap2.add_argument("--no-rescan", action="store_true", help="disable ?scan (volume reindexing)")
|
1310
1317
|
ap2.add_argument("--no-stack", action="store_true", help="disable ?stack (list all stacks)")
|
1318
|
+
ap2.add_argument("--dl-list", metavar="LVL", type=int, default=2, help="who can see active downloads in the controlpanel? [\033[32m0\033[0m]=nobody, [\033[32m1\033[0m]=admins, [\033[32m2\033[0m]=everyone")
|
1311
1319
|
|
1312
1320
|
|
1313
1321
|
def add_thumbnail(ap):
|
1322
|
+
th_ram = (RAM_AVAIL or RAM_TOTAL or 9) * 0.6
|
1323
|
+
th_ram = int(max(min(th_ram, 6), 1) * 10) / 10
|
1314
1324
|
ap2 = ap.add_argument_group('thumbnail options')
|
1315
1325
|
ap2.add_argument("--no-thumb", action="store_true", help="disable all thumbnails (volflag=dthumb)")
|
1316
1326
|
ap2.add_argument("--no-vthumb", action="store_true", help="disable video thumbnails (volflag=dvthumb)")
|
@@ -1318,7 +1328,7 @@ def add_thumbnail(ap):
|
|
1318
1328
|
ap2.add_argument("--th-size", metavar="WxH", default="320x256", help="thumbnail res (volflag=thsize)")
|
1319
1329
|
ap2.add_argument("--th-mt", metavar="CORES", type=int, default=CORES, help="num cpu cores to use for generating thumbnails")
|
1320
1330
|
ap2.add_argument("--th-convt", metavar="SEC", type=float, default=60.0, help="conversion timeout in seconds (volflag=convt)")
|
1321
|
-
ap2.add_argument("--th-ram-max", metavar="GB", type=float, default=
|
1331
|
+
ap2.add_argument("--th-ram-max", metavar="GB", type=float, default=th_ram, help="max memory usage (GiB) permitted by thumbnailer; not very accurate")
|
1322
1332
|
ap2.add_argument("--th-crop", metavar="TXT", type=u, default="y", help="crop thumbnails to 4:3 or keep dynamic height; client can override in UI unless force. [\033[32my\033[0m]=crop, [\033[32mn\033[0m]=nocrop, [\033[32mfy\033[0m]=force-y, [\033[32mfn\033[0m]=force-n (volflag=crop)")
|
1323
1333
|
ap2.add_argument("--th-x3", metavar="TXT", type=u, default="n", help="show thumbs at 3x resolution; client can override in UI unless force. [\033[32my\033[0m]=yes, [\033[32mn\033[0m]=no, [\033[32mfy\033[0m]=force-yes, [\033[32mfn\033[0m]=force-no (volflag=th3x)")
|
1324
1334
|
ap2.add_argument("--th-dec", metavar="LIBS", default="vips,pil,ff", help="image decoders, in order of preference")
|
copyparty/__version__.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
VERSION = (1,
|
4
|
-
CODENAME = "
|
5
|
-
BUILD_DT = (2024,
|
3
|
+
VERSION = (1, 16, 0)
|
4
|
+
CODENAME = "COPYparty"
|
5
|
+
BUILD_DT = (2024, 11, 10)
|
6
6
|
|
7
7
|
S_VERSION = ".".join(map(str, VERSION))
|
8
8
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
copyparty/authsrv.py
CHANGED
@@ -584,10 +584,11 @@ class VFS(object):
|
|
584
584
|
scandir ,
|
585
585
|
permsets ,
|
586
586
|
lstat = False,
|
587
|
+
throw = False,
|
587
588
|
) :
|
588
589
|
"""replaces _ls for certain shares (single-file, or file selection)"""
|
589
590
|
vn, rem = self.shr_src # type: ignore
|
590
|
-
abspath, real, _ = vn.ls(rem, "\n", scandir, permsets, lstat)
|
591
|
+
abspath, real, _ = vn.ls(rem, "\n", scandir, permsets, lstat, throw)
|
591
592
|
real = [x for x in real if os.path.basename(x[0]) in self.shr_files]
|
592
593
|
return abspath, real, {}
|
593
594
|
|
@@ -598,11 +599,12 @@ class VFS(object):
|
|
598
599
|
scandir ,
|
599
600
|
permsets ,
|
600
601
|
lstat = False,
|
602
|
+
throw = False,
|
601
603
|
) :
|
602
604
|
"""return user-readable [fsdir,real,virt] items at vpath"""
|
603
605
|
virt_vis = {} # nodes readable by user
|
604
606
|
abspath = self.canonical(rem)
|
605
|
-
real = list(statdir(self.log, scandir, lstat, abspath))
|
607
|
+
real = list(statdir(self.log, scandir, lstat, abspath, throw))
|
606
608
|
real.sort()
|
607
609
|
if not rem:
|
608
610
|
# no vfs nodes in the list of real inodes
|
@@ -664,6 +666,10 @@ class VFS(object):
|
|
664
666
|
"""
|
665
667
|
recursively yields from ./rem;
|
666
668
|
rel is a unix-style user-defined vpath (not vfs-related)
|
669
|
+
|
670
|
+
NOTE: don't invoke this function from a dbv; subvols are only
|
671
|
+
descended into if rem is blank due to the _ls `if not rem:`
|
672
|
+
which intention is to prevent unintended access to subvols
|
667
673
|
"""
|
668
674
|
|
669
675
|
fsroot, vfs_ls, vfs_virt = self.ls(rem, uname, scandir, permsets, lstat=lstat)
|
@@ -904,7 +910,7 @@ class AuthSrv(object):
|
|
904
910
|
self._reload()
|
905
911
|
return True
|
906
912
|
|
907
|
-
broker.ask("
|
913
|
+
broker.ask("reload", False, True).get()
|
908
914
|
return True
|
909
915
|
|
910
916
|
def _map_volume_idp(
|
@@ -1374,7 +1380,7 @@ class AuthSrv(object):
|
|
1374
1380
|
flags[name] = True
|
1375
1381
|
return
|
1376
1382
|
|
1377
|
-
zs = "mtp on403 on404 xbu xau xiu xbr xar xbd xad xm xban"
|
1383
|
+
zs = "mtp on403 on404 xbu xau xiu xbc xac xbr xar xbd xad xm xban"
|
1378
1384
|
if name not in zs.split():
|
1379
1385
|
if value is True:
|
1380
1386
|
t = "└─add volflag [{}] = {} ({})"
|
@@ -1929,7 +1935,7 @@ class AuthSrv(object):
|
|
1929
1935
|
vol.flags[k] = odfusion(getattr(self.args, k), vol.flags[k])
|
1930
1936
|
|
1931
1937
|
# append additive args from argv to volflags
|
1932
|
-
hooks = "xbu xau xiu xbr xar xbd xad xm xban".split()
|
1938
|
+
hooks = "xbu xau xiu xbc xac xbr xar xbd xad xm xban".split()
|
1933
1939
|
for name in "mtp on404 on403".split() + hooks:
|
1934
1940
|
self._read_volflag(vol.flags, name, getattr(self.args, name), True)
|
1935
1941
|
|
@@ -2380,7 +2386,7 @@ class AuthSrv(object):
|
|
2380
2386
|
self._reload()
|
2381
2387
|
return True, "new password OK"
|
2382
2388
|
|
2383
|
-
broker.ask("
|
2389
|
+
broker.ask("reload", False, False).get()
|
2384
2390
|
return True, "new password OK"
|
2385
2391
|
|
2386
2392
|
def setup_chpw(self, acct ) :
|
@@ -2632,7 +2638,7 @@ class AuthSrv(object):
|
|
2632
2638
|
]
|
2633
2639
|
|
2634
2640
|
csv = set("i p th_covers zm_on zm_off zs_on zs_off".split())
|
2635
|
-
zs = "c ihead ohead mtm mtp on403 on404 xad xar xau xiu xban xbd xbr xbu xm"
|
2641
|
+
zs = "c ihead ohead mtm mtp on403 on404 xac xad xar xau xiu xban xbc xbd xbr xbu xm"
|
2636
2642
|
lst = set(zs.split())
|
2637
2643
|
askip = set("a v c vc cgen exp_lg exp_md theme".split())
|
2638
2644
|
fskip = set("exp_lg exp_md mv_re_r mv_re_t rm_re_r rm_re_t".split())
|
copyparty/broker_mp.py
CHANGED
@@ -39,6 +39,9 @@ class BrokerMp(object):
|
|
39
39
|
self.procs = []
|
40
40
|
self.mutex = threading.Lock()
|
41
41
|
|
42
|
+
self.retpend = {}
|
43
|
+
self.retpend_mutex = threading.Lock()
|
44
|
+
|
42
45
|
self.num_workers = self.args.j or CORES
|
43
46
|
self.log("broker", "booting {} subprocesses".format(self.num_workers))
|
44
47
|
for n in range(1, self.num_workers + 1):
|
@@ -50,6 +53,8 @@ class BrokerMp(object):
|
|
50
53
|
self.procs.append(proc)
|
51
54
|
proc.start()
|
52
55
|
|
56
|
+
Daemon(self.periodic, "mp-periodic")
|
57
|
+
|
53
58
|
def shutdown(self) :
|
54
59
|
self.log("broker", "shutting down")
|
55
60
|
for n, proc in enumerate(self.procs):
|
@@ -86,8 +91,10 @@ class BrokerMp(object):
|
|
86
91
|
self.log(*args)
|
87
92
|
|
88
93
|
elif dest == "retq":
|
89
|
-
|
90
|
-
|
94
|
+
with self.retpend_mutex:
|
95
|
+
retq = self.retpend.pop(retq_id)
|
96
|
+
|
97
|
+
retq.put(args[0])
|
91
98
|
|
92
99
|
else:
|
93
100
|
# new ipc invoking managed service in hub
|
@@ -105,7 +112,6 @@ class BrokerMp(object):
|
|
105
112
|
proc.q_pend.put((retq_id, "retq", rv))
|
106
113
|
|
107
114
|
def ask(self, dest , *args ) :
|
108
|
-
|
109
115
|
# new non-ipc invoking managed service in hub
|
110
116
|
obj = self.hub
|
111
117
|
for node in dest.split("."):
|
@@ -117,17 +123,30 @@ class BrokerMp(object):
|
|
117
123
|
retq.put(rv)
|
118
124
|
return retq
|
119
125
|
|
126
|
+
def wask(self, dest , *args ) :
|
127
|
+
# call from hub to workers
|
128
|
+
ret = []
|
129
|
+
for p in self.procs:
|
130
|
+
retq = ExceptionalQueue(1)
|
131
|
+
retq_id = id(retq)
|
132
|
+
with self.retpend_mutex:
|
133
|
+
self.retpend[retq_id] = retq
|
134
|
+
|
135
|
+
p.q_pend.put((retq_id, dest, list(args)))
|
136
|
+
ret.append(retq)
|
137
|
+
return ret
|
138
|
+
|
120
139
|
def say(self, dest , *args ) :
|
121
140
|
"""
|
122
141
|
send message to non-hub component in other process,
|
123
142
|
returns a Queue object which eventually contains the response if want_retval
|
124
143
|
(not-impl here since nothing uses it yet)
|
125
144
|
"""
|
126
|
-
if dest == "listen":
|
145
|
+
if dest == "httpsrv.listen":
|
127
146
|
for p in self.procs:
|
128
147
|
p.q_pend.put((0, dest, [args[0], len(self.procs)]))
|
129
148
|
|
130
|
-
elif dest == "set_netdevs":
|
149
|
+
elif dest == "httpsrv.set_netdevs":
|
131
150
|
for p in self.procs:
|
132
151
|
p.q_pend.put((0, dest, list(args)))
|
133
152
|
|
@@ -136,3 +155,19 @@ class BrokerMp(object):
|
|
136
155
|
|
137
156
|
else:
|
138
157
|
raise Exception("what is " + str(dest))
|
158
|
+
|
159
|
+
def periodic(self) :
|
160
|
+
while True:
|
161
|
+
time.sleep(1)
|
162
|
+
|
163
|
+
tdli = {}
|
164
|
+
tdls = {}
|
165
|
+
qs = self.wask("httpsrv.read_dls")
|
166
|
+
for q in qs:
|
167
|
+
qr = q.get()
|
168
|
+
dli, dls = qr
|
169
|
+
tdli.update(dli)
|
170
|
+
tdls.update(dls)
|
171
|
+
tdl = (tdli, tdls)
|
172
|
+
for p in self.procs:
|
173
|
+
p.q_pend.put((0, "httpsrv.write_dls", tdl))
|
copyparty/broker_mpw.py
CHANGED
@@ -76,37 +76,38 @@ class MpWorker(BrokerCli):
|
|
76
76
|
while True:
|
77
77
|
retq_id, dest, args = self.q_pend.get()
|
78
78
|
|
79
|
-
|
79
|
+
if dest == "retq":
|
80
|
+
# response from previous ipc call
|
81
|
+
with self.retpend_mutex:
|
82
|
+
retq = self.retpend.pop(retq_id)
|
83
|
+
|
84
|
+
retq.put(args)
|
85
|
+
continue
|
86
|
+
|
80
87
|
if dest == "shutdown":
|
81
88
|
self.httpsrv.shutdown()
|
82
89
|
self.logw("ok bye")
|
83
90
|
sys.exit(0)
|
84
91
|
return
|
85
92
|
|
86
|
-
|
93
|
+
if dest == "reload":
|
87
94
|
self.logw("mpw.asrv reloading")
|
88
95
|
self.asrv.reload()
|
89
96
|
self.logw("mpw.asrv reloaded")
|
97
|
+
continue
|
90
98
|
|
91
|
-
|
99
|
+
if dest == "reload_sessions":
|
92
100
|
with self.asrv.mutex:
|
93
101
|
self.asrv.load_sessions()
|
102
|
+
continue
|
94
103
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
elif dest == "set_netdevs":
|
99
|
-
self.httpsrv.set_netdevs(args[0])
|
104
|
+
obj = self
|
105
|
+
for node in dest.split("."):
|
106
|
+
obj = getattr(obj, node)
|
100
107
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
retq = self.retpend.pop(retq_id)
|
105
|
-
|
106
|
-
retq.put(args)
|
107
|
-
|
108
|
-
else:
|
109
|
-
raise Exception("what is " + str(dest))
|
108
|
+
rv = obj(*args) # type: ignore
|
109
|
+
if retq_id:
|
110
|
+
self.say("retq", rv, retq_id=retq_id)
|
110
111
|
|
111
112
|
def ask(self, dest , *args ) :
|
112
113
|
retq = ExceptionalQueue(1)
|
@@ -117,5 +118,5 @@ class MpWorker(BrokerCli):
|
|
117
118
|
self.q_yield.put((retq_id, dest, list(args)))
|
118
119
|
return retq
|
119
120
|
|
120
|
-
def say(self, dest , *args ) :
|
121
|
-
self.q_yield.put((
|
121
|
+
def say(self, dest , *args , retq_id=0) :
|
122
|
+
self.q_yield.put((retq_id, dest, list(args)))
|
copyparty/broker_thr.py
CHANGED
@@ -49,11 +49,11 @@ class BrokerThr(BrokerCli):
|
|
49
49
|
return NotExQueue(obj(*args)) # type: ignore
|
50
50
|
|
51
51
|
def say(self, dest , *args ) :
|
52
|
-
if dest == "listen":
|
52
|
+
if dest == "httpsrv.listen":
|
53
53
|
self.httpsrv.listen(args[0], 1)
|
54
54
|
return
|
55
55
|
|
56
|
-
if dest == "set_netdevs":
|
56
|
+
if dest == "httpsrv.set_netdevs":
|
57
57
|
self.httpsrv.set_netdevs(args[0])
|
58
58
|
return
|
59
59
|
|
copyparty/cfg.py
CHANGED
@@ -103,10 +103,12 @@ def vf_cmap() :
|
|
103
103
|
"mte",
|
104
104
|
"mth",
|
105
105
|
"mtp",
|
106
|
+
"xac",
|
106
107
|
"xad",
|
107
108
|
"xar",
|
108
109
|
"xau",
|
109
110
|
"xban",
|
111
|
+
"xbc",
|
110
112
|
"xbd",
|
111
113
|
"xbr",
|
112
114
|
"xbu",
|
@@ -212,6 +214,8 @@ flagcats = {
|
|
212
214
|
"xbu=CMD": "execute CMD before a file upload starts",
|
213
215
|
"xau=CMD": "execute CMD after a file upload finishes",
|
214
216
|
"xiu=CMD": "execute CMD after all uploads finish and volume is idle",
|
217
|
+
"xbc=CMD": "execute CMD before a file copy",
|
218
|
+
"xac=CMD": "execute CMD after a file copy",
|
215
219
|
"xbr=CMD": "execute CMD before a file rename/move",
|
216
220
|
"xar=CMD": "execute CMD after a file rename/move",
|
217
221
|
"xbd=CMD": "execute CMD before a file delete",
|