diff --git a/client.js b/client.js index e1b8742..f423cb9 100644 --- a/client.js +++ b/client.js @@ -9,6 +9,8 @@ const ws = new WebSocket('ws://localhost:7080'); ws.onopen = () => { console.log('WebSocket connection established'); + console.log('Initializing handshake'); + ws.send(JSON.stringify({ version: '0.0.1', auth_token: '' })) }; ws.onmessage = (event) => { diff --git a/src/lib.rs b/src/lib.rs index 12aea54..1f56eed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,8 @@ pub use once_cell; #[derive(serde::Serialize, serde::Deserialize)] pub struct ServerConfig { + server_name: String, + server_id: String, port: u16, channels: Vec, } @@ -34,6 +36,8 @@ impl Default for ServerConfig { fn default() -> Self { Self { port: 7080, + server_name: format!("Server Name"), + server_id: format!("offline-server"), channels: Vec::new(), } } @@ -108,6 +112,37 @@ impl Server { // Initialize client let client = Client::new(stream)?; + // Initialize handshake + self.wrap_err( + &client, + client.send(types::handshake::ServerDetails { + name: self.config.server_name.clone(), + id: self.config.server_id.clone(), + version: format!("0.0.1"), + }), + )?; + + match self.wrap_err(&client, client.read_t::())? { + Some(types::WsMessage::Message(_)) => { + // Do auth stuff + self.wrap_err( + &client, + client.send(types::ServerMessage::Authenticated { + user_id: format!(""), + }), + )?; + } + Some(_) => { + self.wrap_err( + &client, + client.send(types::ResponseError::InvalidHandshake(format!( + "Invalid handshake" + ))), + )?; + } + None => {} + } + // Insert to the set of all connected clients self.clients.lock().unwrap().insert(client.clone()); diff --git a/src/requests/message.rs b/src/requests/message.rs index efbf998..e69616e 100644 --- a/src/requests/message.rs +++ b/src/requests/message.rs @@ -15,7 +15,7 @@ pub fn send( if contents.is_empty() { server.wrap_err( &client, - client.send(types::data::ResponseError::InvalidRequest(format!( + client.send(types::ResponseError::InvalidRequest(format!( "Invalid message: empty message" ))), )?; diff --git a/src/types.rs b/src/types.rs index 86f3f65..1b0d26f 100644 --- a/src/types.rs +++ b/src/types.rs @@ -17,9 +17,7 @@ pub enum ClientMessage { }, /// Delete a message (if allowed) - DeleteMessage { - message_id: usize, - }, + DeleteMessage { message_id: usize }, } /// Messages sent *from the server* to the client @@ -27,9 +25,7 @@ pub enum ClientMessage { #[serde(tag = "type", content = "params", rename_all = "snake_case")] pub enum ServerMessage { /// Successful authentication - Authenticated { - user_id: String, - }, + Authenticated { user_id: String }, TempMessage { message: String, @@ -60,6 +56,16 @@ pub enum ServerMessage { }, } +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "error", content = "message", rename_all = "snake_case")] +pub enum ResponseError { + InvalidRequest(String), + InvalidHandshake(String), + Unauthorized(String), + NotFound(String), + InternalError(String), +} + /// WebSocket wrapper #[derive(Debug, Clone)] pub enum WsMessage Deserialize<'de>> { @@ -94,13 +100,21 @@ pub mod data { Text, Voice, } +} + +pub mod handshake { + use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] - #[serde(tag = "error", content = "message", rename_all = "snake_case")] - pub enum ResponseError { - InvalidRequest(String), - Unauthorized(String), - NotFound(String), - InternalError(String), + pub struct ServerDetails { + pub version: String, + pub name: String, + pub id: String, + } + + #[derive(Debug, Clone, Serialize, Deserialize)] + pub struct ClientDetails { + pub version: String, + pub auth_token: String, } } diff --git a/src/utils/client.rs b/src/utils/client.rs index 4f1331f..9137eab 100644 --- a/src/utils/client.rs +++ b/src/utils/client.rs @@ -6,7 +6,7 @@ use std::{ }; use anyhow::anyhow; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use crate::types::{ClientMessage, WsMessage}; @@ -196,7 +196,9 @@ impl Client { /// - Ok(Some(WsMessage)) on an application message (text/binary) /// - Ok(None) if the connection should be closed (close received / read EOF) /// - Err on protocol or IO errors. - pub fn read(&self) -> crate::Result>> { + pub fn read_t Deserialize<'de>>( + &self, + ) -> crate::Result>> { let mut stream = self.0.try_clone()?; let mut message_payload = Vec::new(); @@ -311,6 +313,16 @@ impl Client { Ok(Some(message)) } + + /// Read a full WebSocket message, handling fragmentation and control frames. + /// + /// Returns: + /// - Ok(Some(WsMessage)) on an application message (text/binary) + /// - Ok(None) if the connection should be closed (close received / read EOF) + /// - Err on protocol or IO errors. + pub fn read(&self) -> crate::Result>> { + self.read_t() + } } impl Clone for Client {