From a32f6392b7dcd24db76fbbe96636a1927b823f82 Mon Sep 17 00:00:00 2001 From: shadow cat Date: Sun, 15 Mar 2026 19:34:55 -0400 Subject: [PATCH] USER CACHE --- src/bin/client/main.rs | 2 +- src/bin/client/net.rs | 39 ++++++++++++++++++++++----------- src/bin/client/session.rs | 22 ++++++++++++++++--- src/bin/client/ui/connect.rs | 4 ++-- src/bin/client/ui/friends.rs | 16 ++++++++------ src/bin/client/ui/misc.rs | 8 +++++-- src/bin/client/ui/server.rs | 2 +- src/bin/client/ui/user.rs | 42 ++++++++++++++++-------------------- 8 files changed, 84 insertions(+), 51 deletions(-) diff --git a/src/bin/client/main.rs b/src/bin/client/main.rs index d5af39f..319d660 100644 --- a/src/bin/client/main.rs +++ b/src/bin/client/main.rs @@ -29,7 +29,7 @@ pub struct Client { } pub type Rsc = DefaultRsc; -pub type ClientSender = EventSender; +pub type ClientSender = EventSender; pub enum ClientEvent { CacheUpdate, diff --git a/src/bin/client/net.rs b/src/bin/client/net.rs index 2790557..dddb698 100644 --- a/src/bin/client/net.rs +++ b/src/bin/client/net.rs @@ -1,5 +1,6 @@ -use crate::ClientSender; +use crate::{Client, ClientSender, Rsc}; use dashmap::DashMap; +use iris::prelude::DefaultRsc; use openworm::net::{ ClientMsg, ClientMsgInst, RecvHandler, RequestId, RequestMsg, SERVER_NAME, ServerMsg, ServerMsgInst, SkipServerVerification, recv_uni, send_uni, @@ -30,16 +31,27 @@ pub struct NetHandle { } type NetResult = Result; +type SyncReqFn = Box; pub enum NetCtrlMsg { Send(ClientMsg), Request(ClientMsg, oneshot::Sender), - RequestSync(ClientMsg, Box), + RequestSync(ClientMsg, SyncReqFn), Exit, } type Resp = Result; +// TODO: move into iris? +pub trait MainDataCallback: + FnOnce(Data, &mut DefaultRsc) + Sync + Send + 'static +{ +} +impl) + Sync + Send + 'static, Data, State> + MainDataCallback for F +{ +} + impl NetHandle { fn send_(&self, msg: NetCtrlMsg) { let _ = self.send.send(msg); @@ -60,21 +72,22 @@ impl NetHandle { } } - pub fn request_sync(&self, msg: R) -> SyncRecv { - let (send, recv) = oneshot::channel(); - let sender = self.event_sender.clone(); + pub fn request_sync( + &self, + msg: R, + callback: impl MainDataCallback, Client>, + ) { self.send_(NetCtrlMsg::RequestSync( msg.into(), - Box::new(move |msg| { - let _ = send.send(if let Some(res) = R::result(msg) { + Box::new(move |msg, rsc| { + let res = if let Some(res) = R::result(msg) { Ok(res) } else { Err(()) - }); - sender.run(); + }; + callback(res, rsc); }), )); - SyncRecv:: { recv } } pub fn exit(self) { @@ -174,6 +187,7 @@ impl NetHandle { msg, requests_sync: DashMap::default(), requests: DashMap::default(), + event_sender: event_sender.clone(), }); tokio::spawn(recv_uni(conn_, recv.clone())); tokio::spawn(async move { @@ -239,7 +253,8 @@ where struct ServerRecv { requests: DashMap>, - requests_sync: DashMap>, + requests_sync: DashMap, + event_sender: ClientSender, msg: F, } @@ -249,7 +264,7 @@ impl RecvHandler for ServerRecv { if let Some((_, send)) = self.requests.remove(&id) { let _ = send.send(resp.msg); } else if let Some((_, f)) = self.requests_sync.remove(&id) { - f(resp.msg) + self.event_sender.run(|rsc| f(resp.msg, rsc)); } } else { self.msg.run(resp.msg).await; diff --git a/src/bin/client/session.rs b/src/bin/client/session.rs index 902054c..b68d07c 100644 --- a/src/bin/client/session.rs +++ b/src/bin/client/session.rs @@ -1,8 +1,16 @@ +use std::sync::{Arc, Mutex, MutexGuard}; + use openworm::net::UserId; use crate::{net::NetHandle, ui::UserCache}; -pub struct Session { +// TODO: this really should not be async... +// I mean it could be used async but all widgets +// are sync so I don't really think it makes sense to be... +#[derive(Clone)] +pub struct Session(Arc>); + +pub struct SessionInner { pub con: NetHandle, pub user_id: UserId, pub cache: UserCache, @@ -10,10 +18,18 @@ pub struct Session { impl Session { pub fn new(con: NetHandle, user_id: UserId) -> Self { - Self { + Self(Arc::new(Mutex::new(SessionInner { cache: UserCache::new(con.clone()), con, user_id, - } + }))) + } + + pub fn con(&self) -> NetHandle { + self.get().con.clone() + } + + pub fn get(&self) -> MutexGuard<'_, SessionInner> { + self.0.try_lock().unwrap() } } diff --git a/src/bin/client/ui/connect.rs b/src/bin/client/ui/connect.rs index 6ed679b..926d7be 100644 --- a/src/bin/client/ui/connect.rs +++ b/src/bin/client/ui/connect.rs @@ -91,8 +91,8 @@ pub fn start(rsc: &mut Rsc, data: &ClientData) -> WeakWidget { return fail("invalid password"); } }; - let session = Session::new(con, user_id); ctx.update(move |ctx, rsc| { + let session = Session::new(con, user_id); main_view(rsc, session).set_ptr(ctx.main_ui, rsc); }); }); @@ -190,8 +190,8 @@ pub fn create_account(rsc: &mut Rsc) -> WeakWidget { return fail("invalid account token"); } }; - let session = Session::new(con, user_id); ctx.update(move |ctx, rsc| { + let session = Session::new(con, user_id); main_view(rsc, session).set_ptr(ctx.main_ui, rsc); ctx.data.create_account( ServerInfo { cert_hex }, diff --git a/src/bin/client/ui/friends.rs b/src/bin/client/ui/friends.rs index 286c081..07931c3 100644 --- a/src/bin/client/ui/friends.rs +++ b/src/bin/client/ui/friends.rs @@ -15,8 +15,8 @@ pub fn view(rsc: &mut Rsc, session: &Session) -> StrongWidget { fn add_friend_area(rsc: &mut Rsc, session: &Session) -> WeakWidget { let username_field = field("", "username").add(rsc); let add = Button::submit("add friend", rsc); - let con = session.con.clone(); - rsc.events.register(add, Submit, move |ctx, rsc| { + let con = session.con(); + rsc.events.register(add, Submit, move |_, rsc| { let con = con.clone(); let username = username_field.edit(rsc).take(); add.disable(rsc); @@ -54,7 +54,7 @@ fn add_friend_area(rsc: &mut Rsc, session: &Session) -> WeakWidget { fn gen_token(rsc: &mut Rsc, session: &Session) -> WeakWidget { let generate = Button::normal("generate token", rsc); - let con = session.con.clone(); + let con = session.con(); let token = wtext("") .size(30) .editable(EditMode::SingleLine) @@ -84,9 +84,11 @@ fn gen_token(rsc: &mut Rsc, session: &Session) -> WeakWidget { fn friends_list(rsc: &mut Rsc, session: &Session) -> WeakWidget { let ptr = loading_area("loading friends").add(rsc); - let con = session.con.clone(); + let con = session.con(); + let session = session.clone(); rsc.events.register(ptr, Draw, move |_, rsc| { let con = con.clone(); + let session = session.clone(); // TODO: maybe have rsc.request method that takes in &con? // need to also handle error tho rsc.spawn_task(async move |mut ctx| { @@ -97,13 +99,13 @@ fn friends_list(rsc: &mut Rsc, session: &Session) -> WeakWidget { let mut all = Span::empty(Dir::DOWN); if !resp.incoming.is_empty() { all.push(section_label("incoming").add_strong(rsc)); - all.push(user_list(&resp.incoming, rsc).add_strong(rsc)) + all.push(user_list(&resp.incoming, &session, rsc).add_strong(rsc)) } all.push(section_label("friends").add_strong(rsc)); - all.push(user_list(&resp.current, rsc).add_strong(rsc)); + all.push(user_list(&resp.current, &session, rsc).add_strong(rsc)); if !resp.outgoing.is_empty() { all.push(section_label("outgoing").add_strong(rsc)); - all.push(user_list(&resp.outgoing, rsc).add_strong(rsc)) + all.push(user_list(&resp.outgoing, &session, rsc).add_strong(rsc)) } all.set_ptr(ptr, rsc); }); diff --git a/src/bin/client/ui/misc.rs b/src/bin/client/ui/misc.rs index 3d4ef60..a5f110e 100644 --- a/src/bin/client/ui/misc.rs +++ b/src/bin/client/ui/misc.rs @@ -152,10 +152,14 @@ pub fn section_label(text: impl Into) -> TextBuilder { wtext(text).size(30) } -pub fn user_list<'a>(ids: impl IntoIterator, rsc: &mut Rsc) -> Span { +pub fn user_list<'a>( + ids: impl IntoIterator, + session: &Session, + rsc: &mut Rsc, +) -> Span { let mut span = Span::empty(Dir::DOWN); for id in ids { - let thing = (wtext(id.to_string()).size(20),) + let thing = (session.username(*id, rsc),) .span(Dir::RIGHT) .gap(30) .pad(15); diff --git a/src/bin/client/ui/server.rs b/src/bin/client/ui/server.rs index c429efc..718da04 100644 --- a/src/bin/client/ui/server.rs +++ b/src/bin/client/ui/server.rs @@ -29,7 +29,7 @@ fn info(rsc: &mut Rsc) -> StrongWidget { fn users(rsc: &mut Rsc, session: &Session) -> StrongWidget { let ptr = loading_area("loading users").add(rsc); - let con = session.con.clone(); + let con = session.con(); rsc.events.register(ptr, Draw, move |_, rsc| { let con = con.clone(); rsc.spawn_task(async move |mut ctx| { diff --git a/src/bin/client/ui/user.rs b/src/bin/client/ui/user.rs index 436ef36..5312419 100644 --- a/src/bin/client/ui/user.rs +++ b/src/bin/client/ui/user.rs @@ -19,35 +19,31 @@ impl UserCache { widgets: Default::default(), } } +} - pub fn username(&mut self, id: UserId, rsc: &mut Rsc) -> WeakWidget { - let text = if let Some(user) = self.users.get(&id) { +impl Session { + pub fn username(&self, id: UserId, rsc: &mut Rsc) -> WeakWidget { + let session = self.clone(); + let s = &mut self.get().cache; + let text = if let Some(user) = s.users.get(&id) { &user.username } else { - if !self.requests.contains_key(&id) { - let recv = self.con.request_sync(RequestUserInfo { id }); - self.requests.insert(id, recv); + if !s.requests.contains_key(&id) { + s.con + .request_sync(RequestUserInfo { id }, move |resp, rsc| { + if let Ok(info) = resp { + let s = &mut session.get().cache; + for &widget in s.widgets.get(&id).into_iter().flatten() { + *rsc[widget].content = info.username.clone(); + } + s.users.insert(id, info); + } + }); } "loading..." }; - let wid = wtext(text).add(rsc); - self.widgets.entry(id).or_default().push(wid); + let wid = wtext(text).size(20).add(rsc); + s.widgets.entry(id).or_default().push(wid); wid } - - pub fn update(&mut self, rsc: &mut Rsc) { - self.requests.retain(|id, req| { - if let Some(resp) = req.try_recv() { - if let Ok(info) = resp { - for &widget in self.widgets.get(id).into_iter().flatten() { - *rsc[widget].content = info.username.clone(); - } - self.users.insert(*id, info); - } - false - } else { - true - } - }); - } }