From 97fdbbf968cdf9b0bbc6b4946da8cb4ed72e8fb7 Mon Sep 17 00:00:00 2001 From: Shadow Cat Date: Wed, 18 Feb 2026 16:47:35 -0500 Subject: [PATCH] stuff --- src/bin/client/account.rs | 22 ---------------- src/bin/client/main.rs | 15 +++-------- src/bin/client/net.rs | 37 +++----------------------- src/bin/client/session.rs | 8 ++++++ src/bin/client/state.rs | 50 ------------------------------------ src/bin/client/ui/connect.rs | 19 ++++++++------ src/bin/client/ui/main.rs | 25 +++++++++--------- src/bin/client/ui/misc.rs | 4 +++ src/bin/client/ui/server.rs | 42 +++++++++++++++++++++++++++--- src/bin/server/db/ver.rs | 1 + src/bin/server/main.rs | 26 +++++++++++++++++-- src/net/conversion.rs | 4 +++ src/net/data.rs | 17 ++++++++++++ src/net/mod.rs | 2 +- src/net/msg.rs | 39 ++++++++++++++++++++-------- src/net/request.rs | 44 +++++++++++++++++++++++++++++-- 16 files changed, 199 insertions(+), 156 deletions(-) delete mode 100644 src/bin/client/account.rs create mode 100644 src/bin/client/session.rs delete mode 100644 src/bin/client/state.rs diff --git a/src/bin/client/account.rs b/src/bin/client/account.rs deleted file mode 100644 index 6eceb33..0000000 --- a/src/bin/client/account.rs +++ /dev/null @@ -1,22 +0,0 @@ -use ed25519_dalek::SigningKey; -use rand::{ - SeedableRng, - rngs::{StdRng, SysRng}, -}; - -pub struct Account { - device_key: SigningKey, - account_key: SigningKey, -} - -impl Account { - pub fn new() -> Account { - let mut csprng = StdRng::try_from_rng(&mut SysRng).unwrap(); - let device_key = SigningKey::generate(&mut csprng); - let account_key = SigningKey::generate(&mut csprng); - Account { - device_key, - account_key, - } - } -} diff --git a/src/bin/client/main.rs b/src/bin/client/main.rs index 04c0f72..fbb42e3 100644 --- a/src/bin/client/main.rs +++ b/src/bin/client/main.rs @@ -1,7 +1,7 @@ #![feature(async_fn_traits)] #![windows_subsystem = "windows"] -use crate::{data::ClientData, state::ClientState}; +use crate::data::ClientData; use iris::prelude::*; use openworm::net::{ServerMsg, install_crypto_provider}; use winit::{ @@ -9,11 +9,10 @@ use winit::{ window::WindowAttributes, }; -mod account; mod data; mod debug; mod net; -mod state; +mod session; mod ui; fn main() { @@ -25,10 +24,8 @@ fn main() { pub struct Client { ui_state: DefaultUiState, data: ClientData, - state: ClientState, main_ui: WeakWidget, notif: WeakWidget, - proxy: Proxy, } pub type Rsc = DefaultRsc; @@ -44,7 +41,7 @@ impl DefaultAppState for Client { fn new( mut ui_state: DefaultUiState, rsc: &mut DefaultRsc, - proxy: Proxy, + _: Proxy, ) -> Self { let notif = WidgetPtr::default().add(rsc); let main_ui = WidgetPtr::default().add(rsc); @@ -68,10 +65,8 @@ impl DefaultAppState for Client { Self { ui_state, data, - state: Default::default(), main_ui, notif, - proxy, } } @@ -89,10 +84,6 @@ impl DefaultAppState for Client { } } - fn exit(&mut self, _rsc: &mut DefaultRsc, _render: &mut UiRenderState) { - self.state.exit(); - } - fn window_event( &mut self, event: WindowEvent, diff --git a/src/bin/client/net.rs b/src/bin/client/net.rs index 3deb130..359a12a 100644 --- a/src/bin/client/net.rs +++ b/src/bin/client/net.rs @@ -1,8 +1,8 @@ use crate::ClientEvent; use dashmap::DashMap; use openworm::net::{ - ClientMsg, ClientRequestMsg, CreateAccount, CreateAccountResp, Login, LoginResp, RecvHandler, - RequestId, SERVER_NAME, ServerMsg, ServerRespMsg, SkipServerVerification, recv_uni, send_uni, + ClientMsg, ClientRequestMsg, RecvHandler, RequestId, RequestMsg, SERVER_NAME, ServerMsg, + ServerRespMsg, SkipServerVerification, recv_uni, send_uni, }; use quinn::{ ClientConfig, Connection, Endpoint, IdleTimeout, TransportConfig, @@ -25,6 +25,7 @@ pub struct ConnectInfo { pub cert: Vec, } +#[derive(Clone)] pub struct NetHandle { send: UnboundedSender, } @@ -75,35 +76,6 @@ impl NetHandle { } } -pub trait RequestMsg: Into { - type Result; - fn result(msg: ServerMsg) -> Option; -} - -impl RequestMsg for CreateAccount { - type Result = CreateAccountResp; - - fn result(msg: ServerMsg) -> Option { - if let ServerMsg::CreateAccountResp(res) = msg { - Some(res) - } else { - None - } - } -} - -impl RequestMsg for Login { - type Result = LoginResp; - - fn result(msg: ServerMsg) -> Option { - if let ServerMsg::LoginResp(res) = msg { - Some(res) - } else { - None - } - } -} - async fn connection_cert( addr: SocketAddr, cert: CertificateDer<'_>, @@ -118,8 +90,7 @@ async fn connection_cert( let client_config = ClientConfig::new(Arc::new( QuicClientConfig::try_from(client_crypto).map_err(|e| e.to_string())?, )); - let mut endpoint = quinn::Endpoint::client(SocketAddr::from_str("[::]:0").unwrap()) - .map_err(|e| e.to_string())?; + let mut endpoint = quinn::Endpoint::client(CLIENT_SOCKET).map_err(|e| e.to_string())?; endpoint.set_default_client_config(client_config); let conn = endpoint .connect(addr, SERVER_NAME) diff --git a/src/bin/client/session.rs b/src/bin/client/session.rs new file mode 100644 index 0000000..84512d3 --- /dev/null +++ b/src/bin/client/session.rs @@ -0,0 +1,8 @@ +use openworm::net::UserId; + +use crate::net::NetHandle; + +pub struct Session { + pub con: NetHandle, + pub user_id: UserId, +} diff --git a/src/bin/client/state.rs b/src/bin/client/state.rs deleted file mode 100644 index f0d47e6..0000000 --- a/src/bin/client/state.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::net::NetHandle; -use iris::prelude::*; -use openworm::net::LoadMsg; -use std::thread::JoinHandle; - -#[derive(Default)] -pub struct Connect { - pub handle: Option>, -} - -pub struct Login { - pub handle: NetHandle, -} - -pub struct LoggedIn { - pub network: NetHandle, - pub msgs: Vec, - pub channel: Option>, - pub username: String, -} - -pub enum ClientState { - Connect(Connect), - Login(Login), - LoggedIn(LoggedIn), -} - -impl Default for ClientState { - fn default() -> Self { - Self::Connect(Default::default()) - } -} - -impl ClientState { - pub fn take(&mut self) -> Self { - std::mem::take(self) - } - pub fn exit(&mut self) { - let s = self.take(); - match s { - ClientState::Connect(_) => (), - ClientState::Login(Login { handle }) => { - handle.exit(); - } - ClientState::LoggedIn(state) => { - state.network.exit(); - } - } - } -} diff --git a/src/bin/client/ui/connect.rs b/src/bin/client/ui/connect.rs index bd87600..8be7f83 100644 --- a/src/bin/client/ui/connect.rs +++ b/src/bin/client/ui/connect.rs @@ -1,6 +1,7 @@ use openworm::net::{CreateAccount, CreateAccountResp, Login, LoginResp}; use crate::{ + session::Session, data::{AccountInfo, ClientData, ServerInfo, ServerList}, net::{ConnectInfo, NetHandle}, }; @@ -53,7 +54,7 @@ pub fn start(rsc: &mut Rsc, data: &ClientData) -> WeakWidget { rsc[ctx.notif].inner = Some(werror(&reason, rsc)); }) }; - let net = match NetHandle::connect( + let con = match NetHandle::connect( async |msg| { println!("msg recv :joy:"); }, @@ -70,7 +71,7 @@ pub fn start(rsc: &mut Rsc, data: &ClientData) -> WeakWidget { } }; - let Ok(resp) = net + let Ok(resp) = con .request(Login { username: account.username.clone(), password: password.clone(), @@ -79,7 +80,7 @@ pub fn start(rsc: &mut Rsc, data: &ClientData) -> WeakWidget { else { return fail("failed to create account"); }; - let id = match resp { + let user_id = match resp { LoginResp::Ok { id } => id, LoginResp::UnknownUsername => { return fail("unknown username"); @@ -88,8 +89,9 @@ pub fn start(rsc: &mut Rsc, data: &ClientData) -> WeakWidget { return fail("invalid password"); } }; + let session = Session { con, user_id }; ctx.update(move |ctx, rsc| { - main_view(rsc).set_ptr(ctx.main_ui, rsc); + main_view(rsc, session).set_ptr(ctx.main_ui, rsc); }); }); }); @@ -148,7 +150,7 @@ pub fn create_account(rsc: &mut Rsc) -> WeakWidget { }) }; keyring::use_native_store(true).unwrap(); - let net = match NetHandle::connect( + let con = match NetHandle::connect( async |msg| { println!("msg recv :joy:"); }, @@ -165,7 +167,7 @@ pub fn create_account(rsc: &mut Rsc) -> WeakWidget { } }; - let Ok(resp) = net + let Ok(resp) = con .request(CreateAccount { username: username.clone(), password: password.clone(), @@ -175,7 +177,7 @@ pub fn create_account(rsc: &mut Rsc) -> WeakWidget { else { return fail("failed to create account"); }; - let id = match resp { + let user_id = match resp { CreateAccountResp::Ok { id } => id, CreateAccountResp::UsernameExists => { return fail("username already exists"); @@ -184,8 +186,9 @@ pub fn create_account(rsc: &mut Rsc) -> WeakWidget { return fail("invalid account token"); } }; + let session = Session { con, user_id }; ctx.update(move |ctx, rsc| { - main_view(rsc).set_ptr(ctx.main_ui, rsc); + main_view(rsc, session).set_ptr(ctx.main_ui, rsc); ctx.data.create_account( ServerInfo { cert_hex }, AccountInfo { url, username }, diff --git a/src/bin/client/ui/main.rs b/src/bin/client/ui/main.rs index 503bbd8..2980e14 100644 --- a/src/bin/client/ui/main.rs +++ b/src/bin/client/ui/main.rs @@ -1,6 +1,6 @@ use std::hash::Hash; -use crate::Rsc; +use crate::{Rsc, session::Session}; use super::*; @@ -9,24 +9,25 @@ pub const SIZE: u32 = 20; #[derive(PartialEq, Eq, Hash, Clone, Copy)] pub enum MainView { Channel, + Friends, Server, } -pub fn main_view(rsc: &mut Rsc) -> WeakWidget { +pub fn main_view(rsc: &mut Rsc, session: Session) -> WeakWidget { let mut view = WidgetSelector::new(MainView::Channel, channel::view(rsc)); - view.set(MainView::Server, server::view(rsc)); + view.set(MainView::Server, server::view(rsc, &session)); let view = view.add(rsc); - (top_bar(rsc, view), view).span(Dir::DOWN).add(rsc) -} - -pub fn top_bar(rsc: &mut Rsc, view: WeakWidget>) -> WeakWidget { - let [channel, server] = tabs( + let [channel, friends, server] = tabs( rsc, view, - [("channel", MainView::Channel), ("server", MainView::Server)], + [ + ("channel", MainView::Channel), + ("friends", MainView::Friends), + ("server", MainView::Server), + ], ); - rect(Color::BLACK.alpha(150)) + let top_bar = rect(Color::BLACK.alpha(150)) .height(50) - .foreground((channel, server).span(Dir::RIGHT)) - .add(rsc) + .foreground((channel, friends, server).span(Dir::RIGHT)); + (top_bar, view).span(Dir::DOWN).add(rsc) } diff --git a/src/bin/client/ui/misc.rs b/src/bin/client/ui/misc.rs index 8bdafa5..a3abe2d 100644 --- a/src/bin/client/ui/misc.rs +++ b/src/bin/client/ui/misc.rs @@ -12,6 +12,10 @@ pub fn hint_text(msg: impl Into) -> TextBuilder { wtext(msg).size(20).color(Color::GRAY) } +pub fn large_hint_text(msg: impl Into) -> TextBuilder { + wtext(msg).size(30).color(Color::GRAY) +} + pub fn field(default: &str, hint: &str, rsc: &mut Rsc) -> WeakWidget { wtext(default) .editable(EditMode::SingleLine) diff --git a/src/bin/client/ui/server.rs b/src/bin/client/ui/server.rs index 8a9ab21..4b2c77f 100644 --- a/src/bin/client/ui/server.rs +++ b/src/bin/client/ui/server.rs @@ -1,3 +1,7 @@ +use openworm::net::RequestUsers; + +use crate::session::Session; + use super::*; #[derive(PartialEq, Eq, Hash, Clone, Copy)] @@ -6,9 +10,9 @@ enum View { User, } -pub fn view(rsc: &mut Rsc) -> StrongWidget { +pub fn view(rsc: &mut Rsc, session: &Session) -> StrongWidget { let mut view = WidgetSelector::new(View::Info, info(rsc)); - view.set(View::User, users(rsc)); + view.set(View::User, users(rsc, session)); let view = view.add(rsc); let [info, server] = tabs(rsc, view, [("info", View::Info), ("users", View::User)]); @@ -23,6 +27,36 @@ fn info(rsc: &mut Rsc) -> StrongWidget { wtext("server info").center_text().add_strong(rsc) } -fn users(rsc: &mut Rsc) -> StrongWidget { - wtext("users").center_text().add_strong(rsc) +fn users(rsc: &mut Rsc, session: &Session) -> StrongWidget { + let ptr = WidgetPtr::new( + large_hint_text("loading users...") + .center_text() + .width(rest(1)) + .add_strong(rsc), + ) + .add(rsc); + let con = session.con.clone(); + rsc.events.register(ptr, Draw, move |_, rsc| { + let con = con.clone(); + rsc.spawn_task(async move |mut ctx| { + let Ok(resp) = con.request(RequestUsers).await else { + return; + }; + ctx.update(move |_, rsc| { + let mut span = Span::empty(Dir::DOWN); + for user in resp.users { + let thing = ( + wtext(user.id.to_string()).size(20), + wtext(user.username).size(20), + ) + .span(Dir::RIGHT) + .gap(30) + .pad(15); + span.push(thing.add_strong(rsc)); + } + span.set_ptr(ptr, rsc); + }); + }); + }); + ptr.upgrade(rsc) } diff --git a/src/bin/server/db/ver.rs b/src/bin/server/db/ver.rs index 5cef10d..d19cf86 100644 --- a/src/bin/server/db/ver.rs +++ b/src/bin/server/db/ver.rs @@ -8,6 +8,7 @@ pub struct ServerPermsV0(u32); impl ServerPermsV0 { pub const NONE: Self = Self(0); pub const ACCOUNT_TOKENS: Self = Self(1 << 0); + pub const ALL: Self = Self(u32::MAX); } #[derive(bitcode::Encode, bitcode::Decode)] diff --git a/src/bin/server/main.rs b/src/bin/server/main.rs index 3c8373f..a2db2ce 100644 --- a/src/bin/server/main.rs +++ b/src/bin/server/main.rs @@ -7,7 +7,8 @@ use net::{ClientSender, ConAccepter, listen}; use openworm::{ net::{ ClientMsg, ClientRequestMsg, CreateAccount, CreateAccountResp, DisconnectReason, LoadMsg, - Login, LoginResp, RecvHandler, ServerError, ServerMsg, install_crypto_provider, + Login, LoginResp, RecvHandler, RequestUsersResp, ServerError, ServerMsg, ServerUser, + install_crypto_provider, }, rsc::DataDir, }; @@ -49,7 +50,7 @@ pub async fn run_server(port: u16) { db: db.clone(), }; if db.users.is_empty() { - let token = account_token(&db, ServerPerms::ACCOUNT_TOKENS); + let token = account_token(&db, ServerPerms::ALL); println!("no users found, token for admin: {token}"); } let (endpoint, handle) = listen(port, &dir.path, handler); @@ -231,6 +232,27 @@ impl RecvHandler for ClientHandler { *self.state.write().await = ClientState::Authed(id); let _ = replier.send(LoginResp::Ok { id }).await; } + ClientMsg::RequestUsers(_) => { + if self + .db + .users + .get(&self.id) + .is_some_and(|u| !u.server_perms.contains(ServerPerms::ALL)) + { + let _ = replier.send(ServerError::NoPermission).await; + return; + } + let users: Vec<_> = self + .db + .users + .iter() + .map(|(id, u)| ServerUser { + id, + username: u.username, + }) + .collect(); + let _ = replier.send(RequestUsersResp { users }).await; + } } } diff --git a/src/net/conversion.rs b/src/net/conversion.rs index 396c757..92e19d5 100644 --- a/src/net/conversion.rs +++ b/src/net/conversion.rs @@ -10,6 +10,7 @@ impl From for ClientMsgInst { ClientMsg::RequestMsgs => Self::RequestMsgsV0, ClientMsg::SendMsg(v) => Self::SendMsgV0(v), ClientMsg::Login(v) => Self::LoginV0(v), + ClientMsg::RequestUsers(v) => Self::RequestUsersV0(v), } } } @@ -21,6 +22,7 @@ impl From for ClientMsg { ClientMsgInst::RequestMsgsV0 => Self::RequestMsgs, ClientMsgInst::SendMsgV0(v) => Self::SendMsg(v), ClientMsgInst::LoginV0(v) => Self::Login(v), + ClientMsgInst::RequestUsersV0(v) => Self::RequestUsers(v), } } } @@ -33,6 +35,7 @@ impl From for ServerMsgInst { ServerMsg::LoadMsgs(v) => Self::LoadMsgsV0(v), ServerMsg::ServerError(v) => Self::ServerErrorV0(v), ServerMsg::LoginResp(v) => Self::LoginRespV0(v), + ServerMsg::RequestUsersResp(v) => Self::RequestUsersRespV0(v), } } } @@ -45,6 +48,7 @@ impl From for ServerMsg { ServerMsgInst::LoadMsgsV0(v) => Self::LoadMsgs(v), ServerMsgInst::ServerErrorV0(v) => Self::ServerError(v), ServerMsgInst::LoginRespV0(v) => Self::LoginResp(v), + ServerMsgInst::RequestUsersRespV0(v) => Self::RequestUsersResp(v), } } } diff --git a/src/net/data.rs b/src/net/data.rs index 07a6aed..41bea67 100644 --- a/src/net/data.rs +++ b/src/net/data.rs @@ -7,6 +7,7 @@ pub enum ClientMsgInst { LoginV0(LoginV0) = 1, RequestMsgsV0 = 2, SendMsgV0(SendMsgV0) = 3, + RequestUsersV0(RequestUsersV0) = 4, } #[repr(u32)] @@ -17,6 +18,7 @@ pub enum ServerMsgInst { LoadMsgV0(LoadMsgV0) = 2, LoadMsgsV0(Vec) = 3, ServerErrorV0(ServerErrorV0) = 4, + RequestUsersRespV0(RequestUsersRespV0) = 5, } pub type UserIdV0 = u64; @@ -48,6 +50,20 @@ pub enum LoginRespV0 { InvalidPassword, } +#[derive(Debug, bitcode::Encode, bitcode::Decode)] +pub struct RequestUsersV0; + +#[derive(Debug, bitcode::Encode, bitcode::Decode)] +pub struct RequestUsersRespV0 { + pub users: Vec, +} + +#[derive(Debug, bitcode::Encode, bitcode::Decode)] +pub struct ServerUserV0 { + pub id: UserIdV0, + pub username: String, +} + #[derive(Debug, bitcode::Encode, bitcode::Decode)] pub struct LoginKeyV0(Vec); impl LoginKeyV0 { @@ -86,4 +102,5 @@ pub struct LoadMsgV0 { #[derive(Debug, bitcode::Encode, bitcode::Decode)] pub enum ServerErrorV0 { NotLoggedIn, + NoPermission, } diff --git a/src/net/mod.rs b/src/net/mod.rs index bd8801f..5a54b6b 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -1,5 +1,5 @@ mod conversion; -mod data; +pub mod data; mod msg; mod no_cert; mod request; diff --git a/src/net/msg.rs b/src/net/msg.rs index 73576fb..40aee74 100644 --- a/src/net/msg.rs +++ b/src/net/msg.rs @@ -1,4 +1,4 @@ -use super::data::*; +use super::data; #[derive(Debug)] pub enum ClientMsg { @@ -6,6 +6,7 @@ pub enum ClientMsg { Login(Login), RequestMsgs, SendMsg(SendMsg), + RequestUsers(RequestUsers), } #[derive(Debug)] @@ -15,17 +16,23 @@ pub enum ServerMsg { LoadMsg(LoadMsg), LoadMsgs(Vec), ServerError(ServerError), + RequestUsersResp(RequestUsersResp), } -pub type LoginKey = LoginKeyV0; -pub type SendMsg = SendMsgV0; -pub type LoadMsg = LoadMsgV0; -pub type ServerError = ServerErrorV0; -pub type CreateAccount = CreateAccountV0; -pub type CreateAccountResp = CreateAccountRespV0; -pub type Login = LoginV0; -pub type LoginResp = LoginRespV0; -pub type UserId = UserIdV0; +// TODO: a ton of this should really just be macros :sob: + +pub use data::CreateAccountRespV0 as CreateAccountResp; +pub use data::CreateAccountV0 as CreateAccount; +pub use data::LoadMsgV0 as LoadMsg; +pub use data::LoginKeyV0 as LoginKey; +pub use data::LoginRespV0 as LoginResp; +pub use data::LoginV0 as Login; +pub use data::RequestUsersRespV0 as RequestUsersResp; +pub use data::RequestUsersV0 as RequestUsers; +pub use data::SendMsgV0 as SendMsg; +pub use data::ServerErrorV0 as ServerError; +pub use data::ServerUserV0 as ServerUser; +pub use data::UserIdV0 as UserId; impl From for ClientMsg { fn from(value: CreateAccount) -> Self { @@ -39,6 +46,12 @@ impl From for ClientMsg { } } +impl From for ClientMsg { + fn from(value: RequestUsers) -> Self { + Self::RequestUsers(value) + } +} + impl From for ServerMsg { fn from(value: ServerError) -> Self { Self::ServerError(value) @@ -62,3 +75,9 @@ impl From for ServerMsg { Self::LoginResp(value) } } + +impl From for ServerMsg { + fn from(value: RequestUsersResp) -> Self { + Self::RequestUsersResp(value) + } +} diff --git a/src/net/request.rs b/src/net/request.rs index 45ae483..98bef51 100644 --- a/src/net/request.rs +++ b/src/net/request.rs @@ -1,7 +1,6 @@ +use super::*; use std::num::NonZeroU32; -use crate::net::{ClientMsgInst, ServerMsgInst}; - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, bitcode::Encode, bitcode::Decode)] pub struct RequestId(NonZeroU32); @@ -30,3 +29,44 @@ pub struct ServerRespMsg { pub id: Option, pub msg: ServerMsgInst, } + +pub trait RequestMsg: Into { + type Result; + fn result(msg: ServerMsg) -> Option; +} + +impl RequestMsg for CreateAccount { + type Result = CreateAccountResp; + + fn result(msg: ServerMsg) -> Option { + if let ServerMsg::CreateAccountResp(res) = msg { + Some(res) + } else { + None + } + } +} + +impl RequestMsg for Login { + type Result = LoginResp; + + fn result(msg: ServerMsg) -> Option { + if let ServerMsg::LoginResp(res) = msg { + Some(res) + } else { + None + } + } +} + +impl RequestMsg for RequestUsers { + type Result = RequestUsersResp; + + fn result(msg: ServerMsg) -> Option { + if let ServerMsg::RequestUsersResp(res) = msg { + Some(res) + } else { + None + } + } +}