moved postman into separate crate
This commit is contained in:
parent
d62c8c95c2
commit
a3844dde9e
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -1073,6 +1073,22 @@ version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||
|
||||
[[package]]
|
||||
name = "postman"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"env_logger",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"num-integer",
|
||||
"regex",
|
||||
"serenity",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.16"
|
||||
@ -1228,6 +1244,7 @@ dependencies = [
|
||||
"levenshtein",
|
||||
"log",
|
||||
"num-integer",
|
||||
"postman",
|
||||
"rand 0.7.3",
|
||||
"regex",
|
||||
"regex_command_attr",
|
||||
|
@ -28,6 +28,9 @@ base64 = "0.13.0"
|
||||
[dependencies.regex_command_attr]
|
||||
path = "command_attributes"
|
||||
|
||||
[dependencies.postman]
|
||||
path = "postman"
|
||||
|
||||
[dependencies.serenity]
|
||||
git = "https://github.com/serenity-rs/serenity"
|
||||
branch = "next"
|
||||
|
32
postman/Cargo.toml
Normal file
32
postman/Cargo.toml
Normal file
@ -0,0 +1,32 @@
|
||||
[package]
|
||||
name = "postman"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1", features = ["process", "full"] }
|
||||
regex = "1.4"
|
||||
log = "0.4"
|
||||
env_logger = "0.8"
|
||||
chrono = "0.4"
|
||||
chrono-tz = { version = "0.5", features = ["serde"] }
|
||||
lazy_static = "1.4"
|
||||
num-integer = "0.1"
|
||||
sqlx = { version = "0.5.10", features = ["runtime-tokio-rustls", "macros", "mysql", "bigdecimal", "chrono"]}
|
||||
|
||||
[dependencies.serenity]
|
||||
git = "https://github.com/serenity-rs/serenity"
|
||||
branch = "next"
|
||||
default-features = false
|
||||
features = [
|
||||
"builder",
|
||||
"client",
|
||||
"cache",
|
||||
"gateway",
|
||||
"http",
|
||||
"model",
|
||||
"utils",
|
||||
"rustls_backend",
|
||||
"collector",
|
||||
"unstable_discord_api"
|
||||
]
|
33
postman/src/lib.rs
Normal file
33
postman/src/lib.rs
Normal file
@ -0,0 +1,33 @@
|
||||
mod sender;
|
||||
|
||||
use log::info;
|
||||
use serenity::client::Context;
|
||||
use sqlx::{Executor, MySql};
|
||||
use std::env;
|
||||
use tokio::time::sleep_until;
|
||||
use tokio::time::{Duration, Instant};
|
||||
|
||||
type Database = MySql;
|
||||
|
||||
pub async fn initialize(ctx: Context, pool: impl Executor<'_, Database = Database> + Copy) {
|
||||
let REMIND_INTERVAL = env::var("REMIND_INTERVAL")
|
||||
.map(|inner| inner.parse::<u64>().ok())
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or(10);
|
||||
|
||||
loop {
|
||||
let sleep_to = Instant::now() + Duration::from_secs(REMIND_INTERVAL);
|
||||
let reminders = sender::Reminder::fetch_reminders(pool).await;
|
||||
|
||||
if reminders.len() > 0 {
|
||||
info!("Preparing to send {} reminders.", reminders.len());
|
||||
|
||||
for reminder in reminders {
|
||||
reminder.send(pool, ctx.clone()).await;
|
||||
}
|
||||
}
|
||||
|
||||
sleep_until(sleep_to).await;
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
use crate::Database;
|
||||
use chrono::Duration;
|
||||
use chrono_tz::Tz;
|
||||
use lazy_static::lazy_static;
|
||||
use log::{error, info, warn};
|
||||
use num_integer::Integer;
|
||||
use regex::{Captures, Regex};
|
||||
@ -15,7 +17,7 @@ use serenity::{
|
||||
};
|
||||
use sqlx::{
|
||||
types::chrono::{NaiveDateTime, Utc},
|
||||
MySqlPool,
|
||||
Executor,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
@ -114,7 +116,10 @@ struct EmbedField {
|
||||
}
|
||||
|
||||
impl Embed {
|
||||
pub async fn from_id(pool: &MySqlPool, id: u32) -> Option<Self> {
|
||||
pub async fn from_id(
|
||||
pool: impl Executor<'_, Database = Database> + Copy,
|
||||
id: u32,
|
||||
) -> Option<Self> {
|
||||
let mut inner = sqlx::query_as_unchecked!(
|
||||
EmbedInner,
|
||||
"
|
||||
@ -135,7 +140,7 @@ WHERE
|
||||
",
|
||||
id
|
||||
)
|
||||
.fetch_one(&pool.clone())
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -265,7 +270,7 @@ pub struct Reminder {
|
||||
}
|
||||
|
||||
impl Reminder {
|
||||
pub async fn fetch_reminders(pool: &MySqlPool) -> Vec<Self> {
|
||||
pub async fn fetch_reminders(pool: impl Executor<'_, Database = Database> + Copy) -> Vec<Self> {
|
||||
sqlx::query_as_unchecked!(
|
||||
Reminder,
|
||||
"
|
||||
@ -317,7 +322,7 @@ WHERE
|
||||
.collect::<Vec<Self>>()
|
||||
}
|
||||
|
||||
async fn reset_webhook(&self, pool: &MySqlPool) {
|
||||
async fn reset_webhook(&self, pool: impl Executor<'_, Database = Database> + Copy) {
|
||||
let _ = sqlx::query!(
|
||||
"
|
||||
UPDATE channels SET webhook_id = NULL, webhook_token = NULL WHERE channel = ?
|
||||
@ -328,14 +333,15 @@ UPDATE channels SET webhook_id = NULL, webhook_token = NULL WHERE channel = ?
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn refresh(&self, pool: &MySqlPool) {
|
||||
async fn refresh(&self, pool: impl Executor<'_, Database = Database> + Copy) {
|
||||
if self.interval_seconds.is_some() || self.interval_months.is_some() {
|
||||
let now = Utc::now().naive_local();
|
||||
let mut updated_reminder_time = self.utc_time;
|
||||
|
||||
if let Some(interval) = self.interval_months {
|
||||
let row = sqlx::query!(
|
||||
"SELECT DATE_ADD(?, INTERVAL ? MONTH) AS new_time",
|
||||
// use the second date_add to force return value to datetime
|
||||
"SELECT DATE_ADD(DATE_ADD(?, INTERVAL ? MONTH), INTERVAL 0 SECOND) AS new_time",
|
||||
updated_reminder_time,
|
||||
interval
|
||||
)
|
||||
@ -373,7 +379,7 @@ UPDATE reminders SET `utc_time` = ? WHERE `id` = ?
|
||||
}
|
||||
}
|
||||
|
||||
async fn force_delete(&self, pool: &MySqlPool) {
|
||||
async fn force_delete(&self, pool: impl Executor<'_, Database = Database> + Copy) {
|
||||
sqlx::query!(
|
||||
"
|
||||
DELETE FROM reminders WHERE `id` = ?
|
||||
@ -389,7 +395,11 @@ DELETE FROM reminders WHERE `id` = ?
|
||||
let _ = http.as_ref().pin_message(self.channel_id, message_id.into(), None).await;
|
||||
}
|
||||
|
||||
pub async fn send(&self, pool: MySqlPool, cache_http: impl CacheHttp) {
|
||||
pub async fn send(
|
||||
&self,
|
||||
pool: impl Executor<'_, Database = Database> + Copy,
|
||||
cache_http: impl CacheHttp,
|
||||
) {
|
||||
async fn send_to_channel(
|
||||
cache_http: impl CacheHttp,
|
||||
reminder: &Reminder,
|
||||
@ -521,10 +531,10 @@ UPDATE `channels` SET paused = 0, paused_until = NULL WHERE `channel` = ?
|
||||
",
|
||||
self.channel_id
|
||||
)
|
||||
.execute(&pool.clone())
|
||||
.execute(pool)
|
||||
.await;
|
||||
|
||||
let embed = Embed::from_id(&pool.clone(), self.id).await.map(|e| e.into());
|
||||
let embed = Embed::from_id(pool, self.id).await.map(|e| e.into());
|
||||
|
||||
let result = if let (Some(webhook_id), Some(webhook_token)) =
|
||||
(self.webhook_id, &self.webhook_token)
|
||||
@ -537,7 +547,7 @@ UPDATE `channels` SET paused = 0, paused_until = NULL WHERE `channel` = ?
|
||||
} else {
|
||||
warn!("Webhook vanished: {:?}", webhook_res);
|
||||
|
||||
self.reset_webhook(&pool.clone()).await;
|
||||
self.reset_webhook(pool).await;
|
||||
send_to_channel(cache_http, &self, embed).await
|
||||
}
|
||||
} else {
|
||||
@ -550,20 +560,20 @@ UPDATE `channels` SET paused = 0, paused_until = NULL WHERE `channel` = ?
|
||||
if let Error::Http(error) = e {
|
||||
if error.status_code() == Some(StatusCode::from_u16(404).unwrap()) {
|
||||
error!("Seeing channel is deleted. Removing reminder");
|
||||
self.force_delete(&pool).await;
|
||||
self.force_delete(pool).await;
|
||||
} else {
|
||||
self.refresh(&pool).await;
|
||||
self.refresh(pool).await;
|
||||
}
|
||||
} else {
|
||||
self.refresh(&pool).await;
|
||||
self.refresh(pool).await;
|
||||
}
|
||||
} else {
|
||||
self.refresh(&pool).await;
|
||||
self.refresh(pool).await;
|
||||
}
|
||||
} else {
|
||||
info!("Reminder {} is paused", self.id);
|
||||
|
||||
self.refresh(&pool).await;
|
||||
self.refresh(pool).await;
|
||||
}
|
||||
}
|
||||
}
|
@ -323,7 +323,7 @@ async fn look(ctx: &Context, invoke: &mut CommandInvoke, args: CommandOptions) {
|
||||
.iter()
|
||||
.map(|reminder| reminder.display(&flags, &timezone))
|
||||
.fold(0, |t, r| t + r.len())
|
||||
.div_ceil(EMBED_DESCRIPTION_MAX_LENGTH);
|
||||
.div_ceil(&EMBED_DESCRIPTION_MAX_LENGTH);
|
||||
|
||||
let pager = LookPager::new(flags, timezone);
|
||||
|
||||
|
@ -3,6 +3,7 @@ pub(crate) mod pager;
|
||||
use std::io::Cursor;
|
||||
|
||||
use chrono_tz::Tz;
|
||||
use num_integer::Integer;
|
||||
use rmp_serde::Serializer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serenity::{
|
||||
@ -78,7 +79,7 @@ impl ComponentDataModel {
|
||||
.iter()
|
||||
.map(|reminder| reminder.display(&flags, &pager.timezone))
|
||||
.fold(0, |t, r| t + r.len())
|
||||
.div_ceil(EMBED_DESCRIPTION_MAX_LENGTH);
|
||||
.div_ceil(&EMBED_DESCRIPTION_MAX_LENGTH);
|
||||
|
||||
let channel_name =
|
||||
if let Some(Channel::Guild(channel)) = channel_id.to_channel_cached(&ctx) {
|
||||
|
@ -14,11 +14,6 @@ use regex::Regex;
|
||||
use serenity::model::prelude::AttachmentType;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref REMIND_INTERVAL: u64 = env::var("REMIND_INTERVAL")
|
||||
.map(|inner| inner.parse::<u64>().ok())
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or(10);
|
||||
pub static ref DEFAULT_AVATAR: AttachmentType<'static> = (
|
||||
include_bytes!(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
|
28
src/main.rs
28
src/main.rs
@ -1,4 +1,3 @@
|
||||
#![feature(int_roundings)]
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
@ -9,7 +8,6 @@ mod framework;
|
||||
mod hooks;
|
||||
mod interval_parser;
|
||||
mod models;
|
||||
mod sender;
|
||||
mod time_parser;
|
||||
|
||||
use std::{
|
||||
@ -24,6 +22,7 @@ use std::{
|
||||
use chrono_tz::Tz;
|
||||
use dotenv::dotenv;
|
||||
use log::info;
|
||||
use postman::initialize;
|
||||
use serenity::{
|
||||
async_trait,
|
||||
client::Client,
|
||||
@ -39,15 +38,12 @@ use serenity::{
|
||||
utils::shard_id,
|
||||
};
|
||||
use sqlx::mysql::MySqlPool;
|
||||
use tokio::{
|
||||
sync::RwLock,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::{
|
||||
commands::{info_cmds, moderation_cmds, reminder_cmds, todo_cmds},
|
||||
component_models::ComponentDataModel,
|
||||
consts::{CNC_GUILD, REMIND_INTERVAL, SUBSCRIPTION_ROLES, THEME_COLOR},
|
||||
consts::{CNC_GUILD, SUBSCRIPTION_ROLES, THEME_COLOR},
|
||||
framework::RegexFramework,
|
||||
models::command_macro::CommandMacro,
|
||||
};
|
||||
@ -88,24 +84,10 @@ impl EventHandler for Handler {
|
||||
|
||||
if !self.is_loop_running.load(Ordering::Relaxed) {
|
||||
let ctx = ctx_base.clone();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let pool = ctx.data.read().await.get::<SQLPool>().cloned().unwrap();
|
||||
|
||||
loop {
|
||||
let sleep_until = Instant::now() + Duration::from_secs(*REMIND_INTERVAL);
|
||||
let reminders = sender::Reminder::fetch_reminders(&pool).await;
|
||||
|
||||
if reminders.len() > 0 {
|
||||
info!("Preparing to send {} reminders.", reminders.len());
|
||||
|
||||
for reminder in reminders {
|
||||
reminder.send(pool.clone(), ctx.clone()).await;
|
||||
}
|
||||
}
|
||||
|
||||
tokio::time::sleep_until(sleep_until).await;
|
||||
}
|
||||
tokio::spawn(async move {
|
||||
initialize(ctx, &pool).await;
|
||||
});
|
||||
|
||||
self.is_loop_running.swap(true, Ordering::Relaxed);
|
||||
|
8
web/Cargo.toml
Normal file
8
web/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "web"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
8
web/src/lib.rs
Normal file
8
web/src/lib.rs
Normal file
@ -0,0 +1,8 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = 2 + 2;
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user