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}