use crate::{
checks::EnabledCheckData,
commands::{
deviantart::DeviantartClient,
fml::FmlClient,
iqdb::IqdbClient,
nekos::NekosClient,
quizizz::QuizizzClient,
r6stats::R6StatsClient,
r6tracker::R6TrackerClient,
reddit_embed::RedditEmbedData,
rule34::Rule34Client,
sauce_nao::SauceNaoClient,
shift::ShiftClient,
tic_tac_toe::TicTacToeData,
tiktok_embed::TikTokData,
urban::UrbanClient,
},
config::Config,
database::Database,
util::EncoderTask,
};
use anyhow::Context;
use serenity::gateway::ShardManager;
use std::{
collections::BTreeMap,
fmt::Debug,
sync::Arc,
};
use tracing::error;
#[derive(Debug)]
pub struct CacheStatsBuilder {
stats: BTreeMap<&'static str, BTreeMap<&'static str, f32>>,
}
impl CacheStatsBuilder {
pub fn new() -> Self {
Self {
stats: BTreeMap::new(),
}
}
pub fn publish_stat(&mut self, section: &'static str, name: &'static str, value: f32) {
self.stats.entry(section).or_default().insert(name, value);
}
pub fn into_inner(self) -> BTreeMap<&'static str, BTreeMap<&'static str, f32>> {
self.stats
}
}
impl Default for CacheStatsBuilder {
fn default() -> Self {
Self::new()
}
}
pub trait CacheStatsProvider {
fn publish_cache_stats(&self, cache_stats_builder: &mut CacheStatsBuilder);
}
#[derive(Debug)]
pub struct ClientData {
pub shard_manager: Arc<ShardManager>,
pub nekos_client: NekosClient,
pub r6stats_client: R6StatsClient,
pub r6tracker_client: R6TrackerClient,
pub rule34_client: Rule34Client,
pub quizizz_client: QuizizzClient,
pub fml_client: FmlClient,
pub shift_client: ShiftClient,
pub reddit_embed_data: RedditEmbedData,
pub enabled_check_data: EnabledCheckData,
pub insta_client: insta::Client,
pub deviantart_client: DeviantartClient,
pub urban_client: UrbanClient,
pub xkcd_client: xkcd::Client,
pub tic_tac_toe_data: TicTacToeData,
pub iqdb_client: IqdbClient,
pub sauce_nao_client: SauceNaoClient,
pub open_ai_client: open_ai::Client,
pub yodaspeak: yodaspeak::Client,
pub tiktok_data: TikTokData,
pub encoder_task: EncoderTask,
pub db: Database,
pub config: Arc<Config>,
}
impl ClientData {
pub async fn init(
shard_manager: Arc<ShardManager>,
config: Arc<Config>,
db: Database,
) -> anyhow::Result<Self> {
let cache_dir = config.cache_dir();
let encoder_task = EncoderTask::new();
let deviantart_client = DeviantartClient::new(&db)
.await
.context("failed to init deviantart client")?;
let tiktok_data = TikTokData::new(&cache_dir, encoder_task.clone())
.await
.context("failed to init tiktok data")?;
Ok(ClientData {
shard_manager,
nekos_client: Default::default(),
r6stats_client: Default::default(),
r6tracker_client: Default::default(),
rule34_client: Default::default(),
quizizz_client: Default::default(),
fml_client: FmlClient::new(config.fml.key.to_string()),
shift_client: ShiftClient::new(),
reddit_embed_data: Default::default(),
enabled_check_data: Default::default(),
insta_client: insta::Client::new(),
deviantart_client,
urban_client: Default::default(),
xkcd_client: Default::default(),
tic_tac_toe_data: Default::default(),
iqdb_client: Default::default(),
sauce_nao_client: SauceNaoClient::new(config.sauce_nao.api_key.as_str()),
open_ai_client: open_ai::Client::new(config.open_ai.api_key.as_str()),
yodaspeak: yodaspeak::Client::new(),
tiktok_data,
encoder_task,
db,
config,
})
}
pub fn generate_cache_stats(&self) -> BTreeMap<&'static str, BTreeMap<&'static str, f32>> {
let mut stat_builder = CacheStatsBuilder::new();
let cache_stat_providers: &[&dyn CacheStatsProvider] = &[
&self.fml_client,
&self.nekos_client,
&self.r6stats_client,
&self.r6tracker_client,
&self.reddit_embed_data,
&self.rule34_client,
&self.shift_client,
&self.deviantart_client,
&self.urban_client,
&self.iqdb_client,
];
for cache_stat_provider in cache_stat_providers {
cache_stat_provider.publish_cache_stats(&mut stat_builder);
}
stat_builder.into_inner()
}
pub async fn shutdown(&self) {
if let Err(e) = self.encoder_task.shutdown().await {
error!("{:?}", e);
}
}
}