use geth_auth::AuthExplanation; use geth_resource::ResourceDescriptor; use geth_types::BlobHash; use serde::{Deserialize, Serialize}; use std::path::PathBuf; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "kebab-case")] pub enum ControlRequest { Status, NodeId, ResourceList, ResourceCreate { kind: String, name: String, }, CasAdd { path: PathBuf, }, CasGet { hash: BlobHash, out: PathBuf, }, CasHash { path: PathBuf, }, CasHas { hash: BlobHash, }, CasList, KeychainStatus, AuthExplain { subject: String, resource: String, capability: String, }, ModuleStub { module: String, command: String, }, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "kebab-case")] pub enum ControlResponse { Status(StatusResponse), NodeId(NodeIdResponse), ResourceList { resources: Vec, }, ResourceCreated { resource: ResourceDescriptor, }, CasAdded { hash: BlobHash, size_bytes: u64, }, CasGot { hash: BlobHash, out: PathBuf, size_bytes: u64, }, CasHash { hash: BlobHash, }, CasHas { hash: BlobHash, present: bool, }, CasList { blobs: Vec, }, KeychainStatus(KeychainStatusResponse), AuthExplain(AuthExplanation), NotImplemented { module: String, command: String, }, Error { message: String, }, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct StatusResponse { pub home: PathBuf, pub socket: PathBuf, pub agent_id: String, pub node_id: String, pub iroh: String, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct NodeIdResponse { pub agent_id: String, pub node_id: String, pub endpoint_id: Option, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct KeychainStatusResponse { pub initialized: bool, pub admin_keys: usize, pub users: usize, pub devices: usize, pub nodes: usize, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct CasBlob { pub hash: BlobHash, pub size_bytes: u64, } #[derive(Debug, thiserror::Error)] pub enum ControlError { #[error("json error: {0}")] Json(#[from] serde_json::Error), } pub fn encode_request(request: &ControlRequest) -> Result { let mut line = serde_json::to_string(request)?; line.push('\n'); Ok(line) } pub fn decode_request(line: &str) -> Result { serde_json::from_str(line).map_err(ControlError::from) } pub fn encode_response(response: &ControlResponse) -> Result { let mut line = serde_json::to_string(response)?; line.push('\n'); Ok(line) } pub fn decode_response(line: &str) -> Result { serde_json::from_str(line).map_err(ControlError::from) } #[cfg(test)] mod tests { use super::*; #[test] fn control_request_response_serialization_roundtrip() { let request = ControlRequest::CasHas { hash: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef".into(), }; assert_eq!( decode_request(&encode_request(&request).expect("encode")).expect("decode"), request ); let response = ControlResponse::CasHas { hash: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef".into(), present: true, }; assert_eq!( decode_response(&encode_response(&response).expect("encode")).expect("decode"), response ); } }