Compare commits

...

7 Commits

Author SHA1 Message Date
ed
016dba4ca9 v0.11.38 2021-07-13 00:35:34 +02:00
ed
39c7ef305f add a link to clear settings on the js crash page 2021-07-13 00:33:46 +02:00
ed
849c1dc848 video-player: add hotkeys m=mute, f=fullscreen 2021-07-13 00:23:48 +02:00
ed
61414014fe gallery: fix link overlapping image 2021-07-13 00:14:06 +02:00
ed
578a915884 stack/thread monitors in mpw + better thread names 2021-07-12 23:03:52 +02:00
ed
eacafb8a63 add option to log summary of running threads 2021-07-12 22:57:37 +02:00
ed
4446760f74 fix link to ?stack on rootless configs 2021-07-12 22:55:38 +02:00
13 changed files with 124 additions and 51 deletions

View File

@@ -23,7 +23,7 @@ from textwrap import dedent
from .__init__ import E, WINDOWS, VT100, PY2, unicode
from .__version__ import S_VERSION, S_BUILD_DT, CODENAME
from .svchub import SvcHub
from .util import py_desc, align_tab, IMPLICATIONS, alltrace
from .util import py_desc, align_tab, IMPLICATIONS
HAVE_SSL = True
try:
@@ -191,16 +191,6 @@ def sighandler(sig=None, frame=None):
print("\n".join(msg))
def stackmon(fp, ival):
ctr = 0
while True:
ctr += 1
time.sleep(ival)
st = "{}, {}\n{}".format(ctr, time.time(), alltrace())
with open(fp, "wb") as f:
f.write(st.encode("utf-8", "replace"))
def run_argparse(argv, formatter):
ap = argparse.ArgumentParser(
formatter_class=formatter,
@@ -346,6 +336,7 @@ def run_argparse(argv, formatter):
ap2.add_argument("--no-fastboot", action="store_true", help="wait for up2k indexing")
ap2.add_argument("--no-htp", action="store_true", help="disable httpserver threadpool, create threads as-needed instead")
ap2.add_argument("--stackmon", metavar="P,S", type=u, help="write stacktrace to Path every S second")
ap2.add_argument("--log-thrs", metavar="SEC", type=float, help="list active threads every SEC")
return ap.parse_args(args=argv[1:])
# fmt: on
@@ -385,16 +376,6 @@ def main(argv=None):
except AssertionError:
al = run_argparse(argv, Dodge11874)
if al.stackmon:
fp, f = al.stackmon.rsplit(",", 1)
f = int(f)
t = threading.Thread(
target=stackmon,
args=(fp, f),
)
t.daemon = True
t.start()
# propagate implications
for k1, k2 in IMPLICATIONS:
if getattr(al, k1):

View File

@@ -1,8 +1,8 @@
# coding: utf-8
VERSION = (0, 11, 37)
VERSION = (0, 11, 38)
CODENAME = "the grid"
BUILD_DT = (2021, 7, 12)
BUILD_DT = (2021, 7, 13)
S_VERSION = ".".join(map(str, VERSION))
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)

View File

@@ -27,18 +27,17 @@ class BrokerMp(object):
cores = mp.cpu_count()
self.log("broker", "booting {} subprocesses".format(cores))
for n in range(cores):
for n in range(1, cores + 1):
q_pend = mp.Queue(1)
q_yield = mp.Queue(64)
proc = mp.Process(target=MpWorker, args=(q_pend, q_yield, self.args, n))
proc.q_pend = q_pend
proc.q_yield = q_yield
proc.nid = n
proc.clients = {}
thr = threading.Thread(
target=self.collector, args=(proc,), name="mp-collector"
target=self.collector, args=(proc,), name="mp-sink-{}".format(n)
)
thr.daemon = True
thr.start()

View File

@@ -35,7 +35,7 @@ class MpWorker(object):
self.asrv = AuthSrv(args, None, False)
# instantiate all services here (TODO: inheritance?)
self.httpsrv = HttpSrv(self, True)
self.httpsrv = HttpSrv(self, n)
# on winxp and some other platforms,
# use thr.join() to block all signals

View File

@@ -19,7 +19,7 @@ class BrokerThr(object):
self.mutex = threading.Lock()
# instantiate all services here (TODO: inheritance?)
self.httpsrv = HttpSrv(self)
self.httpsrv = HttpSrv(self, None)
def shutdown(self):
# self.log("broker", "shutting down")

View File

@@ -37,7 +37,6 @@ class HttpCli(object):
self.ip = conn.addr[0]
self.addr = conn.addr # type: tuple[str, int]
self.args = conn.args
self.is_mp = conn.is_mp
self.asrv = conn.asrv # type: AuthSrv
self.ico = conn.ico
self.thumbcli = conn.thumbcli
@@ -343,6 +342,9 @@ class HttpCli(object):
if "tree" in self.uparam:
return self.tx_tree()
if "stack" in self.uparam:
return self.tx_stack()
# conditional redirect to single volumes
if self.vpath == "" and not self.ouparam:
nread = len(self.rvol)
@@ -372,9 +374,6 @@ class HttpCli(object):
if "scan" in self.uparam:
return self.scanvol()
if "stack" in self.uparam:
return self.tx_stack()
return self.tx_browser()
def handle_options(self):

View File

@@ -34,7 +34,6 @@ class HttpConn(object):
self.args = hsrv.args
self.asrv = hsrv.asrv
self.is_mp = hsrv.is_mp
self.cert_path = hsrv.cert_path
enth = HAVE_PIL and not self.args.no_thumb

View File

@@ -27,7 +27,7 @@ except ImportError:
sys.exit(1)
from .__init__ import E, PY2, MACOS
from .util import spack, min_ex
from .util import spack, min_ex, start_stackmon, start_log_thrs
from .httpconn import HttpConn
if PY2:
@@ -42,14 +42,14 @@ class HttpSrv(object):
relying on MpSrv for performance (HttpSrv is just plain threads)
"""
def __init__(self, broker, is_mp=False):
def __init__(self, broker, nid):
self.broker = broker
self.is_mp = is_mp
self.nid = nid
self.args = broker.args
self.log = broker.log
self.asrv = broker.asrv
self.name = "httpsrv-i{:x}".format(os.getpid())
self.name = "httpsrv" + ("-n{}-i{:x}".format(nid, os.getpid()) if nid else "")
self.mutex = threading.Lock()
self.stopping = False
@@ -81,10 +81,18 @@ class HttpSrv(object):
if self.tp_q:
self.start_threads(4)
t = threading.Thread(target=self.thr_scaler)
name = "httpsrv-scaler" + ("-{}".format(nid) if nid else "")
t = threading.Thread(target=self.thr_scaler, name=name)
t.daemon = True
t.start()
if nid:
if self.args.stackmon:
start_stackmon(self.args.stackmon, nid)
if self.args.log_thrs:
start_log_thrs(self.log, self.args.log_thrs, nid)
def start_threads(self, n):
self.tp_nthr += n
if self.args.log_htp:
@@ -93,7 +101,7 @@ class HttpSrv(object):
for _ in range(n):
thr = threading.Thread(
target=self.thr_poolw,
name="httpsrv-poolw",
name=self.name + "-poolw",
)
thr.daemon = True
thr.start()
@@ -115,9 +123,14 @@ class HttpSrv(object):
self.stop_threads(4)
def listen(self, sck, nlisteners):
ip, port = sck.getsockname()
self.srvs.append(sck)
self.nclimax = math.ceil(self.args.nc * 1.0 / nlisteners)
t = threading.Thread(target=self.thr_listen, args=(sck,))
t = threading.Thread(
target=self.thr_listen,
args=(sck,),
name="httpsrv-n{}-listen-{}-{}".format(self.nid or "0", ip, port),
)
t.daemon = True
t.start()
@@ -181,7 +194,7 @@ class HttpSrv(object):
thr = threading.Thread(
target=self.thr_client,
args=(sck, addr),
name="httpsrv-{}-{}".format(addr[0].split(".", 2)[-1][-6:], addr[1]),
name="httpconn-{}-{}".format(addr[0].split(".", 2)[-1][-6:], addr[1]),
)
thr.daemon = True
thr.start()
@@ -198,11 +211,11 @@ class HttpSrv(object):
try:
sck, addr = task
me = threading.current_thread()
me.name = (
"httpsrv-{}-{}".format(addr[0].split(".", 2)[-1][-6:], addr[1]),
me.name = "httpconn-{}-{}".format(
addr[0].split(".", 2)[-1][-6:], addr[1]
)
self.thr_client(sck, addr)
me.name = "httpsrv-poolw"
me.name = self.name + "-poolw"
except:
self.log(self.name, "thr_client: " + min_ex(), 3)
@@ -228,7 +241,7 @@ class HttpSrv(object):
if self.tp_q.empty():
break
self.log("httpsrv-i" + str(os.getpid()), "ok bye")
self.log(self.name, "ok bye")
def thr_client(self, sck, addr):
"""thread managing one tcp client"""

View File

@@ -11,7 +11,7 @@ from datetime import datetime, timedelta
import calendar
from .__init__ import E, PY2, WINDOWS, MACOS, VT100
from .util import mp
from .util import mp, start_log_thrs, start_stackmon
from .authsrv import AuthSrv
from .tcpsrv import TcpSrv
from .up2k import Up2k
@@ -42,6 +42,12 @@ class SvcHub(object):
if args.lo:
self._setup_logfile(printed)
if args.stackmon:
start_stackmon(args.stackmon, 0)
if args.log_thrs:
start_log_thrs(self.log, args.log_thrs, 0)
# initiate all services to manage
self.asrv = AuthSrv(self.args, self.log, False)
if args.ls:

View File

@@ -16,6 +16,7 @@ import mimetypes
import contextlib
import subprocess as sp # nosec
from datetime import datetime
from collections import Counter
from .__init__ import PY2, WINDOWS, ANYWIN
from .stolen import surrogateescape
@@ -282,6 +283,62 @@ def alltrace():
return "\n".join(rret + bret)
def start_stackmon(arg_str, nid):
suffix = "-{}".format(nid) if nid else ""
fp, f = arg_str.rsplit(",", 1)
f = int(f)
t = threading.Thread(
target=stackmon,
args=(fp, f, suffix),
name="stackmon" + suffix,
)
t.daemon = True
t.start()
def stackmon(fp, ival, suffix):
ctr = 0
while True:
ctr += 1
time.sleep(ival)
st = "{}, {}\n{}".format(ctr, time.time(), alltrace())
with open(fp + suffix, "wb") as f:
f.write(st.encode("utf-8", "replace"))
def start_log_thrs(logger, ival, nid):
ival = int(ival)
tname = lname = "log-thrs"
if nid:
tname = "logthr-n{}-i{:x}".format(nid, os.getpid())
lname = tname[3:]
t = threading.Thread(
target=log_thrs,
args=(logger, ival, lname),
name=tname,
)
t.daemon = True
t.start()
def log_thrs(log, ival, name):
while True:
time.sleep(ival)
tv = [x.name for x in threading.enumerate()]
tv = [
x.split("-")[0]
if x.startswith("httpconn-") or x.startswith("thumb-")
else "listen"
if "-listen-" in x
else x
for x in tv
if not x.startswith("pydevd.")
]
tv = ["{}\033[36m{}".format(v, k) for k, v in sorted(Counter(tv).items())]
log(name, "\033[0m \033[33m".join(tv), 3)
def min_ex():
et, ev, tb = sys.exc_info()
tb = traceback.extract_tb(tb)

View File

@@ -32,7 +32,12 @@ window.baguetteBox = (function () {
re_v = /.+\.(webm|mp4)(\?|$)/i,
data = {}, // all galleries
imagesElements = [],
documentLastFocus = null;
documentLastFocus = null,
isFullscreen = false;
var onFSC = function (e) {
isFullscreen = !!document.fullscreenElement;
};
var overlayClickHandler = function (event) {
if (event.target.id.indexOf('baguette-img') !== -1) {
@@ -226,6 +231,16 @@ window.baguetteBox = (function () {
playpause();
else if (k == "KeyU" || k == "KeyO")
relseek(k == "KeyU" ? -10 : 10);
else if (k == "KeyM" && vid())
vid().muted = !vid().muted;
else if (k == "KeyF")
try {
if (isFullscreen)
document.exitFullscreen();
else
vid().requestFullscreen();
}
catch (ex) { }
}
function keyUpHandler(e) {
@@ -335,6 +350,7 @@ window.baguetteBox = (function () {
bind(document, 'keydown', keyDownHandler);
bind(document, 'keyup', keyUpHandler);
bind(document, 'fullscreenchange', onFSC);
currentIndex = chosenImageIndex;
touch = {
count: 0,
@@ -387,6 +403,7 @@ window.baguetteBox = (function () {
unbind(document, 'keydown', keyDownHandler);
unbind(document, 'keyup', keyUpHandler);
unbind(document, 'fullscreenchange', onFSC);
// Fade out and hide the overlay
overlay.className = '';
setTimeout(function () {

View File

@@ -1179,8 +1179,10 @@ html.light #tree::-webkit-scrollbar {
display: inline-block;
width: auto;
height: auto;
max-height: 100%;
max-width: 100%;
max-height: 100%;
max-height: calc(100% - 1.4em);
margin-bottom: 1.4em;
vertical-align: middle;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
}
@@ -1189,11 +1191,10 @@ html.light #tree::-webkit-scrollbar {
}
#baguetteBox-overlay .full-image figcaption {
display: block;
position: absolute;
bottom: 0;
position: fixed;
bottom: .1em;
width: 100%;
text-align: center;
line-height: 1.8;
white-space: normal;
color: #ccc;
}

View File

@@ -37,6 +37,7 @@ function vis_exh(msg, url, lineNo, columnNo, error) {
html.push('<h2>' + find[a] + '</h2>' +
esc(String(error[find[a]])).replace(/\n/g, '<br />\n'));
}
html.push('<p style="border-top:1px solid #999;margin-top:1.5em;font-size:1.4em">if you are stuck here, try to <a href="#" onclick="localStorage.clear();location.reload();">reset copyparty settings</a></p>');
document.body.innerHTML = html.join('\n');
var s = mknod('style');