Base protocol

This commit is contained in:
2025-09-13 10:35:54 +02:00
parent b143295eda
commit 0919ec30d3
5 changed files with 116 additions and 22 deletions
+26 -5
View File
@@ -4,7 +4,10 @@ use std::{
sync::{Arc, Mutex},
};
use tungstenite::{Message, WebSocket, accept};
use anyhow::Error;
use tungstenite::{Message, Utf8Bytes, WebSocket, accept};
use crate::types::{FromClient, ToClient, WsMessage};
#[derive(Clone)]
pub struct Client(Arc<Mutex<WebSocket<TcpStream>>>);
@@ -34,11 +37,29 @@ impl Hash for Client {
}
impl Client {
pub fn read(&self) -> crate::Result<Message> {
self.0.lock().unwrap().read().map_err(|e| e.into())
pub fn read(&self) -> crate::Result<Option<WsMessage<FromClient>>> {
match self.0.lock().unwrap().read()? {
Message::Text(t) => {
let v = t.to_string();
match serde_json::from_str(&v) {
Ok(f) => Ok(Some(WsMessage::FromClient(f))),
Err(_) => Ok(Some(WsMessage::String(v))),
}
}
Message::Binary(b) => Ok(Some(WsMessage::Binary(b))),
Message::Close(_) => Ok(None),
m => Err(Error::msg(format!("Invalid websocket format: {m}"))),
}
}
pub fn send(&self, m: Message) -> crate::Result<()> {
self.0.lock().unwrap().send(m).map_err(|e| e.into())
pub fn send(&self, m: ToClient) -> crate::Result<()> {
self.0
.lock()
.unwrap()
.send(Message::Text(Utf8Bytes::from(serde_json::to_string(&m)?)))
.map_err(|e| e.into())
}
}
+27 -13
View File
@@ -11,12 +11,17 @@ pub mod loader;
pub mod logger;
pub mod macros;
pub mod plugin;
pub mod types;
pub mod vfs;
pub use anyhow::Result;
pub use tungstenite;
use crate::{client::Client, plugin::DynPlugin};
use crate::{
client::Client,
plugin::DynPlugin,
types::{ToClient, data},
};
pub use once_cell;
#[derive(serde::Serialize, serde::Deserialize)]
@@ -116,20 +121,29 @@ impl Server {
// The main req/res loop
loop {
let req = client.read()?;
match client.read()? {
Some(req) => {
println!("Request: {:?}", req);
for plugin in self.plugins.lock().unwrap().iter_mut() {
plugin.on_request(&req, self);
}
for plugin in self.plugins.lock().unwrap().iter_mut() {
plugin.on_request(&req, self);
}
for c in self.clients.lock().unwrap().iter() {
if c == &client {
self.wrap_err(
&client,
c.send(ToClient::Message(data::Message {
from: format!("Server"),
contents: format!("Hello"),
})),
)?;
}
}
}
if req.is_close() {
self.clients.lock().unwrap().remove(&client);
break;
}
for c in self.clients.lock().unwrap().iter() {
if c != &client {
self.wrap_err(&client, c.send(req.clone()))?;
None => {
self.clients.lock().unwrap().remove(&client);
break;
}
}
}
+5 -4
View File
@@ -1,15 +1,16 @@
use std::sync::Arc;
use tungstenite::Message;
use crate::Server;
use crate::{
Server,
types::{FromClient, WsMessage},
};
pub type DynPlugin = Box<dyn Plugin + Send + Sync>;
pub trait Plugin {
fn init(&mut self, server: &Arc<Server>);
#[allow(unused_variables)]
fn on_request(&mut self, msg: &Message, server: &Arc<Server>) -> bool {
fn on_request(&mut self, msg: &WsMessage<FromClient>, server: &Arc<Server>) -> bool {
false
}
}
+40
View File
@@ -0,0 +1,40 @@
use serde::{Deserialize, Serialize};
use tungstenite::Bytes;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "params", rename_all = "snake_case")]
pub enum FromClient {
SendMessage(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "params", rename_all = "snake_case")]
pub enum FromServer {}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "params", rename_all = "snake_case")]
pub enum ToClient {
Message(data::Message),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "params", rename_all = "snake_case")]
pub enum ToServer {}
/// WebSocket for client messages
#[derive(Debug, Clone)]
pub enum WsMessage<T: Serialize + for<'de> Deserialize<'de>> {
FromClient(T),
Binary(Bytes),
String(String),
}
pub mod data {
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
pub from: String,
pub contents: String,
}
}