mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-04 04:56:49 +00:00
feat: add last message cache to gateway
This commit is contained in:
parent
15c992c572
commit
a8664665a6
10 changed files with 172 additions and 18 deletions
|
|
@ -8,7 +8,7 @@ use axum::{
|
|||
use libpk::runtime_config::RuntimeConfig;
|
||||
use serde_json::{json, to_string};
|
||||
use tracing::{error, info};
|
||||
use twilight_model::id::Id;
|
||||
use twilight_model::id::{marker::ChannelMarker, Id};
|
||||
|
||||
use crate::{
|
||||
discord::{
|
||||
|
|
@ -136,7 +136,10 @@ pub async fn run_server(cache: Arc<DiscordCache>, runtime_config: Arc<RuntimeCon
|
|||
)
|
||||
.route(
|
||||
"/guilds/:guild_id/channels/:channel_id/last_message",
|
||||
get(|| async { status_code(StatusCode::NOT_IMPLEMENTED, "".to_string()) }),
|
||||
get(|State(cache): State<Arc<DiscordCache>>, Path((_guild_id, channel_id)): Path<(u64, Id<ChannelMarker>)>| async move {
|
||||
let lm = cache.get_last_message(channel_id).await;
|
||||
status_code(StatusCode::FOUND, to_string(&lm).unwrap())
|
||||
}),
|
||||
)
|
||||
|
||||
.route(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use anyhow::format_err;
|
||||
use lazy_static::lazy_static;
|
||||
use std::sync::Arc;
|
||||
use serde::Serialize;
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use tokio::sync::RwLock;
|
||||
use twilight_cache_inmemory::{
|
||||
model::CachedMember,
|
||||
|
|
@ -8,11 +9,12 @@ use twilight_cache_inmemory::{
|
|||
traits::CacheableChannel,
|
||||
InMemoryCache, ResourceType,
|
||||
};
|
||||
use twilight_gateway::Event;
|
||||
use twilight_model::{
|
||||
channel::{Channel, ChannelType},
|
||||
guild::{Guild, Member, Permissions},
|
||||
id::{
|
||||
marker::{ChannelMarker, GuildMarker, UserMarker},
|
||||
marker::{ChannelMarker, GuildMarker, MessageMarker, UserMarker},
|
||||
Id,
|
||||
},
|
||||
};
|
||||
|
|
@ -123,16 +125,134 @@ pub fn new() -> DiscordCache {
|
|||
.build(),
|
||||
);
|
||||
|
||||
DiscordCache(cache, client, RwLock::new(Vec::new()))
|
||||
DiscordCache(
|
||||
cache,
|
||||
client,
|
||||
RwLock::new(Vec::new()),
|
||||
RwLock::new(HashMap::new()),
|
||||
)
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
pub struct CachedMessage {
|
||||
id: Id<MessageMarker>,
|
||||
referenced_message: Option<Id<MessageMarker>>,
|
||||
author_username: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize)]
|
||||
pub struct LastMessageCacheEntry {
|
||||
pub current: CachedMessage,
|
||||
pub previous: Option<CachedMessage>,
|
||||
}
|
||||
|
||||
pub struct DiscordCache(
|
||||
pub Arc<InMemoryCache>,
|
||||
pub Arc<twilight_http::Client>,
|
||||
pub RwLock<Vec<u32>>,
|
||||
pub RwLock<HashMap<Id<ChannelMarker>, LastMessageCacheEntry>>,
|
||||
);
|
||||
|
||||
impl DiscordCache {
|
||||
pub async fn get_last_message(
|
||||
&self,
|
||||
channel: Id<ChannelMarker>,
|
||||
) -> Option<LastMessageCacheEntry> {
|
||||
self.3.read().await.get(&channel).cloned()
|
||||
}
|
||||
|
||||
pub async fn update(&self, event: &twilight_gateway::Event) {
|
||||
self.0.update(event);
|
||||
|
||||
match event {
|
||||
Event::MessageCreate(m) => match self.3.write().await.entry(m.channel_id) {
|
||||
std::collections::hash_map::Entry::Occupied(mut e) => {
|
||||
let cur = e.get();
|
||||
e.insert(LastMessageCacheEntry {
|
||||
current: CachedMessage {
|
||||
id: m.id,
|
||||
referenced_message: m.referenced_message.as_ref().map(|v| v.id),
|
||||
author_username: m.author.name.clone(),
|
||||
},
|
||||
previous: Some(cur.current.clone()),
|
||||
});
|
||||
}
|
||||
std::collections::hash_map::Entry::Vacant(e) => {
|
||||
e.insert(LastMessageCacheEntry {
|
||||
current: CachedMessage {
|
||||
id: m.id,
|
||||
referenced_message: m.referenced_message.as_ref().map(|v| v.id),
|
||||
author_username: m.author.name.clone(),
|
||||
},
|
||||
previous: None,
|
||||
});
|
||||
}
|
||||
},
|
||||
Event::MessageDelete(m) => {
|
||||
self.handle_message_deletion(m.channel_id, vec![m.id]).await;
|
||||
}
|
||||
Event::MessageDeleteBulk(m) => {
|
||||
self.handle_message_deletion(m.channel_id, m.ids.clone())
|
||||
.await;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
|
||||
async fn handle_message_deletion(
|
||||
&self,
|
||||
channel_id: Id<ChannelMarker>,
|
||||
mids: Vec<Id<MessageMarker>>,
|
||||
) {
|
||||
let mut lm = self.3.write().await;
|
||||
|
||||
let Some(entry) = lm.get(&channel_id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut entry = entry.clone();
|
||||
|
||||
// if none of the deleted messages are relevant, just return
|
||||
if !mids.contains(&entry.current.id)
|
||||
&& entry
|
||||
.previous
|
||||
.clone()
|
||||
.map(|v| !mids.contains(&v.id))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// remove "previous" entry if it was deleted
|
||||
if let Some(prev) = entry.previous.clone()
|
||||
&& mids.contains(&prev.id)
|
||||
{
|
||||
entry.previous = None;
|
||||
}
|
||||
|
||||
// set "current" entry to "previous" if current entry was deleted
|
||||
// (if the "previous" entry still exists, it was not deleted)
|
||||
if let Some(prev) = entry.previous.clone()
|
||||
&& mids.contains(&entry.current.id)
|
||||
{
|
||||
entry.current = prev;
|
||||
entry.previous = None;
|
||||
}
|
||||
|
||||
// if the current entry was already deleted, but previous wasn't,
|
||||
// we would've set current to previous
|
||||
// so if current is deleted this means both current and previous have
|
||||
// been deleted
|
||||
// so just drop the cache entry here
|
||||
if mids.contains(&entry.current.id) && entry.previous.is_none() {
|
||||
lm.remove(&channel_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// ok, update the entry
|
||||
lm.insert(channel_id, entry.clone());
|
||||
}
|
||||
|
||||
pub async fn guild_permissions(
|
||||
&self,
|
||||
guild_id: Id<GuildMarker>,
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ pub async fn runner(
|
|||
cache.2.write().await.push(shard_id);
|
||||
}
|
||||
}
|
||||
cache.0.update(&event);
|
||||
cache.update(&event).await;
|
||||
|
||||
// okay, we've handled the event internally, let's send it to consumers
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ impl EventAwaiter {
|
|||
.remove(&(message.channel_id, message.author.id))
|
||||
.map(|(timeout, target, options)| {
|
||||
if let Some(options) = options
|
||||
&& !options.contains(&message.content)
|
||||
&& !options.contains(&message.content.to_lowercase())
|
||||
{
|
||||
messages.insert(
|
||||
(message.channel_id, message.author.id),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue