add client data cache for ip and username

This commit is contained in:
2025-11-17 17:57:41 -05:00
parent 510fafac9f
commit b3c833c667
8 changed files with 153 additions and 24 deletions

24
Cargo.lock generated
View File

@@ -298,6 +298,9 @@ name = "bitflags"
version = "2.10.0" version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
dependencies = [
"serde_core",
]
[[package]] [[package]]
name = "bitstream-io" name = "bitstream-io"
@@ -1949,6 +1952,7 @@ dependencies = [
"pollster", "pollster",
"quinn", "quinn",
"rcgen", "rcgen",
"ron",
"tokio", "tokio",
"tracing", "tracing",
"wgpu", "wgpu",
@@ -2557,6 +2561,20 @@ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.52.0",
] ]
[[package]]
name = "ron"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd490c5b18261893f14449cbd28cb9c0b637aebf161cd77900bfdedaff21ec32"
dependencies = [
"bitflags 2.10.0",
"once_cell",
"serde",
"serde_derive",
"typeid",
"unicode-ident",
]
[[package]] [[package]]
name = "roxmltree" name = "roxmltree"
version = "0.20.0" version = "0.20.0"
@@ -3262,6 +3280,12 @@ dependencies = [
"core_maths", "core_maths",
] ]
[[package]]
name = "typeid"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.18" version = "0.3.18"

View File

@@ -18,3 +18,4 @@ wgpu = "27.0.1"
winit = "0.30.12" winit = "0.30.12"
bincode = "2.0.1" bincode = "2.0.1"
zstd = "0.13.3" zstd = "0.13.3"
ron = "0.12.0"

View File

@@ -58,6 +58,11 @@ impl ApplicationHandler<ClientEvent> for App {
let client = self.client.as_mut().unwrap(); let client = self.client.as_mut().unwrap();
client.event(event, event_loop); client.event(event, event_loop);
} }
fn exiting(&mut self, _: &ActiveEventLoop) {
let client = self.client.as_mut().unwrap();
client.exit();
}
} }
impl AppHandle { impl AppHandle {

View File

@@ -6,8 +6,9 @@ use render::Renderer;
use winit::{event::WindowEvent, event_loop::ActiveEventLoop}; use winit::{event::WindowEvent, event_loop::ActiveEventLoop};
use crate::{ use crate::{
client::ui::{Submit, main_view, msg_widget}, client::ui::{Edited, Submit, main_view, msg_widget},
net::{ClientMsg, ServerMsg, client::NetSender}, net::{ClientMsg, ServerMsg, client::NetSender},
rsc::{CLIENT_DATA, ClientData, DataDir},
}; };
mod app; mod app;
@@ -30,23 +31,30 @@ pub struct Client {
channel: Option<WidgetId<Span>>, channel: Option<WidgetId<Span>>,
username: String, username: String,
clipboard: Clipboard, clipboard: Clipboard,
dir: DataDir,
data: ClientData,
handle: AppHandle,
} }
impl Client { impl Client {
pub fn new(handle: AppHandle) -> Self { pub fn new(handle: AppHandle) -> Self {
let renderer = Renderer::new(handle.window.clone()); let renderer = Renderer::new(handle.window.clone());
let dir = DataDir::default();
let ui = ui::ui(handle); let mut s = Self {
handle,
Self {
renderer, renderer,
input: Input::default(), input: Input::default(),
ui, ui: Ui::new(),
data: dir.load(CLIENT_DATA),
dir,
channel: None, channel: None,
focus: None, focus: None,
username: "<unknown>".to_string(), username: "<unknown>".to_string(),
clipboard: Clipboard::new().unwrap(), clipboard: Clipboard::new().unwrap(),
} };
ui::init(&mut s);
s
} }
pub fn event(&mut self, event: ClientEvent, _: &ActiveEventLoop) { pub fn event(&mut self, event: ClientEvent, _: &ActiveEventLoop) {
@@ -104,20 +112,25 @@ impl Client {
if let Some(sel) = &self.focus if let Some(sel) = &self.focus
&& event.state.is_pressed() && event.state.is_pressed()
{ {
let sel = &sel.clone();
let mut text = self.ui.text(sel); let mut text = self.ui.text(sel);
match text.apply_event(&event, &self.input.modifiers) { match text.apply_event(&event, &self.input.modifiers) {
TextInputResult::Unfocus => { TextInputResult::Unfocus => {
self.focus = None; self.focus = None;
} }
TextInputResult::Submit => { TextInputResult::Submit => {
self.run_event(&sel.clone(), Submit, ()); self.run_event(sel, Submit, ());
} }
TextInputResult::Paste => { TextInputResult::Paste => {
if let Ok(t) = self.clipboard.get_text() { if let Ok(t) = self.clipboard.get_text() {
text.insert(&t); text.insert(&t);
} }
self.run_event(sel, Edited, ());
} }
TextInputResult::Unused | TextInputResult::Used => (), TextInputResult::Used => {
self.run_event(sel, Edited, ());
}
TextInputResult::Unused => (),
} }
} }
} }
@@ -128,6 +141,10 @@ impl Client {
} }
self.input.end_frame(); self.input.end_frame();
} }
pub fn exit(&mut self) {
self.dir.save(CLIENT_DATA, &self.data);
}
} }
impl UiCtx for Client { impl UiCtx for Client {

View File

@@ -2,7 +2,7 @@ use iris::prelude::*;
use len_fns::*; use len_fns::*;
use crate::{ use crate::{
client::{Client, app::AppHandle}, client::Client,
net::{ net::{
ClientMsg, Msg, ClientMsg, Msg,
client::{ConnectInfo, NetSender, connect}, client::{ConnectInfo, NetSender, connect},
@@ -12,14 +12,19 @@ use crate::{
#[derive(Eq, PartialEq, Hash, Clone)] #[derive(Eq, PartialEq, Hash, Clone)]
pub struct Submit; pub struct Submit;
#[derive(Eq, PartialEq, Hash, Clone)]
pub struct Edited;
impl DefaultEvent for Submit { impl DefaultEvent for Submit {
type Data = (); type Data = ();
} }
pub fn ui(handle: AppHandle) -> Ui { impl DefaultEvent for Edited {
let mut ui = Ui::new(); type Data = ();
login_screen(&mut ui, handle).set_root(&mut ui); }
ui
pub fn init(client: &mut Client) {
login_screen(client).set_root(&mut client.ui);
} }
pub fn main_view(client: &mut Client, network: NetSender) -> WidgetId<AnyWidget> { pub fn main_view(client: &mut Client, network: NetSender) -> WidgetId<AnyWidget> {
@@ -32,10 +37,14 @@ pub fn main_view(client: &mut Client, network: NetSender) -> WidgetId<AnyWidget>
.any() .any()
} }
fn login_screen(ui: &mut Ui, handle: AppHandle) -> WidgetId<AnyWidget> { fn login_screen(client: &mut Client) -> WidgetId<AnyWidget> {
let Client {
ui, handle, data, ..
} = client;
let mut field = |name| text(name).editable().size(20).add(ui); let mut field = |name| text(name).editable().size(20).add(ui);
let ip = field("localhost:16839"); let ip = field(&data.ip);
let username = field("username"); let username = field(&data.username);
// let password = field("password"); // let password = field("password");
let fbx = |field: WidgetId<TextEdit>| { let fbx = |field: WidgetId<TextEdit>| {
@@ -46,6 +55,8 @@ fn login_screen(ui: &mut Ui, handle: AppHandle) -> WidgetId<AnyWidget> {
.on(CursorSense::click(), focus(field)) .on(CursorSense::click(), focus(field))
}; };
// I LAV NOT HAVING ERGONOMIC CLONES
let handle = handle.clone();
let ip_ = ip.clone(); let ip_ = ip.clone();
let username_ = username.clone(); let username_ = username.clone();
let color = Color::GREEN; let color = Color::GREEN;
@@ -60,8 +71,16 @@ fn login_screen(ui: &mut Ui, handle: AppHandle) -> WidgetId<AnyWidget> {
.height(40); .height(40);
( (
text("login").size(30), text("login").size(30),
fbx(ip), fbx(ip
fbx(username), .id_on(Edited, |id, client: &mut Client, _| {
client.data.ip = client.ui[id].content();
})
.add(ui)),
fbx(username
.id_on(Edited, |id, client: &mut Client, _| {
client.data.username = client.ui[id].content();
})
.add(ui)),
// fbx(password), // fbx(password),
submit, submit,
) )

View File

@@ -1,3 +1,4 @@
pub mod client; pub mod client;
pub mod net; pub mod net;
pub mod server; pub mod server;
pub mod rsc;

59
src/rsc.rs Normal file
View File

@@ -0,0 +1,59 @@
use std::{
fs::{self, File},
path::Path,
};
use directories_next::ProjectDirs;
use crate::net::BINCODE_CONFIG;
pub const CLIENT_DATA: &str = "client_data";
pub struct DataDir {
dirs: ProjectDirs,
}
impl Default for DataDir {
fn default() -> Self {
Self {
dirs: ProjectDirs::from("", "", "openworm").unwrap(),
}
}
}
impl DataDir {
pub fn get(&self) -> &Path {
self.dirs.data_local_dir()
}
pub fn load<T: bincode::Decode<()> + Default>(&self, path: &str) -> T {
let path = self.get().join(path);
match fs::read(path) {
Ok(bytes) => match bincode::decode_from_slice(&bytes, BINCODE_CONFIG) {
Ok((data, _)) => data,
Err(_) => todo!(),
},
Err(_) => T::default(),
}
}
pub fn save<T: bincode::Encode>(&self, path: &str, data: &T) {
let mut file = File::create(self.get().join(path)).unwrap();
bincode::encode_into_std_write(data, &mut file, BINCODE_CONFIG).unwrap();
}
}
#[derive(bincode::Encode, bincode::Decode)]
pub struct ClientData {
pub ip: String,
pub username: String,
}
impl Default for ClientData {
fn default() -> Self {
Self {
ip: "localhost:39420".to_string(),
username: "your [NOVEMBER]".to_string(),
}
}
}

View File

@@ -1,7 +1,10 @@
use crate::net::{ use crate::{
ClientMsg, Msg, ServerMsg, net::{
server::{ClientSender, ConAccepter, listen}, ClientMsg, Msg, ServerMsg,
transfer::RecvHandler, server::{ClientSender, ConAccepter, listen},
transfer::RecvHandler,
},
rsc::DataDir,
}; };
use std::{ use std::{
collections::HashMap, collections::HashMap,
@@ -14,8 +17,8 @@ use tokio::sync::RwLock;
#[tokio::main] #[tokio::main]
pub async fn run_server() { pub async fn run_server() {
let dirs = directories_next::ProjectDirs::from("", "", "openworm").unwrap(); let dir = DataDir::default();
let path = dirs.data_local_dir(); let path = dir.get();
let handler = ServerListener { let handler = ServerListener {
msgs: Default::default(), msgs: Default::default(),
senders: Default::default(), senders: Default::default(),