persistence + proper disconnect
This commit is contained in:
+11
-12
@@ -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();
|
||||
}
|
||||
|
||||
+16
-3
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+69
-13
@@ -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,9 +167,18 @@ async fn connect_the(handle: AppHandle, info: ConnectInfo) -> NetResult<()> {
|
||||
tokio::spawn(recv_uni(conn_, recv.into()));
|
||||
|
||||
while let Some(msg) = ui_recv.recv().await {
|
||||
if send_uni(&conn, msg).await.is_err() {
|
||||
println!("disconnected from server");
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user