]> git.lizzy.rs Git - dragonblocks-rs.git/blobdiff - src/server/remote_client.rs
Server: implement login
[dragonblocks-rs.git] / src / server / remote_client.rs
index 6db6eb04bd630ebb6055fe3e4fb94fdae437074f..efe03390836f74f4c62ac3c42ea8a29207eac279 100644 (file)
-use super::pkts::*;
-use super::ServerData;
-use crate::pkt;
-use crate::Quit;
-use connect::{ConnectDatagram, ConnectionReader, ConnectionWriter, StreamExt};
+use crate::{
+    pkt,
+    quit::Quit,
+    server::{pkts::*, ServerData},
+};
+use connect::{ConnectDatagram, Connection, ConnectionReader, ConnectionWriter, StreamExt};
 use log::*;
-use std::sync::Weak;
-use tokio::sync::Mutex as AsyncMutex;
-
-pub type ClientId = u64;
+use once_cell::sync::OnceCell;
+use std::{
+    fmt,
+    net::SocketAddr,
+    sync::{Arc, Weak},
+};
+use tokio::{sync::Mutex as AsyncMutex, task};
 
+#[derive(derivative::Derivative)]
+#[derivative(Debug)]
 pub struct Client {
-    pub id: ClientId,
-    pub conn: AsyncMutex<ConnectionWriter>,
-    pub server: Weak<ServerData>,
-    pub quit: Quit,
+    addr: SocketAddr,
+    data: OnceCell<ClientData>,
+
+    #[allow(unused)]
+    #[derivative(Debug = "ignore")]
+    conn: AsyncMutex<ConnectionWriter>,
+
+    #[derivative(Debug = "ignore")]
+    server: Weak<ServerData>,
+
+    #[derivative(Debug = "ignore")]
+    circle: OnceCell<Weak<Client>>,
+
+    #[derivative(Debug = "ignore")]
+    quit: Quit,
+}
+
+#[derive(Debug)]
+pub struct ClientData {
+    name: String,
 }
 
 impl Client {
+    pub async fn create(conn: Connection, server: Weak<ServerData>, quit: Quit) {
+        let addr = conn.peer_addr();
+        let (reader, writer) = conn.split();
+
+        let client = Arc::new(Self {
+            addr,
+            server,
+            quit,
+            conn: AsyncMutex::new(writer),
+            data: OnceCell::new(),
+            circle: OnceCell::new(),
+        });
+
+        client
+            .circle
+            .set(Arc::downgrade(&client))
+            .expect("OnceCell was just created");
+
+        task::spawn(async move {
+            (*client).run(reader).await;
+        });
+    }
+
     async fn login(&self, pkt: &Login) {
-        info!(
-            "Client {id}: logged in {name} {pwd}",
-            id = self.id,
-            name = pkt.name,
-            pwd = pkt.pwd
-        );
+        if let None = self.data.get() && let Some(server) = self.server.upgrade() {
+                       server
+                               .players
+                               .write()
+                               .expect("deadlock")
+                               .entry(pkt.name.clone())
+                               .or_insert_with(|| {
+                                       self.data.set(ClientData {
+                                               name: pkt.name.clone(),
+                                       }).expect("OnceCell was verified to be empty above");
+
+                                       info!("{self}: logged as {}", pkt.name);
+
+                                       self.circle
+                                               .get()
+                                               .expect("OnceCell was initialized in fn create")
+                                               .upgrade()
+                                               .expect("self can't be dropped")
+                               });
+               }
     }
 
     async fn handle(&self, msg: &ConnectDatagram) {
         match msg.recipient() {
                        LOGIN if let Some(pkt) = pkt::get::<Login>(msg) => self.login(&pkt).await,
-                       _ => warn!("Client {id}: Invalid packet with recipient {rep}",
-                               id = self.id, rep = msg.recipient()),
+                       _ => warn!("{self}: invalid packet with recipient {}", msg.recipient()),
                }
     }
 
-    pub async fn run(&self, mut reader: ConnectionReader) {
+    async fn run(&self, mut reader: ConnectionReader) {
+        info!("{self}: connected");
+
         let mut quit = self.quit.subscribe();
 
         loop {
@@ -42,23 +102,30 @@ impl Client {
                 msg = reader.next() => match msg {
                     Some(msg) => self.handle(&msg).await,
                     None => {
-                        trace!("Client {id}: Closed connection", id = self.id);
+                        trace!("{self}: closed connection");
                         break;
                     }
                 },
                 _ = quit.recv() => {
-                    trace!("Client {id}: Quit signal received", id = self.id);
+                    trace!("{self}: quit signal received");
                     break;
                 },
-                else => unreachable!("Quit channel broke"),
+                else => unreachable!("quit channel broke"),
             }
         }
 
-        if let Some(server) = self.server.upgrade() {
-            server.clients_by_id.write().unwrap().remove(&self.id);
-            trace!("Client {id}: Removed from clients", id = self.id);
-        }
+        if let Some(data) = self.data.get() && let Some(srv) = self.server.upgrade() {
+                       srv.players.write().expect("deadlock").remove(&data.name);
+
+                       trace!("{self}: removed from clients");
+               }
+
+        info!("{self}: disconnected");
+    }
+}
 
-        info!("Client {id}: Disconnected", id = self.id);
+impl fmt::Display for Client {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.addr)
     }
 }