wasmcloud_control_interface/
lib.rs

1//! # Control Interface Client
2//!
3//! This library provides a client API for consuming the [wasmCloud control interface][docs-control-interface]
4//! over a NATS connection.
5//!
6//! This library can be used by multiple types of tools, and is also used
7//! by the control interface capability provider and the [`wash` CLI][wash].
8//!
9//! ## Usage
10//!
11//! All of the [`Client`] functions are handled by a wasmCloud host running in the specified lattice.
12//!
13//! Each function returns a `Result<CtlResponse<T>>` wrapper around the actual response type. The outer
14//! result should be handled for protocol (timeouts, no hosts available) and deserialization errors (invalid response payload).
15//! The inner result is the actual response from the host(s) and should be handled for application-level errors.
16//!
17//! [docs-control-interface]: <https://wasmcloud.com/docs/hosts/lattice-protocols/control-interface>
18//! [wash]: <https://wasmcloud.com/docs/ecosystem/wash>
19
20use serde::{Deserialize, Serialize};
21
22mod broker;
23mod otel;
24
25pub mod client;
26pub use client::{Client, ClientBuilder};
27
28mod types;
29pub use types::component::*;
30pub use types::ctl::*;
31pub use types::host::*;
32pub use types::link::*;
33pub use types::provider::*;
34pub use types::registry::*;
35pub use types::rpc::*;
36
37// NOTE(brooksmtownsend): These are included to avoid a major breaking change
38// in this crate by removing the public type aliases. They should be removed
39// when we release 3.0.0 of this crate.
40#[deprecated(
41    since = "2.3.0",
42    note = "String type aliases are deprecated, use Strings instead"
43)]
44#[allow(dead_code)]
45mod aliases {
46    type ComponentId = String;
47    type KnownConfigName = String;
48    type LatticeTarget = String;
49    type LinkName = String;
50    type WitInterface = String;
51    type WitNamespace = String;
52    type WitPackage = String;
53}
54#[allow(unused_imports)]
55#[allow(deprecated)]
56pub use aliases::*;
57
58/// Generic result
59type Result<T> = ::core::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
60
61/// Enumeration of all kinds of identifiers in a wasmCloud lattice
62#[allow(unused)]
63pub(crate) enum IdentifierKind {
64    /// Identifiers that are host IDs
65    HostId,
66    /// Identifiers that are component IDs
67    ComponentId,
68    /// Identifiers that are component references
69    ComponentRefs,
70    /// Identifiers that are provider reverences
71    ProviderRef,
72    /// Identifiers that are link names
73    LinkName,
74}
75
76impl IdentifierKind {
77    /// Ensure an identifier is a valid as a host ID
78    fn is_host_id(value: impl AsRef<str>) -> Result<String> {
79        assert_non_empty_string(value, "Host ID cannot be empty")
80    }
81
82    /// Ensure an identifier is a valid as a component ID
83    fn is_component_id(value: impl AsRef<str>) -> Result<String> {
84        assert_non_empty_string(value, "Component ID cannot be empty")
85    }
86
87    /// Ensure an identifier is a valid as a component reference
88    fn is_component_ref(value: impl AsRef<str>) -> Result<String> {
89        assert_non_empty_string(value, "Component OCI reference cannot be empty")
90    }
91
92    /// Ensure an identifier is a valid as a provider reference
93    fn is_provider_ref(value: impl AsRef<str>) -> Result<String> {
94        assert_non_empty_string(value, "Provider OCI reference cannot be empty")
95    }
96
97    /// Ensure an identifier is a valid as a provider reference
98    fn is_provider_id(value: impl AsRef<str>) -> Result<String> {
99        assert_non_empty_string(value, "Provider ID cannot be empty")
100    }
101
102    /// Ensure an identifier is a valid as a link name
103    fn is_link_name(value: impl AsRef<str>) -> Result<String> {
104        assert_non_empty_string(value, "Link Name cannot be empty")
105    }
106}
107
108/// Helper function that serializes the data and maps the error
109pub(crate) fn json_serialize<T>(item: T) -> Result<Vec<u8>>
110where
111    T: Serialize,
112{
113    serde_json::to_vec(&item).map_err(|e| format!("JSON serialization failure: {e}").into())
114}
115
116/// Helper function that deserializes the data and maps the error
117pub(crate) fn json_deserialize<'de, T: Deserialize<'de>>(buf: &'de [u8]) -> Result<T> {
118    serde_json::from_slice(buf).map_err(|e| format!("JSON deserialization failure: {e}").into())
119}
120
121/// Check that a likely user-provided string is non empty
122fn assert_non_empty_string(input: impl AsRef<str>, message: impl AsRef<str>) -> Result<String> {
123    let input = input.as_ref();
124    let message = message.as_ref();
125    if input.trim().is_empty() {
126        Err(message.into())
127    } else {
128        Ok(input.trim().to_string())
129    }
130}