persistence + proper disconnect
This commit is contained in:
203
Cargo.lock
generated
203
Cargo.lock
generated
@@ -82,6 +82,56 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.100"
|
||||
@@ -108,7 +158,7 @@ dependencies = [
|
||||
"objc2-core-foundation",
|
||||
"objc2-core-graphics",
|
||||
"objc2-foundation 0.3.2",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.5",
|
||||
"percent-encoding",
|
||||
"windows-sys 0.60.2",
|
||||
"wl-clipboard-rs",
|
||||
@@ -387,6 +437,46 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
|
||||
|
||||
[[package]]
|
||||
name = "clipboard-win"
|
||||
version = "5.4.1"
|
||||
@@ -413,6 +503,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.7"
|
||||
@@ -851,6 +947,16 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
|
||||
|
||||
[[package]]
|
||||
name = "fs2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fxhash"
|
||||
version = "0.2.1"
|
||||
@@ -1101,6 +1207,15 @@ dependencies = [
|
||||
"hashbrown 0.16.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "interpolate_name"
|
||||
version = "0.2.4"
|
||||
@@ -1127,6 +1242,12 @@ dependencies = [
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
@@ -1835,6 +1956,12 @@ version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.6"
|
||||
@@ -1847,12 +1974,14 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"bincode",
|
||||
"clap",
|
||||
"directories-next",
|
||||
"iris",
|
||||
"pollster",
|
||||
"quinn",
|
||||
"rcgen",
|
||||
"ron",
|
||||
"sled",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"wgpu",
|
||||
@@ -1897,6 +2026,17 @@ dependencies = [
|
||||
"ttf-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.5"
|
||||
@@ -1904,7 +2044,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
"parking_lot_core 0.9.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2366,6 +2520,15 @@ dependencies = [
|
||||
"font-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
@@ -2722,6 +2885,22 @@ version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
||||
|
||||
[[package]]
|
||||
name = "sled"
|
||||
version = "0.34.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"fs2",
|
||||
"fxhash",
|
||||
"libc",
|
||||
"log",
|
||||
"parking_lot 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slotmap"
|
||||
version = "1.0.7"
|
||||
@@ -2802,6 +2981,12 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.6.1"
|
||||
@@ -3002,7 +3187,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.5",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
@@ -3192,6 +3377,12 @@ version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "v_frame"
|
||||
version = "0.3.9"
|
||||
@@ -3463,7 +3654,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"naga",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.5",
|
||||
"portable-atomic",
|
||||
"profiling",
|
||||
"raw-window-handle",
|
||||
@@ -3495,7 +3686,7 @@ dependencies = [
|
||||
"log",
|
||||
"naga",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.5",
|
||||
"portable-atomic",
|
||||
"profiling",
|
||||
"raw-window-handle",
|
||||
@@ -3569,7 +3760,7 @@ dependencies = [
|
||||
"objc",
|
||||
"once_cell",
|
||||
"ordered-float",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.5",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"profiling",
|
||||
|
||||
@@ -20,6 +20,8 @@ winit = "0.30.12"
|
||||
bincode = "2.0.1"
|
||||
zstd = "0.13.3"
|
||||
ron = "0.12.0"
|
||||
sled = "0.34.7"
|
||||
clap = { version = "4.5.53", features = ["derive"] }
|
||||
|
||||
[[bin]]
|
||||
name = "openworm-client"
|
||||
|
||||
2
iris
2
iris
Submodule iris updated: ee0616885f...d6a9711ceb
@@ -1,8 +1,7 @@
|
||||
use openworm::net::Msg;
|
||||
|
||||
use crate::Client;
|
||||
|
||||
pub fn debug(_client: &mut Client) {
|
||||
pub fn debug(client: &mut Client) {
|
||||
client.ui.debug_layers();
|
||||
// let mut file = std::fs::OpenOptions::new()
|
||||
// .write(true)
|
||||
// .create(true)
|
||||
@@ -15,14 +14,14 @@ pub fn debug(_client: &mut Client) {
|
||||
// openworm::net::BINCODE_CONFIG,
|
||||
// )
|
||||
// .unwrap();
|
||||
let mut file = std::fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.open("./old_msgs")
|
||||
.unwrap();
|
||||
let msgs: Vec<Msg> =
|
||||
bincode::decode_from_std_read(&mut file, openworm::net::BINCODE_CONFIG).unwrap();
|
||||
for msg in msgs {
|
||||
println!("{msg:?}");
|
||||
}
|
||||
// let mut file = std::fs::OpenOptions::new()
|
||||
// .read(true)
|
||||
// .open("./old_msgs")
|
||||
// .unwrap();
|
||||
// let msgs: Vec<NetMsg> =
|
||||
// bincode::decode_from_std_read(&mut file, openworm::net::BINCODE_CONFIG).unwrap();
|
||||
// for msg in msgs {
|
||||
// println!("{msg:?}");
|
||||
// }
|
||||
// client.ui.debug_layers();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use crate::{
|
||||
app::App,
|
||||
net::NetSender,
|
||||
net::{NetCtrlMsg, NetHandle, NetSender, NetState},
|
||||
rsc::{CLIENT_DATA, ClientData},
|
||||
ui::*,
|
||||
};
|
||||
@@ -11,7 +11,7 @@ use arboard::Clipboard;
|
||||
use input::Input;
|
||||
use iris::prelude::*;
|
||||
use openworm::{
|
||||
net::{ClientMsg, Msg, ServerMsg, install_crypto_provider},
|
||||
net::{ClientMsg, NetMsg, ServerMsg, install_crypto_provider},
|
||||
rsc::DataDir,
|
||||
};
|
||||
use render::Renderer;
|
||||
@@ -53,7 +53,8 @@ pub struct Client {
|
||||
data: ClientData,
|
||||
handle: AppHandle,
|
||||
error: Option<WidgetId<WidgetPtr>>,
|
||||
msgs: Vec<Msg>,
|
||||
net: NetState,
|
||||
msgs: Vec<NetMsg>,
|
||||
ime: usize,
|
||||
last_click: Instant,
|
||||
}
|
||||
@@ -78,6 +79,7 @@ impl Client {
|
||||
dir,
|
||||
channel: None,
|
||||
focus: None,
|
||||
net: Default::default(),
|
||||
username: "<unknown>".to_string(),
|
||||
clipboard: Clipboard::new().unwrap(),
|
||||
error: None,
|
||||
@@ -94,6 +96,13 @@ impl Client {
|
||||
ClientEvent::Connect { send, username } => {
|
||||
self.username = username;
|
||||
send.send(ClientMsg::RequestMsgs);
|
||||
let NetState::Connecting(th) = self.net.take() else {
|
||||
panic!("invalid state");
|
||||
};
|
||||
self.net = NetState::Connected(NetHandle {
|
||||
send: send.clone(),
|
||||
thread: th,
|
||||
});
|
||||
main_view(self, send).set_root(&mut self.ui);
|
||||
}
|
||||
ClientEvent::ServerMsg(msg) => match msg {
|
||||
@@ -213,6 +222,10 @@ impl Client {
|
||||
}
|
||||
|
||||
pub fn exit(&mut self) {
|
||||
if let Some(handle) = self.net.take_connection() {
|
||||
handle.send.send(NetCtrlMsg::Exit);
|
||||
let _ = handle.thread.join();
|
||||
}
|
||||
self.dir.save(CLIENT_DATA, &self.data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use quinn::{
|
||||
use std::{
|
||||
net::{Ipv6Addr, SocketAddr, SocketAddrV6, ToSocketAddrs},
|
||||
sync::Arc,
|
||||
thread::JoinHandle,
|
||||
time::Duration,
|
||||
};
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
@@ -21,24 +22,69 @@ pub struct ConnectInfo {
|
||||
pub username: String,
|
||||
}
|
||||
|
||||
pub fn connect(handle: AppHandle, info: ConnectInfo) {
|
||||
pub struct NetHandle {
|
||||
pub send: NetSender,
|
||||
pub thread: JoinHandle<()>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub enum NetState {
|
||||
#[default]
|
||||
None,
|
||||
Connecting(JoinHandle<()>),
|
||||
Connected(NetHandle),
|
||||
}
|
||||
|
||||
impl NetState {
|
||||
pub fn take_connection(&mut self) -> Option<NetHandle> {
|
||||
match self.take() {
|
||||
NetState::Connected(net_handle) => Some(net_handle),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connection(&self) -> Option<&NetHandle> {
|
||||
match self {
|
||||
NetState::Connected(net_handle) => Some(net_handle),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take(&mut self) -> Self {
|
||||
std::mem::replace(self, Self::None)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect(handle: AppHandle, info: ConnectInfo) -> JoinHandle<()> {
|
||||
std::thread::spawn(move || {
|
||||
if let Err(msg) = connect_the(handle.clone(), info) {
|
||||
handle.send(ClientEvent::Err(msg));
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
type NetResult<T> = Result<T, String>;
|
||||
|
||||
type MsgPayload = ClientMsg;
|
||||
#[derive(Clone)]
|
||||
pub struct NetSender {
|
||||
send: UnboundedSender<MsgPayload>,
|
||||
send: UnboundedSender<NetCtrlMsg>,
|
||||
}
|
||||
|
||||
pub enum NetCtrlMsg {
|
||||
Send(ClientMsg),
|
||||
Exit,
|
||||
}
|
||||
|
||||
impl From<ClientMsg> for NetCtrlMsg {
|
||||
fn from(value: ClientMsg) -> Self {
|
||||
Self::Send(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl NetSender {
|
||||
pub fn send(&self, msg: ClientMsg) {
|
||||
let _ = self.send.send(msg);
|
||||
pub fn send(&self, msg: impl Into<NetCtrlMsg>) {
|
||||
let _ = self.send.send(msg.into());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +114,7 @@ impl NetSender {
|
||||
// .map_err(|e| format!("failed to connect: {}", e))
|
||||
// }
|
||||
|
||||
async fn connection_no_cert(addr: SocketAddr) -> NetResult<Connection> {
|
||||
async fn connection_no_cert(addr: SocketAddr) -> NetResult<(Endpoint, Connection)> {
|
||||
let mut endpoint = Endpoint::client(CLIENT_SOCKET).map_err(|e| e.to_string())?;
|
||||
|
||||
let quic = QuicClientConfig::try_from(
|
||||
@@ -91,16 +137,17 @@ async fn connection_no_cert(addr: SocketAddr) -> NetResult<Connection> {
|
||||
endpoint.set_default_client_config(config);
|
||||
|
||||
// connect to server
|
||||
endpoint
|
||||
let con = endpoint
|
||||
.connect(addr, SERVER_NAME)
|
||||
.map_err(|e| e.to_string())?
|
||||
.await
|
||||
.map_err(|e| e.to_string())
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok((endpoint, con))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn connect_the(handle: AppHandle, info: ConnectInfo) -> NetResult<()> {
|
||||
let (send, mut ui_recv) = tokio::sync::mpsc::unbounded_channel::<MsgPayload>();
|
||||
let (send, mut ui_recv) = tokio::sync::mpsc::unbounded_channel::<NetCtrlMsg>();
|
||||
|
||||
let addr = info
|
||||
.ip
|
||||
@@ -108,7 +155,7 @@ async fn connect_the(handle: AppHandle, info: ConnectInfo) -> NetResult<()> {
|
||||
.map_err(|e| e.to_string())?
|
||||
.next()
|
||||
.ok_or("no addresses found".to_string())?;
|
||||
let conn = connection_no_cert(addr).await?;
|
||||
let (endpoint, conn) = connection_no_cert(addr).await?;
|
||||
let conn_ = conn.clone();
|
||||
|
||||
handle.send(ClientEvent::Connect {
|
||||
@@ -120,11 +167,20 @@ async fn connect_the(handle: AppHandle, info: ConnectInfo) -> NetResult<()> {
|
||||
tokio::spawn(recv_uni(conn_, recv.into()));
|
||||
|
||||
while let Some(msg) = ui_recv.recv().await {
|
||||
match msg {
|
||||
NetCtrlMsg::Send(msg) => {
|
||||
if send_uni(&conn, msg).await.is_err() {
|
||||
println!("disconnected from server");
|
||||
break;
|
||||
}
|
||||
}
|
||||
NetCtrlMsg::Exit => {
|
||||
conn.close(quinn::VarInt::from_u32(0), &[]);
|
||||
endpoint.wait_idle().await;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::net::NetState;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub fn login_screen(client: &mut Client) -> WidgetId {
|
||||
@@ -5,13 +7,7 @@ pub fn login_screen(client: &mut Client) -> WidgetId {
|
||||
ui, handle, data, ..
|
||||
} = client;
|
||||
|
||||
let mut field = |name, hint_| {
|
||||
text(name)
|
||||
.editable(true)
|
||||
.size(20)
|
||||
.hint(hint(hint_))
|
||||
.add(ui)
|
||||
};
|
||||
let mut field = |name, hint_| text(name).editable(true).size(20).hint(hint(hint_)).add(ui);
|
||||
let ip = field(&data.ip, "ip");
|
||||
let username = field(&data.username, "username");
|
||||
// let password = field("password");
|
||||
@@ -35,7 +31,8 @@ pub fn login_screen(client: &mut Client) -> WidgetId {
|
||||
client.ui[id].color = color.darker(0.3);
|
||||
let ip = client.ui[&ip_].content();
|
||||
let username = client.ui[&username_].content();
|
||||
connect(handle.clone(), ConnectInfo { ip, username });
|
||||
let th = connect(handle.clone(), ConnectInfo { ip, username });
|
||||
client.net = NetState::Connecting(th);
|
||||
})
|
||||
.height(40);
|
||||
let modal = (
|
||||
|
||||
@@ -18,7 +18,7 @@ pub fn main_view(client: &mut Client, network: NetSender) -> WidgetId {
|
||||
.any()
|
||||
}
|
||||
|
||||
pub fn msg_widget(msg: Msg) -> impl WidgetLike<FnTag> {
|
||||
pub fn msg_widget(msg: NetMsg) -> impl WidgetLike<FnTag> {
|
||||
let content = text(msg.content)
|
||||
.editable(false)
|
||||
.size(SIZE)
|
||||
@@ -61,7 +61,7 @@ pub fn msg_panel(client: &mut Client, network: NetSender) -> impl WidgetFn<Sized
|
||||
.clone()
|
||||
.id_on(Submit, move |id, client: &mut Client, _| {
|
||||
let content = client.ui.text(id).take();
|
||||
let msg = Msg {
|
||||
let msg = NetMsg {
|
||||
content: content.clone(),
|
||||
user: client.username.clone(),
|
||||
};
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
};
|
||||
use iris::prelude::*;
|
||||
use len_fns::*;
|
||||
use openworm::net::{ClientMsg, Msg};
|
||||
use openworm::net::{ClientMsg, NetMsg};
|
||||
use winit::dpi::{LogicalPosition, LogicalSize};
|
||||
|
||||
mod login;
|
||||
|
||||
3
src/bin/server/data.rs
Normal file
3
src/bin/server/data.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub struct DBMsg {
|
||||
|
||||
}
|
||||
53
src/bin/server/db.rs
Normal file
53
src/bin/server/db.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use std::path::Path;
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
use openworm::net::BINCODE_CONFIG;
|
||||
use sled::{Db, Tree};
|
||||
|
||||
pub const DB_VERSION: u64 = 0;
|
||||
|
||||
pub fn open_db(path: impl AsRef<Path>) -> Db {
|
||||
let db = sled::open(path).expect("failed to open database");
|
||||
if !db.was_recovered() {
|
||||
println!("no previous db found, creating new");
|
||||
db.insert_("version", DB_VERSION);
|
||||
db.flush().unwrap();
|
||||
} else {
|
||||
let version: u64 = db.get_("version").expect("failed to read db version");
|
||||
println!("found existing db version {version}");
|
||||
if version != DB_VERSION {
|
||||
panic!("non matching db version! (auto update in the future)");
|
||||
}
|
||||
}
|
||||
db
|
||||
}
|
||||
|
||||
pub trait DbUtil {
|
||||
fn insert_<K: AsRef<[u8]>, V: Encode>(&self, k: K, v: V);
|
||||
fn get_<K: AsRef<[u8]>, V: Decode<()>>(&self, k: K) -> Option<V>;
|
||||
fn iter_all<V: Decode<()>>(&self) -> impl Iterator<Item = V>;
|
||||
}
|
||||
|
||||
impl DbUtil for Tree {
|
||||
fn insert_<K: AsRef<[u8]>, V: Encode>(&self, k: K, v: V) {
|
||||
let bytes = bincode::encode_to_vec(v, BINCODE_CONFIG).unwrap();
|
||||
self.insert(k, bytes).unwrap();
|
||||
}
|
||||
|
||||
fn get_<K: AsRef<[u8]>, V: Decode<()>>(&self, k: K) -> Option<V> {
|
||||
let bytes = self.get(k).unwrap()?;
|
||||
Some(
|
||||
bincode::decode_from_slice(&bytes, BINCODE_CONFIG)
|
||||
.unwrap()
|
||||
.0,
|
||||
)
|
||||
}
|
||||
|
||||
fn iter_all<V: Decode<()>>(&self) -> impl Iterator<Item = V> {
|
||||
self.iter().map(|r| {
|
||||
bincode::decode_from_slice(&r.unwrap().1, BINCODE_CONFIG)
|
||||
.unwrap()
|
||||
.0
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
// mod data;
|
||||
mod db;
|
||||
mod net;
|
||||
|
||||
use crate::db::{DbUtil, open_db};
|
||||
use clap::Parser;
|
||||
use net::{ClientSender, ConAccepter, listen};
|
||||
use openworm::{
|
||||
net::{ClientMsg, DisconnectReason, Msg, RecvHandler, ServerMsg, install_crypto_provider},
|
||||
net::{ClientMsg, DisconnectReason, RecvHandler, ServerMsg, install_crypto_provider},
|
||||
rsc::DataDir,
|
||||
};
|
||||
use sled::{Db, Tree};
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{
|
||||
@@ -14,27 +19,39 @@ use std::{
|
||||
};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Args {
|
||||
/// port to listen on
|
||||
#[arg(short, long)]
|
||||
port: u16,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
install_crypto_provider();
|
||||
run_server();
|
||||
run_server(args.port);
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
pub async fn run_server() {
|
||||
pub async fn run_server(port: u16) {
|
||||
let dir = DataDir::default();
|
||||
let path = dir.get();
|
||||
let db: Db = open_db(path.join("server.db"));
|
||||
let handler = ServerListener {
|
||||
msgs: Default::default(),
|
||||
msgs: db.open_tree("msgs").unwrap(),
|
||||
senders: Default::default(),
|
||||
count: 0.into(),
|
||||
db,
|
||||
};
|
||||
listen(path, handler).await;
|
||||
listen(port, path, handler).await;
|
||||
}
|
||||
|
||||
type ClientId = u64;
|
||||
|
||||
struct ServerListener {
|
||||
msgs: Arc<RwLock<Vec<Msg>>>,
|
||||
db: Db,
|
||||
msgs: Tree,
|
||||
senders: Arc<RwLock<HashMap<ClientId, ClientSender>>>,
|
||||
count: AtomicU64,
|
||||
}
|
||||
@@ -44,6 +61,7 @@ impl ConAccepter for ServerListener {
|
||||
let id = self.count.fetch_add(1, Ordering::Release);
|
||||
self.senders.write().await.insert(id, send.clone());
|
||||
ClientHandler {
|
||||
db: self.db.clone(),
|
||||
msgs: self.msgs.clone(),
|
||||
senders: self.senders.clone(),
|
||||
send,
|
||||
@@ -53,17 +71,22 @@ impl ConAccepter for ServerListener {
|
||||
}
|
||||
|
||||
struct ClientHandler {
|
||||
msgs: Arc<RwLock<Vec<Msg>>>,
|
||||
db: Db,
|
||||
msgs: Tree,
|
||||
send: ClientSender,
|
||||
senders: Arc<RwLock<HashMap<ClientId, ClientSender>>>,
|
||||
id: ClientId,
|
||||
}
|
||||
|
||||
impl RecvHandler<ClientMsg> for ClientHandler {
|
||||
async fn connect(&self) -> () {
|
||||
println!("connected: {:?}", self.send.remote());
|
||||
}
|
||||
async fn msg(&self, msg: ClientMsg) {
|
||||
match msg {
|
||||
ClientMsg::SendMsg(msg) => {
|
||||
self.msgs.write().await.push(msg.clone());
|
||||
let id = self.db.generate_id().unwrap();
|
||||
self.msgs.insert_(id.to_be_bytes(), &msg);
|
||||
let mut handles = Vec::new();
|
||||
for (&id, send) in self.senders.read().await.iter() {
|
||||
if id == self.id {
|
||||
@@ -81,13 +104,14 @@ impl RecvHandler<ClientMsg> for ClientHandler {
|
||||
}
|
||||
}
|
||||
ClientMsg::RequestMsgs => {
|
||||
let msgs = self.msgs.read().await.clone();
|
||||
let msgs = self.msgs.iter_all().collect();
|
||||
let _ = self.send.send(ServerMsg::LoadMsgs(msgs)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn disconnect(&self, reason: DisconnectReason) -> () {
|
||||
println!("disconnected: {:?}", self.send.remote());
|
||||
match reason {
|
||||
DisconnectReason::Closed | DisconnectReason::Timeout => (),
|
||||
DisconnectReason::Other(e) => println!("connection issue: {e}"),
|
||||
|
||||
@@ -12,12 +12,9 @@ use std::{
|
||||
};
|
||||
use tracing::Instrument;
|
||||
|
||||
pub const DEFAULT_PORT: u16 = 16839;
|
||||
pub const SERVER_HOST: Ipv6Addr = Ipv6Addr::UNSPECIFIED;
|
||||
pub const SERVER_SOCKET: SocketAddr =
|
||||
SocketAddr::V6(SocketAddrV6::new(SERVER_HOST, DEFAULT_PORT, 0, 0));
|
||||
|
||||
pub fn init_endpoint(data_path: &Path) -> Endpoint {
|
||||
pub fn init_endpoint(port: u16, data_path: &Path) -> Endpoint {
|
||||
let cert_path = data_path.join("cert.der");
|
||||
let key_path = data_path.join("key.der");
|
||||
let (cert, key) = match fs::read(&cert_path).and_then(|x| Ok((x, fs::read(&key_path)?))) {
|
||||
@@ -51,7 +48,8 @@ pub fn init_endpoint(data_path: &Path) -> Endpoint {
|
||||
// let transport_config = Arc::get_mut(&mut server_config.transport).unwrap();
|
||||
// transport_config.max_concurrent_uni_streams(0_u8.into());
|
||||
|
||||
quinn::Endpoint::server(server_config, SERVER_SOCKET).unwrap()
|
||||
let server_socket: SocketAddr = SocketAddr::V6(SocketAddrV6::new(SERVER_HOST, port, 0, 0));
|
||||
quinn::Endpoint::server(server_config, server_socket).unwrap()
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -60,6 +58,9 @@ pub struct ClientSender {
|
||||
}
|
||||
|
||||
impl ClientSender {
|
||||
pub fn remote(&self) -> SocketAddr {
|
||||
self.conn.remote_address()
|
||||
}
|
||||
pub async fn send(&self, msg: ServerMsg) -> SendResult {
|
||||
send_uni(&self.conn, msg).await
|
||||
}
|
||||
@@ -72,9 +73,9 @@ pub trait ConAccepter: Send + Sync + 'static {
|
||||
) -> impl Future<Output = impl RecvHandler<ClientMsg>> + Send;
|
||||
}
|
||||
|
||||
pub async fn listen(data_path: &Path, accepter: impl ConAccepter) {
|
||||
pub async fn listen(port: u16, data_path: &Path, accepter: impl ConAccepter) {
|
||||
let accepter = Arc::new(accepter);
|
||||
let endpoint = init_endpoint(data_path);
|
||||
let endpoint = init_endpoint(port, data_path);
|
||||
println!("listening on {}", endpoint.local_addr().unwrap());
|
||||
|
||||
while let Some(conn) = endpoint.accept().await {
|
||||
@@ -93,6 +94,7 @@ async fn handle_connection(
|
||||
) -> std::io::Result<()> {
|
||||
let conn = conn.await?;
|
||||
let handler = Arc::new(accepter.accept(ClientSender { conn: conn.clone() }).await);
|
||||
handler.connect().await;
|
||||
let span = tracing::info_span!(
|
||||
"connection",
|
||||
remote = %conn.remote_address(),
|
||||
|
||||
@@ -11,20 +11,20 @@ pub const BINCODE_CONFIG: Configuration = bincode::config::standard();
|
||||
|
||||
#[derive(Debug, bincode::Encode, bincode::Decode)]
|
||||
pub enum ClientMsg {
|
||||
SendMsg(Msg),
|
||||
SendMsg(NetMsg),
|
||||
RequestMsgs,
|
||||
}
|
||||
|
||||
#[derive(Debug, bincode::Encode, bincode::Decode)]
|
||||
pub enum ServerMsg {
|
||||
SendMsg(Msg),
|
||||
LoadMsgs(Vec<Msg>),
|
||||
SendMsg(NetMsg),
|
||||
LoadMsgs(Vec<NetMsg>),
|
||||
}
|
||||
|
||||
pub type ServerResp<T> = Result<T, String>;
|
||||
|
||||
#[derive(Debug, Clone, bincode::Encode, bincode::Decode)]
|
||||
pub struct Msg {
|
||||
pub struct NetMsg {
|
||||
pub content: String,
|
||||
pub user: String,
|
||||
}
|
||||
|
||||
@@ -6,9 +6,13 @@ use tokio::io::{AsyncReadExt as _, AsyncWriteExt};
|
||||
use tracing::Instrument as _;
|
||||
|
||||
pub trait RecvHandler<M>: Send + Sync + 'static {
|
||||
fn connect(&self) -> impl Future<Output = ()> + Send {
|
||||
async {}
|
||||
}
|
||||
fn msg(&self, msg: M) -> impl Future<Output = ()> + Send;
|
||||
#[allow(unused)]
|
||||
fn disconnect(&self, reason: DisconnectReason) -> impl Future<Output = ()> + Send {
|
||||
async { drop(reason) }
|
||||
async {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +43,7 @@ pub async fn recv_uni<M: bincode::Decode<()>>(
|
||||
Err(quinn::ConnectionError::ApplicationClosed { .. }) => {
|
||||
return DisconnectReason::Closed;
|
||||
}
|
||||
Err(quinn::ConnectionError::LocallyClosed) => return DisconnectReason::Closed,
|
||||
Err(quinn::ConnectionError::TimedOut) => {
|
||||
return DisconnectReason::Timeout;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use directories_next::ProjectDirs;
|
||||
|
||||
use crate::net::BINCODE_CONFIG;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DataDir {
|
||||
dirs: ProjectDirs,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user