use miette::IntoDiagnostic;
use std::ops::Deref;
use std::path::PathBuf;
use ockam::{Context, Result, TcpTransport};
use ockam_core::compat::{string::String, sync::Arc};
use ockam_core::errcode::Kind;
use ockam_transport_tcp::TcpListenerOptions;
use crate::cli_state::random_name;
use crate::cli_state::{add_project_info_to_node_state, init_node_state, CliState};
use crate::cloud::Controller;
use crate::config::cli::TrustContextConfig;
use crate::nodes::service::{
NodeManagerGeneralOptions, NodeManagerTransportOptions, NodeManagerTrustOptions,
};
use crate::nodes::{NodeManager, NODEMANAGER_ADDR};
use crate::session::sessions::Session;
use crate::DefaultAddress;
pub struct InMemoryNode {
pub(crate) node_manager: Arc<NodeManager>,
persistent: bool,
}
impl Deref for InMemoryNode {
type Target = Arc<NodeManager>;
fn deref(&self) -> &Self::Target {
&self.node_manager
}
}
impl Drop for InMemoryNode {
fn drop(&mut self) {
if !self.persistent {
self.node_manager
.delete_node()
.unwrap_or_else(|_| panic!("cannot delete the node {}", self.node_name));
}
}
}
impl InMemoryNode {
pub async fn start(ctx: &Context, cli_state: &CliState) -> miette::Result<Self> {
Self::start_with_trust_context(ctx, cli_state, None, None).await
}
pub async fn start_with_trust_context(
ctx: &Context,
cli_state: &CliState,
project_path: Option<&PathBuf>,
trust_context_config: Option<TrustContextConfig>,
) -> miette::Result<Self> {
Self::start_node(
ctx,
cli_state,
None,
None,
project_path,
trust_context_config,
)
.await
}
pub async fn start_node(
ctx: &Context,
cli_state: &CliState,
vault: Option<String>,
identity: Option<String>,
project_path: Option<&PathBuf>,
trust_context_config: Option<TrustContextConfig>,
) -> miette::Result<InMemoryNode> {
let defaults = NodeManagerDefaults::default();
init_node_state(
cli_state,
&defaults.node_name,
vault.as_deref(),
identity.as_deref(),
)
.await?;
add_project_info_to_node_state(&defaults.node_name, cli_state, project_path).await?;
let tcp = TcpTransport::create(ctx).await.into_diagnostic()?;
let bind = defaults.tcp_listener_address;
let options = TcpListenerOptions::new();
let listener = tcp.listen(&bind, options).await.into_diagnostic()?;
let node_manager = Self::new(
ctx,
NodeManagerGeneralOptions::new(
cli_state.clone(),
defaults.node_name.clone(),
None,
false,
false,
),
NodeManagerTransportOptions::new(listener.flow_control_id().clone(), tcp),
NodeManagerTrustOptions::new(trust_context_config),
)
.await
.into_diagnostic()?;
ctx.flow_controls()
.add_consumer(NODEMANAGER_ADDR, listener.flow_control_id());
Ok(node_manager)
}
pub async fn create_controller(&self) -> miette::Result<Controller> {
self.create_controller_client().await.into_diagnostic()
}
pub fn add_session(&self, session: Session) {
self.medic_handle.add_session(session);
}
pub fn remove_session(&self, key: &str) {
self.medic_handle.remove_session(key);
}
pub async fn stop(&self, ctx: &Context) -> Result<()> {
self.medic_handle.stop_medic(ctx).await?;
for addr in DefaultAddress::iter() {
let result = ctx.stop_worker(addr).await;
if let Err(err) = result {
if err.code().kind == Kind::NotFound {
continue;
} else {
return Err(err);
}
}
}
Ok(())
}
pub async fn new(
ctx: &Context,
general_options: NodeManagerGeneralOptions,
transport_options: NodeManagerTransportOptions,
trust_options: NodeManagerTrustOptions,
) -> Result<Self> {
let persistent = general_options.persistent;
let node_manager =
NodeManager::create(ctx, general_options, transport_options, trust_options).await?;
debug!("start the Medic");
Ok(Self {
node_manager: Arc::new(node_manager),
persistent,
})
}
}
pub struct NodeManagerDefaults {
pub node_name: String,
pub tcp_listener_address: String,
}
impl Default for NodeManagerDefaults {
fn default() -> Self {
Self {
node_name: random_name(),
tcp_listener_address: "127.0.0.1:0".to_string(),
}
}
}