forked from lavina/lavina
handle irc join commands
This commit is contained in:
parent
ae27c04b0a
commit
20b461e81c
|
@ -25,8 +25,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Opaque player identifier.
|
/// Opaque player identifier.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct PlayerId(u64);
|
pub struct PlayerId(pub ByteVec);
|
||||||
|
|
||||||
/// Handle to a player actor.
|
/// Handle to a player actor.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -40,15 +40,6 @@ impl PlayerHandle {
|
||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_room(&mut self) {
|
|
||||||
match self.tx.send(PlayerCommand::CreateRoom).await {
|
|
||||||
Ok(_) => {}
|
|
||||||
Err(_) => {
|
|
||||||
panic!("unexpected err");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send_message(&mut self, room_id: RoomId, body: String) {
|
pub async fn send_message(&mut self, room_id: RoomId, body: String) {
|
||||||
self.tx
|
self.tx
|
||||||
.send(PlayerCommand::SendMessage { room_id, body })
|
.send(PlayerCommand::SendMessage { room_id, body })
|
||||||
|
@ -79,7 +70,6 @@ enum PlayerCommand {
|
||||||
AddSocket {
|
AddSocket {
|
||||||
sender: Sender<Updates>,
|
sender: Sender<Updates>,
|
||||||
},
|
},
|
||||||
CreateRoom,
|
|
||||||
JoinRoom {
|
JoinRoom {
|
||||||
room_id: RoomId,
|
room_id: RoomId,
|
||||||
},
|
},
|
||||||
|
@ -106,7 +96,6 @@ impl PlayerRegistry {
|
||||||
IntGauge::new("chat_players_active", "Number of alive player actors")?;
|
IntGauge::new("chat_players_active", "Number of alive player actors")?;
|
||||||
metrics.register(Box::new(metric_active_players.clone()))?;
|
metrics.register(Box::new(metric_active_players.clone()))?;
|
||||||
let inner = PlayerRegistryInner {
|
let inner = PlayerRegistryInner {
|
||||||
next_id: PlayerId(0),
|
|
||||||
room_registry,
|
room_registry,
|
||||||
players: HashMap::new(),
|
players: HashMap::new(),
|
||||||
metric_active_players,
|
metric_active_players,
|
||||||
|
@ -114,23 +103,20 @@ impl PlayerRegistry {
|
||||||
Ok(PlayerRegistry(Arc::new(RwLock::new(inner))))
|
Ok(PlayerRegistry(Arc::new(RwLock::new(inner))))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_player(&mut self) -> (PlayerId, PlayerHandle) {
|
pub async fn get_or_create_player(&mut self, id: PlayerId) -> PlayerHandle {
|
||||||
let player = Player {
|
let player = Player {
|
||||||
sockets: AnonTable::new(),
|
sockets: AnonTable::new(),
|
||||||
};
|
};
|
||||||
let mut inner = self.0.write().unwrap();
|
let mut inner = self.0.write().unwrap();
|
||||||
let id = inner.next_id;
|
let (handle, fiber) = player.launch(id.clone(), inner.room_registry.clone());
|
||||||
inner.next_id.0 += 1;
|
|
||||||
let (handle, fiber) = player.launch(id, inner.room_registry.clone());
|
|
||||||
inner.players.insert(id, (handle.clone(), fiber));
|
inner.players.insert(id, (handle.clone(), fiber));
|
||||||
inner.metric_active_players.inc();
|
inner.metric_active_players.inc();
|
||||||
(id, handle)
|
handle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The player registry state representation.
|
/// The player registry state representation.
|
||||||
struct PlayerRegistryInner {
|
struct PlayerRegistryInner {
|
||||||
next_id: PlayerId,
|
|
||||||
room_registry: RoomRegistry,
|
room_registry: RoomRegistry,
|
||||||
players: HashMap<PlayerId, (PlayerHandle, JoinHandle<Player>)>,
|
players: HashMap<PlayerId, (PlayerHandle, JoinHandle<Player>)>,
|
||||||
metric_active_players: IntGauge,
|
metric_active_players: IntGauge,
|
||||||
|
@ -155,25 +141,15 @@ impl Player {
|
||||||
PlayerCommand::AddSocket { sender } => {
|
PlayerCommand::AddSocket { sender } => {
|
||||||
self.sockets.insert(sender);
|
self.sockets.insert(sender);
|
||||||
}
|
}
|
||||||
PlayerCommand::CreateRoom => {
|
|
||||||
let (room_id, room_handle) = rooms.create_room();
|
|
||||||
}
|
|
||||||
PlayerCommand::JoinRoom { room_id } => {
|
PlayerCommand::JoinRoom { room_id } => {
|
||||||
let room = rooms.get_room(room_id);
|
let mut room = rooms.get_or_create_room(room_id);
|
||||||
match room {
|
room.subscribe(player_id.clone(), handle.clone()).await;
|
||||||
Some(mut room) => {
|
|
||||||
room.subscribe(player_id, handle.clone()).await;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
tracing::info!("no room found");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PlayerCommand::SendMessage { room_id, body } => {
|
PlayerCommand::SendMessage { room_id, body } => {
|
||||||
let room = rooms.get_room(room_id);
|
let room = rooms.get_room(room_id);
|
||||||
match room {
|
match room {
|
||||||
Some(mut room) => {
|
Some(mut room) => {
|
||||||
room.send_message(player_id, body).await;
|
room.send_message(player_id.clone(), body).await;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
tracing::info!("no room found");
|
tracing::info!("no room found");
|
||||||
|
@ -189,7 +165,7 @@ impl Player {
|
||||||
for socket in &self.sockets {
|
for socket in &self.sockets {
|
||||||
socket
|
socket
|
||||||
.send(Updates::NewMessage {
|
.send(Updates::NewMessage {
|
||||||
room_id,
|
room_id: room_id.clone(),
|
||||||
body: body.clone(),
|
body: body.clone(),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
|
@ -14,8 +14,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Opaque room id
|
/// Opaque room id
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct RoomId(pub u64);
|
pub struct RoomId(pub ByteVec);
|
||||||
|
|
||||||
/// Shared datastructure for storing metadata about rooms.
|
/// Shared datastructure for storing metadata about rooms.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -26,23 +26,21 @@ impl RoomRegistry {
|
||||||
IntGauge::new("chat_rooms_active", "Number of alive room actors")?;
|
IntGauge::new("chat_rooms_active", "Number of alive room actors")?;
|
||||||
metrics.register(Box::new(metric_active_rooms.clone()))?;
|
metrics.register(Box::new(metric_active_rooms.clone()))?;
|
||||||
let inner = RoomRegistryInner {
|
let inner = RoomRegistryInner {
|
||||||
next_room_id: RoomId(0),
|
|
||||||
rooms: HashMap::new(),
|
rooms: HashMap::new(),
|
||||||
metric_active_rooms,
|
metric_active_rooms,
|
||||||
};
|
};
|
||||||
Ok(RoomRegistry(Arc::new(RwLock::new(inner))))
|
Ok(RoomRegistry(Arc::new(RwLock::new(inner))))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_room(&mut self) -> (RoomId, RoomHandle) {
|
pub fn get_or_create_room(&mut self, room_id: RoomId) -> RoomHandle {
|
||||||
let room = Room {
|
let room = Room {
|
||||||
subscriptions: HashMap::new(),
|
subscriptions: HashMap::new(),
|
||||||
};
|
};
|
||||||
let mut inner = self.0.write().unwrap();
|
let mut inner = self.0.write().unwrap();
|
||||||
let room_id = inner.next_room_id;
|
let (room_handle, fiber) = room.launch(room_id.clone());
|
||||||
inner.next_room_id.0 += 1;
|
|
||||||
let (room_handle, fiber) = room.launch(room_id);
|
|
||||||
inner.rooms.insert(room_id, (room_handle.clone(), fiber));
|
inner.rooms.insert(room_id, (room_handle.clone(), fiber));
|
||||||
(room_id, room_handle)
|
inner.metric_active_rooms.inc();
|
||||||
|
room_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_room(&self, room_id: RoomId) -> Option<RoomHandle> {
|
pub fn get_room(&self, room_id: RoomId) -> Option<RoomHandle> {
|
||||||
|
@ -53,7 +51,6 @@ impl RoomRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RoomRegistryInner {
|
struct RoomRegistryInner {
|
||||||
next_room_id: RoomId,
|
|
||||||
rooms: HashMap<RoomId, (RoomHandle, JoinHandle<Room>)>,
|
rooms: HashMap<RoomId, (RoomHandle, JoinHandle<Room>)>,
|
||||||
metric_active_rooms: IntGauge,
|
metric_active_rooms: IntGauge,
|
||||||
}
|
}
|
||||||
|
@ -111,7 +108,8 @@ impl Room {
|
||||||
RoomCommand::SendMessage { player_id, body } => {
|
RoomCommand::SendMessage { player_id, body } => {
|
||||||
tracing::info!("Adding a message to room");
|
tracing::info!("Adding a message to room");
|
||||||
for (_, sub) in &mut self.subscriptions {
|
for (_, sub) in &mut self.subscriptions {
|
||||||
sub.receive_message(room_id, player_id, body.clone()).await;
|
sub.receive_message(room_id.clone(), player_id.clone(), body.clone())
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,3 +9,5 @@ pub mod log {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, anyhow::Error>;
|
pub type Result<T> = std::result::Result<T, anyhow::Error>;
|
||||||
|
|
||||||
|
pub type ByteVec = Vec<u8>;
|
||||||
|
|
|
@ -7,10 +7,12 @@ use tokio::net::tcp::{ReadHalf, WriteHalf};
|
||||||
use tokio::net::{TcpListener, TcpStream};
|
use tokio::net::{TcpListener, TcpStream};
|
||||||
use tokio::sync::oneshot::channel;
|
use tokio::sync::oneshot::channel;
|
||||||
|
|
||||||
use crate::core::player::PlayerRegistry;
|
use crate::core::player::{PlayerId, PlayerRegistry};
|
||||||
|
use crate::core::room::RoomId;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::protos::irc::client::{client_message, ClientMessage};
|
use crate::protos::irc::client::{client_message, ClientMessage};
|
||||||
use crate::protos::irc::server::{ServerMessage, ServerMessageBody};
|
use crate::protos::irc::server::{ServerMessage, ServerMessageBody};
|
||||||
|
use crate::protos::irc::Chan;
|
||||||
use crate::util::Terminator;
|
use crate::util::Terminator;
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
@ -129,6 +131,10 @@ async fn handle_registered_socket<'a>(
|
||||||
let mut buffer = vec![];
|
let mut buffer = vec![];
|
||||||
log::info!("Handling registered user: {user:?}");
|
log::info!("Handling registered user: {user:?}");
|
||||||
|
|
||||||
|
let mut user_handle = players
|
||||||
|
.get_or_create_player(PlayerId(user.nickname.clone()))
|
||||||
|
.await;
|
||||||
|
|
||||||
ServerMessage {
|
ServerMessage {
|
||||||
tags: vec![],
|
tags: vec![],
|
||||||
sender: Some(config.server_name.as_bytes().to_vec()),
|
sender: Some(config.server_name.as_bytes().to_vec()),
|
||||||
|
@ -208,6 +214,14 @@ async fn handle_registered_socket<'a>(
|
||||||
}.write_async(&mut writer).await?;
|
}.write_async(&mut writer).await?;
|
||||||
writer.flush().await?;
|
writer.flush().await?;
|
||||||
},
|
},
|
||||||
|
ClientMessage::Join(chan) => {
|
||||||
|
match chan {
|
||||||
|
Chan::Global(room) => {
|
||||||
|
user_handle.join_room(RoomId(room.clone())).await;
|
||||||
|
},
|
||||||
|
Chan::Local(_) => {},
|
||||||
|
};
|
||||||
|
}
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,6 +23,7 @@ pub enum ClientMessage {
|
||||||
username: ByteVec,
|
username: ByteVec,
|
||||||
realname: ByteVec,
|
realname: ByteVec,
|
||||||
},
|
},
|
||||||
|
Join(Chan),
|
||||||
Quit {
|
Quit {
|
||||||
reason: ByteVec,
|
reason: ByteVec,
|
||||||
},
|
},
|
||||||
|
@ -35,6 +36,7 @@ pub fn client_message(input: &[u8]) -> IResult<&[u8], ClientMessage> {
|
||||||
client_message_pong,
|
client_message_pong,
|
||||||
client_message_nick,
|
client_message_nick,
|
||||||
client_message_user,
|
client_message_user,
|
||||||
|
client_message_join,
|
||||||
client_message_quit,
|
client_message_quit,
|
||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
@ -98,6 +100,12 @@ fn client_message_user(input: &[u8]) -> IResult<&[u8], ClientMessage> {
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
fn client_message_join(input: &[u8]) -> IResult<&[u8], ClientMessage> {
|
||||||
|
let (input, _) = tag("JOIN ")(input)?;
|
||||||
|
let (input, chan) = chan(input)?;
|
||||||
|
|
||||||
|
Ok((input, ClientMessage::Join(chan)))
|
||||||
|
}
|
||||||
|
|
||||||
fn client_message_quit(input: &[u8]) -> IResult<&[u8], ClientMessage> {
|
fn client_message_quit(input: &[u8]) -> IResult<&[u8], ClientMessage> {
|
||||||
let (input, _) = tag("QUIT :")(input)?;
|
let (input, _) = tag("QUIT :")(input)?;
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
use nom::{
|
use nom::{
|
||||||
branch::alt,
|
branch::alt,
|
||||||
bytes::complete::{tag, take, take_while},
|
bytes::complete::{tag, take, take_while},
|
||||||
|
@ -27,6 +25,7 @@ fn token(input: &[u8]) -> IResult<&[u8], &[u8]> {
|
||||||
take_while(|i| i != b'\n' && i != b'\r')(input)
|
take_while(|i| i != b'\n' && i != b'\r')(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Chan {
|
pub enum Chan {
|
||||||
/// #<name> — network-global channel, available from any server in the network.
|
/// #<name> — network-global channel, available from any server in the network.
|
||||||
Global(ByteVec),
|
Global(ByteVec),
|
||||||
|
|
Loading…
Reference in New Issue