wslink-rs 0.0.2

A wslink-compatible WebSocket RPC server runtime for Rust using MessagePack transport.
Documentation
use std::sync::Arc;

use anyhow::Result;
use log::{error, info};

// export for ServerArgument
pub use clap::Parser;

use crate::protocol::ServerProtocol;
use crate::wslink::WsLinkAsync;

#[derive(Parser, Debug, Clone)]
pub struct ServerArgument {
    #[clap(long, default_value = "localhost")]
    pub host: String,

    #[clap(short, long, default_value = "3001")]
    pub port: usize,

    #[clap(short, long, default_value = "wslink-secret")]
    pub auth_key: String,
}

pub async fn start<Protocol: ServerProtocol + Default + 'static>() {
    let args = ServerArgument::parse();
    let protocol = Protocol::default();

    let (ws_handler, mut ws_local) = WsLinkAsync::new(protocol, &args);

    // ws_local logic run one thread
    tokio::task::spawn_blocking(move || ws_local.run());

    match tokio::spawn(inner_start(ws_handler.clone(), args.clone())).await {
        Ok(Ok(())) => {}
        Ok(Err(err)) => error!("wslink server failed: {:#}", err),
        Err(err) => error!("wslink server task join failed: {}", err),
    }

    ws_handler.shutdown().await;
}

async fn inner_start(ws_handler: Arc<WsLinkAsync>, args: ServerArgument) -> Result<()> {
    let listener = tokio::net::TcpListener::bind(format!("{}:{}", args.host, args.port)).await?;

    info!("Listening on: {}:{}", args.host, args.port);
    info!("wslink started");

    loop {
        match listener.accept().await {
            Ok((stream, _)) => {
                let future = ws_handler.clone().handle_connect(stream);
                tokio::spawn(future);
            }
            Err(err) => {
                error!("failed to accept websocket connection: {}", err);
                return Err(err.into());
            }
        }
    }
}