use tokio::sync::Mutex as AsyncMutex;
pub struct Client {
- pub conn: AsyncMutex<ConnectionWriter>,
+ conn: AsyncMutex<ConnectionWriter>,
quit: Quit,
}
}
async fn handle(&self, msg: &ConnectDatagram) {
- println!("{}", msg.recipient());
+ info!("{}", msg.recipient());
}
async fn run_loop(self, mut reader: ConnectionReader) {
msg = reader.next() => match msg {
Some(msg) => self.handle(&msg).await,
None => {
- trace!("Server closed connection");
+ trace!("server closed connection");
break;
}
},
_ = quit.recv() => {
- trace!("Quit signal received");
+ trace!("quit signal received");
break;
},
- else => unreachable!("Quit channel broke"),
+ else => unreachable!("quit channel broke"),
}
}
- info!("Disconnected");
+ info!("disconnected");
}
}
use crate::quit::Quit;
use connect::{tcp::TcpListener, StreamExt};
use log::*;
-use remote_client::{Client, ClientId};
+use remote_client::Client;
use std::{
collections::HashMap,
sync::{Arc, RwLock},
};
-use tokio::{sync::Mutex as AsyncMutex, task};
+#[derive(Debug)]
pub struct ServerData {
- clients_by_id: RwLock<HashMap<ClientId, Arc<Client>>>,
- clients_by_name: RwLock<HashMap<String, Arc<Client>>>,
+ players: RwLock<HashMap<String, Arc<Client>>>,
}
pub struct Server {
quit,
listener: TcpListener::bind(addr).await.unwrap(),
data: Arc::new(ServerData {
- clients_by_id: RwLock::new(HashMap::new()),
- clients_by_name: RwLock::new(HashMap::new()),
+ players: RwLock::new(HashMap::new()),
}),
}
}
pub async fn run(mut self) {
- let mut next_id: ClientId = 0;
let mut quit = self.quit.subscribe();
loop {
tokio::select! {
- conn = self.listener.next() => {
- let conn = conn.expect("Listener interrupted");
-
- info!("Client from {} assigned id {next_id}", conn.peer_addr());
-
- let (reader, writer) = conn.split();
- let client = Arc::new(Client {
- id: next_id,
- conn: AsyncMutex::new(writer),
- server: Arc::downgrade(&self.data),
- quit: self.quit.clone(),
- });
-
- self.data
- .clients_by_id
- .write()
- .unwrap()
- .insert(next_id, Arc::clone(&client));
-
- next_id += 1;
-
- task::spawn(async move { (*client).run(reader).await });
- },
+ conn = self.listener.next() => Client::create(
+ conn.expect("listener interrupted"),
+ Arc::downgrade(&self.data),
+ self.quit.clone()
+ ).await,
_ = quit.recv() => {
- trace!("Quit signal received");
+ trace!("quit signal received");
break;
},
- else => unreachable!("Quit channel broke"),
+ else => unreachable!("quit channel broke"),
}
}
- info!("Stopped server");
+ info!("stopped server");
}
}
-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 {
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)
}
}