xo_api_client/api/
mod.rs

1pub mod session;
2pub mod token;
3pub mod vm;
4pub mod xo;
5
6use std::sync::Arc;
7
8use jsonrpsee_types::{traits::SubscriptionClient, DeserializeOwned, Subscription};
9use jsonrpsee_ws_client::{WsClient, WsClientBuilder};
10
11use crate::RpcError;
12
13use self::{
14    session::SessionProcedures, token::TokenProcedures, vm::VmProcedures, xo::XoProcedures,
15};
16
17/// Client used to communicate with Xen Orchestra's API
18///
19/// Example of listing all VMs with the tag `Test`
20/// ```no_run
21/// use std::collections::BTreeMap;
22/// use xo_api_client::{credentials::EmailAndPassword, Client, api::vm::{Vm, VmId}};
23///
24/// // We dont care about any of the data under the "other" attribute
25/// // in this example
26/// #[derive(serde::Deserialize)]
27/// struct OtherInfo {}
28///
29/// impl xo_api_client::api::vm::OtherInfo for OtherInfo {}
30///
31/// #[tokio::main]
32/// async fn main() {
33///     let url = "ws://localhost:8080/api/";
34///     let email = String::from("admin@admin.net");
35///     let password = String::from("admin");
36///
37///     let con = Client::connect(url)
38///         .await
39///         .expect("Failed to connect to server");
40///
41///     con
42///         .session
43///         .sign_in(EmailAndPassword { email, password })
44///         .await
45///         .expect("Failed to sign in");
46///
47///     let all_vms: BTreeMap<VmId, Vm<OtherInfo>> =
48///         con.xo.get_objects(None, None).await.expect("Failed to list VMs");
49///
50///     let test_vms = all_vms
51///         .iter()
52///         .filter(|(_id, vm)| vm.tags.iter().any(|tag| tag == "Test"));
53///
54///     println!("All VMs with the tag 'Test':");
55///     for (id, vm) in test_vms {
56///         println!("ID: {:?}, Name: {}", id, vm.name_label);
57///     }
58/// }
59/// ```
60pub struct Client {
61    inner: Arc<WsClient>,
62
63    pub vm: VmProcedures,
64    pub xo: XoProcedures,
65    pub token: TokenProcedures,
66    pub session: SessionProcedures,
67}
68
69impl Client {
70    /// Connect to xo-server
71    ///
72    /// Note that `url` is the websocket URL to the API endpoint, usually something like
73    /// wss://example.com/api/ or ws://example.com/api/ for unencrypted
74    pub async fn connect(url: &str) -> Result<Self, RpcError> {
75        log::debug!("Connecting to: {}", url);
76
77        let inner = Arc::new(
78            WsClientBuilder::default()
79                .connection_timeout(std::time::Duration::from_secs(10))
80                .build(url)
81                .await?,
82        );
83
84        log::debug!("Connected");
85
86        Ok(Client {
87            inner: Arc::clone(&inner),
88            vm: VmProcedures {
89                inner: Arc::clone(&inner),
90            },
91            xo: XoProcedures {
92                inner: Arc::clone(&inner),
93            },
94            token: TokenProcedures {
95                inner: Arc::clone(&inner),
96            },
97            session: SessionProcedures {
98                inner: Arc::clone(&inner),
99            },
100        })
101    }
102
103    /// Subscribe to method "all"
104    ///
105    /// xo-server tends to send notifications to the client's JSON RPC procedure "all"
106    /// subscribe_to_notification_all returns a value that can be used to read those
107    /// notifications
108    pub async fn subscribe_to_notification_all<T>(&self) -> Result<Subscription<T>, RpcError>
109    where
110        T: DeserializeOwned,
111    {
112        self.inner.subscribe_to_method::<T>("all").await
113    }
114}