use std::str::FromStr;
use std::sync::Arc;
use miette::IntoDiagnostic;
use tracing::{debug, info, trace, warn};
use ockam::Context;
use ockam_api::cli_state::CliState;
use ockam_api::nodes::models::relay::{RelayInfo, ReturnTiming};
use ockam_api::nodes::InMemoryNode;
use ockam_multiaddr::MultiAddr;
use crate::api::state::OrchestratorStatus;
use crate::state::AppState;
use crate::Result;
impl AppState {
pub async fn refresh_relay(&self) {
let cli_state = self.state().await;
let node_manager = self.node_manager().await;
let context = self.context();
if !self.is_enrolled().await.unwrap_or(false) {
self.update_orchestrator_status_if(
OrchestratorStatus::Disconnected,
vec![
OrchestratorStatus::Connected,
OrchestratorStatus::Connecting,
],
);
self.publish_state().await;
debug!("Not enrolled, skipping relay creation");
match get_relay(&node_manager, &cli_state).await {
Ok(_) => match delete_relay(&node_manager, &cli_state).await {
Ok(_) => {
info!("Relay deleted");
}
Err(err) => {
warn!(%err, "Cannot delete relay")
}
},
Err(err) => {
warn!(%err, "Cannot get relay")
}
}
return;
}
let result = self
.create_relay_impl(&context, &cli_state, node_manager.clone())
.await;
if let Err(e) = result {
warn!(%e, "Failed to create relay, retrying...");
}
}
async fn create_relay_impl(
&self,
context: &Context,
cli_state: &CliState,
node_manager: Arc<InMemoryNode>,
) -> Result<()> {
trace!("Creating relay");
match cli_state.projects().get_default_project().await {
Ok(project) => {
if let Some(_relay) = get_relay(&node_manager, cli_state).await? {
debug!(project = %project.name(), "Relay already exists");
self.update_orchestrator_status(OrchestratorStatus::Connected);
self.publish_state().await;
Ok(())
} else {
self.update_orchestrator_status(OrchestratorStatus::Connecting);
self.publish_state().await;
debug!(project = %project.name(), "Creating relay at project");
let project_route = format!("/project/{}", project.name());
let project_address = MultiAddr::from_str(&project_route).into_diagnostic()?;
let relay_alias = relay_alias(cli_state).await?;
let relay = node_manager
.create_relay(
context,
&project_address,
relay_alias.clone(),
None,
Some(relay_alias),
ReturnTiming::AfterConnection,
)
.await
.into_diagnostic()?;
info!(forwarding_route = %relay.forwarding_route().clone().unwrap_or_default(), "Relay created at project");
self.update_orchestrator_status(OrchestratorStatus::Connected);
self.publish_state().await;
Ok(())
}
}
Err(err) => {
warn!(%err, "No default project has ben set");
Ok(())
}
}
}
}
async fn delete_relay(node_manager: &InMemoryNode, cli_state: &CliState) -> ockam_core::Result<()> {
let remote_address = relay_remote_address(cli_state).await?;
node_manager.delete_relay(&remote_address).await
}
async fn get_relay(
node_manager: &InMemoryNode,
cli_state: &CliState,
) -> ockam::Result<Option<RelayInfo>> {
let relay_alias = relay_alias(cli_state).await?;
Ok(node_manager
.get_relays()
.await
.into_iter()
.find(|r| r.name() == relay_alias))
}
async fn relay_remote_address(cli_state: &CliState) -> ockam::Result<String> {
let bare_relay_name = relay_alias(cli_state).await?;
Ok(format!("forward_to_{bare_relay_name}"))
}
async fn relay_alias(cli_state: &CliState) -> ockam::Result<String> {
Ok(cli_state
.get_or_create_default_named_identity()
.await?
.identifier()
.to_string())
}