use crate::state::AppState;
use crate::Error;
use miette::{IntoDiagnostic, WrapErr};
use ockam::compat::asynchronous::resolve_peer;
use ockam::transport::HostnamePort;
use ockam::Address;
use ockam_api::address::extract_address_value;
use ockam_api::nodes::models::portal::OutletAccessControl;
use std::str::FromStr;
use std::sync::Arc;
use tracing::{debug, info};
const DEFAULT_HOST: &str = "localhost";
impl AppState {
pub async fn tcp_outlet_create(&self, from: String, to: String) -> crate::Result<()> {
debug!(%from, %to, "Creating an outlet");
let addr = if let Some((host, port)) = to.split_once(':') {
format!("{host}:{port}")
} else {
format!("{DEFAULT_HOST}:{to}")
};
let socket_addr = resolve_peer(&HostnamePort::from_str(&addr)?)
.await
.into_diagnostic()
.wrap_err(
"Invalid address. The expected formats are 'host:port', 'ip:port' or 'port'",
)?;
let worker_addr: Address = extract_address_value(&from)
.wrap_err("Invalid service address")?
.into();
let node_manager = self.node_manager().await;
let ac = self
.create_invitations_access_control(worker_addr.clone())
.await?;
let incoming_ac = ac.create_incoming();
let outgoing_ac = ac.create_outgoing(self.context_ref()).await?;
match node_manager
.create_outlet(
&self.context(),
HostnamePort::from(socket_addr),
false,
Some(worker_addr.clone()),
true,
OutletAccessControl::AccessControl((Arc::new(incoming_ac), Arc::new(outgoing_ac))),
false,
)
.await
{
Ok(status) => {
info!(socket_addr = socket_addr.to_string(), "Outlet created");
self.model_mut(|m| m.add_tcp_outlet(status)).await?;
self.publish_state().await;
Ok(())
}
Err(_) => Err(Error::App("Failed to create outlet".to_string())),
}?;
Ok(())
}
}