copyparty 1.13.1__tar.gz → 1.13.3__tar.gz
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-1.13.1 → copyparty-1.13.3}/PKG-INFO +7 -4
- {copyparty-1.13.1 → copyparty-1.13.3}/README.md +6 -3
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/__main__.py +52 -8
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/__version__.py +2 -2
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/authsrv.py +16 -4
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/broker_mp.py +2 -5
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/cfg.py +1 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/httpcli.py +12 -8
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/httpsrv.py +1 -4
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/mdns.py +23 -2
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/mtag.py +74 -3
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/smbd.py +1 -1
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/ssdp.py +22 -2
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/star.py +4 -4
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/sutil.py +12 -6
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/svchub.py +9 -2
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/szip.py +4 -4
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/th_cli.py +5 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/th_srv.py +51 -13
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/up2k.py +16 -10
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/util.py +54 -14
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/a/u2c.py +26 -9
- copyparty-1.13.3/copyparty/web/baguettebox.js.gz +0 -0
- copyparty-1.13.3/copyparty/web/browser.css.gz +0 -0
- copyparty-1.13.3/copyparty/web/browser.js.gz +0 -0
- copyparty-1.13.3/copyparty/web/deps/marked.js.gz +0 -0
- copyparty-1.13.3/copyparty/web/md2.js.gz +0 -0
- copyparty-1.13.3/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty.egg-info/PKG-INFO +7 -4
- copyparty-1.13.1/copyparty/web/baguettebox.js.gz +0 -0
- copyparty-1.13.1/copyparty/web/browser.css.gz +0 -0
- copyparty-1.13.1/copyparty/web/browser.js.gz +0 -0
- copyparty-1.13.1/copyparty/web/deps/marked.js.gz +0 -0
- copyparty-1.13.1/copyparty/web/md2.js.gz +0 -0
- copyparty-1.13.1/copyparty/web/splash.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/LICENSE +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/__init__.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/bos/__init__.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/bos/bos.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/bos/path.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/broker_mpw.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/broker_thr.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/broker_util.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/cert.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/dxml.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/fsutil.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/ftpd.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/httpconn.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/ico.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/metrics.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/multicast.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/pwhash.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/res/COPYING.txt +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/res/__init__.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/res/insecure.pem +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/__init__.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/dnslib/__init__.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/dnslib/bimap.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/dnslib/bit.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/dnslib/buffer.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/dnslib/dns.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/dnslib/label.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/dnslib/lex.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/dnslib/ranges.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/ifaddr/__init__.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/ifaddr/_posix.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/ifaddr/_shared.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/ifaddr/_win32.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/qrcodegen.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/stolen/surrogateescape.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/tcpsrv.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/tftpd.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/u2idx.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/a/__init__.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/a/partyfuse.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/a/webdav-cfg.bat +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/browser.html +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/browser2.html +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/cf.html +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/dbg-audio.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/dd/2.png +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/dd/3.png +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/dd/4.png +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/dd/5.png +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/dd/__init__.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/__init__.py +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/busy.mp3.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/easymde.css.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/easymde.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/mini-fa.css.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/mini-fa.woff +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/prism.css.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/prism.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/prismd.css.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/scp.woff2 +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/sha512.ac.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/deps/sha512.hw.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/md.css.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/md.html +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/md.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/md2.css.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/mde.css.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/mde.html +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/mde.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/msg.css.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/msg.html +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/splash.css.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/splash.html +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/svcs.html +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/svcs.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/ui.css.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/util.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty/web/w.hash.js.gz +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty.egg-info/SOURCES.txt +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty.egg-info/dependency_links.txt +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty.egg-info/entry_points.txt +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty.egg-info/requires.txt +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/copyparty.egg-info/top_level.txt +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/pyproject.toml +0 -0
- {copyparty-1.13.1 → copyparty-1.13.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.13.
|
3
|
+
Version: 1.13.3
|
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
|
@@ -284,6 +284,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
284
284
|
* ☑ ...of videos using FFmpeg
|
285
285
|
* ☑ ...of audio (spectrograms) using FFmpeg
|
286
286
|
* ☑ cache eviction (max-age; maybe max-size eventually)
|
287
|
+
* ☑ multilingual UI (english, norwegian, [add your own](./docs/rice/#translations)))
|
287
288
|
* ☑ SPA (browse while uploading)
|
288
289
|
* server indexing
|
289
290
|
* ☑ [locate files by contents](#file-search)
|
@@ -466,7 +467,7 @@ configuring accounts/volumes with arguments:
|
|
466
467
|
`-v .::r,usr1,usr2:rw,usr3,usr4` = usr1/2 read-only, 3/4 read-write
|
467
468
|
|
468
469
|
permissions:
|
469
|
-
* `r` (read): browse folder contents, download files, download as zip/tar
|
470
|
+
* `r` (read): browse folder contents, download files, download as zip/tar, see filekeys/dirkeys
|
470
471
|
* `w` (write): upload files, move files *into* this folder
|
471
472
|
* `m` (move): move files/folders *from* this folder
|
472
473
|
* `d` (delete): delete files/folders
|
@@ -668,7 +669,7 @@ you can also zip a selection of files or folders by clicking them in the browser
|
|
668
669
|
|
669
670
|
cool trick: download a folder by appending url-params `?tar&opus` or `?tar&mp3` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus/mp3 before they're added to the archive
|
670
671
|
* super useful if you're 5 minutes away from takeoff and realize you don't have any music on your phone but your server only has flac files and downloading those will burn through all your data + there wouldn't be enough time anyways
|
671
|
-
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images
|
672
|
+
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images (`&p` for audio waveforms)
|
672
673
|
* can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
|
673
674
|
|
674
675
|
|
@@ -964,6 +965,8 @@ using arguments or config files, or a mix of both:
|
|
964
965
|
|
965
966
|
**NB:** as humongous as this readme is, there is also a lot of undocumented features. Run copyparty with `--help` to see all available global options; all of those can be used in the `[global]` section of config files, and everything listed in `--help-flags` can be used in volumes as volflags.
|
966
967
|
* if running in docker/podman, try this: `docker run --rm -it copyparty/ac --help`
|
968
|
+
* or see this (probably outdated): https://ocv.me/copyparty/helptext.html
|
969
|
+
* or if you prefer plaintext, https://ocv.me/copyparty/helptext.txt
|
967
970
|
|
968
971
|
|
969
972
|
## zeroconf
|
@@ -1140,7 +1143,7 @@ tweaking the ui
|
|
1140
1143
|
* to sort in music order (album, track, artist, title) with filename as fallback, you could `--sort tags/Cirle,tags/.tn,tags/Artist,tags/Title,href`
|
1141
1144
|
* to sort by upload date, first enable showing the upload date in the listing with `-e2d -mte +.up_at` and then `--sort tags/.up_at`
|
1142
1145
|
|
1143
|
-
see [./docs/rice](./docs/rice) for more, including how to add stuff (css/`<meta>`/...) to the html `<head>` tag
|
1146
|
+
see [./docs/rice](./docs/rice) for more, including how to add stuff (css/`<meta>`/...) to the html `<head>` tag, or to add your own translation
|
1144
1147
|
|
1145
1148
|
|
1146
1149
|
## opengraph
|
@@ -230,6 +230,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
230
230
|
* ☑ ...of videos using FFmpeg
|
231
231
|
* ☑ ...of audio (spectrograms) using FFmpeg
|
232
232
|
* ☑ cache eviction (max-age; maybe max-size eventually)
|
233
|
+
* ☑ multilingual UI (english, norwegian, [add your own](./docs/rice/#translations)))
|
233
234
|
* ☑ SPA (browse while uploading)
|
234
235
|
* server indexing
|
235
236
|
* ☑ [locate files by contents](#file-search)
|
@@ -412,7 +413,7 @@ configuring accounts/volumes with arguments:
|
|
412
413
|
`-v .::r,usr1,usr2:rw,usr3,usr4` = usr1/2 read-only, 3/4 read-write
|
413
414
|
|
414
415
|
permissions:
|
415
|
-
* `r` (read): browse folder contents, download files, download as zip/tar
|
416
|
+
* `r` (read): browse folder contents, download files, download as zip/tar, see filekeys/dirkeys
|
416
417
|
* `w` (write): upload files, move files *into* this folder
|
417
418
|
* `m` (move): move files/folders *from* this folder
|
418
419
|
* `d` (delete): delete files/folders
|
@@ -614,7 +615,7 @@ you can also zip a selection of files or folders by clicking them in the browser
|
|
614
615
|
|
615
616
|
cool trick: download a folder by appending url-params `?tar&opus` or `?tar&mp3` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus/mp3 before they're added to the archive
|
616
617
|
* super useful if you're 5 minutes away from takeoff and realize you don't have any music on your phone but your server only has flac files and downloading those will burn through all your data + there wouldn't be enough time anyways
|
617
|
-
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images
|
618
|
+
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images (`&p` for audio waveforms)
|
618
619
|
* can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
|
619
620
|
|
620
621
|
|
@@ -910,6 +911,8 @@ using arguments or config files, or a mix of both:
|
|
910
911
|
|
911
912
|
**NB:** as humongous as this readme is, there is also a lot of undocumented features. Run copyparty with `--help` to see all available global options; all of those can be used in the `[global]` section of config files, and everything listed in `--help-flags` can be used in volumes as volflags.
|
912
913
|
* if running in docker/podman, try this: `docker run --rm -it copyparty/ac --help`
|
914
|
+
* or see this (probably outdated): https://ocv.me/copyparty/helptext.html
|
915
|
+
* or if you prefer plaintext, https://ocv.me/copyparty/helptext.txt
|
913
916
|
|
914
917
|
|
915
918
|
## zeroconf
|
@@ -1086,7 +1089,7 @@ tweaking the ui
|
|
1086
1089
|
* to sort in music order (album, track, artist, title) with filename as fallback, you could `--sort tags/Cirle,tags/.tn,tags/Artist,tags/Title,href`
|
1087
1090
|
* to sort by upload date, first enable showing the upload date in the listing with `-e2d -mte +.up_at` and then `--sort tags/.up_at`
|
1088
1091
|
|
1089
|
-
see [./docs/rice](./docs/rice) for more, including how to add stuff (css/`<meta>`/...) to the html `<head>` tag
|
1092
|
+
see [./docs/rice](./docs/rice) for more, including how to add stuff (css/`<meta>`/...) to the html `<head>` tag, or to add your own translation
|
1090
1093
|
|
1091
1094
|
|
1092
1095
|
## opengraph
|
@@ -13,6 +13,7 @@ import base64
|
|
13
13
|
import locale
|
14
14
|
import os
|
15
15
|
import re
|
16
|
+
import select
|
16
17
|
import socket
|
17
18
|
import sys
|
18
19
|
import threading
|
@@ -43,11 +44,13 @@ from .util import (
|
|
43
44
|
DEF_MTH,
|
44
45
|
IMPLICATIONS,
|
45
46
|
JINJA_VER,
|
47
|
+
MIMES,
|
46
48
|
PARTFTPY_VER,
|
47
49
|
PY_DESC,
|
48
50
|
PYFTPD_VER,
|
49
51
|
SQLITE_VER,
|
50
52
|
UNPLICATIONS,
|
53
|
+
Daemon,
|
51
54
|
align_tab,
|
52
55
|
ansi_re,
|
53
56
|
dedent,
|
@@ -165,8 +168,10 @@ def init_E(EE ) :
|
|
165
168
|
(os.environ.get, "TMP"),
|
166
169
|
(unicode, "/tmp"),
|
167
170
|
]
|
171
|
+
errs = []
|
168
172
|
for chk in [os.listdir, os.mkdir]:
|
169
|
-
for pf, pa in paths:
|
173
|
+
for npath, (pf, pa) in enumerate(paths):
|
174
|
+
p = ""
|
170
175
|
try:
|
171
176
|
p = pf(pa)
|
172
177
|
# print(chk.__name__, p, pa)
|
@@ -179,9 +184,20 @@ def init_E(EE ) :
|
|
179
184
|
if not os.path.isdir(p):
|
180
185
|
os.mkdir(p)
|
181
186
|
|
187
|
+
if npath > 1:
|
188
|
+
t = "Using [%s] for config; filekeys/dirkeys will change on every restart. Consider setting XDG_CONFIG_HOME or giving the unix-user a ~/.config/"
|
189
|
+
errs.append(t % (p,))
|
190
|
+
elif errs:
|
191
|
+
errs.append("Using [%s] instead" % (p,))
|
192
|
+
|
193
|
+
if errs:
|
194
|
+
print("WARNING: " + ". ".join(errs))
|
195
|
+
|
182
196
|
return p # type: ignore
|
183
|
-
except:
|
184
|
-
|
197
|
+
except Exception as ex:
|
198
|
+
if p and npath < 2:
|
199
|
+
t = "Unable to store config in [%s] due to %r"
|
200
|
+
errs.append(t % (p, ex))
|
185
201
|
|
186
202
|
raise Exception("could not find a writable path for config")
|
187
203
|
|
@@ -464,6 +480,16 @@ def disable_quickedit() :
|
|
464
480
|
cmode(True, mode | 4)
|
465
481
|
|
466
482
|
|
483
|
+
def sfx_tpoke(top ):
|
484
|
+
files = [os.path.join(dp, p) for dp, dd, df in os.walk(top) for p in dd + df]
|
485
|
+
while True:
|
486
|
+
t = int(time.time())
|
487
|
+
for f in [top] + files:
|
488
|
+
os.utime(f, (t, t))
|
489
|
+
|
490
|
+
time.sleep(78123)
|
491
|
+
|
492
|
+
|
467
493
|
def showlic() :
|
468
494
|
p = os.path.join(E.mod, "res", "COPYING.txt")
|
469
495
|
if not os.path.exists(p):
|
@@ -814,7 +840,7 @@ def build_flags_desc():
|
|
814
840
|
v = v.replace("\n", "\n ")
|
815
841
|
ret += "\n \033[36m{}\033[35m {}".format(k, v)
|
816
842
|
|
817
|
-
return ret
|
843
|
+
return ret
|
818
844
|
|
819
845
|
|
820
846
|
# fmt: off
|
@@ -832,6 +858,8 @@ def add_general(ap, nc, srvname):
|
|
832
858
|
ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,get", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m")
|
833
859
|
ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="server terminal title, for example [\033[32m$ip-10.1.2.\033[0m] or [\033[32m$ip-]")
|
834
860
|
ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)")
|
861
|
+
ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
|
862
|
+
ap2.add_argument("--mimes", action="store_true", help="list default mimetype mapping and exit")
|
835
863
|
ap2.add_argument("--license", action="store_true", help="show licenses and exit")
|
836
864
|
ap2.add_argument("--version", action="store_true", help="show versions and exit")
|
837
865
|
|
@@ -878,7 +906,7 @@ def add_upload(ap):
|
|
878
906
|
ap2.add_argument("--rand", action="store_true", help="force randomized filenames, \033[33m--nrand\033[0m chars long (volflag=rand)")
|
879
907
|
ap2.add_argument("--nrand", metavar="NUM", type=int, default=9, help="randomized filenames length (volflag=nrand)")
|
880
908
|
ap2.add_argument("--magic", action="store_true", help="enable filetype detection on nameless uploads (volflag=magic)")
|
881
|
-
ap2.add_argument("--df", metavar="GiB", type=
|
909
|
+
ap2.add_argument("--df", metavar="GiB", type=u, default="0", help="ensure \033[33mGiB\033[0m free disk space by rejecting upload requests; assumes gigabytes unless a unit suffix is given: [\033[32m256m\033[0m], [\033[32m4\033[0m], [\033[32m2T\033[0m] (volflag=df)")
|
882
910
|
ap2.add_argument("--sparse", metavar="MiB", type=int, default=4, help="windows-only: minimum size of incoming uploads through up2k before they are made into sparse files")
|
883
911
|
ap2.add_argument("--turbo", metavar="LVL", type=int, default=0, help="configure turbo-mode in up2k client; [\033[32m-1\033[0m] = forbidden/always-off, [\033[32m0\033[0m] = default-off and warn if enabled, [\033[32m1\033[0m] = default-off, [\033[32m2\033[0m] = on, [\033[32m3\033[0m] = on and disable datecheck")
|
884
912
|
ap2.add_argument("--u2j", metavar="JOBS", type=int, default=2, help="web-client: number of file chunks to upload in parallel; 1 or 2 is good for low-latency (same-country) connections, 4-8 for android clients, 16 for cross-atlantic (max=64)")
|
@@ -1188,7 +1216,8 @@ def add_thumbnail(ap):
|
|
1188
1216
|
ap2.add_argument("--th-r-vips", metavar="T,T", type=u, default="avif,exr,fit,fits,fts,gif,hdr,heic,jp2,jpeg,jpg,jpx,jxl,nii,pfm,pgm,png,ppm,svg,tif,tiff,webp", help="image formats to decode using pyvips")
|
1189
1217
|
ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
|
1190
1218
|
ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="3gp,asf,av1,avc,avi,flv,h264,h265,hevc,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,ts,vob,webm,wmv", help="video formats to decode using ffmpeg")
|
1191
|
-
ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,m4a,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,ogg,okt,opus,ra,s3m,tak,tta,ulaw,wav,wma,wv,xm,xpk", help="audio formats to decode using ffmpeg")
|
1219
|
+
ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg")
|
1220
|
+
ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz", help="audio formats to decompress before passing to ffmpeg")
|
1192
1221
|
|
1193
1222
|
|
1194
1223
|
def add_transcoding(ap):
|
@@ -1301,6 +1330,8 @@ def add_debug(ap):
|
|
1301
1330
|
ap2 = ap.add_argument_group('debug options')
|
1302
1331
|
ap2.add_argument("--vc", action="store_true", help="verbose config file parser (explain config)")
|
1303
1332
|
ap2.add_argument("--cgen", action="store_true", help="generate config file from current config (best-effort; probably buggy)")
|
1333
|
+
if hasattr(select, "poll"):
|
1334
|
+
ap2.add_argument("--no-poll", action="store_true", help="kernel-bug workaround: disable poll; use select instead (limits max num clients to ~700)")
|
1304
1335
|
ap2.add_argument("--no-sendfile", action="store_true", help="kernel-bug workaround: disable sendfile; do a safe and slow read-send-loop instead")
|
1305
1336
|
ap2.add_argument("--no-scandir", action="store_true", help="kernel-bug workaround: disable scandir; do a listdir + stat on each file instead")
|
1306
1337
|
ap2.add_argument("--no-fastboot", action="store_true", help="wait for initial filesystem indexing before accepting client requests")
|
@@ -1399,7 +1430,7 @@ def run_argparse(
|
|
1399
1430
|
k2 = "help_" + k.replace("-", "_")
|
1400
1431
|
if vars(ret)[k2]:
|
1401
1432
|
lprint("# %s help page (%s)" % (k, h))
|
1402
|
-
lprint(t + "\033[0m")
|
1433
|
+
lprint(t.rstrip() + "\033[0m")
|
1403
1434
|
sys.exit(0)
|
1404
1435
|
|
1405
1436
|
return ret
|
@@ -1438,9 +1469,19 @@ def main(argv = None, rsrc = None) :
|
|
1438
1469
|
showlic()
|
1439
1470
|
sys.exit(0)
|
1440
1471
|
|
1472
|
+
if "--mimes" in argv:
|
1473
|
+
print("\n".join("%8s %s" % (k, v) for k, v in sorted(MIMES.items())))
|
1474
|
+
sys.exit(0)
|
1475
|
+
|
1441
1476
|
if EXE:
|
1442
1477
|
print("pybin: {}\n".format(pybin), end="")
|
1443
1478
|
|
1479
|
+
for n, zs in enumerate(argv):
|
1480
|
+
if zs.startswith("--sfx-tpoke="):
|
1481
|
+
Daemon(sfx_tpoke, "sfx-tpoke", (zs.split("=", 1)[1],))
|
1482
|
+
argv.pop(n)
|
1483
|
+
break
|
1484
|
+
|
1444
1485
|
ensure_locale()
|
1445
1486
|
|
1446
1487
|
ensure_webdeps()
|
@@ -1501,7 +1542,7 @@ def main(argv = None, rsrc = None) :
|
|
1501
1542
|
if hard > 0: # -1 == infinite
|
1502
1543
|
nc = min(nc, int(hard / 4))
|
1503
1544
|
except:
|
1504
|
-
nc = 512
|
1545
|
+
nc = 486 # mdns/ssdp restart headroom; select() maxfd is 512 on windows
|
1505
1546
|
|
1506
1547
|
retry = False
|
1507
1548
|
for fmtr in [RiceFormatter, RiceFormatter, Dodge11874, BasicDodge11874]:
|
@@ -1594,6 +1635,9 @@ def main(argv = None, rsrc = None) :
|
|
1594
1635
|
if not hasattr(os, "sendfile"):
|
1595
1636
|
al.no_sendfile = True
|
1596
1637
|
|
1638
|
+
if not hasattr(select, "poll"):
|
1639
|
+
al.no_poll = True
|
1640
|
+
|
1597
1641
|
# signal.signal(signal.SIGINT, sighandler)
|
1598
1642
|
|
1599
1643
|
SvcHub(al, dal, argv, "".join(printed)).run()
|
@@ -17,7 +17,9 @@ from .bos import bos
|
|
17
17
|
from .cfg import flagdescs, permdescs, vf_bmap, vf_cmap, vf_vmap
|
18
18
|
from .pwhash import PWHash
|
19
19
|
from .util import (
|
20
|
+
EXTS,
|
20
21
|
IMPLICATIONS,
|
22
|
+
MIMES,
|
21
23
|
SQLITE_VER,
|
22
24
|
UNPLICATIONS,
|
23
25
|
UTC,
|
@@ -1608,11 +1610,14 @@ class AuthSrv(object):
|
|
1608
1610
|
use = True
|
1609
1611
|
lim.nosub = True
|
1610
1612
|
|
1611
|
-
zs = vol.flags.get("df") or
|
1612
|
-
|
1613
|
-
)
|
1614
|
-
if zs:
|
1613
|
+
zs = vol.flags.get("df") or self.args.df or ""
|
1614
|
+
if zs not in ("", "0"):
|
1615
1615
|
use = True
|
1616
|
+
try:
|
1617
|
+
_ = float(zs)
|
1618
|
+
zs = "%sg" % (zs)
|
1619
|
+
except:
|
1620
|
+
pass
|
1616
1621
|
lim.dfl = unhumanize(zs)
|
1617
1622
|
|
1618
1623
|
zs = vol.flags.get("sz")
|
@@ -2058,6 +2063,13 @@ class AuthSrv(object):
|
|
2058
2063
|
|
2059
2064
|
self.re_pwd = re.compile(zs)
|
2060
2065
|
|
2066
|
+
# to ensure it propagates into tcpsrv with mp on
|
2067
|
+
if self.args.mime:
|
2068
|
+
for zs in self.args.mime:
|
2069
|
+
ext, mime = zs.split("=", 1)
|
2070
|
+
MIMES[ext] = mime
|
2071
|
+
EXTS.update({v: k for k, v in MIMES.items()})
|
2072
|
+
|
2061
2073
|
def setup_pwhash(self, acct ) :
|
2062
2074
|
self.ah = PWHash(self.args)
|
2063
2075
|
if not self.ah.on:
|
@@ -53,11 +53,8 @@ class BrokerMp(object):
|
|
53
53
|
def shutdown(self) :
|
54
54
|
self.log("broker", "shutting down")
|
55
55
|
for n, proc in enumerate(self.procs):
|
56
|
-
|
57
|
-
|
58
|
-
name="mp-shutdown-{}-{}".format(n, len(self.procs)),
|
59
|
-
)
|
60
|
-
thr.start()
|
56
|
+
name = "mp-shut-%d-%d" % (n, len(self.procs))
|
57
|
+
Daemon(proc.q_pend.put, name, ((0, "shutdown", []),))
|
61
58
|
|
62
59
|
with self.mutex:
|
63
60
|
procs = self.procs
|
@@ -190,6 +190,7 @@ flagcats = {
|
|
190
190
|
"dvthumb": "disables video thumbnails",
|
191
191
|
"dathumb": "disables audio thumbnails (spectrograms)",
|
192
192
|
"dithumb": "disables image thumbnails",
|
193
|
+
"pngquant": "compress audio waveforms 33% better",
|
193
194
|
"thsize": "thumbnail res; WxH",
|
194
195
|
"crop": "center-cropping (y/n/fy/fn)",
|
195
196
|
"th3x": "3x resolution (y/n/fy/fn)",
|
@@ -755,7 +755,6 @@ class HttpCli(object):
|
|
755
755
|
is_jinja = True
|
756
756
|
|
757
757
|
if is_jinja:
|
758
|
-
print("applying jinja")
|
759
758
|
with self.conn.hsrv.mutex:
|
760
759
|
if html not in self.conn.hsrv.j2:
|
761
760
|
j2env = jinja2.Environment()
|
@@ -3190,7 +3189,14 @@ class HttpCli(object):
|
|
3190
3189
|
|
3191
3190
|
sendfun = sendfile_kern if use_sendfile else sendfile_py
|
3192
3191
|
remains = sendfun(
|
3193
|
-
self.log,
|
3192
|
+
self.log,
|
3193
|
+
lower,
|
3194
|
+
upper,
|
3195
|
+
f,
|
3196
|
+
self.s,
|
3197
|
+
self.args.s_wr_sz,
|
3198
|
+
self.args.s_wr_slp,
|
3199
|
+
not self.args.no_poll,
|
3194
3200
|
)
|
3195
3201
|
|
3196
3202
|
if remains > 0:
|
@@ -3409,7 +3415,7 @@ class HttpCli(object):
|
|
3409
3415
|
# for f in fgen: print(repr({k: f[k] for k in ["vp", "ap"]}))
|
3410
3416
|
cfmt = ""
|
3411
3417
|
if self.thumbcli and not self.args.no_bacode:
|
3412
|
-
for zs in ("opus", "mp3", "w", "j"):
|
3418
|
+
for zs in ("opus", "mp3", "w", "j", "p"):
|
3413
3419
|
if zs in self.ouparam or uarg == zs:
|
3414
3420
|
cfmt = zs
|
3415
3421
|
|
@@ -3419,7 +3425,7 @@ class HttpCli(object):
|
|
3419
3425
|
|
3420
3426
|
bgen = packer(
|
3421
3427
|
self.log,
|
3422
|
-
self.
|
3428
|
+
self.asrv,
|
3423
3429
|
fgen,
|
3424
3430
|
utf8="utf" in uarg,
|
3425
3431
|
pre_crc="crc" in uarg,
|
@@ -4800,7 +4806,7 @@ class HttpCli(object):
|
|
4800
4806
|
query = "th=%s&cache" % (fmt,)
|
4801
4807
|
query = ub64enc(query.encode("utf-8")).decode("utf-8")
|
4802
4808
|
# discord looks at file extension, not content-type...
|
4803
|
-
query += "/
|
4809
|
+
query += "/th.jpg" if "j" in fmt else "/th.webp"
|
4804
4810
|
j2a["og_thumb"] = "%s/.uqe/%s" % (th_base, query)
|
4805
4811
|
|
4806
4812
|
j2a["og_fn"] = og_fn
|
@@ -4808,9 +4814,7 @@ class HttpCli(object):
|
|
4808
4814
|
if og_fn:
|
4809
4815
|
og_fn_q = quotep(og_fn)
|
4810
4816
|
query = ub64enc(b"raw").decode("utf-8")
|
4811
|
-
|
4812
|
-
query += "/a.%s" % (og_fn.split(".")[-1])
|
4813
|
-
|
4817
|
+
query += "/%s" % (og_fn_q,)
|
4814
4818
|
j2a["og_url"] = ujoin(url_base, og_fn_q)
|
4815
4819
|
j2a["og_raw"] = j2a["og_url"] + "/.uqe/" + query
|
4816
4820
|
else:
|
@@ -262,10 +262,7 @@ class HttpSrv(object):
|
|
262
262
|
msg = "subscribed @ {}:{} f{} p{}".format(hip, port, fno, os.getpid())
|
263
263
|
self.log(self.name, msg)
|
264
264
|
|
265
|
-
|
266
|
-
self.broker.say("cb_httpsrv_up")
|
267
|
-
|
268
|
-
threading.Thread(target=fun, name="sig-hsrv-up1").start()
|
265
|
+
Daemon(self.broker.say, "sig-hsrv-up1", ("cb_httpsrv_up",))
|
269
266
|
|
270
267
|
while not self.stopping:
|
271
268
|
if self.args.log_conn:
|
@@ -288,6 +288,22 @@ class MDNS(MCast):
|
|
288
288
|
def run2(self) :
|
289
289
|
last_hop = time.time()
|
290
290
|
ihop = self.args.mc_hop
|
291
|
+
|
292
|
+
try:
|
293
|
+
if self.args.no_poll:
|
294
|
+
raise Exception()
|
295
|
+
fd2sck = {}
|
296
|
+
srvpoll = select.poll()
|
297
|
+
for sck in self.srv:
|
298
|
+
fd = sck.fileno()
|
299
|
+
fd2sck[fd] = sck
|
300
|
+
srvpoll.register(fd, select.POLLIN)
|
301
|
+
except Exception as ex:
|
302
|
+
srvpoll = None
|
303
|
+
if not self.args.no_poll:
|
304
|
+
t = "WARNING: failed to poll(), will use select() instead: %r"
|
305
|
+
self.log(t % (ex,), 3)
|
306
|
+
|
291
307
|
while self.running:
|
292
308
|
timeout = (
|
293
309
|
0.02 + random.random() * 0.07
|
@@ -296,8 +312,13 @@ class MDNS(MCast):
|
|
296
312
|
if self.unsolicited
|
297
313
|
else (last_hop + ihop if ihop else 180)
|
298
314
|
)
|
299
|
-
|
300
|
-
|
315
|
+
if srvpoll:
|
316
|
+
pr = srvpoll.poll(timeout * 1000)
|
317
|
+
rx = [fd2sck[x[0]] for x in pr if x[1] & select.POLLIN]
|
318
|
+
else:
|
319
|
+
rdy = select.select(self.srv, [], [], timeout)
|
320
|
+
rx = rdy[0] # type: ignore
|
321
|
+
|
301
322
|
self.rx4.cln()
|
302
323
|
self.rx6.cln()
|
303
324
|
buf = b""
|
@@ -7,12 +7,15 @@ import os
|
|
7
7
|
import shutil
|
8
8
|
import subprocess as sp
|
9
9
|
import sys
|
10
|
+
import tempfile
|
10
11
|
|
11
12
|
from .__init__ import ANYWIN, EXE, PY2, WINDOWS, E, unicode
|
13
|
+
from .authsrv import VFS
|
12
14
|
from .bos import bos
|
13
15
|
from .util import (
|
14
16
|
FFMPEG_URL,
|
15
17
|
REKOBO_LKEY,
|
18
|
+
VF_CAREFUL,
|
16
19
|
fsenc,
|
17
20
|
min_ex,
|
18
21
|
pybin,
|
@@ -20,6 +23,7 @@ from .util import (
|
|
20
23
|
runcmd,
|
21
24
|
sfsenc,
|
22
25
|
uncyg,
|
26
|
+
wunlink,
|
23
27
|
)
|
24
28
|
|
25
29
|
def have_ff(scmd ) :
|
@@ -101,6 +105,53 @@ class MParser(object):
|
|
101
105
|
raise Exception()
|
102
106
|
|
103
107
|
|
108
|
+
def au_unpk(
|
109
|
+
log , fmt_map , abspath , vn = None
|
110
|
+
) :
|
111
|
+
ret = ""
|
112
|
+
try:
|
113
|
+
ext = abspath.split(".")[-1].lower()
|
114
|
+
au, pk = fmt_map[ext].split(".")
|
115
|
+
|
116
|
+
fd, ret = tempfile.mkstemp("." + au)
|
117
|
+
|
118
|
+
if pk == "gz":
|
119
|
+
import gzip
|
120
|
+
|
121
|
+
fi = gzip.GzipFile(abspath, mode="rb")
|
122
|
+
|
123
|
+
elif pk == "xz":
|
124
|
+
import lzma
|
125
|
+
|
126
|
+
fi = lzma.open(abspath, "rb")
|
127
|
+
|
128
|
+
elif pk == "zip":
|
129
|
+
import zipfile
|
130
|
+
|
131
|
+
zf = zipfile.ZipFile(abspath, "r")
|
132
|
+
zil = zf.infolist()
|
133
|
+
zil = [x for x in zil if x.filename.lower().split(".")[-1] == au]
|
134
|
+
fi = zf.open(zil[0])
|
135
|
+
|
136
|
+
with os.fdopen(fd, "wb") as fo:
|
137
|
+
while True:
|
138
|
+
buf = fi.read(32768)
|
139
|
+
if not buf:
|
140
|
+
break
|
141
|
+
|
142
|
+
fo.write(buf)
|
143
|
+
|
144
|
+
return ret
|
145
|
+
|
146
|
+
except Exception as ex:
|
147
|
+
if ret:
|
148
|
+
t = "failed to decompress audio file [%s]: %r"
|
149
|
+
log(t % (abspath, ex))
|
150
|
+
wunlink(log, ret, vn.flags if vn else VF_CAREFUL)
|
151
|
+
|
152
|
+
return abspath
|
153
|
+
|
154
|
+
|
104
155
|
def ffprobe(
|
105
156
|
abspath , timeout = 60
|
106
157
|
) :
|
@@ -275,7 +326,7 @@ class MTag(object):
|
|
275
326
|
or_ffprobe = " or FFprobe"
|
276
327
|
|
277
328
|
if self.backend == "mutagen":
|
278
|
-
self.
|
329
|
+
self._get = self.get_mutagen
|
279
330
|
try:
|
280
331
|
from mutagen import version # noqa: F401
|
281
332
|
except:
|
@@ -284,7 +335,7 @@ class MTag(object):
|
|
284
335
|
|
285
336
|
if self.backend == "ffprobe":
|
286
337
|
self.usable = self.can_ffprobe
|
287
|
-
self.
|
338
|
+
self._get = self.get_ffprobe
|
288
339
|
self.prefer_mt = True
|
289
340
|
|
290
341
|
if not HAVE_FFPROBE:
|
@@ -454,6 +505,17 @@ class MTag(object):
|
|
454
505
|
|
455
506
|
return r1
|
456
507
|
|
508
|
+
def get(self, abspath ) :
|
509
|
+
ext = abspath.split(".")[-1].lower()
|
510
|
+
if ext not in self.args.au_unpk:
|
511
|
+
return self._get(abspath)
|
512
|
+
|
513
|
+
ap = au_unpk(self.log, self.args.au_unpk, abspath)
|
514
|
+
ret = self._get(ap)
|
515
|
+
if ap != abspath:
|
516
|
+
wunlink(self.log, ap, VF_CAREFUL)
|
517
|
+
return ret
|
518
|
+
|
457
519
|
def get_mutagen(self, abspath ) :
|
458
520
|
ret = {}
|
459
521
|
|
@@ -547,10 +609,16 @@ class MTag(object):
|
|
547
609
|
except:
|
548
610
|
raise # might be expected outside cpython
|
549
611
|
|
612
|
+
ext = abspath.split(".")[-1].lower()
|
613
|
+
if ext in self.args.au_unpk:
|
614
|
+
ap = au_unpk(self.log, self.args.au_unpk, abspath)
|
615
|
+
else:
|
616
|
+
ap = abspath
|
617
|
+
|
550
618
|
ret = {}
|
551
619
|
for tagname, parser in sorted(parsers.items(), key=lambda x: (x[1].pri, x[0])):
|
552
620
|
try:
|
553
|
-
cmd = [parser.bin,
|
621
|
+
cmd = [parser.bin, ap]
|
554
622
|
if parser.bin.endswith(".py"):
|
555
623
|
cmd = [pybin] + cmd
|
556
624
|
|
@@ -587,4 +655,7 @@ class MTag(object):
|
|
587
655
|
t = "mtag error: tagname {}, parser {}, file {} => {}"
|
588
656
|
self.log(t.format(tagname, parser.bin, abspath, min_ex()))
|
589
657
|
|
658
|
+
if ap != abspath:
|
659
|
+
wunlink(self.log, ap, VF_CAREFUL)
|
660
|
+
|
590
661
|
return ret
|
@@ -137,9 +137,29 @@ class SSDPd(MCast):
|
|
137
137
|
self.log("stopped", 2)
|
138
138
|
|
139
139
|
def run2(self) :
|
140
|
+
try:
|
141
|
+
if self.args.no_poll:
|
142
|
+
raise Exception()
|
143
|
+
fd2sck = {}
|
144
|
+
srvpoll = select.poll()
|
145
|
+
for sck in self.srv:
|
146
|
+
fd = sck.fileno()
|
147
|
+
fd2sck[fd] = sck
|
148
|
+
srvpoll.register(fd, select.POLLIN)
|
149
|
+
except Exception as ex:
|
150
|
+
srvpoll = None
|
151
|
+
if not self.args.no_poll:
|
152
|
+
t = "WARNING: failed to poll(), will use select() instead: %r"
|
153
|
+
self.log(t % (ex,), 3)
|
154
|
+
|
140
155
|
while self.running:
|
141
|
-
|
142
|
-
|
156
|
+
if srvpoll:
|
157
|
+
pr = srvpoll.poll((self.args.z_chk or 180) * 1000)
|
158
|
+
rx = [fd2sck[x[0]] for x in pr if x[1] & select.POLLIN]
|
159
|
+
else:
|
160
|
+
rdy = select.select(self.srv, [], [], self.args.z_chk or 180)
|
161
|
+
rx = rdy[0] # type: ignore
|
162
|
+
|
143
163
|
self.rxc.cln()
|
144
164
|
buf = b""
|
145
165
|
addr = ("0", 0)
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
|
-
import argparse
|
5
4
|
import re
|
6
5
|
import stat
|
7
6
|
import tarfile
|
8
7
|
|
9
8
|
from queue import Queue
|
10
9
|
|
10
|
+
from .authsrv import AuthSrv
|
11
11
|
from .bos import bos
|
12
12
|
from .sutil import StreamArc, errdesc
|
13
13
|
from .util import Daemon, fsenc, min_ex
|
@@ -39,12 +39,12 @@ class StreamTar(StreamArc):
|
|
39
39
|
def __init__(
|
40
40
|
self,
|
41
41
|
log ,
|
42
|
-
|
42
|
+
asrv ,
|
43
43
|
fgen ,
|
44
44
|
cmp = "",
|
45
45
|
**kwargs
|
46
46
|
):
|
47
|
-
super(StreamTar, self).__init__(log,
|
47
|
+
super(StreamTar, self).__init__(log, asrv, fgen)
|
48
48
|
|
49
49
|
self.ci = 0
|
50
50
|
self.co = 0
|
@@ -142,7 +142,7 @@ class StreamTar(StreamArc):
|
|
142
142
|
errors.append((f["vp"], ex))
|
143
143
|
|
144
144
|
if errors:
|
145
|
-
self.errf, txt = errdesc(errors)
|
145
|
+
self.errf, txt = errdesc(self.asrv.vfs, errors)
|
146
146
|
self.log("\n".join(([repr(self.errf)] + txt[1:])))
|
147
147
|
self.ser(self.errf)
|
148
148
|
|