diff --git a/examples/client.rs b/examples/client.rs index 36db0c9..4239b5c 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -1,32 +1,37 @@ use serde::{Deserialize, Serialize}; -use session_rs::session::Session; +use session_rs::{Method, session::Session, ws::Frame}; #[derive(Debug, Serialize, Deserialize)] struct Data {} -type Communication = Session; +impl Method for Data { + const NAME: &'static str = "data"; + type Request = (); + type Response = (); +} #[tokio::main(flavor = "current_thread")] async fn main() -> session_rs::Result<()> { - let session = Communication::connect("127.0.0.1:8080", "/").await?; + let session = Session::connect("127.0.0.1:8080", "/").await?; - // Spawn read loop - // tokio::spawn({ - // let session = session.clone(); - // async move { - // loop { - // match session.read().await { - // Ok(Frame::Text(text)) => { - // println!("Server says: {}", text); - // } - // Ok(_) => {} - // Err(_) => break, - // } - // } - // } - // }); + tokio::spawn({ + let session = session.clone(); + async move { + loop { + match session.ws.read().await { + Ok(Frame::Text(text)) => { + println!("Server says: {}", text); + } + Ok(_) => {} + Err(_) => break, + } + } + } + }); - session.request(&Data {}).await?; + session.request::(()).await?; + + tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; session.close().await?; Ok(()) diff --git a/examples/server.rs b/examples/server.rs index ce36cc8..d515a16 100644 --- a/examples/server.rs +++ b/examples/server.rs @@ -31,7 +31,7 @@ async fn main() -> session_rs::Result<()> { println!("Received text: {}", text); // Echo back - if let Err(e) = session.send(&serde_json::json!({"echo": text}).to_string()).await { + if let Err(e) = session.send(&text).await { eprintln!("Send error: {:?}", e); break; } diff --git a/src/lib.rs b/src/lib.rs index 627be42..4761d38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,17 @@ +use serde::{Deserialize, Serialize}; + pub mod server; pub mod session; pub mod ws; pub type Result = std::result::Result; +pub trait Method { + const NAME: &'static str; + type Request: Serialize + for<'de> Deserialize<'de>; + type Response: Serialize + for<'de> Deserialize<'de>; +} + #[derive(Debug)] pub enum Error { WebSocket(ws::Error), diff --git a/src/session.rs b/src/session.rs index ba0ebac..0235c95 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,82 +1,45 @@ -use std::{marker::PhantomData, sync::Arc}; +use std::sync::Arc; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; -use crate::ws::WebSocket; +use crate::{Method, ws::WebSocket}; #[derive(Debug, Serialize, Deserialize)] -pub enum SessionMessageKind { - Request, - Response, - Notification, +pub enum Message { + Request { + id: u32, + method: String, + data: M::Request, + }, + Response { + id: u32, + error: bool, + result: M::Response, + }, + Notification { + method: String, + data: M::Request, + }, } -#[derive(Debug, Serialize, Deserialize)] -pub struct SessionMessage { - id: u32, - kind: SessionMessageKind, - data: T, -} - -pub struct Session< - Req: Serialize + for<'a> Deserialize<'a>, - Res: Serialize + for<'a> Deserialize<'a>, - PeerReq: Serialize + for<'a> Deserialize<'a>, - PeerRes: Serialize + for<'a> Deserialize<'a>, - Notification: Serialize + for<'a> Deserialize<'a>, -> { - _pd: ( - PhantomData, - PhantomData, - PhantomData, - PhantomData, - PhantomData, - ), +pub struct Session { pub ws: WebSocket, id: Arc>, } -impl< - Req: Serialize + for<'a> Deserialize<'a>, - Res: Serialize + for<'a> Deserialize<'a>, - PeerReq: Serialize + for<'a> Deserialize<'a>, - PeerRes: Serialize + for<'a> Deserialize<'a>, - Notification: Serialize + for<'a> Deserialize<'a>, -> Session -{ +impl Session { pub fn clone(&self) -> Self { Self { - _pd: ( - PhantomData, - PhantomData, - PhantomData, - PhantomData, - PhantomData, - ), ws: self.ws.clone(), id: self.id.clone(), } } } -impl< - Req: Serialize + for<'a> Deserialize<'a>, - Res: Serialize + for<'a> Deserialize<'a>, - PeerReq: Serialize + for<'a> Deserialize<'a>, - PeerRes: Serialize + for<'a> Deserialize<'a>, - Notification: Serialize + for<'a> Deserialize<'a>, -> Session -{ +impl Session { pub fn from_ws(ws: WebSocket) -> Self { Self { - _pd: ( - PhantomData, - PhantomData, - PhantomData, - PhantomData, - PhantomData, - ), ws, id: Arc::new(Mutex::new(0)), } @@ -87,55 +50,49 @@ impl< } } -impl< - Req: Serialize + for<'a> Deserialize<'a>, - Res: Serialize + for<'a> Deserialize<'a>, - PeerReq: Serialize + for<'a> Deserialize<'a>, - PeerRes: Serialize + for<'a> Deserialize<'a>, - Notification: Serialize + for<'a> Deserialize<'a>, -> Session -{ - pub async fn send_id( - &self, - id: u32, - kind: SessionMessageKind, - data: &T, - ) -> crate::Result<()> { +impl Session { + pub async fn send(&self, data: &Message) -> crate::Result<()> { self.ws - .send_text_payload(&serde_json::to_vec(&SessionMessage { id, kind, data })?) + .send_text_payload(&serde_json::to_vec(&data)?) .await?; - Ok(()) } - pub async fn send( - &self, - kind: SessionMessageKind, - data: &T, - ) -> crate::Result<()> { - self.send_id( - { - let mut i = self.id.lock().await; - *i += 1; - *i - }, - kind, - data, - ) + pub async fn use_id(&self) -> u32 { + let mut id = self.id.lock().await; + *id += 1; + *id + } + + pub async fn request(&self, req: M::Request) -> crate::Result<()> { + self.send::(&Message::Request { + id: self.use_id().await, + method: M::NAME.to_string(), + data: req, + }) .await } - pub async fn request(&self, data: &Req) -> crate::Result<()> { - self.send(SessionMessageKind::Request, data).await + pub async fn respond( + &self, + to: u32, + error: bool, + res: M::Response, + ) -> crate::Result<()> { + self.send::(&Message::Response { + id: to, + error, + result: res, + }) + .await } - pub async fn respond(&self, to_req: &SessionMessage, data: &Res) -> crate::Result<()> { - self.send_id(to_req.id, SessionMessageKind::Response, data) - .await - } - - pub async fn notify(&self, data: &Res) -> crate::Result<()> { - self.send(SessionMessageKind::Notification, data).await + pub async fn notify(&self, data: M::Request) -> crate::Result<()> { + self.send::(&Message::Notification { + method: M::NAME.to_string(), + data, + }) + .await } pub async fn close(&self) -> crate::Result<()> {