Expire calls where one of both parties doesn't talk for 10 minutes.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use async_trait::async_trait;
|
||||
use deadpool_redis::redis::AsyncTypedCommands;
|
||||
use scc::HashSet;
|
||||
use time::UtcDateTime;
|
||||
use twilight_model::id::Id;
|
||||
|
||||
use crate::{
|
||||
@@ -115,12 +117,32 @@ impl Command<State, Extras> for CallCommand {
|
||||
))
|
||||
.await
|
||||
.bye();
|
||||
|
||||
ctx.rt
|
||||
.http
|
||||
.create_message(Id::new(call.other_party_channel_id(channel.id)))
|
||||
.content(&format!("☎️ {}", get_string_call_answered(ctx.prefix)))
|
||||
.await
|
||||
.bye();
|
||||
|
||||
let mut redis = ctx.rt.state.redis.get().await?;
|
||||
|
||||
let timestamp = UtcDateTime::now().unix_timestamp();
|
||||
|
||||
redis
|
||||
.zadd(
|
||||
"active-calls",
|
||||
format!("{}:{}", call.id, channel.id),
|
||||
timestamp,
|
||||
)
|
||||
.await?;
|
||||
redis
|
||||
.zadd(
|
||||
"active-calls",
|
||||
format!("{}:{}", call.id, call.other_party_channel_id(channel.id)),
|
||||
timestamp,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
ctx.send()
|
||||
.content(format!(
|
||||
@@ -215,6 +237,19 @@ impl Command<State, Extras> for SkipCommand {
|
||||
log::error!("Failed to send message to other party: {e:?}");
|
||||
})?;
|
||||
|
||||
let mut redis = ctx.rt.state.redis.get().await?;
|
||||
|
||||
let channel_keys = [
|
||||
format!("{}:{}", call.id, call.channel_ids[0]),
|
||||
format!("{}:{}", call.id, call.channel_ids[1]),
|
||||
];
|
||||
|
||||
redis
|
||||
.zrem("active-calls", &channel_keys)
|
||||
.await
|
||||
.inspect_err(|e| log::error!("Failed to remove inactive call from redis: {e}"))
|
||||
.ok();
|
||||
|
||||
let call = Call::start(&channel, &ctx.rt.state.db)
|
||||
.await
|
||||
.inspect_err(|e| {
|
||||
@@ -236,6 +271,25 @@ impl Command<State, Extras> for SkipCommand {
|
||||
.content(&format!("☎️ {}", get_string_call_answered(ctx.prefix)))
|
||||
.await
|
||||
.bye();
|
||||
|
||||
let mut redis = ctx.rt.state.redis.get().await?;
|
||||
|
||||
let timestamp = UtcDateTime::now().unix_timestamp();
|
||||
|
||||
redis
|
||||
.zadd(
|
||||
"active-calls",
|
||||
format!("{}:{}", call.id, channel.id),
|
||||
timestamp,
|
||||
)
|
||||
.await?;
|
||||
redis
|
||||
.zadd(
|
||||
"active-calls",
|
||||
format!("{}:{}", call.id, call.other_party_channel_id(channel.id)),
|
||||
timestamp,
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
ctx.send()
|
||||
.content(format!(
|
||||
@@ -304,6 +358,8 @@ impl Command<State, Extras> for HangupCommand {
|
||||
}
|
||||
|
||||
if let Some(call_id) = channel.call_id {
|
||||
let mut redis = ctx.rt.state.redis.get().await?;
|
||||
|
||||
let Some(call) = Call::get_by_id(call_id, &ctx.rt.state.db)
|
||||
.await
|
||||
.inspect_err(|e| log::error!("Failed to get call: {e:?}"))?
|
||||
@@ -311,11 +367,27 @@ impl Command<State, Extras> for HangupCommand {
|
||||
ctx.send().content("❌ The call could not be found.\n-# This is not supposed to happen. If the issue persists, contact a moderator in the official server.").await?;
|
||||
|
||||
channel.call_id = None;
|
||||
channel.upsert(&ctx.rt.state.db).await?;
|
||||
channel.upsert(&ctx.rt.state.db).await.bye();
|
||||
|
||||
redis
|
||||
.zrem("active-calls", format!("{}:{}", call_id, channel.id))
|
||||
.await
|
||||
.bye();
|
||||
|
||||
return Err(CommandError::DatabaseInconsistentState);
|
||||
};
|
||||
|
||||
let channel_keys = [
|
||||
format!("{call_id}:{}", call.channel_ids[0]),
|
||||
format!("{call_id}:{}", call.channel_ids[1]),
|
||||
];
|
||||
|
||||
redis
|
||||
.zrem("active-calls", &channel_keys)
|
||||
.await
|
||||
.inspect_err(|e| log::error!("Failed to remove inactive call from redis: {e}"))
|
||||
.ok();
|
||||
|
||||
call.hangup(&ctx.rt.state.db)
|
||||
.await
|
||||
.inspect_err(|e| log::error!("Failed to hang up call: {e:?}"))?;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::{error::Error, sync::Arc};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use deadpool_redis::redis::AsyncTypedCommands;
|
||||
use itertools::Itertools;
|
||||
use time::{Duration, UtcDateTime};
|
||||
use twilight_http::{api_error::ApiError, error::ErrorType};
|
||||
@@ -353,15 +354,13 @@ impl OnMessageHandler<State, Extras> for CallMessageHandler {
|
||||
.icon_url(ImageSource::url(avatar_url).unwrap())
|
||||
.url(message_link),
|
||||
)
|
||||
.color(
|
||||
if replying_to.data.author_mask.is_some() {
|
||||
COLOR_WHITE
|
||||
} else {
|
||||
replying_to_user
|
||||
.color(if replying_to.data.author_mask.is_some() {
|
||||
COLOR_WHITE
|
||||
} else {
|
||||
replying_to_user
|
||||
.and_then(|i| i.color.map(|c| c as u32))
|
||||
.unwrap_or(COLOR_WHITE)
|
||||
}
|
||||
)
|
||||
})
|
||||
.description(ellipse(replying_to.data.content, 100))
|
||||
.build(),
|
||||
);
|
||||
@@ -393,6 +392,16 @@ impl OnMessageHandler<State, Extras> for CallMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
let mut redis = rt.state.redis.get().await?;
|
||||
|
||||
redis
|
||||
.zadd(
|
||||
"active-calls",
|
||||
format!("{}:{}", call.id, channel.id),
|
||||
UtcDateTime::now().unix_timestamp(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let message_sent = match rt
|
||||
.http
|
||||
.execute_webhook(Id::new(webhook_id), &webhook_token)
|
||||
|
||||
@@ -8,3 +8,4 @@ pub mod masks;
|
||||
pub(super) mod moderation;
|
||||
pub(super) mod permissions;
|
||||
pub(super) mod strings;
|
||||
pub mod tasks;
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
use async_trait::async_trait;
|
||||
use deadpool_redis::redis::AsyncTypedCommands;
|
||||
use time::{Duration, UtcDateTime};
|
||||
use twilight_model::id::Id;
|
||||
|
||||
use crate::{
|
||||
database::models::Call,
|
||||
extras::Extras,
|
||||
framework::{runtime::Runtime, tasks::Task},
|
||||
state::State,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EndInactiveCallsTask {
|
||||
pub current_shard: u32,
|
||||
pub total_shards: u32,
|
||||
}
|
||||
|
||||
impl EndInactiveCallsTask {
|
||||
pub fn new(current_shard: u32, total_shards: u32) -> Self {
|
||||
Self {
|
||||
current_shard,
|
||||
total_shards,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Task<State, Extras> for EndInactiveCallsTask {
|
||||
fn delay(&self) -> std::time::Duration {
|
||||
std::time::Duration::from_secs(5)
|
||||
}
|
||||
|
||||
async fn run(&self, rt: &Runtime<State, Extras>) -> anyhow::Result<()> {
|
||||
let mut redis = rt.state.redis.get().await?;
|
||||
|
||||
let calls_and_channels = redis
|
||||
.zrangebyscore(
|
||||
"active-calls",
|
||||
0,
|
||||
(UtcDateTime::now() - Duration::minutes(10)).unix_timestamp(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut ended_call_ids = Vec::new();
|
||||
|
||||
for (call_id, channel_id) in calls_and_channels.iter().filter_map(|i| {
|
||||
i.split_once(":").and_then(|(a, b)| {
|
||||
let a = a.parse::<u64>().ok();
|
||||
let b = b.parse::<u64>().ok();
|
||||
|
||||
a.zip(b)
|
||||
})
|
||||
}) {
|
||||
if ended_call_ids.contains(&call_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (call_id) % self.total_shards as u64 != self.current_shard as u64 {
|
||||
continue;
|
||||
}
|
||||
|
||||
ended_call_ids.push(call_id);
|
||||
|
||||
let Ok(Some(call)) = Call::get_by_id(call_id, &rt.state.db).await else {
|
||||
redis
|
||||
.zrem("active-calls", format!("{call_id}:{channel_id}"))
|
||||
.await
|
||||
.inspect_err(|e| log::error!("Failed to remove inactive call from redis: {e}"))
|
||||
.ok();
|
||||
|
||||
continue;
|
||||
};
|
||||
|
||||
let channel_keys = [
|
||||
format!("{call_id}:{}", call.channel_ids[0]),
|
||||
format!("{call_id}:{}", call.channel_ids[1]),
|
||||
];
|
||||
|
||||
redis
|
||||
.zrem("active-calls", &channel_keys)
|
||||
.await
|
||||
.inspect_err(|e| log::error!("Failed to remove inactive call from redis: {e}"))
|
||||
.ok();
|
||||
|
||||
call.hangup(&rt.state.db)
|
||||
.await
|
||||
.inspect_err(|e| log::error!("Failed to hangup inactive call {call_id}: {e}"))
|
||||
.ok();
|
||||
|
||||
for channel_id in call.channel_ids {
|
||||
rt.http
|
||||
.create_message(Id::new(channel_id))
|
||||
.content("☎️ The call was hung up because one or both parties were gone for too long.")
|
||||
.await
|
||||
.inspect_err(|e| {
|
||||
log::error!("Failed to send call end message to channel {channel_id}: {e}")
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user