use crate::entities::{
channel::{Channel, ChannelName},
user::User,
};
use std::{collections::HashMap, net::SocketAddr};
use actix::{io::FramedWrite, prelude::*};
use titanirc_types::RegisteredNick;
use tokio::net::TcpStream;
use tokio_util::codec::FramedRead;
pub struct Server {
sql_pool: sqlx::SqlitePool,
pub channels: HashMap<ChannelName, Addr<Channel>>,
}
impl Server {
pub fn new(sql_pool: sqlx::SqlitePool) -> Self {
Self {
sql_pool,
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 = ();
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_name = ChannelName::new(msg.channel_name.clone());
let channel = Channel::create(|_ctx| Channel::new(channel_name.clone()));
self.channels.entry(channel_name).or_insert(channel)
};
channel.do_send(msg);
}
}
impl Handler<crate::entities::common_events::UserMessage> for Server {
type Result = ();
fn handle(
&mut self,
_msg: crate::entities::common_events::UserMessage,
_ctx: &mut Self::Context,
) -> Self::Result {
todo!()
}
}
impl Handler<events::UserAuth> for Server {
type Result = ();
fn handle(&mut self, msg: events::UserAuth, ctx: &mut Self::Context) -> Self::Result {
let conn = self.sql_pool.clone();
ctx.spawn(
async move {
match crate::models::user::User::fetch_by_nick(&conn, &msg.nick).await {
Ok(Some(user)) => {
if user.password_matches(&msg.password) {
eprintln!("user authed");
} else {
eprintln!("user not authed");
}
}
Ok(None) => {
let passwd = msg.password.clone();
if let Err(e) =
crate::models::user::User::create_user(&conn, &msg.nick, passwd).await
{
eprintln!("failed to create user: {:?}", e);
} else {
eprintln!("successfully registered");
}
}
Err(e) => {
eprintln!("failed to fetch by nick: {:?} ", e)
}
}
}
.into_actor(self),
);
}
}
pub mod events {
use actix::{Addr, Message};
use crate::entities::user::User;
#[derive(Message)]
#[rtype(result = "")]
pub struct UserAuth {
pub user: Addr<User>,
pub nick: bytes::Bytes,
pub password: bytes::Bytes,
}
#[derive(Message)]
#[rtype(result = "")]
pub enum UserAuthResponse {
Valid,
InvalidPassword,
}
}