Handshake
This commit is contained in:
@@ -9,6 +9,8 @@ const ws = new WebSocket('ws://localhost:7080');
|
|||||||
|
|
||||||
ws.onopen = () => {
|
ws.onopen = () => {
|
||||||
console.log('WebSocket connection established');
|
console.log('WebSocket connection established');
|
||||||
|
console.log('Initializing handshake');
|
||||||
|
ws.send(JSON.stringify({ version: '0.0.1', auth_token: '<placeholder>' }))
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onmessage = (event) => {
|
ws.onmessage = (event) => {
|
||||||
|
|||||||
+35
@@ -17,6 +17,8 @@ pub use once_cell;
|
|||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
pub struct ServerConfig {
|
pub struct ServerConfig {
|
||||||
|
server_name: String,
|
||||||
|
server_id: String,
|
||||||
port: u16,
|
port: u16,
|
||||||
channels: Vec<types::data::Channel>,
|
channels: Vec<types::data::Channel>,
|
||||||
}
|
}
|
||||||
@@ -34,6 +36,8 @@ impl Default for ServerConfig {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
port: 7080,
|
port: 7080,
|
||||||
|
server_name: format!("Server Name"),
|
||||||
|
server_id: format!("offline-server"),
|
||||||
channels: Vec::new(),
|
channels: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,6 +112,37 @@ impl Server {
|
|||||||
// Initialize client
|
// Initialize client
|
||||||
let client = Client::new(stream)?;
|
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::<types::handshake::ClientDetails>())? {
|
||||||
|
Some(types::WsMessage::Message(_)) => {
|
||||||
|
// Do auth stuff
|
||||||
|
self.wrap_err(
|
||||||
|
&client,
|
||||||
|
client.send(types::ServerMessage::Authenticated {
|
||||||
|
user_id: format!("<placeholder>"),
|
||||||
|
}),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Some(_) => {
|
||||||
|
self.wrap_err(
|
||||||
|
&client,
|
||||||
|
client.send(types::ResponseError::InvalidHandshake(format!(
|
||||||
|
"Invalid handshake"
|
||||||
|
))),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
// Insert to the set of all connected clients
|
// Insert to the set of all connected clients
|
||||||
self.clients.lock().unwrap().insert(client.clone());
|
self.clients.lock().unwrap().insert(client.clone());
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ pub fn send(
|
|||||||
if contents.is_empty() {
|
if contents.is_empty() {
|
||||||
server.wrap_err(
|
server.wrap_err(
|
||||||
&client,
|
&client,
|
||||||
client.send(types::data::ResponseError::InvalidRequest(format!(
|
client.send(types::ResponseError::InvalidRequest(format!(
|
||||||
"Invalid message: empty message"
|
"Invalid message: empty message"
|
||||||
))),
|
))),
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
+26
-12
@@ -17,9 +17,7 @@ pub enum ClientMessage {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/// Delete a message (if allowed)
|
/// Delete a message (if allowed)
|
||||||
DeleteMessage {
|
DeleteMessage { message_id: usize },
|
||||||
message_id: usize,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Messages sent *from the server* to the client
|
/// Messages sent *from the server* to the client
|
||||||
@@ -27,9 +25,7 @@ pub enum ClientMessage {
|
|||||||
#[serde(tag = "type", content = "params", rename_all = "snake_case")]
|
#[serde(tag = "type", content = "params", rename_all = "snake_case")]
|
||||||
pub enum ServerMessage {
|
pub enum ServerMessage {
|
||||||
/// Successful authentication
|
/// Successful authentication
|
||||||
Authenticated {
|
Authenticated { user_id: String },
|
||||||
user_id: String,
|
|
||||||
},
|
|
||||||
|
|
||||||
TempMessage {
|
TempMessage {
|
||||||
message: String,
|
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
|
/// WebSocket wrapper
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum WsMessage<T: Serialize + for<'de> Deserialize<'de>> {
|
pub enum WsMessage<T: Serialize + for<'de> Deserialize<'de>> {
|
||||||
@@ -94,13 +100,21 @@ pub mod data {
|
|||||||
Text,
|
Text,
|
||||||
Voice,
|
Voice,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod handshake {
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(tag = "error", content = "message", rename_all = "snake_case")]
|
pub struct ServerDetails {
|
||||||
pub enum ResponseError {
|
pub version: String,
|
||||||
InvalidRequest(String),
|
pub name: String,
|
||||||
Unauthorized(String),
|
pub id: String,
|
||||||
NotFound(String),
|
}
|
||||||
InternalError(String),
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ClientDetails {
|
||||||
|
pub version: String,
|
||||||
|
pub auth_token: String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-2
@@ -6,7 +6,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use serde::Serialize;
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::types::{ClientMessage, WsMessage};
|
use crate::types::{ClientMessage, WsMessage};
|
||||||
|
|
||||||
@@ -196,7 +196,9 @@ impl Client {
|
|||||||
/// - Ok(Some(WsMessage)) on an application message (text/binary)
|
/// - Ok(Some(WsMessage)) on an application message (text/binary)
|
||||||
/// - Ok(None) if the connection should be closed (close received / read EOF)
|
/// - Ok(None) if the connection should be closed (close received / read EOF)
|
||||||
/// - Err on protocol or IO errors.
|
/// - Err on protocol or IO errors.
|
||||||
pub fn read(&self) -> crate::Result<Option<WsMessage<ClientMessage>>> {
|
pub fn read_t<T: Serialize + for<'de> Deserialize<'de>>(
|
||||||
|
&self,
|
||||||
|
) -> crate::Result<Option<WsMessage<T>>> {
|
||||||
let mut stream = self.0.try_clone()?;
|
let mut stream = self.0.try_clone()?;
|
||||||
|
|
||||||
let mut message_payload = Vec::new();
|
let mut message_payload = Vec::new();
|
||||||
@@ -311,6 +313,16 @@ impl Client {
|
|||||||
|
|
||||||
Ok(Some(message))
|
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<Option<WsMessage<ClientMessage>>> {
|
||||||
|
self.read_t()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Client {
|
impl Clone for Client {
|
||||||
|
|||||||
Reference in New Issue
Block a user