Compare commits
	
		
			No commits in common. "ddc5d248578e74cc2e2074e76461287150d2737c" and "41d9bd104f48620cc9724d89709a00e026ef4cd3" have entirely different histories.
		
	
	
		
			ddc5d24857
			...
			41d9bd104f
		
	
		
| @ -309,13 +309,7 @@ impl Config { | |||||||
| 
 | 
 | ||||||
|     pub fn get_brain_info() -> (String, String) { |     pub fn get_brain_info() -> (String, String) { | ||||||
|         match Self::init_config().network.as_str() { |         match Self::init_config().network.as_str() { | ||||||
|             "staging" => { |             "staging" => ("https://10.254.254.8:31337".to_string(), "staging-brain".to_string()), | ||||||
|                 let url1 = "https://149.22.95.1:47855".to_string(); // staging brain 2
 |  | ||||||
|                 let url2 = "https://149.36.48.99:48843".to_string(); // staging brain 3
 |  | ||||||
| 
 |  | ||||||
|                 let url = if rand::random::<bool>() { url1 } else { url2 }; |  | ||||||
|                 (url, "staging-brain".to_string()) |  | ||||||
|             } |  | ||||||
|             "localhost" => ("https://localhost:31337".to_string(), "staging-brain".to_string()), |             "localhost" => ("https://localhost:31337".to_string(), "staging-brain".to_string()), | ||||||
|             _ => ("https://173.234.17.2:39477".to_string(), "testnet-brain".to_string()), |             _ => ("https://173.234.17.2:39477".to_string(), "testnet-brain".to_string()), | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -3,9 +3,8 @@ pub mod proto { | |||||||
|     pub use detee_shared::vm_proto::*; |     pub use detee_shared::vm_proto::*; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| use crate::call_with_follow_redirect; |  | ||||||
| use crate::config::Config; | use crate::config::Config; | ||||||
| use crate::utils::{self, sign_request}; | use crate::constants::MAX_REDIRECTS; | ||||||
| use lazy_static::lazy_static; | use lazy_static::lazy_static; | ||||||
| use log::{debug, info, warn}; | use log::{debug, info, warn}; | ||||||
| use proto::{ | use proto::{ | ||||||
| @ -14,7 +13,9 @@ use proto::{ | |||||||
| }; | }; | ||||||
| use tokio_stream::StreamExt; | use tokio_stream::StreamExt; | ||||||
| use tonic::metadata::errors::InvalidMetadataValue; | use tonic::metadata::errors::InvalidMetadataValue; | ||||||
|  | use tonic::metadata::AsciiMetadataValue; | ||||||
| use tonic::transport::Channel; | use tonic::transport::Channel; | ||||||
|  | use tonic::Request; | ||||||
| 
 | 
 | ||||||
| lazy_static! { | lazy_static! { | ||||||
|     static ref SECURE_PUBLIC_KEY: String = use_default_string(); |     static ref SECURE_PUBLIC_KEY: String = use_default_string(); | ||||||
| @ -43,10 +44,6 @@ pub enum Error { | |||||||
|     CorruptedBrainUrl, |     CorruptedBrainUrl, | ||||||
|     #[error("Max redirects exceeded: {0}")] |     #[error("Max redirects exceeded: {0}")] | ||||||
|     MaxRedirectsExceeded(String), |     MaxRedirectsExceeded(String), | ||||||
|     #[error("Redirect error: {0}")] |  | ||||||
|     RedirectError(String), |  | ||||||
|     #[error(transparent)] |  | ||||||
|     InternalError(#[from] utils::Error), |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl crate::HumanOutput for VmContract { | impl crate::HumanOutput for VmContract { | ||||||
| @ -100,6 +97,20 @@ async fn client_from_endpoint( | |||||||
|     Ok(BrainVmCliClient::new(Config::connect_brain_channel(reconnect_endpoint).await?)) |     Ok(BrainVmCliClient::new(Config::connect_brain_channel(reconnect_endpoint).await?)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn sign_request<T: std::fmt::Debug>(req: T) -> Result<Request<T>, Error> { | ||||||
|  |     let pubkey = Config::get_detee_wallet()?; | ||||||
|  |     let timestamp = chrono::Utc::now().to_rfc3339(); | ||||||
|  |     let signature = Config::try_sign_message(&format!("{timestamp}{req:?}"))?; | ||||||
|  |     let timestamp: AsciiMetadataValue = timestamp.parse()?; | ||||||
|  |     let pubkey: AsciiMetadataValue = pubkey.parse()?; | ||||||
|  |     let signature: AsciiMetadataValue = signature.parse()?; | ||||||
|  |     let mut req = Request::new(req); | ||||||
|  |     req.metadata_mut().insert("timestamp", timestamp); | ||||||
|  |     req.metadata_mut().insert("pubkey", pubkey); | ||||||
|  |     req.metadata_mut().insert("request-signature", signature); | ||||||
|  |     Ok(req) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub async fn get_node_list(req: VmNodeFilters) -> Result<Vec<VmNodeListResp>, Error> { | pub async fn get_node_list(req: VmNodeFilters) -> Result<Vec<VmNodeListResp>, Error> { | ||||||
|     debug!("Getting nodes from brain..."); |     debug!("Getting nodes from brain..."); | ||||||
|     let mut client = client().await?; |     let mut client = client().await?; | ||||||
| @ -127,13 +138,30 @@ pub async fn get_one_node(req: VmNodeFilters) -> Result<VmNodeListResp, Error> { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub async fn create_vm(req: NewVmReq) -> Result<NewVmResp, Error> { | pub async fn create_vm(req: NewVmReq) -> Result<NewVmResp, Error> { | ||||||
|  |     let mut client = client().await?; | ||||||
|     debug!("Sending NewVmReq to brain: {req:?}"); |     debug!("Sending NewVmReq to brain: {req:?}"); | ||||||
| 
 |     for attempt in 0..MAX_REDIRECTS { | ||||||
|     let client = client().await?; |         match client.new_vm(sign_request(req.clone())?).await { | ||||||
|     match call_with_follow_redirect!(client, req, new_vm).await { |             Ok(resp) => return Ok(resp.into_inner()), | ||||||
|         Ok(resp) => Ok(resp.into_inner()), |             Err(status) | ||||||
|         Err(e) => Err(e.into()), |                 if status.code() == tonic::Code::Unavailable | ||||||
|  |                     && status.message() == "moved" | ||||||
|  |                     && status.metadata().contains_key("location") => | ||||||
|  |             { | ||||||
|  |                 let redirect_url = status | ||||||
|  |                     .metadata() | ||||||
|  |                     .get("location") | ||||||
|  |                     .and_then(|v| v.to_str().ok().map(|s| format!("https://{s}"))) | ||||||
|  |                     .unwrap_or_default(); | ||||||
|  |                 // TODO: change this println to log::info!()
 | ||||||
|  |                 println!("{attempt}) server moved to a different URL, trying to reconnect... ({redirect_url})"); | ||||||
|  |                 client = client_from_endpoint(redirect_url).await?; | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             Err(e) => return Err(e.into()), | ||||||
|  |         }; | ||||||
|     } |     } | ||||||
|  |     Err(Error::MaxRedirectsExceeded(MAX_REDIRECTS.to_string())) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub async fn list_contracts(req: ListVmContractsReq) -> Result<Vec<VmContract>, Error> { | pub async fn list_contracts(req: ListVmContractsReq) -> Result<Vec<VmContract>, Error> { | ||||||
| @ -157,9 +185,10 @@ pub async fn list_contracts(req: ListVmContractsReq) -> Result<Vec<VmContract>, | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub async fn delete_vm(uuid: &str) -> Result<(), Error> { | pub async fn delete_vm(uuid: &str) -> Result<(), Error> { | ||||||
|     let client = client().await?; |     let mut client = client().await?; | ||||||
|     let req = DeleteVmReq { uuid: uuid.to_string(), admin_pubkey: Config::get_detee_wallet()? }; |     let req = DeleteVmReq { uuid: uuid.to_string(), admin_pubkey: Config::get_detee_wallet()? }; | ||||||
|     match call_with_follow_redirect!(client, req, delete_vm).await { |     let result = client.delete_vm(sign_request(req)?).await; | ||||||
|  |     match result { | ||||||
|         Ok(confirmation) => { |         Ok(confirmation) => { | ||||||
|             log::debug!("VM deletion confirmation: {confirmation:?}"); |             log::debug!("VM deletion confirmation: {confirmation:?}"); | ||||||
|         } |         } | ||||||
| @ -194,8 +223,9 @@ pub async fn extend_vm(uuid: String, admin_pubkey: String, locked_nano: u64) -> | |||||||
| 
 | 
 | ||||||
| pub async fn update_vm(req: UpdateVmReq) -> Result<UpdateVmResp, Error> { | pub async fn update_vm(req: UpdateVmReq) -> Result<UpdateVmResp, Error> { | ||||||
|     info!("Updating VM {req:?}"); |     info!("Updating VM {req:?}"); | ||||||
|     let client = client().await?; |     let mut client = client().await?; | ||||||
|     match call_with_follow_redirect!(client, req, update_vm).await { |     let result = client.update_vm(sign_request(req)?).await; | ||||||
|  |     match result { | ||||||
|         Ok(resp) => { |         Ok(resp) => { | ||||||
|             let resp = resp.into_inner(); |             let resp = resp.into_inner(); | ||||||
|             if resp.error.is_empty() { |             if resp.error.is_empty() { | ||||||
|  | |||||||
							
								
								
									
										46
									
								
								src/utils.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										46
									
								
								src/utils.rs
									
									
									
									
									
								
							| @ -42,49 +42,3 @@ pub fn shorten_string(my_string: &String) -> String { | |||||||
|         format!("{}", first_part) |         format!("{}", first_part) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| #[macro_export] |  | ||||||
| macro_rules! call_with_follow_redirect { |  | ||||||
|     ( |  | ||||||
|         $client:expr, |  | ||||||
|         $req_data:expr, |  | ||||||
|         $method:ident |  | ||||||
|     ) => { |  | ||||||
|         async { |  | ||||||
|             let mut client = $client; |  | ||||||
| 
 |  | ||||||
|             for attempt in 0..crate::constants::MAX_REDIRECTS { |  | ||||||
|                 debug!("Attempt #{}: Calling method '{}'...", attempt + 1, stringify!($method)); |  | ||||||
| 
 |  | ||||||
|                 let req_data_clone = $req_data.clone(); |  | ||||||
|                 let signed_req = crate::utils::sign_request(req_data_clone)?; |  | ||||||
| 
 |  | ||||||
|                 match client.$method(signed_req).await { |  | ||||||
|                     Ok(resp) => return Ok(resp), |  | ||||||
| 
 |  | ||||||
|                     Err(status) |  | ||||||
|                         if status.code() == tonic::Code::Unavailable |  | ||||||
|                             && status.message() == "moved" => |  | ||||||
|                     { |  | ||||||
|                         let redirect_url = status |  | ||||||
|                             .metadata() |  | ||||||
|                             .get("location") |  | ||||||
|                             .and_then(|v| v.to_str().ok()) |  | ||||||
|                             .ok_or_else(|| { |  | ||||||
|                                 Error::RedirectError( |  | ||||||
|                                     "Server indicated a move but provided no location".into(), |  | ||||||
|                                 ) |  | ||||||
|                             })?; |  | ||||||
| 
 |  | ||||||
|                         info!("Server moved. Redirecting to {}...", redirect_url); |  | ||||||
| 
 |  | ||||||
|                         client = client_from_endpoint(format!("https://{}", redirect_url)).await?; |  | ||||||
|                         continue; |  | ||||||
|                     } |  | ||||||
|                     Err(e) => return Err(Error::ResponseStatus(e)), |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             Err(Error::MaxRedirectsExceeded(crate::constants::MAX_REDIRECTS.to_string())) |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user