copyparty 1.16.7__py3-none-any.whl → 1.16.9__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/util.py CHANGED
@@ -120,6 +120,13 @@ try:
120
120
  except:
121
121
  HAVE_SQLITE3 = False
122
122
 
123
+ try:
124
+ import importlib.util
125
+
126
+ HAVE_ZMQ = bool(importlib.util.find_spec("zmq"))
127
+ except:
128
+ HAVE_ZMQ = False
129
+
123
130
  try:
124
131
  if os.environ.get("PRTY_NO_PSUTIL"):
125
132
  raise Exception()
@@ -208,6 +215,10 @@ META_NOBOTS = '<meta name="robots" content="noindex, nofollow">\n'
208
215
 
209
216
  FFMPEG_URL = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z"
210
217
 
218
+ URL_PRJ = "https://github.com/9001/copyparty"
219
+
220
+ URL_BUG = URL_PRJ + "/issues/new?labels=bug&template=bug_report.md"
221
+
211
222
  HTTPCODE = {
212
223
  200: "OK",
213
224
  201: "Created",
@@ -470,6 +481,15 @@ def py_desc() :
470
481
  )
471
482
 
472
483
 
484
+ def expat_ver() :
485
+ try:
486
+ import pyexpat
487
+
488
+ return ".".join([str(x) for x in pyexpat.version_info])
489
+ except:
490
+ return "?"
491
+
492
+
473
493
  def _sqlite_ver() :
474
494
  try:
475
495
  co = sqlite3.connect(":memory:")
@@ -3297,6 +3317,7 @@ def _parsehook(
3297
3317
 
3298
3318
  def runihook(
3299
3319
  log ,
3320
+ verbose ,
3300
3321
  cmd ,
3301
3322
  vol ,
3302
3323
  ups ,
@@ -3326,6 +3347,17 @@ def runihook(
3326
3347
  else:
3327
3348
  sp_ka["sin"] = b"\n".join(fsenc(x) for x in aps)
3328
3349
 
3350
+ if acmd[0].startswith("zmq:"):
3351
+ try:
3352
+ msg = sp_ka["sin"].decode("utf-8", "replace")
3353
+ _zmq_hook(log, verbose, "xiu", acmd[0][4:].lower(), msg, wait, sp_ka)
3354
+ if verbose and log:
3355
+ log("hook(xiu) %r OK" % (cmd,), 6)
3356
+ except Exception as ex:
3357
+ if log:
3358
+ log("zeromq failed: %r" % (ex,))
3359
+ return True
3360
+
3329
3361
  t0 = time.time()
3330
3362
  if fork:
3331
3363
  Daemon(runcmd, cmd, bcmd, ka=sp_ka)
@@ -3335,15 +3367,118 @@ def runihook(
3335
3367
  retchk(rc, bcmd, err, log, 5)
3336
3368
  return False
3337
3369
 
3338
- wait -= time.time() - t0
3339
- if wait > 0:
3340
- time.sleep(wait)
3370
+ if wait:
3371
+ wait -= time.time() - t0
3372
+ if wait > 0:
3373
+ time.sleep(wait)
3341
3374
 
3342
3375
  return True
3343
3376
 
3344
3377
 
3378
+ ZMQ = {}
3379
+ ZMQ_DESC = {
3380
+ "pub": "fire-and-forget to all/any connected SUB-clients",
3381
+ "push": "fire-and-forget to one of the connected PULL-clients",
3382
+ "req": "send messages to a REP-server and blocking-wait for ack",
3383
+ }
3384
+
3385
+
3386
+ def _zmq_hook(
3387
+ log ,
3388
+ verbose ,
3389
+ src ,
3390
+ cmd ,
3391
+ msg ,
3392
+ wait ,
3393
+ sp_ka ,
3394
+ ) :
3395
+ import zmq
3396
+
3397
+ try:
3398
+ mtx = ZMQ["mtx"]
3399
+ except:
3400
+ ZMQ["mtx"] = threading.Lock()
3401
+ time.sleep(0.1)
3402
+ mtx = ZMQ["mtx"]
3403
+
3404
+ ret = ""
3405
+ t0 = time.time()
3406
+ if verbose and log:
3407
+ log("hook(%s) %r entering zmq-main-lock" % (src, cmd), 6)
3408
+
3409
+ with mtx:
3410
+ try:
3411
+ mode, sck, mtx = ZMQ[cmd]
3412
+ except:
3413
+ mode, uri = cmd.split(":", 1)
3414
+ try:
3415
+ desc = ZMQ_DESC[mode]
3416
+ if log:
3417
+ t = "libzmq(%s) pyzmq(%s) init(%s); %s"
3418
+ log(t % (zmq.zmq_version(), zmq.__version__, cmd, desc))
3419
+ except:
3420
+ raise Exception("the only supported ZMQ modes are REQ PUB PUSH")
3421
+
3422
+ try:
3423
+ ctx = ZMQ["ctx"]
3424
+ except:
3425
+ ctx = ZMQ["ctx"] = zmq.Context()
3426
+
3427
+ timeout = sp_ka["timeout"]
3428
+
3429
+ if mode == "pub":
3430
+ sck = ctx.socket(zmq.PUB)
3431
+ sck.bind(uri)
3432
+ time.sleep(1) # give clients time to connect; avoids losing first msg
3433
+ elif mode == "push":
3434
+ sck = ctx.socket(zmq.PUSH)
3435
+ sck.bind(uri)
3436
+ if timeout:
3437
+ sck.SNDTIMEO = int(timeout * 1000)
3438
+ elif mode == "req":
3439
+ sck = ctx.socket(zmq.REQ)
3440
+ sck.connect(uri)
3441
+ if timeout:
3442
+ sck.RCVTIMEO = int(timeout * 1000)
3443
+ else:
3444
+ raise Exception()
3445
+
3446
+ mtx = threading.Lock()
3447
+ ZMQ[cmd] = (mode, sck, mtx)
3448
+
3449
+ if verbose and log:
3450
+ log("hook(%s) %r entering socket-lock" % (src, cmd), 6)
3451
+
3452
+ with mtx:
3453
+ if verbose and log:
3454
+ log("hook(%s) %r sending |%d|" % (src, cmd, len(msg)), 6)
3455
+
3456
+ sck.send_string(msg) # PUSH can safely timeout here
3457
+
3458
+ if mode == "req":
3459
+ if verbose and log:
3460
+ log("hook(%s) %r awaiting ack from req" % (src, cmd), 6)
3461
+ try:
3462
+ ret = sck.recv().decode("utf-8", "replace")
3463
+ except:
3464
+ sck.close()
3465
+ del ZMQ[cmd] # bad state; must reset
3466
+ raise Exception("ack timeout; zmq socket killed")
3467
+
3468
+ if ret and log:
3469
+ log("hook(%s) %r ACK: %r" % (src, cmd, ret), 6)
3470
+
3471
+ if wait:
3472
+ wait -= time.time() - t0
3473
+ if wait > 0:
3474
+ time.sleep(wait)
3475
+
3476
+ return ret
3477
+
3478
+
3345
3479
  def _runhook(
3346
3480
  log ,
3481
+ verbose ,
3347
3482
  src ,
3348
3483
  cmd ,
3349
3484
  ap ,
@@ -3384,6 +3519,15 @@ def _runhook(
3384
3519
  else:
3385
3520
  arg = txt or ap
3386
3521
 
3522
+ if acmd[0].startswith("zmq:"):
3523
+ zs = "zmq-error"
3524
+ try:
3525
+ zs = _zmq_hook(log, verbose, src, acmd[0][4:].lower(), arg, wait, sp_ka)
3526
+ except Exception as ex:
3527
+ if log:
3528
+ log("zeromq failed: %r" % (ex,))
3529
+ return {"rc": 0, "stdout": zs}
3530
+
3387
3531
  acmd += [arg]
3388
3532
  if acmd[0].endswith(".py"):
3389
3533
  acmd = [pybin] + acmd
@@ -3412,9 +3556,10 @@ def _runhook(
3412
3556
  except:
3413
3557
  ret = {"rc": rc, "stdout": v}
3414
3558
 
3415
- wait -= time.time() - t0
3416
- if wait > 0:
3417
- time.sleep(wait)
3559
+ if wait:
3560
+ wait -= time.time() - t0
3561
+ if wait > 0:
3562
+ time.sleep(wait)
3418
3563
 
3419
3564
  return ret
3420
3565
 
@@ -3437,14 +3582,15 @@ def runhook(
3437
3582
  txt ,
3438
3583
  ) :
3439
3584
  args = (broker or up2k).args
3585
+ verbose = args.hook_v
3440
3586
  vp = vp.replace("\\", "/")
3441
3587
  ret = {"rc": 0}
3442
3588
  for cmd in cmds:
3443
3589
  try:
3444
3590
  hr = _runhook(
3445
- log, src, cmd, ap, vp, host, uname, perms, mt, sz, ip, at, txt
3591
+ log, verbose, src, cmd, ap, vp, host, uname, perms, mt, sz, ip, at, txt
3446
3592
  )
3447
- if log and args.hook_v:
3593
+ if verbose and log:
3448
3594
  log("hook(%s) %r => \033[32m%s" % (src, cmd, hr), 6)
3449
3595
  if not hr:
3450
3596
  return {}
copyparty/web/a/u2c.py CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env python3
2
2
  from __future__ import print_function, unicode_literals
3
3
 
4
- S_VERSION = "2.7"
5
- S_BUILD_DT = "2024-12-06"
4
+ S_VERSION = "2.8"
5
+ S_BUILD_DT = "2025-01-21"
6
6
 
7
7
  """
8
8
  u2c.py: upload to copyparty
@@ -1247,7 +1247,7 @@ class Ctl(object):
1247
1247
  for n, zsii in enumerate(file.cids)
1248
1248
  ]
1249
1249
  print("chs: %s\n%s" % (vp, "\n".join(zsl)))
1250
- zsl = [self.ar.wsalt, str(file.size)] + [x[0] for x in file.kchunks]
1250
+ zsl = [self.ar.wsalt, str(file.size)] + [x[0] for x in file.cids]
1251
1251
  zb = hashlib.sha512("\n".join(zsl).encode("utf-8")).digest()[:33]
1252
1252
  wark = ub64enc(zb).decode("utf-8")
1253
1253
  if self.ar.jw:
Binary file
Binary file
copyparty/web/svcs.html CHANGED
@@ -9,7 +9,7 @@
9
9
  <meta name="theme-color" content="#{{ tcolor }}">
10
10
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}">
11
11
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
12
- <style>ul{padding-left:1.3em}li{margin:.4em 0}</style>
12
+ <style>ul{padding-left:1.3em}li{margin:.4em 0}.txa{float:right;margin:0 0 0 1em}</style>
13
13
  {{ html_head }}
14
14
  </head>
15
15
 
@@ -31,15 +31,22 @@
31
31
  <br />
32
32
  <span class="os win lin mac">placeholders:</span>
33
33
  <span class="os win">
34
- {% if accs %}<code><b>{{ pw }}</b></code>=password, {% endif %}<code><b>W:</b></code>=mountpoint
34
+ {% if accs %}<code><b id="pw0">{{ pw }}</b></code>=password, {% endif %}<code><b>W:</b></code>=mountpoint
35
35
  </span>
36
36
  <span class="os lin mac">
37
- {% if accs %}<code><b>{{ pw }}</b></code>=password, {% endif %}<code><b>mp</b></code>=mountpoint
37
+ {% if accs %}<code><b id="pw0">{{ pw }}</b></code>=password, {% endif %}<code><b>mp</b></code>=mountpoint
38
38
  </span>
39
+ <a href="#" id="setpw">use real password</a>
39
40
  </p>
40
41
 
41
42
 
42
43
 
44
+ {% if args.idp_h_usr %}
45
+ <p style="line-height:2em"><b>WARNING:</b> this server is using IdP-based authentication, so this stuff may not work as advertised. Depending on server config, these commands can probably only be used to access areas which don't require authentication, unless you auth using any non-IdP accounts defined in the copyparty config. Please see <a href="https://github.com/9001/copyparty/blob/hovudstraum/docs/idp.md#connecting-webdav-clients">the IdP docs</a></p>
46
+ {% endif %}
47
+
48
+
49
+
43
50
  {% if not args.no_dav %}
44
51
  <h1>WebDAV</h1>
45
52
 
@@ -229,6 +236,60 @@
229
236
 
230
237
 
231
238
 
239
+ <div class="os win">
240
+ <h1>ShareX</h1>
241
+
242
+ <p>to upload screenshots using ShareX <a href="https://github.com/ShareX/ShareX/releases/tag/v12.1.1">v12</a> or <a href="https://getsharex.com/">v15+</a>, save this as <code>copyparty.sxcu</code> and run it:</p>
243
+
244
+ <pre class="dl" name="copyparty.sxcu">
245
+ { "Name": "copyparty",
246
+ "RequestURL": "http{{ s }}://{{ ep }}/{{ rvp }}",
247
+ "Headers": {
248
+ {% if accs %}"pw": "<b>{{ pw }}</b>",{% endif %}
249
+ "accept": "url"
250
+ },
251
+ "DestinationType": "ImageUploader, TextUploader, FileUploader",
252
+ "FileFormName": "f" }
253
+ </pre>
254
+ </div>
255
+
256
+
257
+
258
+ <div class="os mac">
259
+ <h1>ishare</h1>
260
+
261
+ <p>to upload screenshots using <a href="https://isharemac.app/">ishare</a>, save this as <code>copyparty.iscu</code> and run it:</p>
262
+
263
+ <pre class="dl" name="copyparty.iscu">
264
+ { "Name": "copyparty",
265
+ "RequestURL": "http{{ s }}://{{ ep }}/{{ rvp }}",
266
+ "Headers": {
267
+ {% if accs %}"pw": "<b>{{ pw }}</b>",{% endif %}
268
+ "accept": "json"
269
+ },
270
+ "ResponseURL": "{{ '{{fileurl}}' }}",
271
+ "FileFormName": "f" }
272
+ </pre>
273
+ </div>
274
+
275
+
276
+
277
+ <div class="os lin">
278
+ <h1>flameshot</h1>
279
+
280
+ <p>to upload screenshots using <a href="https://flameshot.org/">flameshot</a>, save this as <code>flameshot.sh</code> and run it:</p>
281
+
282
+ <pre class="dl" name="flameshot.sh">
283
+ #!/bin/bash
284
+ pw="<b>{{ pw }}</b>"
285
+ url="http{{ s }}://{{ ep }}/{{ rvp }}"
286
+ filename="$(date +%Y-%m%d-%H%M%S).png"
287
+ flameshot gui -s -r | curl -sT- "$url$filename?want=url&pw=$pw" | xsel -ib
288
+ </pre>
289
+ </div>
290
+
291
+
292
+
232
293
  </div>
233
294
  <a href="#" id="repl">π</a>
234
295
  <script>
copyparty/web/svcs.js.gz CHANGED
Binary file
copyparty/web/ui.css.gz CHANGED
Binary file
copyparty/web/up2k.js.gz CHANGED
Binary file
copyparty/web/util.js.gz CHANGED
Binary file
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: copyparty
3
- Version: 1.16.7
3
+ Version: 1.16.9
4
4
  Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
5
5
  Author-email: ed <copyparty@ocv.me>
6
6
  License: MIT
@@ -52,6 +52,8 @@ Provides-Extra: tftpd
52
52
  Requires-Dist: partftpy>=0.4.0; extra == "tftpd"
53
53
  Provides-Extra: pwhash
54
54
  Requires-Dist: argon2-cffi; extra == "pwhash"
55
+ Provides-Extra: zeromq
56
+ Requires-Dist: pyzmq; extra == "zeromq"
55
57
 
56
58
  <img src="https://github.com/9001/copyparty/raw/hovudstraum/docs/logo.svg" width="250" align="right"/>
57
59
 
@@ -135,6 +137,7 @@ turn almost any device into a file server with resumable uploads/downloads using
135
137
  * [metadata from audio files](#metadata-from-audio-files) - set `-e2t` to index tags on upload
136
138
  * [file parser plugins](#file-parser-plugins) - provide custom parsers to index additional tags
137
139
  * [event hooks](#event-hooks) - trigger a program on uploads, renames etc ([examples](./bin/hooks/))
140
+ * [zeromq](#zeromq) - event-hooks can send zeromq messages
138
141
  * [upload events](#upload-events) - the older, more powerful approach ([examples](./bin/mtag/))
139
142
  * [handlers](#handlers) - redefine behavior with plugins ([examples](./bin/handlers/))
140
143
  * [ip auth](#ip-auth) - autologin based on IP range (CIDR)
@@ -147,6 +150,7 @@ turn almost any device into a file server with resumable uploads/downloads using
147
150
  * [listen on port 80 and 443](#listen-on-port-80-and-443) - become a *real* webserver
148
151
  * [reverse-proxy](#reverse-proxy) - running copyparty next to other websites
149
152
  * [real-ip](#real-ip) - teaching copyparty how to see client IPs
153
+ * [reverse-proxy performance](#reverse-proxy-performance)
150
154
  * [prometheus](#prometheus) - metrics/stats can be enabled
151
155
  * [other extremely specific features](#other-extremely-specific-features) - you'll never find a use for these
152
156
  * [custom mimetypes](#custom-mimetypes) - change the association of a file extension
@@ -195,6 +199,7 @@ just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/
195
199
  * or if you cannot install python, you can use [copyparty.exe](#copypartyexe) instead
196
200
  * or install [on arch](#arch-package) ╱ [on NixOS](#nixos-module) ╱ [through nix](#nix-package)
197
201
  * or if you are on android, [install copyparty in termux](#install-on-android)
202
+ * or maybe you have a [synology nas / dsm](./docs/synology-dsm.md)
198
203
  * or if your computer is messed up and nothing else works, [try the pyz](#zipapp)
199
204
  * or if you prefer to [use docker](./scripts/docker/) 🐋 you can do that too
200
205
  * docker has all deps built-in, so skip this step:
@@ -668,8 +673,8 @@ select which type of archive you want in the `[⚙️] config` tab:
668
673
  | `pax` | `?tar=pax` | pax-format tar, futureproof, not as fast |
669
674
  | `tgz` | `?tar=gz` | gzip compressed gnu-tar (slow), for `curl \| tar -xvz` |
670
675
  | `txz` | `?tar=xz` | gnu-tar with xz / lzma compression (v.slow) |
671
- | `zip` | `?zip=utf8` | works everywhere, glitchy filenames on win7 and older |
672
- | `zip_dos` | `?zip` | traditional cp437 (no unicode) to fix glitchy filenames |
676
+ | `zip` | `?zip` | works everywhere, glitchy filenames on win7 and older |
677
+ | `zip_dos` | `?zip=dos` | traditional cp437 (no unicode) to fix glitchy filenames |
673
678
  | `zip_crc` | `?zip=crc` | cp437 with crc32 computed early for truly ancient software |
674
679
 
675
680
  * gzip default level is `3` (0=fast, 9=best), change with `?tar=gz:9`
@@ -677,7 +682,7 @@ select which type of archive you want in the `[⚙️] config` tab:
677
682
  * bz2 default level is `2` (1=fast, 9=best), change with `?tar=bz2:9`
678
683
  * hidden files ([dotfiles](#dotfiles)) are excluded unless account is allowed to list them
679
684
  * `up2k.db` and `dir.txt` is always excluded
680
- * bsdtar supports streaming unzipping: `curl foo?zip=utf8 | bsdtar -xv`
685
+ * bsdtar supports streaming unzipping: `curl foo?zip | bsdtar -xv`
681
686
  * good, because copyparty's zip is faster than tar on small files
682
687
  * `zip_crc` will take longer to download since the server has to read each file twice
683
688
  * this is only to support MS-DOS PKZIP v2.04g (october 1993) and older
@@ -701,7 +706,7 @@ dragdrop is the recommended way, but you may also:
701
706
 
702
707
  * select some files (not folders) in your file explorer and press CTRL-V inside the browser window
703
708
  * use the [command-line uploader](https://github.com/9001/copyparty/tree/hovudstraum/bin#u2cpy)
704
- * upload using [curl or sharex](#client-examples)
709
+ * upload using [curl, sharex, ishare, ...](#client-examples)
705
710
 
706
711
  when uploading files through dragdrop or CTRL-V, this initiates an upload using `up2k`; there are two browser-based uploaders available:
707
712
  * `[🎈] bup`, the basic uploader, supports almost every browser since netscape 4.0
@@ -1159,6 +1164,8 @@ on macos, connect from finder:
1159
1164
 
1160
1165
  in order to grant full write-access to webdav clients, the volflag `daw` must be set and the account must also have delete-access (otherwise the client won't be allowed to replace the contents of existing files, which is how webdav works)
1161
1166
 
1167
+ > note: if you have enabled [IdP authentication](#identity-providers) then that may cause issues for some/most webdav clients; see [the webdav section in the IdP docs](https://github.com/9001/copyparty/blob/hovudstraum/docs/idp.md#connecting-webdav-clients)
1168
+
1162
1169
 
1163
1170
  ### connecting to webdav from windows
1164
1171
 
@@ -1509,6 +1516,23 @@ there's a bunch of flags and stuff, see `--help-hooks`
1509
1516
  if you want to write your own hooks, see [devnotes](./docs/devnotes.md#event-hooks)
1510
1517
 
1511
1518
 
1519
+ ### zeromq
1520
+
1521
+ event-hooks can send zeromq messages instead of running programs
1522
+
1523
+ to send a 0mq message every time a file is uploaded,
1524
+
1525
+ * `--xau zmq:pub:tcp://*:5556` sends a PUB to any/all connected SUB clients
1526
+ * `--xau t3,zmq:push:tcp://*:5557` sends a PUSH to exactly one connected PULL client
1527
+ * `--xau t3,j,zmq:req:tcp://localhost:5555` sends a REQ to the connected REP client
1528
+
1529
+ the PUSH and REQ examples have `t3` (timeout after 3 seconds) because they block if there's no clients to talk to
1530
+
1531
+ * the REQ example does `t3,j` to send extended upload-info as json instead of just the filesystem-path
1532
+
1533
+ see [zmq-recv.py](https://github.com/9001/copyparty/blob/hovudstraum/bin/zmq-recv.py) if you need something to receive the messages with
1534
+
1535
+
1512
1536
  ### upload events
1513
1537
 
1514
1538
  the older, more powerful approach ([examples](./bin/mtag/)):
@@ -1596,12 +1620,16 @@ connecting to an aws s3 bucket and similar
1596
1620
 
1597
1621
  there is no built-in support for this, but you can use FUSE-software such as [rclone](https://rclone.org/) / [geesefs](https://github.com/yandex-cloud/geesefs) / [JuiceFS](https://juicefs.com/en/) to first mount your cloud storage as a local disk, and then let copyparty use (a folder in) that disk as a volume
1598
1622
 
1599
- you may experience poor upload performance this way, but that can sometimes be fixed by specifying the volflag `sparse` to force the use of sparse files; this has improved the upload speeds from `1.5 MiB/s` to over `80 MiB/s` in one case, but note that you are also more likely to discover funny bugs in your FUSE software this way, so buckle up
1623
+ you will probably get decent speeds with the default config, however most likely restricted to using one TCP connection per file, so the upload-client won't be able to send multiple chunks in parallel
1624
+
1625
+ > before [v1.13.5](https://github.com/9001/copyparty/releases/tag/v1.13.5) it was recommended to use the volflag `sparse` to force-allow multiple chunks in parallel; this would improve the upload-speed from `1.5 MiB/s` to over `80 MiB/s` at the risk of provoking latent bugs in S3 or JuiceFS. But v1.13.5 added chunk-stitching, so this is now probably much less important. On the contrary, `nosparse` *may* now increase performance in some cases. Please try all three options (default, `sparse`, `nosparse`) as the optimal choice depends on your network conditions and software stack (both the FUSE-driver and cloud-server)
1600
1626
 
1601
1627
  someone has also tested geesefs in combination with [gocryptfs](https://nuetzlich.net/gocryptfs/) with surprisingly good results, getting 60 MiB/s upload speeds on a gbit line, but JuiceFS won with 80 MiB/s using its built-in encryption
1602
1628
 
1603
1629
  you may improve performance by specifying larger values for `--iobuf` / `--s-rd-sz` / `--s-wr-sz`
1604
1630
 
1631
+ > if you've experimented with this and made interesting observations, please share your findings so we can add a section with specific recommendations :-)
1632
+
1605
1633
 
1606
1634
  ## hiding from google
1607
1635
 
@@ -1724,10 +1752,16 @@ some reverse proxies (such as [Caddy](https://caddyserver.com/)) can automatical
1724
1752
 
1725
1753
  for improved security (and a 10% performance boost) consider listening on a unix-socket with `-i unix:770:www:/tmp/party.sock` (permission `770` means only members of group `www` can access it)
1726
1754
 
1727
- example webserver configs:
1755
+ example webserver / reverse-proxy configs:
1728
1756
 
1729
- * [nginx config](contrib/nginx/copyparty.conf) -- entire domain/subdomain
1730
- * [apache2 config](contrib/apache/copyparty.conf) -- location-based
1757
+ * [apache config](contrib/apache/copyparty.conf)
1758
+ * caddy uds: `caddy reverse-proxy --from :8080 --to unix///dev/shm/party.sock`
1759
+ * caddy tcp: `caddy reverse-proxy --from :8081 --to http://127.0.0.1:3923`
1760
+ * [haproxy config](contrib/haproxy/copyparty.conf)
1761
+ * [lighttpd subdomain](contrib/lighttpd/subdomain.conf) -- entire domain/subdomain
1762
+ * [lighttpd subpath](contrib/lighttpd/subpath.conf) -- location-based (not optimal, but in case you need it)
1763
+ * [nginx config](contrib/nginx/copyparty.conf) -- recommended
1764
+ * [traefik config](contrib/traefik/copyparty.yaml)
1731
1765
 
1732
1766
 
1733
1767
  ### real-ip
@@ -1739,6 +1773,38 @@ if you (and maybe everybody else) keep getting a message that says `thank you fo
1739
1773
  for most common setups, there should be a helpful message in the server-log explaining what to do, but see [docs/xff.md](docs/xff.md) if you want to learn more, including a quick hack to **just make it work** (which is **not** recommended, but hey...)
1740
1774
 
1741
1775
 
1776
+ ### reverse-proxy performance
1777
+
1778
+ most reverse-proxies support connecting to copyparty either using uds/unix-sockets (`/dev/shm/party.sock`, faster/recommended) or using tcp (`127.0.0.1`)
1779
+
1780
+ with copyparty listening on a uds / unix-socket / unix-domain-socket and the reverse-proxy connecting to that:
1781
+
1782
+ | index.html | upload | download | software |
1783
+ | ------------ | ----------- | ----------- | -------- |
1784
+ | 28'900 req/s | 6'900 MiB/s | 7'400 MiB/s | no-proxy |
1785
+ | 18'750 req/s | 3'500 MiB/s | 2'370 MiB/s | haproxy |
1786
+ | 9'900 req/s | 3'750 MiB/s | 2'200 MiB/s | caddy |
1787
+ | 18'700 req/s | 2'200 MiB/s | 1'570 MiB/s | nginx |
1788
+ | 9'700 req/s | 1'750 MiB/s | 1'830 MiB/s | apache |
1789
+ | 9'900 req/s | 1'300 MiB/s | 1'470 MiB/s | lighttpd |
1790
+
1791
+ when connecting the reverse-proxy to `127.0.0.1` instead (the basic and/or old-fasioned way), speeds are a bit worse:
1792
+
1793
+ | index.html | upload | download | software |
1794
+ | ------------ | ----------- | ----------- | -------- |
1795
+ | 21'200 req/s | 5'700 MiB/s | 6'700 MiB/s | no-proxy |
1796
+ | 14'500 req/s | 1'700 MiB/s | 2'170 MiB/s | haproxy |
1797
+ | 11'100 req/s | 2'750 MiB/s | 2'000 MiB/s | traefik |
1798
+ | 8'400 req/s | 2'300 MiB/s | 1'950 MiB/s | caddy |
1799
+ | 13'400 req/s | 1'100 MiB/s | 1'480 MiB/s | nginx |
1800
+ | 8'400 req/s | 1'000 MiB/s | 1'000 MiB/s | apache |
1801
+ | 6'500 req/s | 1'270 MiB/s | 1'500 MiB/s | lighttpd |
1802
+
1803
+ in summary, `haproxy > caddy > traefik > nginx > apache > lighttpd`, and use uds when possible (traefik does not support it yet)
1804
+
1805
+ * if these results are bullshit because my config exampels are bad, please submit corrections!
1806
+
1807
+
1742
1808
  ## prometheus
1743
1809
 
1744
1810
  metrics/stats can be enabled at URL `/.cpr/metrics` for grafana / prometheus / etc (openmetrics 1.0.0)
@@ -2052,7 +2118,8 @@ interact with copyparty using non-browser clients
2052
2118
  * can be downloaded from copyparty: controlpanel -> connect -> [partyfuse.py](http://127.0.0.1:3923/.cpr/a/partyfuse.py)
2053
2119
  * [rclone](https://rclone.org/) as client can give ~5x performance, see [./docs/rclone.md](docs/rclone.md)
2054
2120
 
2055
- * sharex (screenshot utility): see [./contrib/sharex.sxcu](contrib/#sharexsxcu)
2121
+ * sharex (screenshot utility): see [./contrib/sharex.sxcu](./contrib/#sharexsxcu)
2122
+ * and for screenshots on macos, see [./contrib/ishare.iscu](./contrib/#ishareiscu)
2056
2123
  * and for screenshots on linux, see [./contrib/flameshot.sh](./contrib/flameshot.sh)
2057
2124
 
2058
2125
  * contextlet (web browser integration); see [contrib contextlet](contrib/#send-to-cppcontextletjson)
@@ -2316,13 +2383,13 @@ mandatory deps:
2316
2383
 
2317
2384
  install these to enable bonus features
2318
2385
 
2319
- enable hashed passwords in config: `argon2-cffi`
2386
+ enable [hashed passwords](#password-hashing) in config: `argon2-cffi`
2320
2387
 
2321
- enable ftp-server:
2388
+ enable [ftp-server](#ftp-server):
2322
2389
  * for just plaintext FTP, `pyftpdlib` (is built into the SFX)
2323
2390
  * with TLS encryption, `pyftpdlib pyopenssl`
2324
2391
 
2325
- enable music tags:
2392
+ enable [music tags](#metadata-from-audio-files):
2326
2393
  * either `mutagen` (fast, pure-python, skips a few tags, makes copyparty GPL? idk)
2327
2394
  * or `ffprobe` (20x slower, more accurate, possibly dangerous depending on your distro and users)
2328
2395
 
@@ -2333,8 +2400,9 @@ enable [thumbnails](#thumbnails) of...
2333
2400
  * **AVIF pictures:** `pyvips` or `ffmpeg` or `pillow-avif-plugin`
2334
2401
  * **JPEG XL pictures:** `pyvips` or `ffmpeg`
2335
2402
 
2336
- enable [smb](#smb-server) support (**not** recommended):
2337
- * `impacket==0.12.0`
2403
+ enable sending [zeromq messages](#zeromq) from event-hooks: `pyzmq`
2404
+
2405
+ enable [smb](#smb-server) support (**not** recommended): `impacket==0.12.0`
2338
2406
 
2339
2407
  `pyvips` gives higher quality thumbnails than `Pillow` and is 320% faster, using 270% more ram: `sudo apt install libvips42 && python3 -m pip install --user -U pyvips`
2340
2408