use color_eyre::{
Result,
eyre::{Context, bail},
};
use serde::Serialize;
use crate::{
Error, PROTOCOL_VERSION,
internal_prelude::*,
network::{message::*, protocol::*, secret::read_shared_secret},
settings::Settings,
};
pub struct Client {
pub settings: Settings,
pub stream: GenericStream,
pub daemon_version: String,
}
impl std::fmt::Debug for Client {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Client")
.field("settings", &self.settings)
.field("stream", &"GenericStream<not_debuggable>")
.finish()
}
}
impl Client {
pub async fn new(settings: Settings, show_version_warning: bool) -> Result<Self> {
let mut stream = get_client_stream(&settings.shared)
.await
.context("Failed to initialize stream.")?;
let secret = read_shared_secret(&settings.shared.shared_secret_path())?;
send_bytes(&secret, &mut stream)
.await
.context("Failed to send secret.")?;
let version_bytes = receive_bytes(&mut stream)
.await
.context("Failed to receive version during handshake with daemon.")?;
if version_bytes.is_empty() {
bail!("Daemon went away after sending secret. Did you use the correct secret?")
}
let daemon_version = match String::from_utf8(version_bytes) {
Ok(version) => version,
Err(_) => {
bail!("Daemon sent invalid UTF-8. Did you use the correct secret?")
}
};
if daemon_version != PROTOCOL_VERSION && show_version_warning {
warn!(
"Different protocol version detected '{daemon_version}'. Consider updating and restarting the daemon."
);
}
Ok(Client {
settings,
stream,
daemon_version,
})
}
pub fn stream(&mut self) -> &mut GenericStream {
&mut self.stream
}
pub async fn send_request<T>(&mut self, message: T) -> Result<(), Error>
where
T: Into<Request>,
T: Serialize + std::fmt::Debug,
{
send_message::<_, Request>(message, &mut self.stream).await
}
pub async fn receive_response(&mut self) -> Result<Response, Error> {
receive_message::<Response>(&mut self.stream).await
}
pub fn daemon_version(&self) -> &String {
&self.daemon_version
}
}