Skip to main content

PluginIpcClient

Struct PluginIpcClient 

Source
pub struct PluginIpcClient { /* private fields */ }
Expand description

Async client. One instance per plugin runner process.

Implementations§

Source§

impl PluginIpcClient

Source

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.

Source

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.

Source

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

Source

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.

Source

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.

Source

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

Source

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").

Source

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.

Source

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

Send a MAVLink frame, optionally from a registered component id. Mirrors mavlink_send.

Register a MAVLink component of the given kind (camera, gimbal, payload, peripheral, vio). The required cap is mavlink.component.<kind>. Mirrors mavlink_register_component.

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.

Source

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.

Source

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.

Source

pub async fn telemetry_extend( &self, channel: &str, payload: Value, ) -> Result<Value, ClientError>

Extend the heartbeat schema with a new channel. Mirrors telemetry_extend.

Source

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

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.

Source

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.

Source

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

Source

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: ..").

Source

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: ..").

Source

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

Source

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.

Source

pub async fn peripheral_unregister_driver( &self, handle_id: &str, ) -> Result<Value, ClientError>

Release a previously-registered driver by handle. Mirrors peripheral_unregister_driver.

Source

pub async fn camera_claim( &self, device_path: &str, exclusive: bool, ) -> Result<Value, ClientError>

Claim a /dev/videoN path, optionally exclusive. Mirrors camera_claim.

Source

pub async fn camera_release( &self, device_path: &str, ) -> Result<Value, ClientError>

Release a previously-claimed camera path. Mirrors camera_release.

Source

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.

Source

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

Source

pub fn register_button_callback(&self, callback: EventCallback)

Register a callback for button.deliver pushes.

Source§

impl PluginIpcClient

Source

pub async fn button_subscribe(&self) -> Result<Value, ClientError>

Arm the host’s front-panel button push stream for this connection.

Source

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.

Source

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.

Source

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.

Source

pub async fn radio_aux_stream_open(&self) -> Result<Value, ClientError>

Open the additive auxiliary application stream on the radio link.

Source

pub async fn radio_aux_stream_close(&self) -> Result<Value, ClientError>

Close the auxiliary application stream.

Source

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.

Source

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.

Source

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

Source

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.

Source

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

Source

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.

Source

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.

Source

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

Source

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.

Source

pub async fn vision_register_model( &self, model: &ModelMetadata, ) -> Result<Value, ClientError>

Register an inference model. The required cap is vision.model.register.

Source

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.

Source

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

Source

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.

Source

pub fn with_request_timeout(self, timeout: Duration) -> Self

Override the per-request timeout (default DEFAULT_REQUEST_TIMEOUT).

Source

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.

Source

pub fn plugin_id(&self) -> &str

The plugin id this client carries.

Source

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.

Source

pub async fn close(&self)

Cancel the reader loop and drop the write half. Mirrors close.

Source

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.

Source

pub async fn ping(&self) -> Result<Value, ClientError>

Health probe. Mirrors ping: {"pong": true, "plugin_id": <id>}.

Source

pub async fn event_publish( &self, topic: &str, payload: Value, ) -> Result<i64, ClientError>

Publish an event. Returns the delivered count. Mirrors event_publish.

Source

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.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more