terrazzo-terminal 0.2.8

A simple web-based terminal emulator built on Terrazzo.
use tracing::warn;
use trz_gateway_common::id::ClientName;

use crate::api::client_address::ClientAddress;
use crate::api::shared::terminal_schema::RegisterTerminalMode;
use crate::api::shared::terminal_schema::RegisterTerminalRequest;
use crate::api::shared::terminal_schema::TabTitle;
use crate::api::shared::terminal_schema::TerminalAddress;
use crate::api::shared::terminal_schema::TerminalDef;
use crate::backend::protos::terrazzo::shared::ClientAddress as ClientAddressProto;
use crate::backend::protos::terrazzo::terminal::MaybeString;
use crate::backend::protos::terrazzo::terminal::RegisterTerminalRequest as RegisterTerminalRequestProto;
use crate::backend::protos::terrazzo::terminal::TerminalAddress as TerminalAddressProto;
use crate::backend::protos::terrazzo::terminal::TerminalDef as TerminalDefProto;
use crate::backend::protos::terrazzo::terminal::register_terminal_request::RegisterTerminalMode as RegisterTerminalModeProto;
use crate::tiles::id::TileId;

impl From<TerminalDefProto> for TerminalDef {
    fn from(proto: TerminalDefProto) -> Self {
        Self {
            address: proto.address.unwrap_or_default().into(),
            title: TabTitle {
                shell_title: proto.shell_title,
                override_title: proto.override_title.map(|s| s.s),
            },
            order: proto.order,
            tile: TileId::try_from(proto.tile).unwrap_or_else(|error| {
                warn!("{error}");
                TileId::first_tile_id()
            }),
        }
    }
}

impl From<TerminalDef> for TerminalDefProto {
    fn from(terminal_def: TerminalDef) -> Self {
        Self {
            address: Some(terminal_def.address.into()),
            shell_title: terminal_def.title.shell_title,
            override_title: terminal_def.title.override_title.map(|s| MaybeString { s }),
            order: terminal_def.order,
            tile: terminal_def.tile.into(),
        }
    }
}

impl TerminalDefProto {
    pub fn client_address(&self) -> &[String] {
        fn aux(proto: &TerminalDefProto) -> Option<&[String]> {
            let address = proto.address.as_ref()?;
            Some(address.client_address())
        }
        aux(self).unwrap_or(&[])
    }
}

impl From<TerminalAddressProto> for TerminalAddress {
    fn from(proto: TerminalAddressProto) -> Self {
        Self {
            id: proto.terminal_id.into(),
            via: ClientAddress::from(proto.via.unwrap_or_default()),
        }
    }
}

impl From<TerminalAddress> for TerminalAddressProto {
    fn from(address: TerminalAddress) -> Self {
        Self {
            terminal_id: address.id.to_string(),
            via: (!address.via.is_empty()).then(|| ClientAddressProto {
                via: address.via.iter().map(ClientName::to_string).collect(),
            }),
        }
    }
}

impl TerminalAddressProto {
    pub fn client_address(&self) -> &[String] {
        fn aux(proto: &TerminalAddressProto) -> Option<&[String]> {
            let via = proto.via.as_ref()?;
            Some(via.via.as_slice())
        }
        aux(self).unwrap_or(&[])
    }
}

impl From<RegisterTerminalRequest> for RegisterTerminalRequestProto {
    fn from(request: RegisterTerminalRequest) -> Self {
        let mut proto = Self {
            mode: Default::default(),
            def: Some(request.def.into()),
        };
        proto.set_mode(request.mode.into());
        return proto;
    }
}

impl TryFrom<RegisterTerminalModeProto> for RegisterTerminalMode {
    type Error = tonic::Status;

    fn try_from(proto: RegisterTerminalModeProto) -> Result<Self, Self::Error> {
        Ok(match proto {
            RegisterTerminalModeProto::Unspecified => {
                return Err(tonic::Status::invalid_argument("mode"));
            }
            RegisterTerminalModeProto::Create => Self::Create,
            RegisterTerminalModeProto::Reopen => Self::Reopen,
        })
    }
}

impl From<RegisterTerminalMode> for RegisterTerminalModeProto {
    fn from(mode: RegisterTerminalMode) -> Self {
        match mode {
            RegisterTerminalMode::Create => Self::Create,
            RegisterTerminalMode::Reopen => Self::Reopen,
        }
    }
}