diff --git a/Cargo.lock b/Cargo.lock index 2a65922..5a8cbcf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2274,6 +2274,15 @@ dependencies = [ "syn", ] +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + [[package]] name = "objc" version = "0.2.7" @@ -2599,6 +2608,7 @@ dependencies = [ "rcgen", "ron", "scrypt", + "time", "tokio", "tracing", "wgpu 27.0.1", @@ -3878,13 +3888,15 @@ dependencies = [ [[package]] name = "time" -version = "0.3.46" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", "serde_core", "time-core", @@ -3899,9 +3911,9 @@ checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.26" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc610bac2dcee56805c99642447d4c5dbde4d01f752ffea0199aee1f601dc4" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", diff --git a/Cargo.toml b/Cargo.toml index ecf8589..c904f5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ keyring = { version = "3.6.3", features = ["apple-native", "sync-secret-service" bitcode = "0.6.9" dashmap = "6.1.0" fjall = "3.0.1" +time = { version = "0.3.47", features = ["local-offset"] } [[bin]] name = "openworm-client" diff --git a/src/bin/client/net.rs b/src/bin/client/net.rs index ccf8023..630bd2e 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::{ - AccountCreated, ClientMsg, ClientMsgInst, CreateAccount, RecvHandler, RequestId, SERVER_NAME, - ServerMsg, ServerRespMsg, SkipServerVerification, recv_uni, send_uni, + AccountCreated, ClientMsg, ClientMsgInst, ClientRequestMsg, CreateAccount, RecvHandler, + RequestId, SERVER_NAME, ServerMsg, ServerRespMsg, SkipServerVerification, recv_uni, send_uni, }; use quinn::{ ClientConfig, Connection, Endpoint, IdleTimeout, TransportConfig, @@ -60,11 +60,11 @@ impl NetHandle { pub async fn request(&self, msg: R) -> Result { let (send, recv) = oneshot::channel(); self.send_(NetCtrlMsg::Request(msg.into(), send)); - let Ok(recv) = recv.await else { todo!() }; + let Ok(recv) = recv.await else { return Err(()) }; if let Some(res) = R::result(recv) { Ok(res) } else { - todo!() + Err(()) } } @@ -167,17 +167,24 @@ pub async fn connect(msg: impl MsgHandler, info: ConnectInfo) -> Result { - let msg = ClientMsgInst::from(msg); + let msg = ClientRequestMsg { + id: request_id, + msg: msg.into(), + }; if send_uni(&conn, msg).await.is_err() { println!("disconnected from server"); break; } } NetCtrlMsg::Request(msg, send) => { - let msg = ClientMsgInst::from(msg); - recv.requests.insert(req_id.next(), send); + let msg = ClientRequestMsg { + id: request_id, + msg: msg.into(), + }; + recv.requests.insert(request_id, send); if send_uni(&conn, msg).await.is_err() { println!("disconnected from server"); break; @@ -215,7 +222,7 @@ struct ServerRecv { impl RecvHandler for ServerRecv { async fn msg(&self, resp: ServerRespMsg) { let msg = resp.msg.into(); - if let Some(id) = resp.request_id + if let Some(id) = resp.id && let Some((_, send)) = self.requests.remove(&id) { send.send(msg); diff --git a/src/bin/client/ui/connect.rs b/src/bin/client/ui/connect.rs index fd0a157..5771065 100644 --- a/src/bin/client/ui/connect.rs +++ b/src/bin/client/ui/connect.rs @@ -40,7 +40,7 @@ pub fn start(rsc: &mut Rsc) -> WeakWidget { pub fn create_account(rsc: &mut Rsc) -> WeakWidget { let url = field("", "server", rsc); - let token = field("", "account token", rsc); + let token = field("", "account creation token", rsc); let username = field("", "username", rsc); let password = field("", "password", rsc); @@ -81,6 +81,7 @@ pub fn create_account(rsc: &mut Rsc) -> WeakWidget { else { return fail("failed to create account"); }; + println!("account created!!!!"); }); }); diff --git a/src/bin/server/data.rs b/src/bin/server/data.rs deleted file mode 100644 index d0831f8..0000000 --- a/src/bin/server/data.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub struct DBMsg { - -} diff --git a/src/bin/server/db.rs b/src/bin/server/db.rs deleted file mode 100644 index 995bf2e..0000000 --- a/src/bin/server/db.rs +++ /dev/null @@ -1,163 +0,0 @@ -use std::{marker::PhantomData, path::Path}; - -use bitcode::{Decode, DecodeOwned, Encode}; -use fjall::{Database, Keyspace, KeyspaceCreateOptions, UserValue}; - -pub struct DbU64(u64); -pub const DB_VERSION: DbU64 = DbU64(0); - -impl Into for DbU64 { - fn into(self) -> UserValue { - UserValue::new(&self.0.to_be_bytes()) - } -} - -#[derive(Encode, Decode)] -pub struct User { - pub username: String, - pub password_hash: String, -} - -#[derive(Clone, Encode, Decode)] -pub struct Msg { - pub user: u64, - pub content: String, -} - -#[derive(Clone)] -pub struct Db { - pub db: fjall::Database, - pub msgs: DbMap, - pub users: DbMap, - pub usernames: DbMap, -} - -pub struct DbMap { - keyspace: Keyspace, - _pd: PhantomData<(K, V)>, -} - -pub trait Key { - type Output<'a>: AsRef<[u8]> - where - Self: 'a; - fn bytes(&self) -> Self::Output<'_>; -} - -impl Key for String { - type Output<'a> = &'a Self; - fn bytes(&self) -> Self::Output<'_> { - self - } -} - -impl Key for str { - type Output<'a> = &'a Self; - fn bytes(&self) -> Self::Output<'_> { - self - } -} - -impl Key for u64 { - type Output<'a> = [u8; 8]; - - fn bytes(&self) -> Self::Output<'_> { - self.to_be_bytes() - } -} - -impl DbMap { - pub fn insert(&self, k: &K, v: &V) { - self.keyspace.insert_(k, v); - } - - pub fn get(&self, k: &K) -> Option { - self.keyspace.get_(k) - } - - pub fn init_unique(&self, k: &K) -> bool { - self.keyspace - .compare_and_swap(k.bytes(), None as Option<&[u8]>, Some(&[0])) - .unwrap() - .is_ok() - } - - pub fn iter_all(&self) -> impl Iterator { - self.keyspace.iter_all() - } -} - -pub fn open_db(path: impl AsRef) -> Db { - let config = fjall::Config::new(path.as_ref()); - let db = Database::open(config).expect("failed to open database"); - let info = open_ks("info", &db); - if !info.contains_key("version").unwrap() { - println!("no previous db found, creating new"); - info.insert("version", DB_VERSION); - } else { - let version: u64 = info.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 { - msgs: open_ks("msg", &db), - users: open_ks("user", &db), - usernames: open_ks("username", &db), - db, - } -} - -trait DbUtil { - fn insert_(&self, k: &(impl Key + ?Sized), v: V); - fn get_(&self, k: &(impl Key + ?Sized)) -> Option; - fn iter_all(&self) -> impl Iterator; -} - -impl DbUtil for Tree { - fn insert_(&self, k: &(impl Key + ?Sized), v: &V) { - let bytes = bitcode::encode(v); - self.insert(k.bytes(), bytes).unwrap(); - } - - fn get_>(&self, k: &(impl Key + ?Sized)) -> Option { - let bytes = self.get(k.bytes()).unwrap()?; - Some( - bincode::decode_from_slice(&bytes, BINCODE_CONFIG) - .unwrap() - .0, - ) - } - - fn iter_all>(&self) -> impl Iterator { - self.iter().map(|r| { - bincode::decode_from_slice(&r.unwrap().1, BINCODE_CONFIG) - .unwrap() - .0 - }) - } -} - -pub fn open_ks(name: &str, db: &Database) -> DbMap { - DbMap { - keyspace: db.keyspace(name, KeyspaceCreateOptions::default).unwrap(), - _pd: PhantomData, - } -} - -impl Clone for DbMap { - fn clone(&self) -> Self { - Self { - keyspace: self.keyspace.clone(), - _pd: self._pd, - } - } -} - -impl Db { - pub fn flush(&self) { - // test to see if it gets dropped and just works - // self.db.persist(fjall::PersistMode::SyncAll).unwrap(); - } -} diff --git a/src/bin/server/db/mod.rs b/src/bin/server/db/mod.rs new file mode 100644 index 0000000..d41d82d --- /dev/null +++ b/src/bin/server/db/mod.rs @@ -0,0 +1,55 @@ +mod util; +mod ver; + +use std::path::Path; + +use util::*; +use ver::*; + +pub const DB_VERSION: u64 = 0; + +#[derive(Clone)] +pub struct Db { + db: Database, + pub msgs: DbMap, + pub users: DbMap, + pub usernames: DbMap, +} + +pub type UserId = UserIdV0; +pub type MsgId = MsgIdV0; +pub type ChannelId = ChannelIdV0; +pub type ImageId = ImageIdV0; +pub type User = UserV0; +pub type Msg = MsgV0; +pub type ChannelInfo = ChannelV0; + +impl Db { + pub fn open(path: impl AsRef) -> Db { + let db = Database::open(path); + let info: DbMap = DbMap::open("info", &db); + if let Some(version) = info.get("version") { + println!("found existing db version {version}"); + if version != DB_VERSION { + panic!("non matching db version! (auto update in the future)"); + } + } else { + println!("no previous db found, creating new"); + info.insert("version", &DB_VERSION); + } + Db { + msgs: DbMap::open("msg", &db), + users: DbMap::open("user", &db), + usernames: DbMap::open("username", &db), + db, + } + } +} + +impl std::ops::Deref for Db { + type Target = Database; + + fn deref(&self) -> &Self::Target { + &self.db + } +} diff --git a/src/bin/server/db/util.rs b/src/bin/server/db/util.rs new file mode 100644 index 0000000..f54d461 --- /dev/null +++ b/src/bin/server/db/util.rs @@ -0,0 +1,202 @@ +use std::{marker::PhantomData, path::Path}; + +use bitcode::{DecodeOwned, Encode}; +use fjall::{KeyspaceCreateOptions, OptimisticTxDatabase, OptimisticTxKeyspace, Readable, Slice}; + +#[derive(Clone)] +pub struct Database(fjall::OptimisticTxDatabase); + +pub struct DbMap { + db: Database, + keyspace: OptimisticTxKeyspace, + _pd: PhantomData<(K, V)>, +} + +impl Clone for DbMap { + fn clone(&self) -> Self { + Self { + db: self.db.clone(), + keyspace: self.keyspace.clone(), + _pd: self._pd.clone(), + } + } +} + +impl DbMap { + pub fn open(name: &str, db: &Database) -> DbMap { + DbMap { + db: db.clone(), + keyspace: db.0.keyspace(name, KeyspaceCreateOptions::default).unwrap(), + _pd: PhantomData, + } + } +} + +impl, V: Encode + DecodeOwned> DbMap { + // TODO: K2 IS NOT A SAFE ABSTRACTION!! need to have KeyLike which has key assoc type + pub fn insert + ?Sized>(&self, k: &K2, v: &V) { + let k = Slice::new(k.to_bytes().as_ref()); + let v = Slice::new(&bitcode::encode(v)); + self.keyspace.insert(k, v).unwrap(); + } + + pub fn get + ?Sized>(&self, k: &K2) -> Option { + let k = Slice::new(k.to_bytes().as_ref()); + let v = self.keyspace.get(k).unwrap()?; + Some(bitcode::decode(&v).unwrap()) + } + + pub fn iter(&self) -> impl Iterator { + self.db.read_tx().iter(self) + } + + pub fn values(&self) -> impl Iterator { + self.db.read_tx().values(self) + } +} + +impl Database { + pub fn open(path: impl AsRef) -> Self { + let inner = OptimisticTxDatabase::builder(path.as_ref()) + .open() + .expect("failed to open database"); + Self(inner) + } + pub fn read_tx(&self) -> ReadTx { + ReadTx(self.0.read_tx()) + } + + pub fn write_tx(&self) -> WriteTx { + WriteTx(self.0.write_tx().unwrap()) + } +} + +pub struct ReadTx(fjall::Snapshot); + +impl ReadTx { + pub fn values( + &self, + map: &DbMap, + ) -> impl Iterator + use { + self.0.iter(&map.keyspace).map(|g| { + let v = g.value().unwrap(); + bitcode::decode(&v).unwrap() + }) + } + + pub fn iter, V: DecodeOwned>( + &self, + map: &DbMap, + ) -> impl Iterator + use { + self.0.iter(&map.keyspace).map(|g| { + let (k, v) = g.into_inner().unwrap(); + (K::from_bytes(&k), bitcode::decode(&v).unwrap()) + }) + } +} + +pub struct WriteTx(fjall::OptimisticWriteTx); + +impl WriteTx { + pub fn values( + &self, + map: &DbMap, + ) -> impl Iterator + use { + self.0.iter(&map.keyspace).map(|g| { + let v = g.value().unwrap(); + bitcode::decode(&v).unwrap() + }) + } + + pub fn iter, V: DecodeOwned>( + &self, + map: &DbMap, + ) -> impl Iterator + use { + self.0.iter(&map.keyspace).map(|g| { + let (k, v) = g.into_inner().unwrap(); + (K::from_bytes(&k), bitcode::decode(&v).unwrap()) + }) + } + + pub fn get, V: DecodeOwned>(&self, map: &DbMap, k: K) -> Option { + let k = Slice::new(k.to_bytes().as_ref()); + let v = self.0.get(&map.keyspace, k).unwrap()?; + Some(bitcode::decode(&v).unwrap()) + } + + pub fn has_key, V>(&self, map: &DbMap, k: K) -> bool { + let k = Slice::new(k.to_bytes().as_ref()); + self.0.get(&map.keyspace, k).unwrap().is_some() + } + + // TODO: K2 IS NOT A SAFE ABSTRACTION!! need to have KeyLike which has key assoc type + pub fn insert, K2: Key + ?Sized, V: Encode>( + &mut self, + map: &DbMap, + k: &K2, + v: &V, + ) { + let k = Slice::new(k.to_bytes().as_ref()); + let v = Slice::new(&bitcode::encode(v)); + self.0.insert(&map.keyspace, k, v); + } + + pub fn commit(self) -> bool { + self.0.commit().unwrap().is_ok() + } +} + +pub trait Key { + type Input<'a>: AsRef<[u8]> + where + Self: 'a; + type Output; + fn to_bytes(&self) -> Self::Input<'_>; + fn from_bytes(bytes: &[u8]) -> Self::Output; +} + +impl Key for String { + type Input<'a> = &'a Self; + type Output = String; + fn to_bytes(&self) -> Self::Input<'_> { + self + } + fn from_bytes(bytes: &[u8]) -> Self { + Self::from_utf8(bytes.to_vec()).unwrap() + } +} + +impl Key for str { + type Input<'a> = &'a Self; + type Output = String; + fn to_bytes(&self) -> Self::Input<'_> { + self + } + fn from_bytes(bytes: &[u8]) -> String { + String::from_utf8(bytes.to_vec()).unwrap() + } +} + +impl Key for u64 { + type Input<'a> = [u8; 8]; + type Output = u64; + + fn to_bytes(&self) -> Self::Input<'_> { + self.to_be_bytes() + } + fn from_bytes(bytes: &[u8]) -> Self { + Self::from_be_bytes(bytes.try_into().unwrap()) + } +} + +impl Key for i128 { + type Input<'a> = [u8; 16]; + type Output = i128; + + fn to_bytes(&self) -> Self::Input<'_> { + self.to_be_bytes() + } + fn from_bytes(bytes: &[u8]) -> Self { + Self::from_be_bytes(bytes.try_into().unwrap()) + } +} diff --git a/src/bin/server/db/ver.rs b/src/bin/server/db/ver.rs new file mode 100644 index 0000000..e93d89f --- /dev/null +++ b/src/bin/server/db/ver.rs @@ -0,0 +1,23 @@ +pub type UserIdV0 = u64; +pub type MsgIdV0 = i128; +pub type ChannelIdV0 = u64; +pub type ImageIdV0 = u64; + +#[derive(bitcode::Encode, bitcode::Decode)] +pub struct UserV0 { + pub username: String, + pub password_hash: String, + pub pfp: Option, + pub bio: String, +} + +#[derive(bitcode::Encode, bitcode::Decode)] +pub struct MsgV0 { + pub content: String, + pub author: UserIdV0, +} + +pub struct ChannelV0 { + pub name: String, + pub desc: String, +} diff --git a/src/bin/server/main.rs b/src/bin/server/main.rs index 056daac..bc0b062 100644 --- a/src/bin/server/main.rs +++ b/src/bin/server/main.rs @@ -1,14 +1,13 @@ -// mod data; mod db; mod net; -use crate::db::{Db, Msg, User, open_db}; +use crate::db::{Db, Msg, User}; use clap::Parser; use net::{ClientSender, ConAccepter, listen}; use openworm::{ net::{ - ClientMsg, ClientMsgInst, CreateAccount, DisconnectReason, LoadMsg, RecvHandler, - ServerError, ServerMsg, install_crypto_provider, + AccountCreated, ClientMsg, ClientRequestMsg, CreateAccount, DisconnectReason, LoadMsg, + RecvHandler, ServerError, ServerMsg, install_crypto_provider, }, rsc::DataDir, }; @@ -43,7 +42,7 @@ fn main() { 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 db = Db::open(path.join("server_db")); let handler = ServerListener { senders: Default::default(), count: 0.into(), @@ -56,9 +55,6 @@ pub async fn run_server(port: u16) { endpoint.close(0u32.into(), &[]); let _ = handle.await; endpoint.wait_idle().await; - println!("saving..."); - db.flush(); - println!("saved"); } type ClientId = u64; @@ -76,7 +72,7 @@ pub enum ClientState { } impl ConAccepter for ServerListener { - async fn accept(&self, send: ClientSender) -> impl RecvHandler { + async fn accept(&self, send: ClientSender) -> impl RecvHandler { let id = self.count.fetch_add(1, Ordering::Release); self.senders.write().await.insert(id, send.clone()); ClientHandler { @@ -97,29 +93,33 @@ struct ClientHandler { state: Arc>, } -impl RecvHandler for ClientHandler { +impl RecvHandler for ClientHandler { async fn connect(&self) -> () { println!("connected: {:?}", self.send.remote().ip()); } - async fn msg(&self, msg: ClientMsgInst) { - let msg = ClientMsg::from(msg); + async fn msg(&self, req: ClientRequestMsg) { + let msg = ClientMsg::from(req.msg); + let replier = self.send.replier(req.id); match msg { ClientMsg::SendMsg(msg) => { let ClientState::Authed(uid) = &*self.state.read().await else { - let _ = self.send.send(ServerError::NotLoggedIn).await; + let _ = replier.send(ServerError::NotLoggedIn).await; return; }; let msg = Msg { - user: *uid, + author: *uid, content: msg.content, }; - let id = self.db.generate_id().unwrap(); - self.db.msgs.insert(&id, &msg); + // TODO: it is technically possible to send 2 messages at the exact same time... + // should probably append a number if one already exists at that time, + // but also I can't see this ever happening...? + // should be an easy fix later (write tx) + let timestamp = time::OffsetDateTime::now_utc().unix_timestamp_nanos(); + self.db.msgs.insert(×tamp, &msg); let mut handles = Vec::new(); - let user: User = self.db.users.get(uid).unwrap(); let msg = LoadMsg { content: msg.content, - user: user.username, + author: *uid, }; for (&id, send) in self.senders.read().await.iter() { if id == self.id { @@ -128,7 +128,12 @@ impl RecvHandler for ClientHandler { let send = send.clone(); let msg = msg.clone(); let fut = async move { - let _ = send.send(msg).await; + let _ = send + .send(LoadMsg { + content: msg.content, + author: msg.author, + }) + .await; }; handles.push(tokio::spawn(fut)); } @@ -138,27 +143,19 @@ impl RecvHandler for ClientHandler { } ClientMsg::RequestMsgs => { let ClientState::Authed(_uid) = &*self.state.read().await else { - let _ = self.send.send(ServerError::NotLoggedIn).await; + let _ = replier.send(ServerError::NotLoggedIn).await; return; }; let msgs = self .db .msgs - .iter_all() - .map(|msg| { - let user = self - .db - .users - .get(&msg.user) - .map(|user| user.username.to_string()) - .unwrap_or("deleted user".to_string()); - LoadMsg { - content: msg.content, - user, - } + .values() + .map(|msg| LoadMsg { + content: msg.content, + author: msg.author, }) .collect(); - let _ = self.send.send(ServerMsg::LoadMsgs(msgs)).await; + let _ = replier.send(ServerMsg::LoadMsgs(msgs)).await; } ClientMsg::CreateAccount(info) => { let CreateAccount { @@ -167,28 +164,41 @@ impl RecvHandler for ClientHandler { password, login_key, } = &info; - if !self.db.usernames.init_unique(username) { - let _ = self.send.send(ServerError::UsernameTaken).await; - return; - } - let id = self.db.generate_id().unwrap(); let salt = SaltString::generate(&mut OsRng); let params = scrypt::Params::new(11, 8, 1, 32).unwrap(); let hash = Scrypt .hash_password_customized(password.as_bytes(), None, None, params, &salt) .unwrap() .to_string(); - self.db.users.insert( - &id, - &User { - username: username.clone(), - password_hash: hash, - }, - ); + let mut id; + loop { + let mut tx = self.db.write_tx(); + if tx.has_key(&self.db.usernames, username.clone()) { + let _ = replier.send(ServerError::UsernameTaken).await; + return; + } + id = rand::random(); + while tx.has_key(&self.db.users, id) { + id = rand::random(); + } + tx.insert( + &self.db.users, + &id, + &User { + username: username.clone(), + password_hash: hash.clone(), + bio: String::new(), + pfp: None, + }, + ); + tx.insert(&self.db.usernames, username, &id); + if tx.commit() { + break; + } + } println!("account created: \"{username}\""); - self.db.usernames.insert(&username, &id); *self.state.write().await = ClientState::Authed(id); - // let _ = self.send.send(ServerMsg::Login()).await; + let _ = replier.send(AccountCreated {}).await; } // ClientMsgType::Login { username, password } => { // let Some(id) = self.db.usernames.get(&username) else { // let _ = self.send.send(ServerError::UnknownUsername).await; diff --git a/src/bin/server/net.rs b/src/bin/server/net.rs index 48f04a1..9a945ba 100644 --- a/src/bin/server/net.rs +++ b/src/bin/server/net.rs @@ -1,5 +1,5 @@ use openworm::net::{ - ClientMsg, ClientMsgInst, RecvHandler, SERVER_NAME, SendResult, ServerMsg, ServerMsgInst, + ClientRequestMsg, RecvHandler, RequestId, SERVER_NAME, SendResult, ServerMsg, ServerRespMsg, recv_uni, send_uni, }; use quinn::{ @@ -63,8 +63,34 @@ impl ClientSender { pub fn remote(&self) -> SocketAddr { self.conn.remote_address() } + + pub fn replier(&self, id: RequestId) -> ClientReplier { + ClientReplier { + conn: self.conn.clone(), + req_id: id, + } + } + pub async fn send(&self, msg: impl Into) -> SendResult { - let msg = ServerMsgInst::from(msg.into()); + let msg = ServerRespMsg { + id: None, + msg: msg.into().into(), + }; + send_uni(&self.conn, msg).await + } +} + +pub struct ClientReplier { + conn: Connection, + req_id: RequestId, +} + +impl ClientReplier { + pub async fn send(&self, msg: impl Into) -> SendResult { + let msg = ServerRespMsg { + id: Some(self.req_id), + msg: msg.into().into(), + }; send_uni(&self.conn, msg).await } } @@ -73,7 +99,7 @@ pub trait ConAccepter: Send + Sync + 'static { fn accept( &self, send: ClientSender, - ) -> impl Future> + Send; + ) -> impl Future> + Send; } pub fn listen( diff --git a/src/net/data.rs b/src/net/data.rs index 72e9c49..ae12c65 100644 --- a/src/net/data.rs +++ b/src/net/data.rs @@ -17,6 +17,8 @@ pub enum ServerMsgInst { ServerErrorV0(ServerErrorV0) = 3, } +pub type UserIdV0 = u64; + #[derive(Debug, bitcode::Encode, bitcode::Decode)] pub struct CreateAccountV0 { pub username: String, @@ -56,7 +58,7 @@ pub struct SendMsgV0 { #[derive(Debug, Clone, bitcode::Encode, bitcode::Decode)] pub struct LoadMsgV0 { pub content: String, - pub user: String, + pub author: UserIdV0, } #[derive(Debug, bitcode::Encode, bitcode::Decode)] diff --git a/src/net/msg.rs b/src/net/msg.rs index 4e9861e..9230b98 100644 --- a/src/net/msg.rs +++ b/src/net/msg.rs @@ -21,6 +21,7 @@ pub type LoadMsg = LoadMsgV0; pub type ServerError = ServerErrorV0; pub type CreateAccount = CreateAccountV0; pub type AccountCreated = AccountCreatedV0; +pub type UserId = UserIdV0; impl From for ClientMsg { fn from(value: CreateAccount) -> Self { @@ -33,3 +34,15 @@ impl From for ServerMsg { Self::ServerError(value) } } + +impl From for ServerMsg { + fn from(value: LoadMsg) -> Self { + Self::LoadMsg(value) + } +} + +impl From for ServerMsg { + fn from(value: AccountCreated) -> Self { + Self::AccountCreated(value) + } +} diff --git a/src/net/request.rs b/src/net/request.rs index 10b8755..45ae483 100644 --- a/src/net/request.rs +++ b/src/net/request.rs @@ -21,12 +21,12 @@ impl RequestId { #[derive(Debug, bitcode::Encode, bitcode::Decode)] pub struct ClientRequestMsg { - pub request_id: Option, + pub id: RequestId, pub msg: ClientMsgInst, } #[derive(Debug, bitcode::Encode, bitcode::Decode)] pub struct ServerRespMsg { - pub request_id: Option, + pub id: Option, pub msg: ServerMsgInst, }