use futures::stream::BoxStream; pub use mid_chat; use mid_chat::{ChatMessageReference, ChatReference}; use sqlx::{Row, SqliteConnection, SqlitePool}; use tokio::sync::broadcast::*; use tokio_stream::StreamExt; pub mod db; pub mod prelude; pub mod service; pub type ChatEventSender = Sender; pub type ChatEventReceiver = Receiver; pub type DynServiceLookup = fn(&str) -> &'static str; pub async fn open_core_db() -> sqlx::Result { let db = db::open("main").await?; sqlx::migrate!().run(&db).await?; Ok(db) } pub async fn get_linked_channels( conn: &mut SqliteConnection, channel: &ChatReference, dyn_service: DynServiceLookup, ) -> Vec { let from_service = channel.service; let from_channel = &channel.id; let query = sqlx::query!( "SELECT * FROM channel_links WHERE from_service = ? AND from_channel = ?", from_service, from_channel ); query .fetch(&mut *conn) .filter_map(Result::ok) .map(|r| ChatReference { service: dyn_service(&r.to_service), id: r.to_channel, }) .collect() .await } pub async fn link_messages( conn: &mut SqliteConnection, origin: &ChatMessageReference, messages: &[ChatMessageReference], ) -> sqlx::Result<()> { let message_link = sqlx::query!("INSERT INTO message_links DEFAULT VALUES") .execute(&mut *conn) .await? .last_insert_rowid(); for resultant in std::iter::once(origin).chain(messages) { let service = &resultant.channel.service; let channel = &resultant.channel.id; let message = &resultant.message_id; let query = sqlx::query!( "INSERT INTO messages VALUES (?, ?, ?, ?)", message_link, service, channel, message ); let _ = query.execute(&mut *conn).await?; } Ok(()) } pub async fn get_linked_messages<'a>( conn: &'a mut SqliteConnection, message: &ChatMessageReference, dyn_service: DynServiceLookup, ) -> sqlx::Result> { let link_id = { let service = &message.channel.service; let channel = &message.channel.id; let message_id = &message.message_id; let query = sqlx::query!( "SELECT link_id FROM messages WHERE service = ? AND channel = ? AND message = ?", service, channel, message_id ); query.fetch_one(&mut *conn).await }? .link_id; let stream = sqlx::query("SELECT * FROM messages WHERE link_id = ?") .bind(link_id) .fetch(&mut *conn) .filter_map(Result::ok) .map(move |r| { ChatMessageReference::new( ChatReference { service: dyn_service(&r.get::("service")), id: r.get("channel"), }, r.get::("message"), ) }); Ok(Box::pin(stream)) }