pub struct PluginIpcClient { /* private fields */ }Expand description
Async client. One instance per plugin runner process.
Implementations§
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub async fn cloud_publish(
&self,
stream: &str,
payload: &[u8],
) -> Result<Value, ClientError>
pub async fn cloud_publish( &self, stream: &str, payload: &[u8], ) -> Result<Value, ClientError>
Publish one message on this plugin’s own cloud stream.
The host forwards {stream, payload} to the cloud relay under the
caller’s verified plugin id, which publishes it at QoS 0 on
ados/{device_id}/plugin/{plugin_id}/{stream}. stream must match
[a-z0-9][a-z0-9._-]{0,63} and payload is opaque bytes of at most
ados_protocol::cloud_publish::MAX_PAYLOAD. The stream
ados_protocol::cloud_publish::VISION_DETECTIONS_STREAM instead lands
on the core detection topic and additionally needs
vision.detection.publish. Gated on cloud.publish.
The reply is {ok: true} once the relay queued the message (the lane is
lossy, so this is not broker delivery), or a not_available map while
the relay is down.
Sourcepub async fn cloud_records_put(
&self,
collection: &str,
key: &str,
data: Value,
device_id: Option<&str>,
) -> Result<Value, ClientError>
pub async fn cloud_records_put( &self, collection: &str, key: &str, data: Value, device_id: Option<&str>, ) -> Result<Value, ClientError>
Upsert one record {collection, key, data} into this plugin’s own cloud
records in the operator’s account.
collection must match [a-z0-9_.-]{1,64}, key is 1..=256 UTF-8
bytes, and data must be JSON-representable (the host re-encodes it as
JSON, at most ados_protocol::cloud_publish::MAX_PAYLOAD). The record’s
subject is device_id when given (e.g. the drone a workstation wrote a
job for), otherwise this node. Gated on cloud.records.
The reply is {ok: true} only once the cloud accepted the write, so this
call waits past the relay’s record bound rather than the default request
timeout; a not_available map comes back while the relay is down.
Sourcepub async fn offload_advertise(
&self,
advert: &OffloadAdvertisement,
) -> Result<Value, ClientError>
pub async fn offload_advertise( &self, advert: &OffloadAdvertisement, ) -> Result<Value, ClientError>
Report the perception-offload link this plugin holds.
The host writes it as the offload-link sidecar, which goes stale
ados_protocol::offload_link::OFFLOAD_LINK_STALE_MS (20 s) after the
last write, so a plugin keeps an active link counted by re-advertising at
least every ~10 s, and advertises paired: false as soon as the link
drops rather than waiting out the window. The optional strings must be
1..=256 printable bytes. The host stamps paired only when target
accepts a TCP connection, and refuses the call while another plugin’s
link is fresh. Gated on vision.offload.advertise. The reply is
{ok: true, paired: <as stamped>}.
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub async fn config_get(
&self,
key: &str,
default: Value,
) -> Result<Value, ClientError>
pub async fn config_get( &self, key: &str, default: Value, ) -> Result<Value, ClientError>
Read a config key, returning the host’s value (nil when absent).
Mirrors config_get.
Sourcepub async fn config_set(
&self,
key: &str,
value: Value,
scope: &str,
) -> Result<Value, ClientError>
pub async fn config_set( &self, key: &str, value: Value, scope: &str, ) -> Result<Value, ClientError>
Write a config key in the given scope (drone or global). Mirrors
config_set.
Sourcepub async fn process_spawn(
&self,
basename: &str,
args: Vec<String>,
env: Vec<(String, String)>,
) -> Result<Value, ClientError>
pub async fn process_spawn( &self, basename: &str, args: Vec<String>, env: Vec<(String, String)>, ) -> Result<Value, ClientError>
Authorize a vendor-binary spawn through the supervisor. The host enforces
the manifest allowlist and audit-logs the attempt. Mirrors
process_spawn. The required cap is process.spawn.
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub async fn node_info(&self) -> Result<NodeInfo, ClientError>
pub async fn node_info(&self) -> Result<NodeInfo, ClientError>
Read this node’s facts: profile, board (with NPU presence), the
ground-station role, camera readiness and the main stream’s geometry.
Each absent source is None, never a guess. Gated on node.info.read.
A host that predates the method answers not_implemented, surfaced as
ClientError::Rpc("not_implemented: node.info").
Sourcepub async fn mdns_advertise(
&self,
service_type: &str,
port: u16,
txt: &BTreeMap<String, String>,
) -> Result<Advertised, ClientError>
pub async fn mdns_advertise( &self, service_type: &str, port: u16, txt: &BTreeMap<String, String>, ) -> Result<Advertised, ClientError>
Publish one of this plugin’s listen ports on the local network over
mDNS, as service_type (_<name>._tcp) with txt.
The host runs the responder: a sandboxed plugin cannot bind the
multicast port. port must be a listen port the plugin declares for a
service that runs on this node, and the agent’s own service types
(_ados._tcp, _ados-receiver._tcp) are refused. The SRV target is the
system hostname. The record lives as long as this connection: the host
withdraws it when the connection ends, and calling again with the same
service type replaces it (a TXT update). Gated on network.listen.
Sourcepub async fn mdns_browse(
&self,
service_type: &str,
window: Duration,
) -> Result<Vec<DiscoveredService>, ClientError>
pub async fn mdns_browse( &self, service_type: &str, window: Duration, ) -> Result<Vec<DiscoveredService>, ClientError>
Every instance of service_type (_<name>._tcp or _<name>._udp)
that answers on the local network within window (clamped by the host
to 0.1-5 s). The call returns once the window has closed. Gated on
network.outbound.
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub async fn mavlink_send(
&self,
msg_bytes: &[u8],
component_id: Option<i64>,
) -> Result<Value, ClientError>
pub async fn mavlink_send( &self, msg_bytes: &[u8], component_id: Option<i64>, ) -> Result<Value, ClientError>
Send a MAVLink frame, optionally from a registered component id.
Mirrors mavlink_send.
Sourcepub async fn mavlink_register_component(
&self,
comp_id: i64,
kind: &str,
) -> Result<Value, ClientError>
pub async fn mavlink_register_component( &self, comp_id: i64, kind: &str, ) -> Result<Value, ClientError>
Register a MAVLink component of the given kind (camera, gimbal, payload,
peripheral, vio). The required cap is mavlink.component.<kind>. Mirrors
mavlink_register_component.
Sourcepub async fn mavlink_subscribe(
&self,
msg_name: &str,
callback: EventCallback,
) -> Result<(), ClientError>
pub async fn mavlink_subscribe( &self, msg_name: &str, callback: EventCallback, ) -> Result<(), ClientError>
Subscribe to a MAVLink message name and register a callback. MAVLink
deliveries arrive as mavlink.deliver envelopes and route by
msg_name. Mirrors mavlink_subscribe.
Sourcepub async fn msp_send(&self, msg_bytes: &[u8]) -> Result<Value, ClientError>
pub async fn msp_send(&self, msg_bytes: &[u8]) -> Result<Value, ClientError>
Write raw MSP bytes (already framed by ados_protocol::msp) to the FC.
Gated on msp.write. The reply is {sent, len} or a not_available
map when no MSP FC is wired.
Sourcepub async fn msp_subscribe(
&self,
callback: EventCallback,
) -> Result<(), ClientError>
pub async fn msp_subscribe( &self, callback: EventCallback, ) -> Result<(), ClientError>
Subscribe to the raw FC->host MSP byte stream and register a callback.
Deliveries arrive as msp.deliver events carrying {bytes, timestamp_ms};
MSP has no per-message topic, so the callback sees every chunk and its own
codec parses it. Gated on msp.read. Mirrors the button subscribe shape.
Sourcepub async fn telemetry_extend(
&self,
channel: &str,
payload: Value,
) -> Result<Value, ClientError>
pub async fn telemetry_extend( &self, channel: &str, payload: Value, ) -> Result<Value, ClientError>
Extend the heartbeat schema with a new channel. Mirrors
telemetry_extend.
Sourcepub async fn telemetry_subscribe(
&self,
callback: EventCallback,
) -> Result<(), ClientError>
pub async fn telemetry_subscribe( &self, callback: EventCallback, ) -> Result<(), ClientError>
Subscribe to the vehicle-state snapshot and register a callback. The
host pushes the state object as an event on TELEMETRY_STATE_TOPIC,
at most TELEMETRY_STATE_MAX_HZ
times a second and always the newest; the callback receives the event’s
args map (topic, payload, publisher, timestamp_ms) like any event.
Gated on telemetry.read. A node with no flight controller never fires
it.
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub async fn mavlink_tunnel_send(
&self,
payload_type: u16,
payload: &[u8],
) -> Result<Value, ClientError>
pub async fn mavlink_tunnel_send( &self, payload_type: u16, payload: &[u8], ) -> Result<Value, ClientError>
Send one application payload over a MAVLink TUNNEL frame.
payload_type must be a private type (> 32767); the host validates it
before anything is sent.
Sourcepub async fn flight_guided_setpoint(
&self,
args: Value,
) -> Result<Value, ClientError>
pub async fn flight_guided_setpoint( &self, args: Value, ) -> Result<Value, ClientError>
Send one guided-mode setpoint through the scoped sender.
args is the setpoint map the host validates (kind, coordinate_frame,
type_mask and the axis fields). Single-shot by design: the host owns no
flight mode and no schedule, so a caller holding a velocity re-sends above
the autopilot’s setpoint timeout or the vehicle brakes.
Sourcepub async fn flight_rate_setpoint(
&self,
args: Value,
) -> Result<Value, ClientError>
pub async fn flight_rate_setpoint( &self, args: Value, ) -> Result<Value, ClientError>
Send one attitude/body-rate + thrust setpoint (SET_ATTITUDE_TARGET) through the scoped sender.
args is the setpoint map the host validates (type_mask, qw/qx/
qy/qz, body_*_rate, thrust, optional target_system/
target_component). Single-shot by design, like the guided sender: the
host owns no flight mode and no schedule, so a caller holding an attitude
re-sends above the autopilot’s setpoint timeout or the vehicle reverts.
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub async fn whep_offer(
&self,
camera_id: &str,
offer_sdp: &str,
) -> Result<WhepAnswer, ClientError>
pub async fn whep_offer( &self, camera_id: &str, offer_sdp: &str, ) -> Result<WhepAnswer, ClientError>
Open a WebRTC playback (WHEP) session on the configured camera
camera_id (its roster id) for a viewer’s offer_sdp, and return the
answer. The host resolves the camera to the media leg publishing it.
Gated on video.whep.relay (ClientError::CapabilityDenied without
it). An id that is not a configured, enabled camera is
ClientError::Rpc("unknown_camera: .."); the media server refusing
the offer or being down is ClientError::Rpc("whep_unavailable: ..").
Sourcepub async fn whep_close(&self, location: &str) -> Result<(), ClientError>
pub async fn whep_close(&self, location: &str) -> Result<(), ClientError>
Close a session whep_offer opened for this plugin,
by the location it returned. Any other location is refused as
ClientError::Rpc("whep_unavailable: ..").
Sourcepub async fn put_rig(&self, rig: &Value) -> Result<(u16, Value), ClientError>
pub async fn put_rig(&self, rig: &Value) -> Result<(u16, Value), ClientError>
Store rig through the agent’s PUT /api/v1/sensors/rig and return
the route’s HTTP status and JSON body ({"ok":true,"rig_id", "calib_version"}, or {"error":"E_RIG_INVALID","detail"} with 400).
Gated on sensors.rig.write. The route being unreachable is
ClientError::Rpc("rig_unavailable: ..").
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub async fn peripheral_register_driver(
&self,
kind: &str,
driver_ref: &str,
) -> Result<Value, ClientError>
pub async fn peripheral_register_driver( &self, kind: &str, driver_ref: &str, ) -> Result<Value, ClientError>
Register a driver of the given kind, referenced by an opaque id the host
records. The required cap comes from driver_kind_capability
(camera, lidar, or the payload cap for gimbal/gps/esc/payload-actuator);
an unknown kind is refused here and nothing is sent. Mirrors
peripheral_register_driver.
Sourcepub async fn peripheral_unregister_driver(
&self,
handle_id: &str,
) -> Result<Value, ClientError>
pub async fn peripheral_unregister_driver( &self, handle_id: &str, ) -> Result<Value, ClientError>
Release a previously-registered driver by handle. Mirrors
peripheral_unregister_driver.
Sourcepub async fn camera_claim(
&self,
device_path: &str,
exclusive: bool,
) -> Result<Value, ClientError>
pub async fn camera_claim( &self, device_path: &str, exclusive: bool, ) -> Result<Value, ClientError>
Claim a /dev/videoN path, optionally exclusive. Mirrors camera_claim.
Sourcepub async fn camera_release(
&self,
device_path: &str,
) -> Result<Value, ClientError>
pub async fn camera_release( &self, device_path: &str, ) -> Result<Value, ClientError>
Release a previously-claimed camera path. Mirrors camera_release.
Sourcepub async fn camera_get_frame(
&self,
device_path: &str,
format: &str,
timeout_ms: i64,
) -> Result<Value, ClientError>
pub async fn camera_get_frame( &self, device_path: &str, format: &str, timeout_ms: i64, ) -> Result<Value, ClientError>
Pull the latest captured frame from a claimed camera path. Mirrors
camera_get_frame.
Sourcepub async fn camera_set_controls(
&self,
req: &CameraControlRequest,
) -> Result<CameraControlResult, ClientError>
pub async fn camera_set_controls( &self, req: &CameraControlRequest, ) -> Result<CameraControlResult, ClientError>
Set exposure, gain (a multiplier, 1.0 is unity) or auto exposure on a
capture: true camera the vision engine owns and return what the camera
reads back. Gated on camera.control.write
(ClientError::CapabilityDenied without it). applied is true only
when every requested control was set and reads back as asked; any other
camera, a simulated or control-less one, or a gain control with no known
unit gain answers applied: false with a
reason code.
Source§impl PluginIpcClient
impl PluginIpcClient
Register a callback for button.deliver pushes.
Source§impl PluginIpcClient
impl PluginIpcClient
Arm the host’s front-panel button push stream for this connection.
Sourcepub async fn gpio_output_set(
&self,
chip: i64,
pin: i64,
high: bool,
) -> Result<Value, ClientError>
pub async fn gpio_output_set( &self, chip: i64, pin: i64, high: bool, ) -> Result<Value, ClientError>
Drive a host GPIO output line high or low.
Sourcepub async fn gpio_buzzer_beep(
&self,
chip: i64,
pin: i64,
on_ms: i64,
cycles: i64,
off_ms: Option<i64>,
freq_hz: Option<i64>,
) -> Result<Value, ClientError>
pub async fn gpio_buzzer_beep( &self, chip: i64, pin: i64, on_ms: i64, cycles: i64, off_ms: Option<i64>, freq_hz: Option<i64>, ) -> Result<Value, ClientError>
Play a bounded beep pattern on a host GPIO line.
The gpio service is the single owner of the safe bounds and clamps the pattern itself, so this sends the requested values verbatim rather than pre-clamping them to a second, drifting opinion of what is safe.
Sourcepub async fn display_page_set(
&self,
title: &str,
rows: &[(String, String)],
zones: &[(i64, i64, i64, i64, String, String)],
) -> Result<Value, ClientError>
pub async fn display_page_set( &self, title: &str, rows: &[(String, String)], zones: &[(i64, i64, i64, i64, String, String)], ) -> Result<Value, ClientError>
Set the content of the host’s reserved data-driven display page.
rows are (label, value) pairs and zones are
(x, y, w, h, key, label) touch rectangles in page-local content
coordinates. The host writes the page sidecar the display service renders.
Sourcepub async fn radio_aux_stream_open(&self) -> Result<Value, ClientError>
pub async fn radio_aux_stream_open(&self) -> Result<Value, ClientError>
Open the additive auxiliary application stream on the radio link.
Sourcepub async fn radio_aux_stream_close(&self) -> Result<Value, ClientError>
pub async fn radio_aux_stream_close(&self) -> Result<Value, ClientError>
Close the auxiliary application stream.
Sourcepub async fn radio_aux_stream_send(
&self,
channel: u8,
payload: &[u8],
) -> Result<Value, ClientError>
pub async fn radio_aux_stream_send( &self, channel: u8, payload: &[u8], ) -> Result<Value, ClientError>
Send one application datagram on the open auxiliary stream.
channel is the reserved aux application channel: AppStream (8, the
stream direction) or AppCommand (9, the command direction). The payload
is the application bytes, opaque to the host; a payload over
ados_protocol::aux_mux::AUX_MAX_PAYLOAD is refused by the host before
it is sent. Gated on radio.aux_stream.
Sourcepub async fn radio_aux_stream_subscribe(&self) -> Result<Value, ClientError>
pub async fn radio_aux_stream_subscribe(&self) -> Result<Value, ClientError>
Subscribe to application datagrams received on the open auxiliary stream.
The host forwards each received (channel, payload) as a
radio.aux_stream.deliver event to every registered aux callback
(the plugin’s codec routes by channel). Register a callback first with
Self::register_aux_callback so no early frame is missed. Gated on
radio.aux_stream. Mirrors the button subscribe shape.
Sourcepub fn register_aux_callback(&self, callback: EventCallback)
pub fn register_aux_callback(&self, callback: EventCallback)
Register a callback for radio.aux_stream.deliver pushes. Mirrors the
button callback shape: every subscriber receives every application
datagram.
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub fn register_vision_callback(
&self,
camera_id: Option<&str>,
callback: EventCallback,
)
pub fn register_vision_callback( &self, camera_id: Option<&str>, callback: EventCallback, )
Register a callback for vision.deliver frame pushes, keyed by the
camera id the subscriber filtered on (None ⇒ every camera, the
wildcard key). The reader loop decodes each delivered descriptor and
invokes the callbacks whose key is the descriptor’s camera_id or the
wildcard, passing the envelope args map (which carries the
descriptor binary). Unlike events, vision.deliver carries no topic,
so it routes on the decoded descriptor’s camera id, not the event map.
Sourcepub fn register_detection_callback(
&self,
camera_id: Option<&str>,
callback: EventCallback,
)
pub fn register_detection_callback( &self, camera_id: Option<&str>, callback: EventCallback, )
Register a callback for vision.deliver_detection pushes.
camera_id of None receives every camera’s batches. The engine fans
all cameras out on one stream, so the filter is applied here rather than
at the engine — the same posture the Python client takes.
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub async fn vision_subscribe_detections(
&self,
camera_id: Option<&str>,
) -> Result<Value, ClientError>
pub async fn vision_subscribe_detections( &self, camera_id: Option<&str>, ) -> Result<Value, ClientError>
Arm the host’s detection-batch push stream for this connection.
Sourcepub async fn vision_designate_track(
&self,
camera_id: &str,
target: &Detection,
) -> Result<Value, ClientError>
pub async fn vision_designate_track( &self, camera_id: &str, target: &Detection, ) -> Result<Value, ClientError>
Designate the tracker’s locked target, overriding its auto-lock. Only
the target’s box, label and confidence cross; the box is required. The
required cap is vision.track.designate.
Sourcepub async fn vision_read_model(&self) -> Result<Value, ClientError>
pub async fn vision_read_model(&self) -> Result<Value, ClientError>
Read this plugin’s resolved model-delivery status. Sends
framebus::methods::READ_MODEL (gated on vision.model.read); the host
returns {models: [ {state, model_id, runtime, path, reason}, ... ]} off
this plugin’s install record. No args.
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub async fn vision_subscribe_frames(
&self,
camera_id: Option<&str>,
) -> Result<Value, ClientError>
pub async fn vision_subscribe_frames( &self, camera_id: Option<&str>, ) -> Result<Value, ClientError>
Subscribe to vision frame descriptors. The host starts (or widens) the
engine’s frame stream toward this plugin and then delivers descriptors
as vision.deliver events. camera_id of None requests every
camera’s frames; Some(id) narrows the stream at the engine. The
required cap is vision.frame.read. The caller registers the matching
frame callback via register_vision_callback;
vision.deliver pushes carry the descriptor directly (no topic), so they
do not ride the event.subscribe path.
Sourcepub async fn vision_register_model(
&self,
model: &ModelMetadata,
) -> Result<Value, ClientError>
pub async fn vision_register_model( &self, model: &ModelMetadata, ) -> Result<Value, ClientError>
Register an inference model. The required cap is
vision.model.register.
Sourcepub async fn vision_infer(
&self,
model_id: &str,
frame: &FrameDescriptor,
) -> Result<Value, ClientError>
pub async fn vision_infer( &self, model_id: &str, frame: &FrameDescriptor, ) -> Result<Value, ClientError>
Run a registered model against one frame, named by the descriptor the
engine published for it, on the shared backend and return the engine’s
reply (decode it with vision_rpc::decode_infer_reply). The required
cap is vision.model.register.
Sourcepub async fn vision_publish_detection(
&self,
batch: &DetectionBatch,
) -> Result<Value, ClientError>
pub async fn vision_publish_detection( &self, batch: &DetectionBatch, ) -> Result<Value, ClientError>
Publish a detection batch on vision.detection. The required cap is
vision.detection.publish.
Source§impl PluginIpcClient
impl PluginIpcClient
Sourcepub fn new(
plugin_id: impl Into<String>,
token: impl Into<String>,
socket_path: impl AsRef<Path>,
) -> Self
pub fn new( plugin_id: impl Into<String>, token: impl Into<String>, socket_path: impl AsRef<Path>, ) -> Self
Build a client for one plugin, bound to a socket path and the capability token the supervisor minted for this process.
Sourcepub fn with_request_timeout(self, timeout: Duration) -> Self
pub fn with_request_timeout(self, timeout: Duration) -> Self
Override the per-request timeout (default DEFAULT_REQUEST_TIMEOUT).
Sourcepub fn set_tool_handler(&self, handler: ToolHandler)
pub fn set_tool_handler(&self, handler: ToolHandler)
Register the handler that answers host-to-plugin tool.invoke
requests (the plugin’s MCP tools). Replaces any earlier handler.
Sourcepub async fn connect(&self) -> Result<(), ClientError>
pub async fn connect(&self) -> Result<(), ClientError>
Connect to the socket, spawn the reader loop, and run the hello
handshake. Mirrors connect: open the connection, start the reader,
then send the handshake request and await the {"ready": true} reply.
Sourcepub async fn session_lost(&self)
pub async fn session_lost(&self)
Resolve once the host session is lost: the host closed the connection
(a plugin-host restart) or the stream broke. The client never
reconnects — a restarted host re-mints this plugin’s socket and token
and hands them to a fresh process — so a plugin that sees this should
exit non-zero and let its unit’s Restart= bring it back.
crate::run_plugin does exactly that. Pending until then, including
after a deliberate Self::close.
Sourcepub async fn ping(&self) -> Result<Value, ClientError>
pub async fn ping(&self) -> Result<Value, ClientError>
Health probe. Mirrors ping: {"pong": true, "plugin_id": <id>}.
Sourcepub async fn event_publish(
&self,
topic: &str,
payload: Value,
) -> Result<i64, ClientError>
pub async fn event_publish( &self, topic: &str, payload: Value, ) -> Result<i64, ClientError>
Publish an event. Returns the delivered count. Mirrors event_publish.
Sourcepub async fn event_subscribe(
&self,
topic_pattern: &str,
callback: EventCallback,
) -> Result<(), ClientError>
pub async fn event_subscribe( &self, topic_pattern: &str, callback: EventCallback, ) -> Result<(), ClientError>
Subscribe to an event topic pattern and register a callback for matched
deliveries. Mirrors event_subscribe.