16 changed files with 266 additions and 35 deletions
@ -1 +1 @@
|
||||
DATABASE_URL="sqlite://PHOEBE_DB_ROOT/main.db" |
||||
DATABASE_URL="sqlite://${PHOEBE_DB_ROOT}/main.db" |
||||
|
@ -0,0 +1,3 @@
|
||||
fn main() { |
||||
println!("cargo:rerun-if-changed=migrations"); |
||||
} |
@ -0,0 +1,10 @@
|
||||
CREATE TABLE message_links ( |
||||
id INTEGER PRIMARY KEY AUTOINCREMENT |
||||
) STRICT; |
||||
|
||||
CREATE TABLE messages ( |
||||
link_id INTEGER NOT NULL REFERENCES message_links(id), |
||||
service TEXT NOT NULL, |
||||
channel TEXT NOT NULL, |
||||
message TEXT NOT NULL |
||||
) |
@ -0,0 +1,8 @@
|
||||
CREATE TABLE channel_links ( |
||||
from_service TEXT NOT NULL, |
||||
from_channel TEXT NOT NULL, |
||||
to_service TEXT NOT NULL, |
||||
to_channel TEXT NOT NULL, |
||||
|
||||
PRIMARY KEY (from_service, from_channel, to_service, to_channel) |
||||
) STRICT; |
@ -1,14 +1,111 @@
|
||||
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 = tokio::sync::broadcast::Sender<mid_chat::event::ChatEvent>; |
||||
pub type ChatEventReceiver = tokio::sync::broadcast::Receiver<mid_chat::event::ChatEvent>; |
||||
pub type ChatEventSender = Sender<mid_chat::event::ChatEvent>; |
||||
pub type ChatEventReceiver = Receiver<mid_chat::event::ChatEvent>; |
||||
|
||||
pub type DynServiceLookup = fn(&str) -> &'static str; |
||||
|
||||
pub async fn open_core_db() -> sqlx::Result<sqlx::SqlitePool> { |
||||
pub async fn open_core_db() -> sqlx::Result<SqlitePool> { |
||||
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<ChatReference> { |
||||
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<BoxStream<'a, ChatMessageReference>> { |
||||
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::<String, _>("service")), |
||||
id: r.get("channel"), |
||||
}, |
||||
r.get::<String, _>("message"), |
||||
) |
||||
}); |
||||
|
||||
Ok(Box::pin(stream)) |
||||
} |
||||
|
@ -1,7 +1,11 @@
|
||||
use mid_chat::event::ChatEvent; |
||||
use mid_chat::{ChatMessage, ChatMessageReference, ChatReference}; |
||||
|
||||
#[async_trait::async_trait] |
||||
pub trait Service { |
||||
fn get_service_tag(&self) -> &'static str; |
||||
async fn handle_chat_event(&mut self, event: &ChatEvent); |
||||
fn tag(&self) -> &'static str; |
||||
async fn send_chat_message( |
||||
&mut self, |
||||
source: &ChatMessage, |
||||
destination_channel: ChatReference, |
||||
) -> Vec<ChatMessageReference>; |
||||
} |
||||
|
@ -1 +1 @@
|
||||
DATABASE_URL="sqlite://PHOEBE_DB_ROOT/discord_media.db" |
||||
DATABASE_URL="sqlite://${PHOEBE_DB_ROOT}/discord_media.db" |
||||
|
@ -0,0 +1,41 @@
|
||||
use phoebe::{ |
||||
mid_chat::{ChatMessage, ChatMessageReference, ChatReference}, |
||||
prelude::Result, |
||||
}; |
||||
|
||||
use serenity::{model::prelude::*, prelude::*}; |
||||
|
||||
use crate::{chat_conv, discord_reference}; |
||||
|
||||
pub async fn send_discord_message( |
||||
context: &mut Context, |
||||
source: &ChatMessage, |
||||
destination_channel: ChatReference, |
||||
) -> Result<ChatMessageReference> { |
||||
// TODO: If we have a webhook we should use the webhook
|
||||
|
||||
let channel_id = destination_channel.id.parse::<ChannelId>()?; |
||||
let formatted_message = chat_conv::format(&source.content); |
||||
let content = format!( |
||||
"{} ({}): {}", |
||||
source.author.display_name, source.author.reference.service, formatted_message |
||||
); |
||||
|
||||
let sent_message = channel_id |
||||
.send_message(&context, move |m| { |
||||
let m = m.content(content); |
||||
if let Some(reply) = &source.replying { |
||||
let channel_id: ChannelId = reply.channel.id.parse().unwrap(); |
||||
let message_id: MessageId = reply.message_id.parse::<u64>().unwrap().into(); |
||||
m.reference_message((channel_id, message_id)) |
||||
} else { |
||||
m |
||||
} |
||||
}) |
||||
.await?; |
||||
|
||||
Ok(ChatMessageReference::new( |
||||
discord_reference(sent_message.channel_id), |
||||
sent_message.id, |
||||
)) |
||||
} |
Loading…
Reference in new issue