use downcast_rs::{Downcast, impl_downcast};
use log::{error, warn};
use serde::Serialize;
use tokio::sync::mpsc;
use tokio::sync::mpsc::error::TrySendError;
use crate::server::ServerArgument;
use crate::wslink::{Local2Async, WsLinkRpc, WsRsp};
pub trait ServerProtocol: Downcast + Send {
fn on_connect(&mut self) {}
fn on_close(&mut self) {}
fn initialize(&mut self, _args: &ServerArgument, _config: &mut ServerConfig) {}
}
impl_downcast!(ServerProtocol);
pub struct ServerConfig {
pub(crate) secret: String,
pub(crate) rpcs: Vec<WsLinkRpc>,
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
secret: "wslink-secret".to_string(),
rpcs: Vec::new(),
}
}
}
impl ServerConfig {
pub fn register_rpc(&mut self, rpc: WsLinkRpc) -> &mut Self {
self.rpcs.push(rpc);
self
}
pub fn register_rpcs<I>(&mut self, rpcs: I) -> &mut Self
where
I: IntoIterator<Item = WsLinkRpc>,
{
self.rpcs.extend(rpcs);
self
}
pub fn update_secret(&mut self, secret: impl Into<String>) -> &mut Self {
self.secret = secret.into();
self
}
pub(crate) fn into_parts(self) -> (String, Vec<WsLinkRpc>) {
(self.secret, self.rpcs)
}
}
#[derive(Clone)]
pub struct Publisher {
tx: mpsc::Sender<Local2Async>,
}
impl Publisher {
pub(crate) fn new(tx: mpsc::Sender<Local2Async>) -> Self {
Self { tx }
}
pub fn publish<T: Serialize + Send + Sync + 'static>(&self, topic: &str, payload: T, client_id: Option<usize>) {
let f = Box::new(move |rpc_id: &str| -> anyhow::Result<Vec<u8>> {
let res = WsRsp {
wslink: "1.0".into(),
id: rpc_id.into(),
result: payload,
};
let data = crate::rmp::to_vec_named(&res)?;
Ok(data)
});
match self.tx.try_send(Local2Async {
topic: Some(topic.to_string()),
rpc_id: String::new(),
client_id,
f,
}) {
Ok(()) => {}
Err(TrySendError::Full(_)) => {
warn!("publish '{}' dropped because async queue is full", topic);
}
Err(TrySendError::Closed(_)) => {
error!("publish ignored because async context is closed");
}
}
}
}