1use crate::broker::VmgsBrokerError;
8use crate::broker::VmgsBrokerRpc;
9use inspect::Inspect;
10use mesh::MeshPayload;
11use mesh::rpc::RpcError;
12use mesh::rpc::RpcSend;
13use thiserror::Error;
14use tracing::instrument;
15use vmgs::VmgsFileInfo;
16use vmgs_format::FileId;
17
18#[derive(Debug, Error)]
20#[non_exhaustive]
21pub enum VmgsClientError {
22 #[error("broker is offline")]
24 BrokerOffline(#[source] RpcError),
25 #[error("vmgs error")]
27 Vmgs(#[source] VmgsBrokerError),
28}
29
30impl From<RpcError> for VmgsClientError {
31 fn from(value: RpcError) -> Self {
32 match value {
33 RpcError::Channel(e) => VmgsClientError::BrokerOffline(RpcError::Channel(e)),
34 }
35 }
36}
37
38impl From<RpcError<VmgsBrokerError>> for VmgsClientError {
39 fn from(value: RpcError<VmgsBrokerError>) -> Self {
40 match value {
41 RpcError::Call(e) => VmgsClientError::Vmgs(e),
42 RpcError::Channel(e) => VmgsClientError::BrokerOffline(RpcError::Channel(e)),
43 }
44 }
45}
46
47#[derive(Clone, Inspect, MeshPayload)]
49pub struct VmgsClient {
50 #[inspect(flatten, send = "VmgsBrokerRpc::Inspect")]
51 pub(crate) control: mesh::Sender<VmgsBrokerRpc>,
52}
53
54impl VmgsClient {
55 #[instrument(skip_all, fields(file_id))]
57 pub async fn get_file_info(&self, file_id: FileId) -> Result<VmgsFileInfo, VmgsClientError> {
58 let res = self
59 .control
60 .call_failable(VmgsBrokerRpc::GetFileInfo, file_id.into())
61 .await?;
62
63 Ok(res)
64 }
65
66 #[instrument(skip_all, fields(file_id))]
68 pub async fn read_file(&self, file_id: FileId) -> Result<Vec<u8>, VmgsClientError> {
69 let res = self
70 .control
71 .call_failable(VmgsBrokerRpc::ReadFile, file_id.into())
72 .await?;
73
74 Ok(res)
75 }
76
77 #[instrument(skip_all, fields(file_id))]
82 pub async fn write_file(&self, file_id: FileId, buf: Vec<u8>) -> Result<(), VmgsClientError> {
83 self.control
84 .call_failable(VmgsBrokerRpc::WriteFile, (file_id.into(), buf))
85 .await?;
86
87 Ok(())
88 }
89
90 #[cfg(with_encryption)]
94 #[instrument(skip_all, fields(file_id))]
95 pub async fn write_file_encrypted(
96 &self,
97 file_id: FileId,
98 buf: Vec<u8>,
99 ) -> Result<(), VmgsClientError> {
100 self.control
101 .call_failable(VmgsBrokerRpc::WriteFileEncrypted, (file_id.into(), buf))
102 .await?;
103
104 Ok(())
105 }
106
107 pub async fn save(&self) -> Result<vmgs::save_restore::state::SavedVmgsState, VmgsClientError> {
113 let res = self.control.call(VmgsBrokerRpc::Save, ()).await?;
114 Ok(res)
115 }
116}