Redirect to pubsub node and some bug fixes #8
| @ -309,7 +309,13 @@ 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" => ("https://10.254.254.8:31337".to_string(), "staging-brain".to_string()), |             "staging" => { | ||||||
|  |                 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,8 +3,9 @@ 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::constants::MAX_REDIRECTS; | use crate::utils::{self, sign_request}; | ||||||
| use lazy_static::lazy_static; | use lazy_static::lazy_static; | ||||||
| use log::{debug, info, warn}; | use log::{debug, info, warn}; | ||||||
| use proto::{ | use proto::{ | ||||||
| @ -13,9 +14,7 @@ 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(); | ||||||
| @ -44,6 +43,10 @@ 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 { | ||||||
| @ -97,20 +100,6 @@ 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?; | ||||||
| @ -138,30 +127,13 @@ 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 { | 
 | ||||||
|         match client.new_vm(sign_request(req.clone())?).await { |     let client = client().await?; | ||||||
|             Ok(resp) => return Ok(resp.into_inner()), |     match call_with_follow_redirect!(client, req, new_vm).await { | ||||||
|             Err(status) |         Ok(resp) => Ok(resp.into_inner()), | ||||||
|                 if status.code() == tonic::Code::Unavailable |         Err(e) => Err(e.into()), | ||||||
|                     && 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> { | ||||||
|  | |||||||
							
								
								
									
										46
									
								
								src/utils.rs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										46
									
								
								src/utils.rs
									
									
									
									
									
								
							| @ -42,3 +42,49 @@ 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