feat(tower): register server + delta push to box
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Always-on: POST /register {id, have} -> push the staging delta to the box's
|
||||
file-server (:8080). The box IP is the request source address."""
|
||||
import json, os, urllib.request
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
|
||||
STAGING = os.environ.get("LISAEL_STAGING", "/home/clems/lisael-content/podcasts")
|
||||
PORT = int(os.environ.get("LISAEL_PORT", "9555"))
|
||||
BOX_PORT = int(os.environ.get("LISAEL_BOX_PORT", "8080"))
|
||||
|
||||
def staging_files():
|
||||
if not os.path.isdir(STAGING):
|
||||
return []
|
||||
return sorted(f for f in os.listdir(STAGING) if not f.startswith("."))
|
||||
|
||||
def compute_delta(staging, have):
|
||||
"""Files the box is missing; manifest.json only when something else changed."""
|
||||
haveset = set(have)
|
||||
files = [f for f in staging if f != "manifest.json" and f not in haveset]
|
||||
if files and "manifest.json" in staging:
|
||||
files.append("manifest.json")
|
||||
return files
|
||||
|
||||
def push_file(ip, name):
|
||||
data = open(os.path.join(STAGING, name), "rb").read()
|
||||
url = f"http://{ip}:{BOX_PORT}/put?name=podcasts/{name}"
|
||||
with urllib.request.urlopen(urllib.request.Request(url, data=data, method="POST"),
|
||||
timeout=40) as r:
|
||||
return r.status
|
||||
|
||||
class H(BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
if self.path.split("?")[0] != "/register":
|
||||
self.send_error(404); return
|
||||
ip = self.client_address[0]
|
||||
try:
|
||||
n = int(self.headers.get("Content-Length", 0))
|
||||
body = json.loads(self.rfile.read(n) or b"{}")
|
||||
except Exception:
|
||||
self.send_error(400); return
|
||||
delta = compute_delta(staging_files(), body.get("have", []) or [])
|
||||
print(f"register {ip} id={body.get('id')} have={len(body.get('have',[]) or [])} push={len(delta)}",
|
||||
flush=True)
|
||||
ok = 0
|
||||
for f in delta:
|
||||
try:
|
||||
push_file(ip, f); ok += 1
|
||||
except Exception as e:
|
||||
print("push fail", f, e, flush=True)
|
||||
self.send_response(200); self.send_header("Content-Type", "application/json"); self.end_headers()
|
||||
self.wfile.write(json.dumps({"pushed": ok, "of": len(delta)}).encode())
|
||||
|
||||
def log_message(self, *a):
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"lisael-content on :{PORT} staging={STAGING}", flush=True)
|
||||
ThreadingHTTPServer(("0.0.0.0", PORT), H).serve_forever()
|
||||
@@ -0,0 +1,14 @@
|
||||
from lisael_server import compute_delta
|
||||
|
||||
def test_delta():
|
||||
stg = ["oli_01.m4a", "oli.bin", "bestioles_01.mp3", "manifest.json"]
|
||||
# empty box -> everything, manifest last
|
||||
assert compute_delta(stg, []) == ["oli_01.m4a", "oli.bin", "bestioles_01.mp3", "manifest.json"]
|
||||
# up-to-date box -> nothing (not even the manifest)
|
||||
assert compute_delta(stg, ["oli_01.m4a", "oli.bin", "bestioles_01.mp3"]) == []
|
||||
# box missing the cover -> .bin + manifest
|
||||
assert compute_delta(stg, ["oli_01.m4a", "bestioles_01.mp3"]) == ["oli.bin", "manifest.json"]
|
||||
print("OK")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_delta()
|
||||
Reference in New Issue
Block a user