more status on admin panel

This commit is contained in:
ed 2021-06-12 01:39:14 +02:00
parent 081d2cc5d7
commit 88ce008e16
7 changed files with 124 additions and 45 deletions

View file

@ -1373,11 +1373,13 @@ class HttpCli(object):
for y in [self.rvol, self.wvol, self.avol] for y in [self.rvol, self.wvol, self.avol]
] ]
vstate = {}
if self.avol and not self.args.no_rescan: if self.avol and not self.args.no_rescan:
x = self.conn.hsrv.broker.put(True, "up2k.get_volstate") x = self.conn.hsrv.broker.put(True, "up2k.get_state")
vstate = json.loads(x.get()) vs = json.loads(x.get())
vstate = {("/" + k).rstrip("/") + "/": v for k, v in vstate.items()} vstate = {("/" + k).rstrip("/") + "/": v for k, v in vs["volstate"].items()}
else:
vstate = {}
vs = {"scanning": None, "hashq": None, "tagq": None}
html = self.j2( html = self.j2(
"splash", "splash",
@ -1386,6 +1388,9 @@ class HttpCli(object):
wvol=wvol, wvol=wvol,
avol=avol, avol=avol,
vstate=vstate, vstate=vstate,
scanning=vs["scanning"],
hashq=vs["hashq"],
tagq=vs["tagq"],
url_suf=suf, url_suf=suf,
) )
self.reply(html.encode("utf-8"), headers=NO_STORE) self.reply(html.encode("utf-8"), headers=NO_STORE)

View file

@ -1,7 +1,6 @@
# coding: utf-8 # coding: utf-8
from __future__ import print_function, unicode_literals from __future__ import print_function, unicode_literals
import re
import os import os
import sys import sys
import json import json

View file

@ -61,6 +61,8 @@ class Up2k(object):
self.mutex = threading.Lock() self.mutex = threading.Lock()
self.hashq = Queue() self.hashq = Queue()
self.tagq = Queue() self.tagq = Queue()
self.n_hashq = 0
self.n_tagq = 0
self.volstate = {} self.volstate = {}
self.registry = {} self.registry = {}
self.entags = {} self.entags = {}
@ -129,8 +131,14 @@ class Up2k(object):
def log(self, msg, c=0): def log(self, msg, c=0):
self.log_func("up2k", msg + "\033[K", c) self.log_func("up2k", msg + "\033[K", c)
def get_volstate(self): def get_state(self):
return json.dumps(self.volstate, indent=4) ret = {
"volstate": self.volstate,
"scanning": hasattr(self, "pp"),
"hashq": self.n_hashq,
"tagq": self.n_tagq,
}
return json.dumps(ret, indent=4)
def rescan(self, all_vols, scan_vols): def rescan(self, all_vols, scan_vols):
if hasattr(self, "pp"): if hasattr(self, "pp"):
@ -1233,6 +1241,7 @@ class Up2k(object):
if "e2t" in self.flags[ptop]: if "e2t" in self.flags[ptop]:
self.tagq.put([ptop, wark, rd, fn]) self.tagq.put([ptop, wark, rd, fn])
self.n_tagq += 1
return True return True
@ -1410,7 +1419,13 @@ class Up2k(object):
prev[ptop] = etag prev[ptop] = etag
def _tagger(self): def _tagger(self):
with self.mutex:
self.n_tagq += 1
while True: while True:
with self.mutex:
self.n_tagq -= 1
ptop, wark, rd, fn = self.tagq.get() ptop, wark, rd, fn = self.tagq.get()
if "e2t" not in self.flags[ptop]: if "e2t" not in self.flags[ptop]:
continue continue
@ -1441,8 +1456,16 @@ class Up2k(object):
self.log("tagged {} ({}+{})".format(abspath, ntags1, len(tags) - ntags1)) self.log("tagged {} ({}+{})".format(abspath, ntags1, len(tags) - ntags1))
def _hasher(self): def _hasher(self):
with self.mutex:
self.n_hashq += 1
while True: while True:
with self.mutex:
self.n_hashq -= 1
# self.log("hashq {}".format(self.n_hashq))
ptop, rd, fn = self.hashq.get() ptop, rd, fn = self.hashq.get()
# self.log("hashq {} pop {}/{}/{}".format(self.n_hashq, ptop, rd, fn))
if "e2d" not in self.flags[ptop]: if "e2d" not in self.flags[ptop]:
continue continue
@ -1458,6 +1481,8 @@ class Up2k(object):
with self.mutex: with self.mutex:
self.register_vpath(ptop, flags) self.register_vpath(ptop, flags)
self.hashq.put([ptop, rd, fn]) self.hashq.put([ptop, rd, fn])
self.n_hashq += 1
# self.log("hashq {} push {}/{}/{}".format(self.n_hashq, ptop, rd, fn))
def up2k_chunksize(filesize): def up2k_chunksize(filesize):

View file

@ -26,10 +26,20 @@ a {
border-radius: .2em; border-radius: .2em;
padding: .2em .8em; padding: .2em .8em;
} }
td, th { table {
border-collapse: collapse;
}
.vols td,
.vols th {
padding: .3em .6em; padding: .3em .6em;
text-align: left; text-align: left;
} }
.num td {
padding: .1em .7em .1em 0;
}
.num td:first-child {
text-align: right;
}
.btns { .btns {
margin: 1em 0; margin: 1em 0;
} }

View file

@ -15,16 +15,24 @@
{%- if avol %} {%- if avol %}
<h1>admin panel:</h1> <h1>admin panel:</h1>
<table> <table><tr><td> <!-- hehehe -->
<thead><tr><th>vol</th><th>action</th><th>status</th></tr></thead> <table class="num">
<tbody> <tr><td>scanning</td><td>{{ scanning }}</td></tr>
{% for mp in avol %} <tr><td>hash-q</td><td>{{ hashq }}</td></tr>
{%- if mp in vstate and vstate[mp] %} <tr><td>tag-q</td><td>{{ tagq }}</td></tr>
<tr><td><a href="{{ mp }}{{ url_suf }}">{{ mp }}</a></td><td><a href="{{ mp }}?scan">rescan</a></td><td>{{ vstate[mp] }}</td></tr> </table>
{%- endif %} </td><td>
{% endfor %} <table class="vols">
</tbody> <thead><tr><th>vol</th><th>action</th><th>status</th></tr></thead>
</table> <tbody>
{% for mp in avol %}
{%- if mp in vstate and vstate[mp] %}
<tr><td><a href="{{ mp }}{{ url_suf }}">{{ mp }}</a></td><td><a href="{{ mp }}?scan">rescan</a></td><td>{{ vstate[mp] }}</td></tr>
{%- endif %}
{% endfor %}
</tbody>
</table>
</td></tr></table>
<div class="btns"> <div class="btns">
<a href="{{ avol[0] }}?stack">dump stack</a> <a href="{{ avol[0] }}?stack">dump stack</a>
</div> </div>

View file

@ -3,10 +3,13 @@ set -ex
pids=() pids=()
for py in python{2,3}; do for py in python{2,3}; do
$py -m unittest discover -s tests >/dev/null & nice $py -m unittest discover -s tests >/dev/null &
pids+=($!) pids+=($!)
done done
python3 scripts/test/smoketest.py &
pids+=($!)
for pid in ${pids[@]}; do for pid in ${pids[@]}; do
wait $pid wait $pid
done done

View file

@ -1,18 +1,25 @@
import os import os
import sys import sys
import time import time
import signal import shlex
import shutil import shutil
import signal
import tempfile import tempfile
import requests import requests
import threading import threading
import subprocess as sp import subprocess as sp
CPP = []
class Cpp(object): class Cpp(object):
def __init__(self, args): def __init__(self, args):
args = [sys.executable, "-m", "copyparty"] + args
print(" ".join([shlex.quote(x) for x in args]))
self.ls_pre = set(list(os.listdir())) self.ls_pre = set(list(os.listdir()))
self.p = sp.Popen([sys.executable, "-m", "copyparty"] + args) self.p = sp.Popen(args)
# , stdout=sp.PIPE, stderr=sp.PIPE) # , stdout=sp.PIPE, stderr=sp.PIPE)
self.t = threading.Thread(target=self._run) self.t = threading.Thread(target=self._run)
@ -23,10 +30,11 @@ class Cpp(object):
self.so, self.se = self.p.communicate() self.so, self.se = self.p.communicate()
def stop(self, wait): def stop(self, wait):
# self.p.kill()
os.kill(self.p.pid, signal.SIGINT)
if wait: if wait:
self.t.join() os.kill(self.p.pid, signal.SIGINT)
self.t.join(timeout=2)
else:
self.p.kill() # macos py3.8
def clean(self): def clean(self):
t = os.listdir() t = os.listdir()
@ -34,6 +42,22 @@ class Cpp(object):
if f not in self.ls_pre and f.startswith("up."): if f not in self.ls_pre and f.startswith("up."):
os.unlink(f) os.unlink(f)
def await_idle(self, ub, timeout):
req = ["scanning</td><td>False", "hash-q</td><td>0", "tag-q</td><td>0"]
u = ub + "?h"
for _ in range(timeout * 10):
try:
time.sleep(0.1)
r = requests.get(u, timeout=0.1)
for x in req:
if x not in r.text:
print("ST: miss " + x)
raise Exception()
print("ST: idle")
return
except:
pass
def tc1(): def tc1():
ub = "http://127.0.0.1:4321/" ub = "http://127.0.0.1:4321/"
@ -61,10 +85,10 @@ def tc1():
ovid = f.read() ovid = f.read()
args = [ args = [
"-p", "-p4321",
"4321",
"-e2dsa", "-e2dsa",
"-e2tsr", "-e2tsr",
"--no-mutagen",
"--th-ff-jpg", "--th-ff-jpg",
"--hist", "--hist",
os.path.join(td, "dbm"), os.path.join(td, "dbm"),
@ -89,30 +113,24 @@ def tc1():
hp = None hp = None
if pd.endswith("st/a"): if pd.endswith("st/a"):
hp = os.path.join(td, "db1") hp = hpaths[ud] = os.path.join(td, "db1")
elif pd[:-1].endswith("a/j/"): elif pd[:-1].endswith("a/j/"):
hp = os.path.join(td, "dbm") hpaths[ud] = os.path.join(td, "dbm")
hp = None
else: else:
hp = "-" hp = "-"
hpaths[ud] = os.path.join(pd, ".hist")
hpaths[ud] = os.path.join(pd, ".hist") if hp == "-" else hp arg = "{}:{}:{}".format(pd, ud, p, hp)
args += ["-v", "{}:{}:{}:chist={}".format(pd, ud, p, hp)] if hp:
arg += ":chist=" + hp
args += ["-v", arg]
# print(repr(args))
# return # return
cpp = Cpp(args) cpp = Cpp(args)
CPP.append(cpp)
up = False cpp.await_idle(ub, 3)
for n in range(30):
try:
time.sleep(0.1)
requests.get(ub + "?h", timeout=0.1)
up = True
break
except:
pass
assert up
for d in udirs: for d in udirs:
vid = ovid + "\n{}".format(d).encode("utf-8") vid = ovid + "\n{}".format(d).encode("utf-8")
@ -147,6 +165,7 @@ def tc1():
raise Exception("thumb {} with perm {} at {}".format(ok, p, u)) raise Exception("thumb {} with perm {} at {}".format(ok, p, u))
# check tags # check tags
cpp.await_idle(ub, 5)
for d, p in zip(udirs, perms): for d, p in zip(udirs, perms):
u = "{}{}?ls".format(ub, d) u = "{}{}?ls".format(ub, d)
r = requests.get(u) r = requests.get(u)
@ -163,7 +182,7 @@ def tc1():
raise Exception("ls {} with perm {} at {}".format(ok, p, u)) raise Exception("ls {} with perm {} at {}".format(ok, p, u))
if (tag and p != "a") or (not tag and p == "a"): if (tag and p != "a") or (not tag and p == "a"):
raise Exception("tag {} with perm {} at {}".format(ok, p, u)) raise Exception("tag {} with perm {} at {}".format(tag, p, u))
if tag is not None and tag != "48x32": if tag is not None and tag != "48x32":
raise Exception("tag [{}] at {}".format(tag, u)) raise Exception("tag [{}] at {}".format(tag, u))
@ -171,8 +190,18 @@ def tc1():
cpp.stop(True) cpp.stop(True)
def run(tc):
try:
tc()
finally:
try:
CPP[0].stop(False)
except:
pass
def main(): def main():
tc1() run(tc1)
if __name__ == "__main__": if __name__ == "__main__":