//! PrismNET client for port management use prismnet_api::proto::{ port_service_client::PortServiceClient, GetPortRequest, AttachDeviceRequest, DetachDeviceRequest, }; use tonic::metadata::MetadataValue; use tonic::transport::Channel; /// PrismNET client wrapper pub struct PrismNETClient { auth_token: String, port_client: PortServiceClient, } impl PrismNETClient { /// Create a new PrismNET client pub async fn new( endpoint: String, auth_token: String, ) -> Result> { let channel = Channel::from_shared(endpoint)? .connect() .await?; let port_client = PortServiceClient::new(channel); Ok(Self { auth_token, port_client, }) } fn request_with_auth( auth_token: &str, payload: T, ) -> Result, Box> { let mut request = tonic::Request::new(payload); let token_value = MetadataValue::try_from(auth_token)?; request .metadata_mut() .insert("x-photon-auth-token", token_value); Ok(request) } /// Get port details pub async fn get_port( &mut self, org_id: &str, project_id: &str, subnet_id: &str, port_id: &str, ) -> Result> { let request = Self::request_with_auth(&self.auth_token, GetPortRequest { org_id: org_id.to_string(), project_id: project_id.to_string(), subnet_id: subnet_id.to_string(), id: port_id.to_string(), })?; let response = self.port_client.get_port(request).await?; Ok(response.into_inner().port.ok_or("Port not found in response")?) } /// Attach a device to a port pub async fn attach_device( &mut self, org_id: &str, project_id: &str, subnet_id: &str, port_id: &str, device_id: &str, device_type: i32, ) -> Result<(), Box> { let request = Self::request_with_auth(&self.auth_token, AttachDeviceRequest { org_id: org_id.to_string(), project_id: project_id.to_string(), subnet_id: subnet_id.to_string(), port_id: port_id.to_string(), device_id: device_id.to_string(), device_type, })?; self.port_client.attach_device(request).await?; Ok(()) } /// Detach a device from a port pub async fn detach_device( &mut self, org_id: &str, project_id: &str, subnet_id: &str, port_id: &str, ) -> Result<(), Box> { let request = Self::request_with_auth(&self.auth_token, DetachDeviceRequest { org_id: org_id.to_string(), project_id: project_id.to_string(), subnet_id: subnet_id.to_string(), port_id: port_id.to_string(), })?; self.port_client.detach_device(request).await?; Ok(()) } } #[cfg(test)] mod tests { use super::*; #[test] fn request_with_auth_adds_internal_token_header() { let request = PrismNETClient::request_with_auth( "test-token", GetPortRequest { org_id: "org".to_string(), project_id: "project".to_string(), subnet_id: "subnet".to_string(), id: "port".to_string(), }, ) .expect("request metadata should be constructible"); assert_eq!( request .metadata() .get("x-photon-auth-token") .and_then(|value| value.to_str().ok()), Some("test-token") ); } }