fleetmesh-protocols 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fleetmesh_protocols/__init__.py +6 -0
- fleetmesh_protocols/arcade/__init__.py +22 -0
- fleetmesh_protocols/arcade/routes.py +95 -0
- fleetmesh_protocols/arcade/store.py +618 -0
- fleetmesh_protocols/circles/__init__.py +25 -0
- fleetmesh_protocols/circles/persistence.py +76 -0
- fleetmesh_protocols/circles/store.py +555 -0
- fleetmesh_protocols/dm/__init__.py +46 -0
- fleetmesh_protocols/dm/mailbox.py +404 -0
- fleetmesh_protocols/dm/spool.py +325 -0
- fleetmesh_protocols/grasp/__init__.py +18 -0
- fleetmesh_protocols/grasp/git_http.py +114 -0
- fleetmesh_protocols/grasp/git_store.py +570 -0
- fleetmesh_protocols/grasp/seeds.py +146 -0
- fleetmesh_protocols/textile/__init__.py +103 -0
- fleetmesh_protocols/textile/fiber_routes.py +237 -0
- fleetmesh_protocols/textile/fiber_store.py +307 -0
- fleetmesh_protocols/textile/hosted_relay.py +518 -0
- fleetmesh_protocols/textile/leaf_relay.py +375 -0
- fleetmesh_protocols/textile/quilt_routes.py +98 -0
- fleetmesh_protocols/textile/quilt_store.py +185 -0
- fleetmesh_protocols-0.1.0.dist-info/METADATA +38 -0
- fleetmesh_protocols-0.1.0.dist-info/RECORD +26 -0
- fleetmesh_protocols-0.1.0.dist-info/WHEEL +5 -0
- fleetmesh_protocols-0.1.0.dist-info/licenses/LICENSE +121 -0
- fleetmesh_protocols-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""fleetmesh_protocols.arcade - host-side arcade stores and route handlers (moved from meshnode `node.protocols.arcade`)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from .routes import HttpResult, JSON_CT, handle_arcade_http
|
|
5
|
+
from .store import (
|
|
6
|
+
ArcadeError,
|
|
7
|
+
MAX_DESKTOP_JSON_BYTES,
|
|
8
|
+
MAX_RECORD_JSON_BYTES,
|
|
9
|
+
TOMBSTONE_TTL_SEC,
|
|
10
|
+
StandaloneArcadeStore,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"HttpResult",
|
|
15
|
+
"JSON_CT",
|
|
16
|
+
"handle_arcade_http",
|
|
17
|
+
"ArcadeError",
|
|
18
|
+
"MAX_DESKTOP_JSON_BYTES",
|
|
19
|
+
"MAX_RECORD_JSON_BYTES",
|
|
20
|
+
"TOMBSTONE_TTL_SEC",
|
|
21
|
+
"StandaloneArcadeStore",
|
|
22
|
+
]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""`/api/arcade*` HTTP routing for `StandaloneArcadeStore` (`node.protocols.arcade.routes`)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import urllib.parse
|
|
5
|
+
from typing import Any, Dict, Mapping, Optional, Tuple
|
|
6
|
+
|
|
7
|
+
from fleetmesh_core.textile.principal import MeshAccessError, Principal, is_public
|
|
8
|
+
|
|
9
|
+
from ..textile.fiber_routes import binary_http_response
|
|
10
|
+
|
|
11
|
+
HttpResult = Tuple[int, Any, str, Dict[str, str]]
|
|
12
|
+
JSON_CT = "application/json; charset=utf-8"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _item_binary_response(raw: bytes, rec: Mapping[str, Any], as_json: bool) -> HttpResult:
|
|
16
|
+
return binary_http_response(
|
|
17
|
+
raw,
|
|
18
|
+
bao_root=str(rec.get("bao_root") or ""),
|
|
19
|
+
sha256_hex=str(rec.get("sha256_hex") or ""),
|
|
20
|
+
mime_type=str(rec.get("mime_type") or ""),
|
|
21
|
+
public=is_public(rec),
|
|
22
|
+
filename=str(rec.get("filename") or rec.get("item_id") or "arcade.bin"),
|
|
23
|
+
as_json=as_json,
|
|
24
|
+
json_extra={"item_id": rec.get("item_id")},
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _sub(payload: Mapping[str, Any], key: str) -> Mapping[str, Any]:
|
|
29
|
+
inner = payload.get(key)
|
|
30
|
+
return inner if isinstance(inner, Mapping) else payload
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def handle_arcade_http(
|
|
34
|
+
store: Any,
|
|
35
|
+
method: str,
|
|
36
|
+
route: str,
|
|
37
|
+
query: Any = "",
|
|
38
|
+
body: Optional[Mapping[str, Any]] = None,
|
|
39
|
+
principal: Principal = None,
|
|
40
|
+
) -> Optional[HttpResult]:
|
|
41
|
+
"""Route `/api/arcade*`. `principal` must come from the server's own session resolution."""
|
|
42
|
+
store = getattr(store, "arcade_store", store)
|
|
43
|
+
qp = query if isinstance(query, Mapping) else urllib.parse.parse_qs(str(query or ""))
|
|
44
|
+
try:
|
|
45
|
+
if method == "GET":
|
|
46
|
+
if route == "/api/arcade":
|
|
47
|
+
return 200, store.snapshot(principal), JSON_CT, {"Cache-Control": "private, no-store"}
|
|
48
|
+
if (
|
|
49
|
+
route.startswith("/api/arcade/items/") or route.startswith("/api/arcade/engines/")
|
|
50
|
+
) and route.endswith("/binary"):
|
|
51
|
+
prefix = "/api/arcade/items/" if route.startswith("/api/arcade/items/") else "/api/arcade/engines/"
|
|
52
|
+
item_id = urllib.parse.unquote(route[len(prefix) : -len("/binary")].strip("/"))
|
|
53
|
+
found = store.get_item_binary(item_id, principal)
|
|
54
|
+
if found is None:
|
|
55
|
+
return 404, {"ok": False, "error": "arcade_binary_not_found", "item_id": item_id}, JSON_CT, {}
|
|
56
|
+
as_json = (qp.get("format", [""])[0] or "").strip().lower() == "json"
|
|
57
|
+
return _item_binary_response(found[0], found[1], as_json)
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
if method != "POST" or not route.startswith("/api/arcade"):
|
|
61
|
+
return None
|
|
62
|
+
payload_in: Mapping[str, Any] = body or {}
|
|
63
|
+
if route in ("/api/arcade", "/api/arcade/items", "/api/arcade/items/save"):
|
|
64
|
+
item_in = _sub(payload_in, "item")
|
|
65
|
+
saved = store.save_item(item_in, payload_in.get("data_b64") or item_in.get("data_b64"), principal)
|
|
66
|
+
return 200, {"ok": True, "item": saved}, JSON_CT, {}
|
|
67
|
+
if route == "/api/arcade/items/delete":
|
|
68
|
+
iid = str(payload_in.get("item_id") or "")
|
|
69
|
+
existed = store.delete_item(iid, principal)
|
|
70
|
+
return (200 if existed else 404), {"ok": existed, "deleted_id": iid}, JSON_CT, {}
|
|
71
|
+
if route in ("/api/arcade/engines", "/api/arcade/engines/save"):
|
|
72
|
+
eng_in = _sub(payload_in, "engine")
|
|
73
|
+
saved = store.save_engine(
|
|
74
|
+
eng_in, principal, data_b64=payload_in.get("data_b64") or eng_in.get("data_b64")
|
|
75
|
+
)
|
|
76
|
+
return 200, {"ok": True, "engine": saved}, JSON_CT, {}
|
|
77
|
+
if route == "/api/arcade/engines/delete":
|
|
78
|
+
eid = str(payload_in.get("engine_id") or "")
|
|
79
|
+
existed = store.delete_engine(eid, principal)
|
|
80
|
+
return (200 if existed else 404), {"ok": existed, "deleted_id": eid}, JSON_CT, {}
|
|
81
|
+
if route in ("/api/arcade/desktop", "/api/arcade/desktop/save"):
|
|
82
|
+
saved = store.save_desktop_state(_sub(payload_in, "desktop_state"), principal)
|
|
83
|
+
return 200, {"ok": True, "arcade_desktop_state": saved}, JSON_CT, {}
|
|
84
|
+
if route in ("/api/arcade/metadata", "/api/arcade/metadata/save"):
|
|
85
|
+
saved = store.save_metadata_record(_sub(_sub(payload_in, "metadata"), "record"), principal)
|
|
86
|
+
return 200, {"ok": True, "metadata": saved}, JSON_CT, {}
|
|
87
|
+
if route in ("/api/arcade/scores", "/api/arcade/scores/save"):
|
|
88
|
+
saved = store.save_score(_sub(payload_in, "score"), principal)
|
|
89
|
+
return 200, {"ok": True, "score": saved}, JSON_CT, {}
|
|
90
|
+
if route in ("/api/arcade/repos", "/api/arcade/repos/save"):
|
|
91
|
+
saved = store.save_repo(_sub(payload_in, "repo"), principal)
|
|
92
|
+
return 200, {"ok": True, "repo": saved}, JSON_CT, {}
|
|
93
|
+
return None
|
|
94
|
+
except MeshAccessError as exc:
|
|
95
|
+
return exc.status, {"ok": False, "error": exc.error}, JSON_CT, {}
|