| |
| import { normalizeOptionalLowercaseString } from "@openclaw/normalization-core/string-coerce"; |
| import type { Command } from "commander"; |
| import { defaultRuntime } from "../../runtime.js"; |
| import { runNodesCommand } from "./cli-utils.js"; |
| import { |
| buildNodeInvokeParams, |
| callNodesGatewayCli, |
| nodesCallOpts, |
| parseOptionalNodeNonNegativeInteger, |
| parseOptionalNodePositiveInteger, |
| resolveCliNodeId, |
| } from "./rpc.js"; |
| import type { NodesRpcOpts } from "./types.js"; |
|
|
| |
| export function registerNodesLocationCommands(nodes: Command) { |
| const location = nodes.command("location").description("Fetch location from a paired node"); |
|
|
| nodesCallOpts( |
| location |
| .command("get") |
| .description("Fetch the current location from a node") |
| .requiredOption("--node <idOrNameOrIp>", "Node id, name, or IP") |
| .option("--max-age <ms>", "Use cached location newer than this (ms)") |
| .option( |
| "--accuracy <coarse|balanced|precise>", |
| "Desired accuracy (default: balanced/precise depending on node setting)", |
| ) |
| .option("--location-timeout <ms>", "Location fix timeout (ms)", "10000") |
| .option("--invoke-timeout <ms>", "Node invoke timeout in ms (default 20000)", "20000") |
| .action(async (opts: NodesRpcOpts) => { |
| await runNodesCommand("location get", async () => { |
| const desiredAccuracyRaw = normalizeOptionalLowercaseString(opts.accuracy); |
| const desiredAccuracy = |
| desiredAccuracyRaw === "coarse" || |
| desiredAccuracyRaw === "balanced" || |
| desiredAccuracyRaw === "precise" |
| ? desiredAccuracyRaw |
| : undefined; |
| if (opts.accuracy !== undefined && desiredAccuracy === undefined) { |
| throw new Error("invalid --accuracy (use coarse|balanced|precise)"); |
| } |
| const maxAgeMs = parseOptionalNodeNonNegativeInteger(opts.maxAge, "--max-age"); |
| const timeoutMs = parseOptionalNodePositiveInteger( |
| opts.locationTimeout, |
| "--location-timeout", |
| ); |
| const invokeTimeoutMs = parseOptionalNodePositiveInteger( |
| opts.invokeTimeout, |
| "--invoke-timeout", |
| ); |
| const nodeId = await resolveCliNodeId(opts, opts.node ?? ""); |
|
|
| const invokeParams = buildNodeInvokeParams({ |
| nodeId, |
| command: "location.get", |
| params: { |
| maxAgeMs, |
| desiredAccuracy, |
| timeoutMs, |
| }, |
| timeoutMs: invokeTimeoutMs, |
| }); |
|
|
| const raw = await callNodesGatewayCli("node.invoke", opts, invokeParams); |
| const res = typeof raw === "object" && raw !== null ? (raw as { payload?: unknown }) : {}; |
| const payload = |
| res.payload && typeof res.payload === "object" |
| ? (res.payload as Record<string, unknown>) |
| : {}; |
|
|
| if (opts.json) { |
| defaultRuntime.writeJson(payload); |
| return; |
| } |
|
|
| const lat = payload.lat; |
| const lon = payload.lon; |
| const acc = payload.accuracyMeters; |
| if (typeof lat === "number" && typeof lon === "number") { |
| const accText = typeof acc === "number" ? ` ±${acc.toFixed(1)}m` : ""; |
| defaultRuntime.log(`${lat},${lon}${accText}`); |
| return; |
| } |
| defaultRuntime.writeJson(payload, 0); |
| }); |
| }), |
| { timeoutMs: 30_000 }, |
| ); |
| } |
|
|