mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-10 17:23:25 +08:00
重构仓库目录为统一的 runtime 分层并清理历史 openclaw 残留。
本次迁移将网关/通道/工具/技能/脚本与协议资源集中到新结构,统一路径常量与脚本转发机制,减少顶层噪音并保证运行与测试行为一致。 Made-with: Cursor
This commit is contained in:
parent
ba3836f00f
commit
4a23b715a2
498 changed files with 2760 additions and 2200 deletions
158
interfaces/gateway/server_methods/nodes_pending.py
Normal file
158
interfaces/gateway/server_methods/nodes_pending.py
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from .shared_types import GatewayRequestHandlers
|
||||
from .validation import error_shape
|
||||
|
||||
|
||||
def _ok(respond, payload: Any) -> None:
|
||||
if callable(respond):
|
||||
respond(True, payload, None, None)
|
||||
|
||||
|
||||
def _bad(respond, message: str) -> None:
|
||||
if callable(respond):
|
||||
respond(False, None, error_shape("INVALID_REQUEST", message), None)
|
||||
|
||||
|
||||
def _unavailable(respond, message: str) -> None:
|
||||
if callable(respond):
|
||||
respond(False, None, error_shape("UNAVAILABLE", message), None)
|
||||
|
||||
|
||||
def _norm_str(v: Any) -> str | None:
|
||||
if isinstance(v, str):
|
||||
s = v.strip()
|
||||
return s or None
|
||||
return None
|
||||
|
||||
|
||||
def _resolve_client_node_id(client: Any) -> str | None:
|
||||
if not isinstance(client, dict):
|
||||
return None
|
||||
connect = client.get("connect")
|
||||
if not isinstance(connect, dict):
|
||||
return None
|
||||
device = connect.get("device")
|
||||
client_info = connect.get("client")
|
||||
node_id = None
|
||||
if isinstance(device, dict):
|
||||
node_id = _norm_str(device.get("id"))
|
||||
if node_id:
|
||||
return node_id
|
||||
if isinstance(client_info, dict):
|
||||
return _norm_str(client_info.get("id"))
|
||||
return None
|
||||
|
||||
|
||||
def _state(context: Any) -> dict[str, list[dict[str, Any]]]:
|
||||
if not isinstance(context, dict):
|
||||
return {}
|
||||
st = context.get("_node_pending_work")
|
||||
if isinstance(st, dict):
|
||||
return st
|
||||
created: dict[str, list[dict[str, Any]]] = {}
|
||||
context["_node_pending_work"] = created
|
||||
return created
|
||||
|
||||
|
||||
def _enqueue_work(context: Any, item: dict[str, Any]) -> dict[str, Any]:
|
||||
hook = context.get("enqueue_node_pending_work") if isinstance(context, dict) else None
|
||||
if callable(hook):
|
||||
out = hook(item)
|
||||
if isinstance(out, dict):
|
||||
return out
|
||||
st = _state(context)
|
||||
bucket = st.setdefault(item["nodeId"], [])
|
||||
deduped = any(x.get("type") == item["type"] for x in bucket)
|
||||
entry = {
|
||||
"id": f"npw_{int(time.time()*1000)}_{len(bucket)+1}",
|
||||
"nodeId": item["nodeId"],
|
||||
"type": item["type"],
|
||||
"priority": item.get("priority") or "normal",
|
||||
"createdAtMs": int(time.time() * 1000),
|
||||
"status": "queued",
|
||||
}
|
||||
if not deduped:
|
||||
bucket.append(entry)
|
||||
return {"deduped": deduped, "item": entry}
|
||||
|
||||
|
||||
def _drain_work(context: Any, node_id: str, max_items: int | None) -> dict[str, Any]:
|
||||
hook = context.get("drain_node_pending_work") if isinstance(context, dict) else None
|
||||
if callable(hook):
|
||||
out = hook({"nodeId": node_id, "maxItems": max_items, "includeDefaultStatus": True})
|
||||
if isinstance(out, dict):
|
||||
return out
|
||||
st = _state(context)
|
||||
bucket = st.get(node_id, [])
|
||||
n = len(bucket) if max_items is None else max(0, int(max_items))
|
||||
drained = bucket[:n]
|
||||
st[node_id] = bucket[n:]
|
||||
return {"items": drained, "count": len(drained), "remaining": len(st[node_id]), "defaultStatusIncluded": True}
|
||||
|
||||
|
||||
def _node_pending_drain_handler(opts: dict[str, Any]) -> None:
|
||||
params = opts.get("params") or {}
|
||||
respond = opts.get("respond")
|
||||
client = opts.get("client")
|
||||
context = opts.get("context")
|
||||
if params is not None and not isinstance(params, dict):
|
||||
_bad(respond, "invalid node.pending.drain params")
|
||||
return
|
||||
node_id = _resolve_client_node_id(client)
|
||||
if not node_id:
|
||||
_bad(respond, "node.pending.drain requires a connected device identity")
|
||||
return
|
||||
max_items = params.get("maxItems") if isinstance(params, dict) else None
|
||||
if max_items is not None and not isinstance(max_items, (int, float)):
|
||||
_bad(respond, "invalid node.pending.drain params")
|
||||
return
|
||||
drained = _drain_work(context, node_id, int(max_items) if isinstance(max_items, (int, float)) else None)
|
||||
_ok(respond, {"nodeId": node_id, **drained})
|
||||
|
||||
|
||||
def _node_pending_enqueue_handler(opts: dict[str, Any]) -> None:
|
||||
params = opts.get("params") or {}
|
||||
respond = opts.get("respond")
|
||||
context = opts.get("context")
|
||||
if not isinstance(params, dict):
|
||||
_bad(respond, "invalid node.pending.enqueue params")
|
||||
return
|
||||
node_id = _norm_str(params.get("nodeId"))
|
||||
work_type = _norm_str(params.get("type"))
|
||||
if not node_id or not work_type:
|
||||
_bad(respond, "invalid node.pending.enqueue params")
|
||||
return
|
||||
item = {
|
||||
"nodeId": node_id,
|
||||
"type": work_type,
|
||||
"priority": _norm_str(params.get("priority")) or "normal",
|
||||
"expiresInMs": params.get("expiresInMs"),
|
||||
}
|
||||
try:
|
||||
queued = _enqueue_work(context, item)
|
||||
except Exception as exc:
|
||||
_unavailable(respond, str(exc))
|
||||
return
|
||||
|
||||
wake_triggered = False
|
||||
if params.get("wake", True) is not False:
|
||||
wake_hook = context.get("wake_node_pending") if isinstance(context, dict) else None
|
||||
if callable(wake_hook):
|
||||
try:
|
||||
wake_triggered = bool(wake_hook({"nodeId": node_id, "reason": "node.pending", "requestId": queued.get("item", {}).get("id")}))
|
||||
except Exception:
|
||||
wake_triggered = False
|
||||
else:
|
||||
wake_triggered = True
|
||||
_ok(respond, {"queued": queued, "wakeTriggered": wake_triggered})
|
||||
|
||||
|
||||
node_pending_handlers: GatewayRequestHandlers = {
|
||||
"node.pending.drain": _node_pending_drain_handler,
|
||||
"node.pending.enqueue": _node_pending_enqueue_handler,
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue