mod commands;
pub mod events;
use crate::server::Server;
use std::{collections::HashMap, hash::Hash, sync::Arc};
use actix::{
io::{FramedWrite, WriteHandler},
prelude::*,
};
use derive_more::Deref;
use std::time::{Duration, Instant};
use titanirc_types::{
protocol::commands::{JoinCommand, PrivmsgCommand},
protocol::primitives::{Channel, FreeText, Nick, Receiver},
protocol::replies::Source,
protocol::ServerMessage,
RegisteredNick,
};
use tokio::{io::WriteHalf, net::TcpStream};
use uuid::Uuid;
use super::channel::ChannelName;
#[derive(Debug, Deref, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[allow(clippy::module_name_repetitions)]
pub struct UserUuid(Uuid);
pub struct User {
pub session_id: UserUuid,
pub server: Addr<Server>,
pub writer: FramedWrite<
WriteHalf<TcpStream>,
titanirc_codec::Encoder,
<titanirc_codec::Encoder as tokio_util::codec::Encoder<ServerMessage<'static>>>::Error,
>,
pub last_active: Instant,
pub nick: RegisteredNick,
pub channels: HashMap<ChannelName, crate::entities::channel::Handle>,
}
impl User {
pub fn new(
server: Addr<Server>,
writer: FramedWrite<WriteHalf<TcpStream>, titanirc_codec::Encoder>,
nick: RegisteredNick,
) -> Self {
Self {
session_id: UserUuid(Uuid::new_v4()),
server,
writer,
last_active: Instant::now(),
nick,
channels: HashMap::new(),
}
}
}
fn schedule_ping(ctx: &mut <User as Actor>::Context) {
ctx.run_later(Duration::from_secs(30), |act, ctx| {
if Instant::now().duration_since(act.last_active) > Duration::from_secs(240) {
ctx.stop();
}
act.writer
.write(titanirc_types::protocol::ServerMessage::Ping);
schedule_ping(ctx);
});
}
impl Actor for User {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
schedule_ping(ctx);
}
}
impl WriteHandler<std::io::Error> for User {}
impl actix::Handler<crate::entities::channel::Handle> for User {
type Result = ();
fn handle(
&mut self,
msg: crate::entities::channel::Handle,
_ctx: &mut Self::Context,
) -> Self::Result {
self.channels.insert(msg.channel_name.clone(), msg);
}
}
impl actix::Handler<Arc<super::channel::events::Join>> for User {
type Result = ();
fn handle(
&mut self,
msg: Arc<super::channel::events::Join>,
_ctx: &mut Self::Context,
) -> Self::Result {
self.writer.write(ServerMessage::Command(
Source::User(Nick((*msg.nick.load().unwrap()).clone().into())),
JoinCommand {
_phantom: std::marker::PhantomData,
channel: Channel((&msg.channel_name[..]).into()),
}
.into(),
));
}
}
impl actix::Handler<Arc<super::common_events::ChannelMessage>> for User {
type Result = ();
fn handle(
&mut self,
msg: Arc<super::common_events::ChannelMessage>,
_ctx: &mut Self::Context,
) -> Self::Result {
self.writer.write(ServerMessage::Command(
Source::User(Nick((*msg.0.from.load().unwrap()).clone().into())),
PrivmsgCommand {
_phantom: std::marker::PhantomData,
free_text: FreeText(msg.0.message.as_bytes().into()),
receiver: Receiver::Channel(msg.0.to.clone()),
}
.into(),
));
}
}
impl actix::Handler<Arc<super::common_events::UserMessage>> for User {
type Result = ();
fn handle(
&mut self,
msg: Arc<super::common_events::UserMessage>,
_ctx: &mut Self::Context,
) -> Self::Result {
self.writer.write(ServerMessage::Command(
Source::User(Nick((*msg.0.from.load().unwrap()).clone().into())),
PrivmsgCommand {
_phantom: std::marker::PhantomData,
free_text: FreeText(msg.0.message.as_bytes().into()),
receiver: Receiver::User(msg.0.to.clone()),
}
.into(),
));
}
}