mirror of
https://github.com/natsukagami/youmubot.git
synced 2025-05-24 01:00:49 +00:00
osu: Introduce Env
and propagate it to other functions (#40)
This commit is contained in:
parent
94dc225b86
commit
1066f249b0
17 changed files with 598 additions and 433 deletions
|
@ -1,4 +1,5 @@
|
|||
use crate::{AppData, MemberCache, Result};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use futures_util::{
|
||||
future::{join_all, ready, FutureExt},
|
||||
|
@ -18,9 +19,11 @@ use serenity::{
|
|||
prelude::*,
|
||||
utils::MessageBuilder,
|
||||
};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use youmubot_db::DB;
|
||||
|
||||
use crate::{AppData, MemberCache, Result};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CacheAndHttp(Arc<Cache>, Arc<Http>);
|
||||
|
||||
|
@ -28,15 +31,19 @@ impl CacheAndHttp {
|
|||
pub fn from_client(client: &Client) -> Self {
|
||||
Self(client.cache.clone(), client.http.clone())
|
||||
}
|
||||
|
||||
pub fn from_context(context: &Context) -> Self {
|
||||
Self(context.cache.clone(), context.http.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl CacheHttp for CacheAndHttp {
|
||||
fn cache(&self) -> Option<&Arc<Cache>> {
|
||||
Some(&self.0)
|
||||
}
|
||||
fn http(&self) -> &Http {
|
||||
&self.1
|
||||
}
|
||||
fn cache(&self) -> Option<&Arc<Cache>> {
|
||||
Some(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// A list of assigned channels for an announcer.
|
||||
|
@ -94,23 +101,14 @@ impl MemberToChannels {
|
|||
///
|
||||
/// This struct manages the list of all Announcers, firing them in a certain interval.
|
||||
pub struct AnnouncerHandler {
|
||||
cache_http: CacheAndHttp,
|
||||
data: AppData,
|
||||
announcers: HashMap<&'static str, RwLock<Box<dyn Announcer + Send + Sync>>>,
|
||||
}
|
||||
|
||||
// Querying for the AnnouncerHandler in the internal data returns a vec of keys.
|
||||
impl TypeMapKey for AnnouncerHandler {
|
||||
type Value = Vec<&'static str>;
|
||||
}
|
||||
|
||||
/// Announcer-managing related.
|
||||
impl AnnouncerHandler {
|
||||
/// Create a new instance of the handler.
|
||||
pub fn new(client: &serenity::Client) -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
cache_http: CacheAndHttp(client.cache.clone(), client.http.clone()),
|
||||
data: client.data.clone(),
|
||||
announcers: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
@ -136,10 +134,30 @@ impl AnnouncerHandler {
|
|||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(self, client: &Client) -> AnnouncerRunner {
|
||||
let runner = AnnouncerRunner {
|
||||
cache_http: CacheAndHttp::from_client(client),
|
||||
data: client.data.clone(),
|
||||
announcers: self.announcers,
|
||||
};
|
||||
runner
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AnnouncerRunner {
|
||||
cache_http: CacheAndHttp,
|
||||
data: AppData,
|
||||
announcers: HashMap<&'static str, RwLock<Box<dyn Announcer + Send + Sync>>>,
|
||||
}
|
||||
|
||||
// Querying for the AnnouncerRunner in the internal data returns a vec of keys.
|
||||
impl TypeMapKey for AnnouncerRunner {
|
||||
type Value = Vec<&'static str>;
|
||||
}
|
||||
|
||||
/// Execution-related.
|
||||
impl AnnouncerHandler {
|
||||
impl AnnouncerRunner {
|
||||
/// Collect the list of guilds and their respective channels, by the key of the announcer.
|
||||
async fn get_guilds(data: &AppData, key: &'static str) -> Result<Vec<(GuildId, ChannelId)>> {
|
||||
let data = AnnouncerChannels::open(&*data.read().await)
|
||||
|
@ -214,7 +232,7 @@ pub async fn list_announcers(ctx: &Context, m: &Message, _: Args) -> CommandResu
|
|||
let guild_id = m.guild_id.unwrap();
|
||||
let data = &*ctx.data.read().await;
|
||||
let announcers = AnnouncerChannels::open(data);
|
||||
let channels = data.get::<AnnouncerHandler>().unwrap();
|
||||
let channels = data.get::<AnnouncerRunner>().unwrap();
|
||||
let channels = channels
|
||||
.iter()
|
||||
.filter_map(|&key| {
|
||||
|
@ -249,7 +267,7 @@ pub async fn list_announcers(ctx: &Context, m: &Message, _: Args) -> CommandResu
|
|||
pub async fn register_announcer(ctx: &Context, m: &Message, mut args: Args) -> CommandResult {
|
||||
let data = ctx.data.read().await;
|
||||
let key = args.single::<String>()?;
|
||||
let keys = data.get::<AnnouncerHandler>().unwrap();
|
||||
let keys = data.get::<AnnouncerRunner>().unwrap();
|
||||
if !keys.contains(&&key[..]) {
|
||||
m.reply(
|
||||
&ctx,
|
||||
|
@ -296,7 +314,7 @@ pub async fn register_announcer(ctx: &Context, m: &Message, mut args: Args) -> C
|
|||
pub async fn remove_announcer(ctx: &Context, m: &Message, mut args: Args) -> CommandResult {
|
||||
let data = ctx.data.read().await;
|
||||
let key = args.single::<String>()?;
|
||||
let keys = data.get::<AnnouncerHandler>().unwrap();
|
||||
let keys = data.get::<AnnouncerRunner>().unwrap();
|
||||
if !keys.contains(&key.as_str()) {
|
||||
m.reply(
|
||||
&ctx,
|
||||
|
|
|
@ -1,7 +1,24 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
/// Re-export the anyhow errors
|
||||
pub use anyhow::{anyhow as error, bail, Error, Result};
|
||||
/// Re-exporting async_trait helps with implementing Announcer.
|
||||
pub use async_trait::async_trait;
|
||||
/// Re-export useful future and stream utils
|
||||
pub use futures_util::{future, stream, FutureExt, StreamExt, TryFutureExt, TryStreamExt};
|
||||
/// Module `prelude` provides a sane set of default imports that can be used inside
|
||||
/// a Youmubot source file.
|
||||
pub use serenity::prelude::*;
|
||||
use std::sync::Arc;
|
||||
/// Re-export the spawn function
|
||||
pub use tokio::spawn as spawn_future;
|
||||
|
||||
pub use announcer::{Announcer, AnnouncerRunner};
|
||||
pub use args::{ChannelId, Duration, RoleId, UserId, UsernameArg};
|
||||
pub use debugging_ok::OkPrint;
|
||||
pub use flags::Flags;
|
||||
pub use hook::Hook;
|
||||
pub use member_cache::MemberCache;
|
||||
pub use pagination::{paginate, paginate_fn, paginate_reply, paginate_reply_fn, Paginate};
|
||||
|
||||
pub mod announcer;
|
||||
pub mod args;
|
||||
|
@ -13,26 +30,6 @@ pub mod ratelimit;
|
|||
pub mod setup;
|
||||
pub mod table_format;
|
||||
|
||||
pub use announcer::{Announcer, AnnouncerHandler};
|
||||
pub use args::{ChannelId, Duration, RoleId, UserId, UsernameArg};
|
||||
pub use flags::Flags;
|
||||
pub use hook::Hook;
|
||||
pub use member_cache::MemberCache;
|
||||
pub use pagination::{paginate, paginate_fn, paginate_reply, paginate_reply_fn, Paginate};
|
||||
|
||||
/// Re-exporting async_trait helps with implementing Announcer.
|
||||
pub use async_trait::async_trait;
|
||||
|
||||
/// Re-export the anyhow errors
|
||||
pub use anyhow::{anyhow as error, bail, Error, Result};
|
||||
pub use debugging_ok::OkPrint;
|
||||
|
||||
/// Re-export useful future and stream utils
|
||||
pub use futures_util::{future, stream, FutureExt, StreamExt, TryFutureExt, TryStreamExt};
|
||||
|
||||
/// Re-export the spawn function
|
||||
pub use tokio::spawn as spawn_future;
|
||||
|
||||
/// The global app data.
|
||||
pub type AppData = Arc<RwLock<TypeMap>>;
|
||||
|
||||
|
@ -50,8 +47,18 @@ impl TypeMapKey for SQLClient {
|
|||
type Value = youmubot_db_sql::Pool;
|
||||
}
|
||||
|
||||
/// The created base environment.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Env {
|
||||
// clients
|
||||
pub http: reqwest::Client,
|
||||
pub sql: youmubot_db_sql::Pool,
|
||||
pub members: Arc<MemberCache>,
|
||||
// databases
|
||||
// pub(crate) announcer_channels: announcer::AnnouncerChannels,
|
||||
}
|
||||
|
||||
pub mod prelude_commands {
|
||||
use crate::announcer::ANNOUNCERCOMMANDS_GROUP;
|
||||
use serenity::{
|
||||
framework::standard::{
|
||||
macros::{command, group},
|
||||
|
@ -61,6 +68,8 @@ pub mod prelude_commands {
|
|||
prelude::Context,
|
||||
};
|
||||
|
||||
use crate::announcer::ANNOUNCERCOMMANDS_GROUP;
|
||||
|
||||
#[group("Prelude")]
|
||||
#[description = "All the commands that makes the base of Youmu"]
|
||||
#[commands(ping)]
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
use std::ops::Deref;
|
||||
/// Provides a simple ratelimit lock (that only works in tokio)
|
||||
// use tokio::time::
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::Result;
|
||||
use flume::{bounded as channel, Receiver, Sender};
|
||||
use std::ops::Deref;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
/// Holds the underlying `T` in a rate-limited way.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Ratelimit<T> {
|
||||
inner: T,
|
||||
recv: Receiver<()>,
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use serenity::prelude::*;
|
||||
use std::{path::Path, time::Duration};
|
||||
|
||||
use serenity::prelude::*;
|
||||
|
||||
use crate::Env;
|
||||
|
||||
/// Set up the prelude libraries.
|
||||
///
|
||||
/// Panics on failure: Youmubot should *NOT* attempt to continue when this function fails.
|
||||
|
@ -8,8 +11,8 @@ pub async fn setup_prelude(
|
|||
db_path: impl AsRef<Path>,
|
||||
sql_path: impl AsRef<Path>,
|
||||
data: &mut TypeMap,
|
||||
) {
|
||||
// Setup the announcer DB.
|
||||
) -> Env {
|
||||
// Set up the announcer DB.
|
||||
crate::announcer::AnnouncerChannels::insert_into(
|
||||
data,
|
||||
db_path.as_ref().join("announcers.yaml"),
|
||||
|
@ -22,17 +25,25 @@ pub async fn setup_prelude(
|
|||
.expect("SQL database set up");
|
||||
|
||||
// Set up the HTTP client.
|
||||
data.insert::<crate::HTTPClient>(
|
||||
reqwest::ClientBuilder::new()
|
||||
.connect_timeout(Duration::from_secs(5))
|
||||
.timeout(Duration::from_secs(60))
|
||||
.build()
|
||||
.expect("Build be able to build HTTP client"),
|
||||
);
|
||||
let http_client = reqwest::ClientBuilder::new()
|
||||
.connect_timeout(Duration::from_secs(5))
|
||||
.timeout(Duration::from_secs(60))
|
||||
.build()
|
||||
.expect("Build be able to build HTTP client");
|
||||
data.insert::<crate::HTTPClient>(http_client.clone());
|
||||
|
||||
// Set up the member cache.
|
||||
data.insert::<crate::MemberCache>(std::sync::Arc::new(crate::MemberCache::default()));
|
||||
let member_cache = std::sync::Arc::new(crate::MemberCache::default());
|
||||
data.insert::<crate::MemberCache>(member_cache.clone());
|
||||
|
||||
// Set up the SQL client.
|
||||
data.insert::<crate::SQLClient>(sql_pool);
|
||||
data.insert::<crate::SQLClient>(sql_pool.clone());
|
||||
|
||||
let env = Env {
|
||||
http: http_client,
|
||||
sql: sql_pool,
|
||||
members: member_cache,
|
||||
};
|
||||
|
||||
env
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue