terrazzo-terminal 0.2.8

A simple web-based terminal emulator built on Terrazzo.
use std::collections::HashMap;
use std::collections::hash_map::Entry::Occupied;
use std::collections::hash_map::Entry::Vacant;

use scopeguard::defer;
use tonic::Request;
use tracing::Instrument as _;
use tracing::debug;
use tracing::info;
use tracing::info_span;
use tracing::warn;

use crate::backend::Server;
use crate::backend::protos::terrazzo::shared::Empty;
use crate::backend::protos::terrazzo::terminal::OrderedTerminal;
use crate::backend::protos::terrazzo::terminal::SetOrderRequest;
use crate::backend::protos::terrazzo::terminal::terminal_service_client::TerminalServiceClient;
use crate::processes::get_processes;

pub async fn set_order(server: &Server, terminals: Vec<OrderedTerminal>) {
    async {
        info!("Start");
        defer!(info!("Done"));
        debug!("Terminals = {terminals:?}");

        let mut next: HashMap<String, Vec<OrderedTerminal>> = HashMap::new();
        let processes = get_processes();
        for mut terminal in terminals {
            let address = terminal.address.get_or_insert_default();
            let client_address = address.via.get_or_insert_default();
            let terminal_id = address.terminal_id.as_str().into();
            match client_address.via.as_slice() {
                [] => {
                    let Some(mut entry) = processes.get_mut(&terminal_id) else {
                        warn!("Terminal '{terminal_id}' not found");
                        continue;
                    };
                    entry.0.order = terminal.order;
                }
                [rest @ .., leaf] => {
                    let leaf = leaf.to_owned();
                    client_address.via = rest.to_vec();
                    match next.entry(leaf) {
                        Occupied(mut entry) => {
                            entry.get_mut().push(terminal);
                        }
                        Vacant(entry) => {
                            entry.insert(vec![terminal]);
                        }
                    }
                }
            }
        }

        for (client, terminals) in next {
            let Some(channel) = server.connections().get_client(&client.as_str().into()) else {
                warn!("Client '{client}' not found");
                continue;
            };
            let mut grpc = TerminalServiceClient::new(channel);
            match grpc
                .set_order(Request::new(SetOrderRequest { terminals }))
                .await
            {
                Ok(response) => {
                    let Empty {} = response.into_inner();
                }
                Err(error) => {
                    warn!("Set order on '{client}' failed with {error}");
                }
            }
        }
    }
    .instrument(info_span!("Set order"))
    .await
}