Initial commit: LoraTester Android + server

This commit is contained in:
2026-06-04 14:39:14 +03:00
parent 253a7d74ca
commit 81eaa95df3
26 changed files with 1898 additions and 106 deletions
+92
View File
@@ -145,6 +145,98 @@ def get_chat():
return jsonify(storage.get_chat(since, limit))
@app.post("/api/commands")
def post_command():
body = request.get_json(force=True, silent=True) or {}
from_id = body.get("from_device_id")
to_id = body.get("to_device_id")
kind = body.get("kind")
if not from_id or not to_id or not kind:
return jsonify({"error": "from_device_id, to_device_id, kind required"}), 400
try:
return jsonify(
storage.enqueue_command(
str(from_id), str(to_id), str(kind), body.get("payload")
)
)
except ValueError as e:
return jsonify({"error": str(e)}), 400
@app.get("/api/commands/pending")
def commands_pending():
if not is_android_client(request.headers):
return jsonify({"error": "Android only"}), 403
device_id = request.args.get("device_id")
if not device_id:
return jsonify({"error": "device_id required"}), 400
limit = int(request.args.get("limit", 20))
try:
return jsonify(storage.poll_pending_commands(str(device_id), limit))
except ValueError as e:
return jsonify({"error": str(e)}), 400
@app.get("/api/commands")
def commands_list():
to_device_id = request.args.get("to_device_id")
limit = int(request.args.get("limit", 50))
return jsonify(storage.list_commands(to_device_id, limit))
@app.post("/api/paired-tracks/start")
def paired_tracks_start():
body = request.get_json(force=True, silent=True) or {}
initiator = body.get("initiator") or (
body.get("device_id") if is_android_client(request.headers) else storage.WEB_SENDER_ID
)
device_ids = body.get("device_ids")
try:
return jsonify(
storage.start_paired_track(
device_ids if isinstance(device_ids, list) else None,
str(initiator),
)
)
except ValueError as e:
return jsonify({"error": str(e)}), 400
@app.get("/api/paired-tracks/active")
def paired_tracks_active():
session = storage.get_active_paired_track()
return jsonify({"active": session is not None, "session": session})
@app.post("/api/paired-tracks/ack")
def paired_tracks_ack():
if not is_android_client(request.headers):
return jsonify({"error": "Android only"}), 403
body = request.get_json(force=True, silent=True) or {}
session_id = body.get("session_id")
device_id = body.get("device_id")
track_id = body.get("track_id")
if session_id is None or not device_id or track_id is None:
return jsonify({"error": "session_id, device_id, track_id required"}), 400
try:
return jsonify(
storage.ack_paired_track(int(session_id), str(device_id), int(track_id))
)
except ValueError as e:
return jsonify({"error": str(e)}), 400
@app.post("/api/paired-tracks/cancel")
def paired_tracks_cancel():
body = request.get_json(force=True, silent=True) or {}
session_id = body.get("session_id")
try:
sid = int(session_id) if session_id is not None else None
return jsonify(storage.cancel_paired_track(sid))
except ValueError as e:
return jsonify({"error": str(e)}), 400
@app.get("/api/health")
def health():
status = storage.db_status()