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