use std::sync::Arc;
use futures::channel::mpsc;
use nameth::NamedEnumValues as _;
use nameth::nameth;
use scopeguard::defer;
use terrazzo::http::StatusCode;
use tracing::debug;
use tracing::warn;
use tracing_futures as _;
use trz_gateway_common::http_error::IsHttpError;
use trz_gateway_common::id::ClientName;
use super::registration::Registration;
use crate::api::shared::terminal_schema::RegisterTerminalRequest;
use crate::api::shared::terminal_schema::TerminalAddress;
use crate::backend::Server;
use crate::backend::client_service::terminal_service;
use crate::processes;
use crate::processes::io::LocalReader;
pub async fn register(
my_client_name: Option<ClientName>,
server: &Arc<Server>,
request: RegisterTerminalRequest,
) -> Result<(), RegisterStreamError> {
defer!(debug!("End"));
debug!("Start");
async {
let terminal_address = request.def.address.clone();
let stream =
self::terminal_service::register::register(my_client_name, server, request.into())
.await?;
let stream = LocalReader(stream);
push_lease(terminal_address, stream)?;
Ok(())
}
.await
.inspect_err(|err| warn!("{err}"))
}
fn push_lease(
terminal_address: TerminalAddress,
stream: LocalReader,
) -> Result<(), PushLeaseError> {
#[cfg(debug_assertions)]
let stream = tracing_futures::Instrument::instrument(stream, tracing::debug_span!("Lease"));
Ok(Registration::current()
.ok_or(PushLeaseError::NoClientRegisteredError)?
.try_send((terminal_address, stream))
.map_err(|err| err.into_send_error())?)
}
#[nameth]
#[derive(thiserror::Error, Debug)]
pub enum RegisterStreamError {
#[error("[{n}] {0}", n = self.name())]
GetOrCreateProcessError(#[from] processes::stream::GetOrCreateProcessError),
#[error("[{n}] {0}", n = self.name())]
PushLeaseError(#[from] PushLeaseError),
#[error("[{n}] {0}", n = self.name())]
Distributed(#[from] self::terminal_service::register::RegisterStreamError),
}
impl IsHttpError for RegisterStreamError {
fn status_code(&self) -> StatusCode {
match self {
Self::GetOrCreateProcessError { .. } => StatusCode::INTERNAL_SERVER_ERROR,
Self::PushLeaseError(error) => error.status_code(),
Self::Distributed(error) => error.status_code(),
}
}
}
#[nameth]
#[derive(thiserror::Error, Debug)]
pub enum PushLeaseError {
#[error("[{n}] Expected a client to be registered", n = self.name())]
NoClientRegisteredError,
#[error("[{n}] Failed to send lease: {0}", n = self.name())]
SendError(#[from] mpsc::SendError),
}
impl IsHttpError for PushLeaseError {
fn status_code(&self) -> StatusCode {
match self {
Self::NoClientRegisteredError => StatusCode::BAD_REQUEST,
Self::SendError { .. } => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}