stablessh 0.1.5

Keeps SSH on even when laptop is closed
use crate::{pool, proto, utils};
use anyhow::Result;
use std::sync::Arc;
use tokio::sync::Mutex;

pub struct CtlServiceImpl {
    pool: Arc<Mutex<pool::ConnPool>>,
}

impl CtlServiceImpl {
    pub fn new(pool: pool::ConnPool) -> Self {
        Self {
            pool: Arc::new(Mutex::new(pool)),
        }
    }
}

#[tonic::async_trait]
impl proto::ctl_service_server::CtlService for CtlServiceImpl {
    async fn conn_list(
        &self,
        _req: tonic::Request<proto::ConnListRequest>,
    ) -> Result<tonic::Response<proto::ConnListResponse>, tonic::Status> {
        let mut pool = self.pool.lock().await;
        let pubkeys = pool.list().await;

        let mut res = proto::ConnListResponse::default();
        for pubkey in pubkeys {
            let mut res_info = proto::ConnInfo::default();
            let info = pool.get(pubkey.clone()).await;
            res_info.id = utils::pubkey_to_id(&pubkey);
            res_info.name = info.unwrap().name;
            res_info.last_active = pool.last_active(pubkey.clone()).await;
            res_info.pkt_buf = pool.qlen(pubkey.clone()).await;

            res.conns.push(res_info);
        }

        Ok(tonic::Response::new(res))
    }
    async fn conn_kill(
        &self,
        _req: tonic::Request<proto::ConnKillRequest>,
    ) -> Result<tonic::Response<proto::ConnKillResponse>, tonic::Status> {
        let pool = self.pool.lock().await;
        let pubkeys = pool.list().await;
        let pubkey = pubkeys
            .iter()
            .find(|&k| utils::pubkey_to_id(k) == _req.get_ref().id);
        if pubkey.is_none() {
            return Err(tonic::Status::not_found("Connection not found"));
        }
        match pool.kill(pubkey.unwrap().clone()).await {
            Ok(true) => Ok(tonic::Response::new(proto::ConnKillResponse {})),
            Ok(false) => Err(tonic::Status::internal("Connection is in use")),
            Err(e) => Err(tonic::Status::internal(e.to_string())),
        }
    }
}

pub struct CtlClient {
    client: proto::ctl_service_client::CtlServiceClient<tonic::transport::Channel>,
}

impl CtlClient {
    pub async fn new(uri: &str) -> Result<Self> {
        let client = proto::ctl_service_client::CtlServiceClient::connect(uri.to_string()).await?;
        Ok(Self { client })
    }

    pub async fn conn_list(&mut self) -> Result<proto::ConnListResponse, tonic::Status> {
        self.client
            .conn_list(proto::ConnListRequest {})
            .await
            .map(|r| r.into_inner())
    }

    pub async fn conn_kill(
        &mut self,
        conn_id: &str,
    ) -> Result<proto::ConnKillResponse, tonic::Status> {
        self.client
            .conn_kill(proto::ConnKillRequest {
                id: conn_id.to_string(),
            })
            .await
            .map(|r| r.into_inner())
    }
}