use detee_shared::app_proto::brain_app_cli_client::BrainAppCliClient; use detee_shared::app_proto::{ AppContract, AppNodeFilters, AppNodeListResp, DelAppReq, ListAppContractsReq, NewAppReq, NewAppRes, }; use detee_shared::sgx::types::brain::AppDeployConfig; use tokio_stream::StreamExt; use tonic::transport::Channel; use crate::config::Config; use crate::sgx::utils::calculate_nanolp_for_app; use crate::utils::{self, sign_request}; #[derive(thiserror::Error, Debug)] pub enum Error { #[error("Failed to connect to the brain: {0}")] BrainConnection(#[from] tonic::transport::Error), #[error("Received error from brain: {}", _0.message())] ResponseStatus(#[from] tonic::Status), #[error(transparent)] InternalError(#[from] utils::Error), #[error(transparent)] ConfigError(#[from] crate::config::Error), #[error("The Root CA file got corrupted.")] CorruptedRootCa(#[from] std::io::Error), #[error("Internal app error: could not parse Brain URL")] CorruptedBrainUrl, } type Result = std::result::Result; impl crate::HumanOutput for AppNodeListResp { fn human_cli_print(&self) { println!("The pubkey of this node is {} and the IP is {}", self.node_pubkey, self.ip); println!("It belongs to the operator {}", self.operator); println!( "This node is located in the city {}, within the region of {}, in {}", self.city, self.region, self.country ); println!("The price multiplier for the node is {}.", self.price); } } impl crate::HumanOutput for AppContract { fn human_cli_print(&self) { let app_resource = self.resource.clone().unwrap_or_default(); let mapped_ports = self .mapped_ports .clone() .iter() .map(|p| format!("({},{})", p.host_port, p.app_port)) .collect::>() .join(", "); println!( "The App {} has the UUID {}, and it runs on the node {}", self.app_name, self.uuid, self.node_pubkey ); println!("The app has mapped ports by the node are: {mapped_ports}"); println!( "The App has {} vCPUS, {}MB of memory and a disk of {} MB.", app_resource.vcpu, app_resource.memory_mb, app_resource.disk_mb ); println!("You have locked {} nanoLP in the contract, that get collected at a rate of {} nanoLP per minute.", self.locked_nano, self.nano_per_minute); } } async fn client() -> Result> { Ok(BrainAppCliClient::new(Config::get_brain_channel().await?)) } pub async fn new_app(app_deploy_config: AppDeployConfig) -> Result { let resource = app_deploy_config.clone().resource; let mut req: NewAppReq = app_deploy_config.clone().into(); let locked_nano = calculate_nanolp_for_app( resource.vcpu, resource.memory_mb, resource.disk_mb, app_deploy_config.hours, req.price_per_unit, ); req.uuid = "".to_string(); req.locked_nano = locked_nano; req.admin_pubkey = Config::get_detee_wallet()?; req.hratls_pubkey = Config::get_hratls_pubkey_hex()?; let res = client().await?.deploy_app(sign_request(req)?).await?; Ok(res.into_inner()) } pub async fn delete_app(app_uuid: String) -> Result<()> { let admin_pubkey = Config::get_detee_wallet()?; let delete_req = DelAppReq { uuid: app_uuid, admin_pubkey }; let _ = client().await?.delete_app(sign_request(delete_req)?).await?; Ok(()) } pub async fn list_contracts(req: ListAppContractsReq) -> Result> { let mut daemon_serivce = client().await?; let mut res_stream = daemon_serivce.list_app_contracts(sign_request(req)?).await?.into_inner(); let mut app_contracts = vec![]; while let Some(stream_update) = res_stream.next().await { match stream_update { Ok(contract) => { app_contracts.push(contract); } Err(e) => { eprintln!("Brain disconnected from register_node: {e}"); } } } Ok(app_contracts) } pub async fn get_one_app_node(req: AppNodeFilters) -> Result { let res = client().await?.get_one_app_node(sign_request(req)?).await?; Ok(res.into_inner()) } pub async fn get_app_node_list(req: AppNodeFilters) -> Result> { log::debug!("Getting app nodes from brain..."); let mut nodes = Vec::new(); let mut grpc_stream = client().await?.list_app_nodes(sign_request(req)?).await?.into_inner(); while let Some(stream_update) = grpc_stream.next().await { match stream_update { Ok(node) => { log::debug!("Received node from brain: {node:?}"); nodes.push(node); } Err(e) => { log::warn!("Received error instead of node list: {e:?}"); } } } log::debug!("Brain terminated list_nodes stream."); Ok(nodes) }