feat(server): modularize backend and admin console

This commit is contained in:
2026-07-14 01:38:41 +00:00
parent 9a6ac1e4ed
commit 95dd32c75a
261 changed files with 39289 additions and 2156 deletions
@@ -0,0 +1,168 @@
from datetime import datetime, timezone, timedelta
import secrets
import db
def get_device(device_id: str):
conn = db.get_conn()
row = conn.execute("SELECT * FROM devices WHERE device_id=?", (device_id,)).fetchone()
conn.close()
return row
def get_license(license_id: str):
conn = db.get_conn()
row = conn.execute("SELECT * FROM licenses WHERE license_id=?", (license_id,)).fetchone()
conn.close()
return row
def touch_device(device_id: str):
conn = db.get_conn()
conn.execute("UPDATE devices SET last_seen_at=datetime('now') WHERE device_id=?", (device_id,))
conn.commit()
conn.close()
def issue_device(app_id: str, channel: str, license_key_hash: str, installation_id: str, machine_hash: str, ip: str):
now = datetime.now(timezone.utc)
conn = db.get_conn()
conn.execute("BEGIN IMMEDIATE")
try:
channel_row = conn.execute("SELECT * FROM channels WHERE app_id=? AND channel_code=?", (app_id, channel)).fetchone()
if not channel_row:
conn.rollback()
return {"status": "channel_not_found"}
if not channel_row["enabled"]:
conn.rollback()
return {"status": "channel_disabled"}
license_row = conn.execute("SELECT * FROM licenses WHERE license_key_hash=?", (license_key_hash,)).fetchone()
try:
expiry = datetime.fromisoformat((license_row["valid_until"] if license_row else "").replace("Z", "+00:00"))
except ValueError:
expiry = now - timedelta(seconds=1)
if (
not license_row
or license_row["status"] != "active"
or expiry <= now
or license_row["app_id"] != app_id
or license_row["channel_code"] != channel
):
conn.rollback()
return {"status": "license_invalid"}
device_row = conn.execute("SELECT * FROM devices WHERE app_id=? AND installation_id=?", (app_id, installation_id)).fetchone()
if device_row and device_row["disabled"]:
conn.rollback()
return {"status": "device_disabled", "reason": device_row["disabled_reason"] or "设备已被禁用"}
if device_row and device_row["license_id"] not in ("", license_row["license_id"]):
conn.rollback()
return {"status": "license_conflict"}
device_id = device_row["device_id"] if device_row else "dev_" + secrets.token_hex(16)
seq = int(device_row["credential_seq"]) if device_row else 1
bound = conn.execute("SELECT 1 FROM license_devices WHERE license_id=? AND device_id=?", (license_row["license_id"], device_id)).fetchone()
used = conn.execute("SELECT COUNT(*) FROM license_devices WHERE license_id=?", (license_row["license_id"],)).fetchone()[0]
if not bound and used >= int(license_row["max_devices"]):
conn.rollback()
return {"status": "license_device_limit"}
if device_row:
conn.execute(
"UPDATE devices SET machine_hash=?,license_id=?,channel=?,last_seen_at=datetime('now'),last_ip=? WHERE device_id=?",
(machine_hash, license_row["license_id"], channel, ip, device_id),
)
else:
conn.execute(
"INSERT INTO devices(device_id,app_id,installation_id,machine_hash,credential_seq,last_ip,license_id,channel) VALUES(?,?,?,?,?,?,?,?)",
(device_id, app_id, installation_id, machine_hash, seq, ip, license_row["license_id"], channel),
)
conn.execute("INSERT OR IGNORE INTO license_devices(license_id,device_id) VALUES(?,?)", (license_row["license_id"], device_id))
conn.commit()
return {"status": "ok", "device_id": device_id, "license": license_row, "credential_seq": seq, "issued_at": now}
except Exception:
conn.rollback()
raise
finally:
conn.close()
def get_update_context(app_id: str, channel: str):
conn = db.get_conn()
try:
channel_row = conn.execute("SELECT * FROM channels WHERE app_id=? AND channel_code=?", (app_id, channel)).fetchone()
if not channel_row:
return {"status": "channel_not_found"}
if not channel_row["enabled"]:
return {"status": "channel_disabled"}
version = conn.execute(
"SELECT * FROM versions WHERE app_id=? AND channel=? AND latest=1",
(app_id, channel),
).fetchone()
policy = conn.execute(
"SELECT * FROM version_policies WHERE app_id=? AND channel=?",
(app_id, channel),
).fetchone()
return {"status": "ok", "version": version, "policy": policy}
finally:
conn.close()
def get_download_files(version_id: int, app_id: str, channel: str, version: str, identity: dict, ip: str, user_agent: str):
conn = db.get_conn()
version_row = conn.execute("SELECT app_id,channel,version FROM versions WHERE id=?", (version_id,)).fetchone()
if not version_row or version_row["app_id"] != app_id or version_row["channel"] != channel or version_row["version"] != version:
conn.close()
return {"status": "not_found"}
rows = conn.execute("SELECT path, sha256, size FROM version_files WHERE version_id=?", (version_id,)).fetchall()
conn.executemany(
"""INSERT INTO download_logs(device_id,license_id,app_id,version,channel_code,file_path,file_size,result,ip,user_agent)
VALUES(?,?,?,?,?,?,?,?,?,?)""",
[
(identity["device_id"], identity["license_id"], app_id, version, channel, row["path"], row["size"], "authorized", ip, user_agent)
for row in rows
],
)
conn.commit()
conn.close()
return {"status": "ok", "files": rows}
def insert_download_report_logs(values: list[tuple]) -> int:
conn = db.get_conn()
if values:
conn.executemany(
"INSERT INTO download_logs(device_id,license_id,app_id,version,channel_code,file_path,file_size,result,ip,user_agent) VALUES(?,?,?,?,?,?,?,?,?,?)",
values,
)
conn.commit()
conn.close()
return len(values)
def get_manifest_version_files(version_id: int):
conn = db.get_conn()
version = conn.execute(
"SELECT app_id, channel, version, create_time FROM versions WHERE id=?",
(version_id,),
).fetchone()
if not version:
conn.close()
return None, []
rows = conn.execute("SELECT path, sha256, size FROM version_files WHERE version_id=?", (version_id,)).fetchall()
conn.close()
return version, rows
def insert_upgrade_log(device_id: str, from_version: str, to_version: str, result: str):
conn = db.get_conn()
conn.execute(
"""
INSERT INTO upgrade_logs(device_id,from_ver,to_ver,result,create_time)
VALUES (?,?,?,?,datetime('now'))
""",
(device_id, from_version, to_version, result),
)
conn.commit()
conn.close()