use crate::db; use crate::grpc::{check_admin_key, check_sig_from_req}; use detee_shared::app_proto::AppContract; use detee_shared::common_proto::{Empty, Pubkey}; use detee_shared::general_proto::brain_general_cli_server::BrainGeneralCli; use detee_shared::general_proto::{ Account, AccountBalance, AirdropReq, BanUserReq, InspectOperatorResp, KickReq, KickResp, ListOperatorsResp, RegOperatorReq, ReportNodeReq, SlashReq, }; use detee_shared::vm_proto::VmContract; use surrealdb::engine::remote::ws::Client; use surrealdb::Surreal; use std::pin::Pin; use std::sync::Arc; use tokio::sync::mpsc; use tokio_stream::wrappers::ReceiverStream; use tokio_stream::Stream; use tonic::{Request, Response, Status}; pub struct BrainCliServer { pub db: Arc>, } impl BrainCliServer { pub fn new(db: Arc>) -> Self { Self { db } } } #[tonic::async_trait] impl BrainGeneralCli for BrainCliServer { type ListAccountsStream = Pin> + Send>>; type ListAllAppContractsStream = Pin> + Send>>; type ListAllVmContractsStream = Pin> + Send>>; type ListOperatorsStream = Pin> + Send>>; async fn get_balance(&self, req: Request) -> Result, Status> { let req = check_sig_from_req(req)?; Ok(Response::new(db::general::Account::get(&self.db, &req.pubkey).await?.into())) } async fn report_node(&self, req: Request) -> Result, Status> { let req = check_sig_from_req(req)?; let (account, node, contract_id) = match db::vm::ActiveVmWithNode::get_by_uuid(&self.db, &req.contract).await? { Some(vm_contract) if vm_contract.admin.key().to_string() == req.admin_pubkey && vm_contract.vm_node.id.key().to_string() == req.node_pubkey => { (vm_contract.admin, vm_contract.vm_node.id, vm_contract.id.to_string()) } _ => match db::app::ActiveAppWithNode::get_by_uuid(&self.db, &req.contract).await? { Some(app_contract) if app_contract.admin.key().to_string() == req.admin_pubkey && app_contract.app_node.id.key().to_string() == req.node_pubkey => { (app_contract.admin, app_contract.app_node.id, app_contract.id.to_string()) } _ => { return Err(Status::unauthenticated("No contract found by this ID.")); } }, }; db::general::Report::create(&self.db, account, node, req.reason, contract_id).await?; Ok(Response::new(Empty {})) } async fn list_operators( &self, req: Request, ) -> Result, Status> { let _ = check_sig_from_req(req)?; let operators = db::general::Operator::list(&self.db).await?; let (tx, rx) = mpsc::channel(6); tokio::spawn(async move { for op in operators { let _ = tx.send(Ok(op.into())).await; } }); let output_stream = ReceiverStream::new(rx); Ok(Response::new(Box::pin(output_stream) as Self::ListOperatorsStream)) } async fn inspect_operator( &self, req: Request, ) -> Result, Status> { match db::general::Operator::inspect_nodes(&self.db, &req.into_inner().pubkey).await? { (Some(op), vm_nodes, app_nodes) => Ok(Response::new(InspectOperatorResp { operator: Some(op.into()), vm_nodes: vm_nodes.into_iter().map(|n| n.into()).collect(), app_nodes: app_nodes.into_iter().map(|n| n.into()).collect(), })), (None, _, _) => Err(Status::not_found("The wallet you specified is not an operator")), } } async fn register_operator( &self, _req: Request, ) -> Result, Status> { todo!(); // let req = check_sig_from_req(req)?; // info!("Regitering new operator: {req:?}"); // match self.data.register_operator(req) { // Ok(()) => Ok(Response::new(Empty {})), // Err(e) => Err(Status::failed_precondition(e.to_string())), // } } async fn kick_contract(&self, _req: Request) -> Result, Status> { todo!(); // let req = check_sig_from_req(req)?; // match self.data.kick_contract(&req.operator_wallet, &req.contract_uuid, &req.reason).await { // Ok(nano_lp) => Ok(Response::new(KickResp { nano_lp })), // Err(e) => Err(Status::permission_denied(e.to_string())), // } } async fn ban_user(&self, _req: Request) -> Result, Status> { todo!(); // let req = check_sig_from_req(req)?; // self.data.ban_user(&req.operator_wallet, &req.user_wallet); // Ok(Response::new(Empty {})) } // admin commands async fn airdrop(&self, req: Request) -> Result, Status> { check_admin_key(&req)?; let req = check_sig_from_req(req)?; db::general::Account::airdrop(&self.db, &req.pubkey, req.tokens).await?; Ok(Response::new(Empty {})) } async fn slash(&self, _req: Request) -> Result, Status> { todo!(); // check_admin_key(&req)?; // let req = check_sig_from_req(req)?; // self.data.slash_account(&req.pubkey, req.tokens); // Ok(Response::new(Empty {})) } async fn list_accounts( &self, _req: Request, ) -> Result, Status> { todo!(); // check_admin_key(&req)?; // let _ = check_sig_from_req(req)?; // let accounts = self.data.list_accounts(); // let (tx, rx) = mpsc::channel(6); // tokio::spawn(async move { // for account in accounts { // let _ = tx.send(Ok(account.into())).await; // } // }); // let output_stream = ReceiverStream::new(rx); // Ok(Response::new(Box::pin(output_stream) as Self::ListAccountsStream)) } async fn list_all_vm_contracts( &self, _req: Request, ) -> Result, Status> { todo!(); // check_admin_key(&req)?; // let _ = check_sig_from_req(req)?; // let contracts = self.data.list_all_contracts(); // let (tx, rx) = mpsc::channel(6); // tokio::spawn(async move { // for contract in contracts { // let _ = tx.send(Ok(contract.into())).await; // } // }); // let output_stream = ReceiverStream::new(rx); // Ok(Response::new(Box::pin(output_stream) as Self::ListAllVmContractsStream)) } async fn list_all_app_contracts( &self, _req: tonic::Request, ) -> Result, Status> { todo!(); // check_admin_key(&req)?; // let _ = check_sig_from_req(req)?; // let contracts = self.data.list_all_app_contracts(); // let (tx, rx) = mpsc::channel(6); // tokio::spawn(async move { // for contract in contracts { // let _ = tx.send(Ok(contract.into())).await; // } // }); // let output_stream = ReceiverStream::new(rx); // Ok(Response::new(Box::pin(output_stream))) } }