From a3b141685012c53cd31d997abd982c29eab28abf Mon Sep 17 00:00:00 2001 From: shadow cat Date: Mon, 6 Jul 2026 22:48:40 -0400 Subject: [PATCH] new msg macro --- iris | 2 +- src/bin/client/net.rs | 69 ++++++----- src/bin/client/session.rs | 6 +- src/bin/client/ui/user.rs | 1 + src/bin/server/handle.rs | 18 +-- src/bin/server/net.rs | 16 +-- src/lib.rs | 2 + src/net/data.rs | 100 ---------------- src/net/msg.rs | 235 +++++++++++++++++++++++++++++++------- src/net/request.rs | 8 +- 10 files changed, 260 insertions(+), 197 deletions(-) diff --git a/iris b/iris index a648c62..e817bc8 160000 --- a/iris +++ b/iris @@ -1 +1 @@ -Subproject commit a648c62aa22908d8182c6bc5e9d52be43418837c +Subproject commit e817bc83afde463d4e4e49812c31172f859df838 diff --git a/src/bin/client/net.rs b/src/bin/client/net.rs index 77faf18..4a1770d 100644 --- a/src/bin/client/net.rs +++ b/src/bin/client/net.rs @@ -1,9 +1,9 @@ -use crate::{Client, ClientEvent, ClientSender, Rsc, session::Session}; +use crate::{Client, ClientSender, Rsc, session::Session}; use dashmap::DashMap; use iris::prelude::DefaultRsc; use openworm::net::{ - ClientMsg, ClientMsgInst, RecvHandler, RequestId, RequestMsg, SERVER_NAME, ServerMsg, - ServerMsgInst, SkipServerVerification, recv_uni, send_uni, + ClientMsg, ClientMsgInst, RecvHandler, ReqErr, RequestId, RequestMsg, SERVER_NAME, ServerMsg, + ServerResp, SkipServerVerification, recv_uni, send_uni, }; use quinn::{ ClientConfig, Connection, Endpoint, IdleTimeout, TransportConfig, @@ -31,16 +31,16 @@ pub struct NetHandle { } type NetResult = Result; -type SyncReqFn = Box; +type SyncReqFn = Box; pub enum NetCtrlMsg { Send(ClientMsg), - Request(ClientMsg, oneshot::Sender), + Request(ClientMsg, oneshot::Sender), RequestSync(ClientMsg, SyncReqFn), Exit, } -type Resp = Result; +type Resp = Result<::Result, Error>; // TODO: move into iris? pub trait MainDataCallback: @@ -52,6 +52,12 @@ impl) + Sync + Send + 'static, Data, Stat { } +pub enum Error { + Req(ReqErr), + InvalidResp, + Connection, +} + impl NetHandle { fn send_(&self, msg: NetCtrlMsg) { let _ = self.send.send(msg); @@ -64,26 +70,32 @@ impl NetHandle { pub async fn request(&self, msg: R) -> Resp { let (send, recv) = oneshot::channel(); self.send_(NetCtrlMsg::Request(msg.into(), send)); - let Ok(recv) = recv.await else { return Err(()) }; - if let Some(res) = R::result(recv) { - Ok(res) - } else { - Err(()) + let Ok(recv) = recv.await else { + return Err(Error::Connection); + }; + match recv { + ServerResp::Ok(resp) => match R::result(resp) { + Some(val) => Ok(val), + None => Err(Error::InvalidResp), + }, + ServerResp::Err(err) => Err(Error::Req(err)), } } pub fn request_sync( &self, msg: R, - callback: impl MainDataCallback, Client>, + callback: impl MainDataCallback, Client>, ) { self.send_(NetCtrlMsg::RequestSync( msg.into(), Box::new(move |msg, rsc| { - let res = if let Some(res) = R::result(msg) { - Ok(res) - } else { - Err(()) + let res = match msg { + ServerResp::Ok(resp) => match R::result(resp) { + Some(val) => Ok(val), + None => Err(Error::InvalidResp), + }, + ServerResp::Err(err) => Err(Error::Req(err)), }; callback(res, rsc); }), @@ -104,7 +116,7 @@ impl SyncRecv { match self.recv.try_recv() { Ok(res) => Some(res), Err(oneshot::error::TryRecvError::Empty) => None, - Err(oneshot::error::TryRecvError::Closed) => Some(Err(())), + Err(oneshot::error::TryRecvError::Closed) => Some(Err(Error::Connection)), } } } @@ -252,22 +264,25 @@ where } struct ServerRecv { - requests: DashMap>, + requests: DashMap>, requests_sync: DashMap, event_sender: ClientSender, id: usize, } -impl RecvHandler for ServerRecv { - async fn msg(&self, resp: ServerMsgInst) { - if let Some(id) = resp.id { - if let Some((_, send)) = self.requests.remove(&id) { - let _ = send.send(resp.msg); - } else if let Some((_, f)) = self.requests_sync.remove(&id) { - self.event_sender.run(|rsc| f(resp.msg, rsc)); +impl RecvHandler for ServerRecv { + async fn msg(&self, resp: ServerMsg) { + match resp { + ServerMsg::Response { id, msg } => { + if let Some((_, send)) = self.requests.remove(&id) { + let _ = send.send(msg); + } else if let Some((_, f)) = self.requests_sync.remove(&id) { + self.event_sender.run(|rsc| f(msg, rsc)); + } + } + ServerMsg::Notif(notif) => { + Session::handle(&self.event_sender, self.id, notif); } - } else { - Session::handle(&self.event_sender, self.id, resp); } } } diff --git a/src/bin/client/session.rs b/src/bin/client/session.rs index 65679b1..26a9767 100644 --- a/src/bin/client/session.rs +++ b/src/bin/client/session.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, Mutex, MutexGuard}; use iris::prelude::*; -use openworm::net::{ServerMsgInst, UserId}; +use openworm::net::{ServerNotif, UserId}; use crate::{ClientSender, Rsc, net::NetHandle, ui::UserCache}; @@ -39,8 +39,8 @@ impl Session { span } - pub fn handle(sender: &ClientSender, id: usize, inst: ServerMsgInst) { - match inst.msg { + pub fn handle(sender: &ClientSender, id: usize, notif: ServerNotif) { + match notif { _ => { println!("Unknown server message recieved"); } diff --git a/src/bin/client/ui/user.rs b/src/bin/client/ui/user.rs index f5fafa4..a9aa73d 100644 --- a/src/bin/client/ui/user.rs +++ b/src/bin/client/ui/user.rs @@ -32,6 +32,7 @@ impl Session { s.con .request_sync(RequestUserInfo { id }, move |resp, rsc| { if let Ok(info) = resp { + let info = info.info; let s = &mut session.get().cache; for &widget in s.widgets.get(&id).into_iter().flatten() { *rsc[widget].content = info.username.clone(); diff --git a/src/bin/server/handle.rs b/src/bin/server/handle.rs index ca8a578..d10d884 100644 --- a/src/bin/server/handle.rs +++ b/src/bin/server/handle.rs @@ -41,7 +41,7 @@ impl ClientHandler { if let ClientState::Authed(uid) = &*self.state.read().await { Some(*uid) } else { - reply!(NotLoggedIn); + reply!(ReqErr::NotLoggedIn); } }; let check_user = async || { @@ -49,10 +49,10 @@ impl ClientHandler { if let Some(user) = self.db.users.get(uid) { Some((*uid, user)) } else { - reply!(InvalidUser); + reply!(ReqErr::InvalidUser); } } else { - reply!(NotLoggedIn); + reply!(ReqErr::NotLoggedIn); } }; let check_server_perms = async |perms| { @@ -63,7 +63,7 @@ impl ClientHandler { .get(&id) .is_some_and(|u| !u.server_perms.contains(perms)) { - reply!(NoPermission); + reply!(ReqErr::NoPermission); } else { Some(()) } @@ -172,7 +172,7 @@ impl ClientHandler { loop { let mut tx = db.write_tx(); let Some(mut user) = tx.get(&db.users, &user_id) else { - reply!(InvalidUser); + reply!(ReqErr::InvalidUser); }; let Some(other_id) = tx.get(&db.usernames, &info.username) else { reply!(AddFriendResp::UnknownUser); @@ -265,11 +265,13 @@ impl ClientHandler { ClientMsg::RequestUserInfo(info) => { check_user().await?; let Some(other_user) = db.users.get(&info.id) else { - reply!(InvalidUser); + reply!(ReqErr::InvalidUser); }; // TODO: check perms... (privacy settings) - reply!(UserInfo { - username: other_user.username + reply!(RequestUserInfoResp { + info: UserInfo { + username: other_user.username + } }); } } diff --git a/src/bin/server/net.rs b/src/bin/server/net.rs index c7f843b..330ece5 100644 --- a/src/bin/server/net.rs +++ b/src/bin/server/net.rs @@ -1,6 +1,6 @@ use openworm::net::{ - ClientMsgInst, RecvHandler, RequestId, SERVER_NAME, SendResult, ServerMsg, ServerMsgInst, - recv_uni, send_uni, + ClientMsgInst, RecvHandler, RequestId, ServerResp, SERVER_NAME, SendResult, ServerMsg, recv_uni, + send_uni, }; use quinn::{ Connection, Endpoint, ServerConfig, @@ -65,11 +65,7 @@ impl ClientSender { } pub async fn send(&self, msg: impl Into) -> SendResult { - let msg = ServerMsgInst { - id: None, - msg: msg.into(), - }; - send_uni(&self.conn, msg).await + send_uni(&self.conn, msg.into()).await } } @@ -79,9 +75,9 @@ pub struct ClientReplier { } impl ClientReplier { - pub async fn send(&self, msg: impl Into) { - let msg = ServerMsgInst { - id: Some(self.req_id), + pub async fn send(&self, msg: impl Into) { + let msg = ServerMsg::Response { + id: self.req_id, msg: msg.into(), }; let _ = send_uni(&self.conn, msg).await; diff --git a/src/lib.rs b/src/lib.rs index 2605742..f30c918 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,4 @@ +#![feature(macro_metavar_expr_concat)] + pub mod net; pub mod rsc; diff --git a/src/net/data.rs b/src/net/data.rs index 1320e9e..eed15d0 100644 --- a/src/net/data.rs +++ b/src/net/data.rs @@ -1,22 +1,3 @@ -use iris::core::util::HashSet; - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct CreateChannel { - pub name: String, -} - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub enum CreateChannelResp { - Ok, -} - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct RequestUserInfo { - pub id: UserId, -} - -pub type RequestUserInfoResp = UserInfo; - #[derive(Debug, bitcode::Encode, bitcode::Decode)] pub struct UserInfo { pub username: String, @@ -25,92 +6,18 @@ pub struct UserInfo { pub type UserId = u64; pub type AccountToken = String; -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct CreateAccount { - pub username: String, - pub password: String, - pub token: String, -} - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub enum CreateAccountResp { - Ok { id: UserId }, - UsernameExists, - InvalidToken, -} - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct Login { - pub username: String, - pub password: String, -} - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub enum LoginResp { - Ok { id: UserId }, - UnknownUsername, - InvalidPassword, -} - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct RequestUsers; -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct RequestUsersResp { - pub users: Vec, -} #[derive(Debug, bitcode::Encode, bitcode::Decode)] pub struct ServerUser { pub id: UserId, pub username: String, } -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct RequestFriends; -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct RequestFriendsResp { - pub current: HashSet, - pub incoming: HashSet, - pub outgoing: HashSet, -} - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct AddFriend { - pub username: String, -} -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub enum AddFriendResp { - Ok, - UnknownUser, - CannotAddSelf, - AlreadySent, - AlreadyFriends, -} - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct RemoveFriend { - pub id: UserId, -} - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct AnswerFriendRequest { - pub id: UserId, - pub action: FriendRequestAction, -} #[derive(Debug, bitcode::Encode, bitcode::Decode)] pub enum FriendRequestAction { Accept, Deny, } -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct GenerateToken { - pub perms: ServerPerms, -} -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct GenerateTokenResp { - pub token: AccountToken, -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, bitcode::Encode, bitcode::Decode)] pub struct ServerPerms(u32); impl ServerPerms { @@ -123,10 +30,3 @@ impl ServerPerms { (self.0 & other.0) == other.0 } } - -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct NotLoggedIn; -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct NoPermission; -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct InvalidUser; diff --git a/src/net/msg.rs b/src/net/msg.rs index 55175e6..bb976c0 100644 --- a/src/net/msg.rs +++ b/src/net/msg.rs @@ -1,57 +1,210 @@ +use crate::net::RequestId; + use super::{RequestMsg, data::*}; +use iris::core::util::HashSet; -msg_type!(ClientMsg: { - 0: CreateAccount => CreateAccountResp, - 1: Login => LoginResp, - 2: RequestUsers => RequestUsersResp, - 3: RequestFriends => RequestFriendsResp, - 4: AddFriend => AddFriendResp, - 5: RemoveFriend, - 6: AnswerFriendRequest, - 7: GenerateToken => GenerateTokenResp, - 8: RequestUserInfo => RequestUserInfoResp, - 9: CreateChannel => CreateChannelResp, -}); -msg_type!(ServerMsg: { - 0: NotLoggedIn, - 1: NoPermission, - 2: InvalidUser, - 3: CreateAccountResp, - 4: LoginResp, - 5: RequestUsersResp, - 6: RequestFriendsResp, - 7: AddFriendResp, - 8: GenerateTokenResp, - 9: RequestUserInfoResp, - 10: CreateChannelResp, -}); +def_msgs! { + ClientMsg => ClientMsgResp { + 0: CreateAccount { + username: String, + password: String, + token: String, + } => enum { + Ok { id: UserId }, + UsernameExists, + InvalidToken, + }, + + 1: Login { + username: String, + password: String, + } => enum { + Ok { id: UserId }, + UnknownUsername, + InvalidPassword, + }, + + 2: RequestUsers; => struct { + users: Vec, + }, + + 3: RequestFriends; => struct { + current: HashSet, + incoming: HashSet, + outgoing: HashSet, + }, + + 4: AddFriend { + username: String, + } => enum { + Ok, + UnknownUser, + CannotAddSelf, + AlreadySent, + AlreadyFriends, + }, + + 5: RemoveFriend { + id: UserId, + } => struct;, + + 6: AnswerFriendRequest { + id: UserId, + action: FriendRequestAction, + } => struct;, + + 7: GenerateToken { + perms: ServerPerms, + } => struct { + token: AccountToken, + }, + + 8: RequestUserInfo { + id: UserId, + } => struct { + info: UserInfo, + }, + + 9: CreateChannel { + name: String, + } => enum { + Ok + }, + } + ServerNotif { + 0: struct Dummy;, + } + RequestMsg, ServerResp +} + +#[derive(Debug, bitcode::Encode, bitcode::Decode)] +pub enum ServerResp { + Ok(ClientMsgResp), + Err(ReqErr), +} + +#[derive(Debug, bitcode::Encode, bitcode::Decode)] +pub enum ReqErr { + UnknownRequest, + NotLoggedIn, + NoPermission, + InvalidUser, +} + +#[repr(u32)] +#[derive(Debug, bitcode::Encode, bitcode::Decode)] +pub enum ServerMsg { + Response { id: RequestId, msg: ServerResp } = 0, + Notif(ServerNotif), +} + +impl From for ServerResp { + fn from(value: ReqErr) -> Self { + Self::Err(value) + } +} + +macro_rules! def_msgs { + ( + $c_msg:ident => $s_resp:ident { + $($c_num:literal: $c_name:ident $c_def:tt => $c_resp_kind:tt $c_resp_def:tt,)* + } + $s_notif:ident { + $($s_num:literal: $s_kind:tt $s_name:ident $s_def:tt,)* + } + $req_t:ident, $resp:ident + ) => { + msg_type! { $c_msg; + $($c_num: struct $c_name $c_def,)* + } + + msg_type! { $s_resp; + $($c_num: $c_resp_kind ${concat($c_name, Resp)} $c_resp_def,)* + } + + msg_type! { $s_notif; + $($s_num: $s_kind $s_name $s_def,)* + } -macro_rules! msg_type { - ($msg:ident: {$($num:literal: $name:ident $(=> $resp:ident)?,)*}) => { - #[repr(u32)] - #[derive(Debug, bitcode::Encode, bitcode::Decode)] - pub enum $msg {$( - $name($name) = $num, - )*} $( - impl From<$name> for $msg { - fn from(value: $name) -> Self { - Self::$name(value) + impl From<${concat($c_name, Resp)}> for $resp { + fn from(value: ${concat($c_name, Resp)}) -> Self { + Self::Ok(value.into()) } } - $( - impl RequestMsg for $name { - type Result = $resp; - fn result(msg: ServerMsg) -> Option { - if let ServerMsg::$resp(res) = msg { + impl $req_t for $c_name { + type Result = ${concat($c_name, Resp)}; + fn result(msg: $s_resp) -> Option { + if let $s_resp::${concat($c_name, Resp)}(res) = msg { Some(res) } else { None } } } - )? )* }; } +use def_msgs; + +macro_rules! msg_type { + ( + @finish + $msg:ident {$($num:literal: $name:ident,)*} + ) => { + #[repr(u32)] + #[derive(Debug, bitcode::Encode, bitcode::Decode)] + pub enum $msg { + $( + $name($name) = $num, + )* + } + $( + impl From<$name> for $msg { + fn from(value: $name) -> Self { + Self::$name(value) + } + } + )* + }; + + ( + @derive $item:item + ) => { + #[derive(Debug, bitcode::Encode, bitcode::Decode)] + $item + }; + + ( + @def struct $name:ident {$($field:ident: $ty:ty,)*} + ) => { + msg_type!(@derive pub struct $name {$(pub $field: $ty,)*}); + }; + + ( + @def struct $name:ident ($($ty:ty $(,)?)*) + ) => { + msg_type!(@derive pub struct $name ($(pub $ty, )*);); + }; + + ( + @def struct $name:ident; + ) => { + msg_type!(@derive pub struct $name;); + }; + + ( + @def enum $name:ident $rest:tt + ) => { + msg_type!(@derive pub enum $name $rest); + }; + + ( + $msg:ident; + $($num:literal: $kind:tt $name:tt $def:tt,)* + ) => { + $(msg_type!(@def $kind $name $def);)* + msg_type!(@finish $msg {$($num: $name,)*}); + }; +} use msg_type; diff --git a/src/net/request.rs b/src/net/request.rs index ad4f742..f01ea66 100644 --- a/src/net/request.rs +++ b/src/net/request.rs @@ -24,13 +24,7 @@ pub struct ClientMsgInst { pub msg: ClientMsg, } -#[derive(Debug, bitcode::Encode, bitcode::Decode)] -pub struct ServerMsgInst { - pub id: Option, - pub msg: ServerMsg, -} - pub trait RequestMsg: Into { type Result: Send + Sync + 'static; - fn result(msg: ServerMsg) -> Option; + fn result(msg: ClientMsgResp) -> Option; }