From 7667e172403712fd3d4af87e6478716a3386efb5 Mon Sep 17 00:00:00 2001 From: Hatter Jiang Date: Sun, 5 Nov 2023 19:38:19 +0800 Subject: [PATCH] feat: v0.1.8 --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 30 +++++++++++++ src/main.rs | 2 +- src/msg.rs | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 158 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d253d1..f46259d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -571,7 +571,7 @@ dependencies = [ [[package]] name = "room-rs" -version = "0.1.7" +version = "0.1.8" dependencies = [ "chrono", "futures-channel", diff --git a/Cargo.toml b/Cargo.toml index ce6f949..83e3c4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "room-rs" -version = "0.1.7" +version = "0.1.8" authors = ["Hatter Jiang@Pixelbook "] edition = "2018" diff --git a/README.md b/README.md index 21cada0..4404f0e 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,11 @@ Enter room: } ``` +or +``` +.enter room-id: client-id: +``` + Exit room: ```json { @@ -32,6 +37,11 @@ Exit room: } ``` +or +``` +.exit +``` + Destroy room: ```json { @@ -39,6 +49,11 @@ Destroy room: } ``` +or +``` +.destroy +``` + List room peers: ```json { @@ -46,6 +61,11 @@ List room peers: } ``` +or +``` +.list-peers +``` + Broadcast room message: ```json { @@ -54,6 +74,11 @@ Broadcast room message: } ``` +or +``` +.broadcast data: +``` + Send room peer message: ```json { @@ -63,6 +88,11 @@ Send room peer message: } ``` +or +``` +.peer peer-id: data: +``` + Test with command line: > WebSocket cat: https://www.npmjs.com/package/wscat diff --git a/src/main.rs b/src/main.rs index 34a24b4..ce83a9b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -163,7 +163,7 @@ fn handle_text_message(handle_context: &mut HandleContext, tx: &Tx, addr: Socket } } - let room_message = match serde_json::from_str::(&msg) { + let room_message = match RoomMessage::parse(&msg) { Ok(room_message) => room_message, Err(e) => { warning!("Parse message: from: {:?} - {:?}, failed: {}", handle_context.room_id, handle_context.client_id, e); diff --git a/src/msg.rs b/src/msg.rs index 3eddd00..ced0027 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -1,7 +1,9 @@ +use rust_util::XResult; use serde::{Deserialize, Serialize}; + use crate::types::{Tx, TxSendMessage}; -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] pub enum RoomMessageType { #[serde(rename = "Enter")] CreateOrEnter, @@ -39,6 +41,21 @@ pub struct RoomMessage { pub data: Option, } +impl RoomMessage { + pub fn parse(msg: &str) -> XResult { + if let Ok(room_message) = serde_json::from_str::(msg) { + return Ok(room_message); + } + if msg.starts_with('.') { + let msg_parts = parse_message_parts(msg); + if !msg_parts.is_empty() { + return parse_message_parts_to_room_message(&msg_parts); + } + } + simple_error!("Not valid room message.") + } +} + #[derive(Clone, Debug, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct RoomMessageDown { @@ -138,3 +155,110 @@ impl RoomMessageDown { } } } + +fn parse_message_parts_to_room_message(msg_parts: &[String]) -> XResult { + let room_message_type = get_room_message_type(&msg_parts[0])?; + let mut message_id = None; + let mut room_id = None; + let mut client_id = None; + let mut peer_id = None; + let mut data = None; + + msg_parts.iter().skip(1).for_each(|part| { + let before_colon = part.chars().take_while(|c| *c != ':').collect::(); + let after_colon = part.chars().skip_while(|c| *c != ':').skip(1).collect::(); + match before_colon.as_str() { + "message_id" | "message-id" => { message_id = Some(after_colon); } + "room_id" | "room-id" => { room_id = Some(after_colon); } + "client_id" | "client-id" => { client_id = Some(after_colon); } + "peer_id" | "peer-id" => { peer_id = Some(after_colon); } + "data" => { data = Some(after_colon); } + _ => debugging!("Unknown key: {}", before_colon), + } + }); + + Ok(RoomMessage { + r#type: room_message_type, + message_id, + room_id, + client_id, + peer_id, + data, + }) +} + +pub fn get_room_message_type(first_part: &str) -> XResult { + let room_message_type = match first_part { + "create-or-enter" | "enter" => RoomMessageType::CreateOrEnter, + "exit" => RoomMessageType::Exit, + "destroy" => RoomMessageType::Destroy, + "listpeers" | "list-peers" => RoomMessageType::ListPeers, + "broadcast" => RoomMessageType::Broadcast, + "peer" => RoomMessageType::Peer, + _ => return simple_error!("Unknown message type: {}", first_part), + }; + Ok(room_message_type) +} + +fn parse_message_parts(msg: &str) -> Vec { + let mut msg_parts = vec![]; + let mut in_quote = false; + let mut is_back_slash = false; + let mut last_part = vec![]; + for c in msg.chars().skip(1) { + if is_back_slash { + last_part.push(c); + is_back_slash = false; + continue; + } + match c { + ' ' if in_quote => { + last_part.push(c); + } + ' ' => { + if !last_part.is_empty() { + msg_parts.push(last_part.iter().collect::()); + last_part.clear(); + } + } + '\\' => { + is_back_slash = true; + } + '\'' => { + in_quote = !in_quote; + } + _ => { + last_part.push(c); + } + } + } + if !last_part.is_empty() { + msg_parts.push(last_part.iter().collect::()); + } + msg_parts +} + +#[test] +fn test_room_message_parse() { + let room_message = RoomMessage::parse(".enter").unwrap(); + assert_eq!(RoomMessageType::CreateOrEnter, room_message.r#type); + assert_eq!(None, room_message.message_id); + assert_eq!(None, room_message.room_id); + assert_eq!(None, room_message.client_id); + assert_eq!(None, room_message.peer_id); + assert_eq!(None, room_message.data); + let room_message = RoomMessage::parse(".enter message-id:123 room-id:'ROOM ID'").unwrap(); + assert_eq!(RoomMessageType::CreateOrEnter, room_message.r#type); + assert_eq!(Some("123".to_string()), room_message.message_id); + assert_eq!(Some("ROOM ID".to_string()), room_message.room_id); + assert_eq!(None, room_message.client_id); + assert_eq!(None, room_message.peer_id); + assert_eq!(None, room_message.data); + let room_message = RoomMessage::parse(".peer client-id:'CLIENT ID' peer_id:PEER 'data:DATA ---'").unwrap(); + assert_eq!(RoomMessageType::Peer, room_message.r#type); + assert_eq!(None, room_message.message_id); + assert_eq!(None, room_message.room_id); + assert_eq!(Some("CLIENT ID".to_string()), room_message.client_id); + assert_eq!(Some("PEER".to_string()), room_message.peer_id); + assert_eq!(Some("DATA ---".to_string()), room_message.data); +}