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},
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct Client(Arc<Mutex<WebSocket<TcpStream>>>);
|
pub struct Client(Arc<Mutex<WebSocket<TcpStream>>>);
|
||||||
@@ -34,11 +37,29 @@ impl Hash for Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn read(&self) -> crate::Result<Message> {
|
pub fn read(&self) -> crate::Result<Option<WsMessage<FromClient>>> {
|
||||||
self.0.lock().unwrap().read().map_err(|e| e.into())
|
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<()> {
|
pub fn send(&self, m: ToClient) -> crate::Result<()> {
|
||||||
self.0.lock().unwrap().send(m).map_err(|e| e.into())
|
self.0
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.send(Message::Text(Utf8Bytes::from(serde_json::to_string(&m)?)))
|
||||||
|
.map_err(|e| e.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-13
@@ -11,12 +11,17 @@ pub mod loader;
|
|||||||
pub mod logger;
|
pub mod logger;
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
pub mod plugin;
|
pub mod plugin;
|
||||||
|
pub mod types;
|
||||||
pub mod vfs;
|
pub mod vfs;
|
||||||
|
|
||||||
pub use anyhow::Result;
|
pub use anyhow::Result;
|
||||||
pub use tungstenite;
|
pub use tungstenite;
|
||||||
|
|
||||||
use crate::{client::Client, plugin::DynPlugin};
|
use crate::{
|
||||||
|
client::Client,
|
||||||
|
plugin::DynPlugin,
|
||||||
|
types::{ToClient, data},
|
||||||
|
};
|
||||||
pub use once_cell;
|
pub use once_cell;
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
@@ -116,20 +121,29 @@ impl Server {
|
|||||||
|
|
||||||
// The main req/res loop
|
// The main req/res loop
|
||||||
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() {
|
for c in self.clients.lock().unwrap().iter() {
|
||||||
plugin.on_request(&req, self);
|
if c == &client {
|
||||||
}
|
self.wrap_err(
|
||||||
|
&client,
|
||||||
|
c.send(ToClient::Message(data::Message {
|
||||||
|
from: format!("Server"),
|
||||||
|
contents: format!("Hello"),
|
||||||
|
})),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if req.is_close() {
|
None => {
|
||||||
self.clients.lock().unwrap().remove(&client);
|
self.clients.lock().unwrap().remove(&client);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
for c in self.clients.lock().unwrap().iter() {
|
|
||||||
if c != &client {
|
|
||||||
self.wrap_err(&client, c.send(req.clone()))?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-4
@@ -1,15 +1,16 @@
|
|||||||
use std::sync::Arc;
|
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 type DynPlugin = Box<dyn Plugin + Send + Sync>;
|
||||||
|
|
||||||
pub trait Plugin {
|
pub trait Plugin {
|
||||||
fn init(&mut self, server: &Arc<Server>);
|
fn init(&mut self, server: &Arc<Server>);
|
||||||
#[allow(unused_variables)]
|
#[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
|
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