use crate::entities::{channel::Channel, user::User};
use std::{collections::HashMap, net::SocketAddr};
use actix::{io::FramedWrite, prelude::*};
use titanirc_types::{protocol::primitives::Receiver, RegisteredNick, UserIdent};
use tokio::net::TcpStream;
use tokio_util::codec::FramedRead;
pub struct Server {
pub channels: HashMap<String, Addr<Channel>>,
}
impl Server {
pub fn new() -> Self {
Self {
channels: HashMap::new(),
}
}
}
impl Actor for Server {
type Context = Context<Self>;
}
#[derive(Message)]
#[rtype(result = "()")]
pub struct Connection(pub TcpStream, pub SocketAddr);
impl Handler<Connection> for Server {
type Result = ();
fn handle(&mut self, Connection(stream, remote): Connection, server_ctx: &mut Self::Context) {
println!("Accepted connection from {}", remote);
User::create(move |ctx| {
let nick = RegisteredNick::new();
let (read, write) = tokio::io::split(stream);
let read = FramedRead::new(read, titanirc_codec::Decoder);
let write = FramedWrite::new(
write,
titanirc_codec::Encoder::new("my.cool.server", nick.clone()),
ctx,
);
ctx.add_stream(read);
User::new(server_ctx.address(), write, nick)
});
}
}
impl Handler<crate::entities::channel::events::Join> for Server {
type Result = ResponseActFuture<Self, crate::entities::channel::events::JoinResult>;
fn handle(
&mut self,
msg: crate::entities::channel::events::Join,
_ctx: &mut Self::Context,
) -> Self::Result {
#[allow(clippy::option_if_let_else)]
let channel = if let Some(channel) = self.channels.get(&msg.channel_name) {
channel
} else {
let channel = Channel::create(|_ctx| Channel::new());
self.channels
.entry(msg.channel_name.clone())
.or_insert(channel)
};
Box::pin(
channel
.send(msg)
.into_actor(self)
.map(|v, _, _| v.map_err(|e| e.into()).and_then(|v| v)),
)
}
}
impl Handler<crate::entities::common_events::Message> for Server {
type Result = ();
fn handle(
&mut self,
msg: crate::entities::common_events::Message,
ctx: &mut Self::Context,
) -> Self::Result {
let dest = MessageDestination::get_destination_from_receiver(&self, &msg.to).unwrap();
dest.send(ctx, msg);
}
}
pub enum MessageDestination<'a> {
User(&'a Server, Addr<User>),
Channel(&'a Server, Addr<Channel>),
}
impl<'a> MessageDestination<'a> {
pub fn get_destination_from_receiver<'b>(
server: &'a Server,
receiver: &Receiver<'b>,
) -> Option<Self> {
match receiver {
Receiver::Channel(c) => server
.channels
.get(&c.to_string())
.cloned()
.map(move |c| Self::Channel(server, c)),
Receiver::User(_u) => todo!(),
}
}
pub fn send(self, ctx: &mut Context<Server>, msg: crate::entities::common_events::Message) {
match self {
Self::Channel(actor, channel) => {
ctx.spawn(
async move {
channel.send(msg).await.unwrap();
}
.into_actor(actor),
);
}
Self::User(_actor, _u) => todo!(),
}
}
}