pub mod events;
use actix::{Context, Handler, ResponseFuture};
use tracing::instrument;
use crate::persistence::events::{ChannelCreated, ChannelJoined, ChannelParted, FetchUserChannels};
pub struct Persistence {
pub database: sqlx::Pool<sqlx::Any>,
}
impl actix::Supervised for Persistence {}
impl actix::Actor for Persistence {
type Context = Context<Self>;
}
impl Handler<ChannelCreated> for Persistence {
type Result = ResponseFuture<()>;
fn handle(&mut self, msg: ChannelCreated, _ctx: &mut Self::Context) -> Self::Result {
let conn = self.database.clone();
Box::pin(async move {
sqlx::query("INSERT OR IGNORE INTO channels (name) VALUES (?)")
.bind(msg.name)
.execute(&conn)
.await
.unwrap();
})
}
}
impl Handler<ChannelJoined> for Persistence {
type Result = ResponseFuture<()>;
#[instrument(parent = &msg.span, skip_all)]
fn handle(&mut self, msg: ChannelJoined, _ctx: &mut Self::Context) -> Self::Result {
let conn = self.database.clone();
Box::pin(async move {
sqlx::query(
"INSERT INTO channel_users (channel, user, permissions, in_channel)
VALUES ((SELECT id FROM channels WHERE name = ?), (SELECT id FROM users WHERE username = ?), ?, ?)
ON CONFLICT(channel, user) DO UPDATE SET in_channel = excluded.in_channel"
)
.bind(msg.channel_name)
.bind(msg.username)
.bind(0i32)
.bind(true)
.execute(&conn)
.await
.unwrap();
})
}
}
impl Handler<ChannelParted> for Persistence {
type Result = ResponseFuture<()>;
#[instrument(parent = &msg.span, skip_all)]
fn handle(&mut self, msg: ChannelParted, _ctx: &mut Self::Context) -> Self::Result {
let conn = self.database.clone();
Box::pin(async move {
sqlx::query(
"UPDATE channel_users
SET in_channel = false
WHERE channel = (SELECT id FROM channels WHERE name = ?)
AND user = (SELECT id FROM users WHERE username = ?)",
)
.bind(msg.channel_name)
.bind(msg.username)
.execute(&conn)
.await
.unwrap();
})
}
}
impl Handler<FetchUserChannels> for Persistence {
type Result = ResponseFuture<Vec<String>>;
fn handle(&mut self, msg: FetchUserChannels, _ctx: &mut Self::Context) -> Self::Result {
let conn = self.database.clone();
Box::pin(async move {
sqlx::query_as(
"SELECT channels.name
FROM channel_users
INNER JOIN channels
ON channels.id = channel_users.channel
WHERE user = (SELECT id FROM users WHERE username = ?)
AND in_channel = true",
)
.bind(msg.username)
.fetch_all(&conn)
.await
.unwrap()
.into_iter()
.map(|(v,)| v)
.collect()
})
}
}