terrazzo-terminal 0.2.8

A simple web-based terminal emulator built on Terrazzo.
#![cfg(feature = "server")]

use std::sync::Arc;

use nameth::nameth;
use terrazzo::declare_trait_aliias;
use tonic::Status;

use super::api::Conversion;
use super::api::Conversions;
use super::api::ConversionsRequest;
use crate::backend::client_service::remote_fn_service;
use crate::converter::api::Language;

mod asn1;
mod base64;
mod dns;
mod json;
mod jwt;
mod pkcs7;
mod timestamps;
mod tls_info;
mod unescaped;
mod x509;

#[nameth]
pub async fn get_conversions(input: Arc<str>) -> Result<Conversions, Status> {
    let mut conversions = vec![];
    let mut add_conversion = |language, content| {
        conversions.push(Conversion::new(language, content));
    };
    add_conversions(&input, &mut add_conversion).await;
    return Ok(Conversions {
        conversions: conversions.into(),
    });
}

async fn add_conversions(input: &str, add: &mut impl AddConversionFn) {
    if input.trim().is_empty() {
        return;
    }
    if self::x509::add_x509_pem(input, add) {
        return;
    }
    if self::jwt::add_jwt(input, add) {
        return;
    }
    if self::base64::add_base64(input, add) {
        return;
    }
    if !self::json::add_json(input, add) {
        self::json::add_yaml(input, add);
    }
    self::unescaped::add_unescape(input, add);
    if self::tls_info::add_tls_info(input, add).await {
        return;
    }
    self::dns::add_dns(input, add).await;
    self::timestamps::add_timestamps(input, add);
}

declare_trait_aliias!(AddConversionFn, FnMut(Language, String));

remote_fn_service::unary::declare_remote_fn!(
    GET_CONVERSIONS_FN,
    GET_CONVERSIONS,
    ConversionsRequest,
    Conversions,
    |_server, arg| get_conversions(arg.input)
);

#[cfg(test)]
mod tests {

    pub trait GetConversionForTest {
        async fn get_conversion(&self, language: &str) -> String;
        async fn get_languages(&self) -> Vec<String>;
    }

    impl GetConversionForTest for &str {
        async fn get_conversion(&self, language: &str) -> String {
            let conversions = super::get_conversions(self.to_string().into())
                .await
                .unwrap();
            let matches = conversions
                .conversions
                .iter()
                .filter(|conversion| conversion.language.name.as_ref() == language)
                .collect::<Vec<_>>();
            match *matches.as_slice() {
                [] => "Not found".to_string(),
                [conversion] => conversion.content.clone(),
                _ => "Duplicates".to_string(),
            }
        }

        async fn get_languages(&self) -> Vec<String> {
            let conversions = super::get_conversions(self.to_string().into())
                .await
                .unwrap();
            let mut languages = conversions
                .conversions
                .iter()
                .map(|conversion| conversion.language.name.to_string())
                .collect::<Vec<_>>();
            languages.sort();
            return languages;
        }
    }

    #[tokio::test]
    async fn empty_input_has_no_conversions() {
        assert!(
            super::get_conversions("".into())
                .await
                .unwrap()
                .conversions
                .is_empty()
        );
    }
}