Abstract away connection logic

This commit is contained in:
Joscha 2022-02-12 14:37:06 +01:00
parent e482ba3e05
commit 805df53699
7 changed files with 217 additions and 9 deletions

View file

@ -1,12 +1,17 @@
mod conn;
use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};
use anyhow::anyhow;
use cove_core::packets::{Cmd, HelloRpl, Packet, Rpl};
use cove_core::{Identity, MessageId, Session, SessionId};
use futures::stream::{SplitSink, SplitStream};
use futures::{future, Sink, SinkExt, Stream, StreamExt, TryStreamExt};
use rand::prelude::ThreadRng;
use rand::Rng;
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::mpsc::{self, UnboundedSender};
use tokio::sync::{self, Mutex, RwLock};
@ -26,18 +31,40 @@ struct Room {
last_timestamp: u128,
}
impl Room {
fn new() -> Self {
Self {
clients: HashMap::new(),
last_message: MessageId::of(&format!("{}", rand::thread_rng().gen::<u64>())),
last_timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("executed after 1970")
.as_millis(),
}
}
}
#[derive(Debug, Clone)]
struct Server {
rooms: Arc<RwLock<HashMap<String, Arc<Mutex<Room>>>>>,
rooms: Arc<Mutex<HashMap<String, Arc<Mutex<Room>>>>>,
}
impl Server {
fn new() -> Self {
Self {
rooms: Arc::new(RwLock::new(HashMap::new())),
rooms: Arc::new(Mutex::new(HashMap::new())),
}
}
async fn room(&self, name: String) -> Arc<Mutex<Room>> {
self.rooms
.lock()
.await
.entry(name)
.or_insert_with(|| Arc::new(Mutex::new(Room::new())))
.clone()
}
async fn recv(rx: &mut SplitStream<WebSocketStream<TcpStream>>) -> anyhow::Result<Packet> {
loop {
let msg = rx.next().await.ok_or(anyhow!("connection closed"))??;
@ -106,7 +133,8 @@ impl Server {
&self,
tx: &mut SplitSink<WebSocketStream<TcpStream>, TkMessage>,
rx: &mut SplitStream<WebSocketStream<TcpStream>>,
) -> anyhow::Result<(String, String, Identity, u64)> {
) -> anyhow::Result<(String, Session, u64)> {
// TODO Allow multiple Hello commands until the first succeeds
let packet = Self::recv(rx).await?;
let (id, cmd) = match packet {
Packet::Cmd {
@ -127,18 +155,38 @@ impl Server {
Self::send(tx, &Packet::rpl(id, HelloRpl::InvalidNick { reason })).await?;
return Err(anyhow!("invalid identity"));
}
let identity = Identity::of(&cmd.identity);
Ok((cmd.room, cmd.nick, identity, id))
let session = Session {
id: SessionId::of(&format!("{}", rand::thread_rng().gen::<u64>())),
nick: cmd.nick,
identity: Identity::of(&cmd.identity),
};
Ok((cmd.room, session, id))
}
async fn on_conn(self, stream: TcpStream) {
// TODO Ping-pong starting from the beginning (not just after hello)
println!("Connection from {}", stream.peer_addr().unwrap());
let stream = tokio_tungstenite::accept_async(stream).await.unwrap();
let (mut tx, mut rx) = stream.split();
let (room, nick, identity, id) = match self.greet(&mut tx, &mut rx).await {
let (room, session, id) = match self.greet(&mut tx, &mut rx).await {
Ok(info) => info,
Err(_) => return,
};
let room = self.room(room).await;
let (packets, client_rx) = mpsc::unbounded_channel();
{
let mut room = room.lock().await;
packets.send(Packet::rpl(
id,
HelloRpl::Success {
you: session.clone(),
others: room.clients.values().map(|c| c.session.clone()).collect(),
last_message: room.last_message,
},
));
let client = Client { session, packets };
room.clients.insert(client.session.id, client);
}
todo!()
}
}