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