mirror of
https://github.com/PluralKit/PluralKit.git
synced 2026-02-04 04:56:49 +00:00
feat: add remote config over http/redis
This commit is contained in:
parent
c4db95796d
commit
a72afb35a0
12 changed files with 326 additions and 4 deletions
|
|
@ -2,9 +2,10 @@ use axum::{
|
|||
extract::{Path, State},
|
||||
http::StatusCode,
|
||||
response::{IntoResponse, Response},
|
||||
routing::get,
|
||||
routing::{delete, get, post},
|
||||
Router,
|
||||
};
|
||||
use libpk::runtime_config::RuntimeConfig;
|
||||
use serde_json::{json, to_string};
|
||||
use tracing::{error, info};
|
||||
use twilight_model::id::Id;
|
||||
|
|
@ -21,7 +22,11 @@ fn status_code(code: StatusCode, body: String) -> Response {
|
|||
|
||||
// this function is manually formatted for easier legibility of route_services
|
||||
#[rustfmt::skip]
|
||||
pub async fn run_server(cache: Arc<DiscordCache>) -> anyhow::Result<()> {
|
||||
pub async fn run_server(cache: Arc<DiscordCache>, runtime_config: Arc<RuntimeConfig>) -> anyhow::Result<()> {
|
||||
// hacky fix for `move`
|
||||
let runtime_config_for_post = runtime_config.clone();
|
||||
let runtime_config_for_delete = runtime_config.clone();
|
||||
|
||||
let app = Router::new()
|
||||
.route(
|
||||
"/guilds/:guild_id",
|
||||
|
|
@ -171,6 +176,20 @@ pub async fn run_server(cache: Arc<DiscordCache>) -> anyhow::Result<()> {
|
|||
status_code(StatusCode::FOUND, to_string(&stats).unwrap())
|
||||
}))
|
||||
|
||||
.route("/runtime_config", get(|| async move {
|
||||
status_code(StatusCode::FOUND, to_string(&runtime_config.get_all().await).unwrap())
|
||||
}))
|
||||
.route("/runtime_config/:key", post(|Path(key): Path<String>, body: String| async move {
|
||||
let runtime_config = runtime_config_for_post;
|
||||
runtime_config.set(key, body).await.expect("failed to update runtime config");
|
||||
status_code(StatusCode::FOUND, to_string(&runtime_config.get_all().await).unwrap())
|
||||
}))
|
||||
.route("/runtime_config/:key", delete(|Path(key): Path<String>| async move {
|
||||
let runtime_config = runtime_config_for_delete;
|
||||
runtime_config.delete(key).await.expect("failed to update runtime config");
|
||||
status_code(StatusCode::FOUND, to_string(&runtime_config.get_all().await).unwrap())
|
||||
}))
|
||||
|
||||
.layer(axum::middleware::from_fn(crate::logger::logger))
|
||||
.with_state(cache);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
#![feature(if_let_guard)]
|
||||
|
||||
use chrono::Timelike;
|
||||
use discord::gateway::cluster_config;
|
||||
use fred::{clients::RedisPool, interfaces::*};
|
||||
use libpk::runtime_config::RuntimeConfig;
|
||||
use signal_hook::{
|
||||
consts::{SIGINT, SIGTERM},
|
||||
iterator::Signals,
|
||||
|
|
@ -28,6 +30,14 @@ async fn real_main() -> anyhow::Result<()> {
|
|||
|
||||
let redis = libpk::db::init_redis().await?;
|
||||
|
||||
let runtime_config = Arc::new(
|
||||
RuntimeConfig::new(
|
||||
redis.clone(),
|
||||
format!("gateway:{}", cluster_config().node_id),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
|
||||
let shard_state = discord::shard_state::new(redis.clone());
|
||||
let cache = Arc::new(discord::cache::new());
|
||||
|
||||
|
|
@ -57,7 +67,7 @@ async fn real_main() -> anyhow::Result<()> {
|
|||
// todo: probably don't do it this way
|
||||
let api_shutdown_tx = shutdown_tx.clone();
|
||||
set.spawn(tokio::spawn(async move {
|
||||
match cache_api::run_server(cache).await {
|
||||
match cache_api::run_server(cache, runtime_config).await {
|
||||
Err(error) => {
|
||||
tracing::error!(?error, "failed to serve cache api");
|
||||
let _ = api_shutdown_tx.send(());
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilte
|
|||
use sentry_tracing::event_from_event;
|
||||
|
||||
pub mod db;
|
||||
pub mod runtime_config;
|
||||
pub mod state;
|
||||
|
||||
pub mod _config;
|
||||
|
|
|
|||
72
crates/libpk/src/runtime_config.rs
Normal file
72
crates/libpk/src/runtime_config.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
use fred::{clients::RedisPool, interfaces::HashesInterface};
|
||||
use std::collections::HashMap;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::info;
|
||||
|
||||
pub struct RuntimeConfig {
|
||||
redis: RedisPool,
|
||||
settings: RwLock<HashMap<String, String>>,
|
||||
redis_key: String,
|
||||
}
|
||||
|
||||
impl RuntimeConfig {
|
||||
pub async fn new(redis: RedisPool, component_key: String) -> anyhow::Result<Self> {
|
||||
let redis_key = format!("remote_config:{component_key}");
|
||||
|
||||
let mut c = RuntimeConfig {
|
||||
redis,
|
||||
settings: RwLock::new(HashMap::new()),
|
||||
redis_key,
|
||||
};
|
||||
|
||||
c.load().await?;
|
||||
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
pub async fn load(&mut self) -> anyhow::Result<()> {
|
||||
let redis_config: HashMap<String, String> = self.redis.hgetall(&self.redis_key).await?;
|
||||
|
||||
let mut settings = self.settings.write().await;
|
||||
|
||||
for (key, value) in redis_config {
|
||||
settings.insert(key, value);
|
||||
}
|
||||
|
||||
info!("starting with runtime config: {:?}", self.settings);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn set(&self, key: String, value: String) -> anyhow::Result<()> {
|
||||
self.redis
|
||||
.hset::<(), &str, (String, String)>(&self.redis_key, (key.clone(), value.clone()))
|
||||
.await?;
|
||||
self.settings
|
||||
.write()
|
||||
.await
|
||||
.insert(key.clone(), value.clone());
|
||||
info!("updated runtime config: {key}={value}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete(&self, key: String) -> anyhow::Result<()> {
|
||||
self.redis
|
||||
.hdel::<(), &str, String>(&self.redis_key, key.clone())
|
||||
.await?;
|
||||
self.settings.write().await.remove(&key.clone());
|
||||
info!("updated runtime config: {key} removed");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get(&self, key: String) -> Option<String> {
|
||||
self.settings.read().await.get(&key).cloned()
|
||||
}
|
||||
|
||||
pub async fn exists(&self, key: &str) -> bool {
|
||||
self.settings.read().await.contains_key(key)
|
||||
}
|
||||
|
||||
pub async fn get_all(&self) -> HashMap<String, String> {
|
||||
self.settings.read().await.clone()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue