Base protocol
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
setInterval(() => {
|
||||
const ws = new WebSocket('ws://localhost:7080');
|
||||
|
||||
function sendMessage(message) {
|
||||
ws.send(JSON.stringify({ type: 'send_message', params: message }));
|
||||
}
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('WebSocket connection established');
|
||||
sendMessage('Hello, Server!');
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const message = JSON.parse(event.data);
|
||||
console.log('Received:', message);
|
||||
ws.close();
|
||||
};
|
||||
}, 100)
|
||||
+26
-5
@@ -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))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self, m: Message) -> crate::Result<()> {
|
||||
self.0.lock().unwrap().send(m).map_err(|e| e.into())
|
||||
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: ToClient) -> crate::Result<()> {
|
||||
self.0
|
||||
.lock()
|
||||
.unwrap()
|
||||
.send(Message::Text(Utf8Bytes::from(serde_json::to_string(&m)?)))
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
}
|
||||
|
||||
+23
-9
@@ -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);
|
||||
}
|
||||
|
||||
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(ToClient::Message(data::Message {
|
||||
from: format!("Server"),
|
||||
contents: format!("Hello"),
|
||||
})),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user