mirror of
https://github.com/perfect-panel/ppanel-web.git
synced 2026-08-29 05:52:08 -04:00
feat: README, config.example, turnstile integration, exchange rate, auth utils refactor
This commit is contained in:
@@ -77,11 +77,17 @@ pub fn register_all(repos: Arc<Repositories>, config: Arc<Config>) -> ServeMux {
|
||||
},
|
||||
);
|
||||
|
||||
// ── Quota task ────────────────────────────────────────────────────────────
|
||||
// ── Quota task + Rate task ─────────────────────────────────────────────────
|
||||
let quota_repos = Arc::clone(&repos);
|
||||
let quota_config = Arc::clone(&config);
|
||||
mux.handle_async_func(crate::queue::types::FORTHWITH_QUOTA_TASK, move |task| {
|
||||
task::quota_task(task, Arc::clone("a_repos), Arc::clone("a_config))
|
||||
mux.handle_async_func(crate::queue::types::FORTHWITH_QUOTA_TASK, move |t| {
|
||||
task::quota_task(t, Arc::clone("a_repos), Arc::clone("a_config))
|
||||
});
|
||||
|
||||
let rate_repos = Arc::clone(&repos);
|
||||
let rate_config = Arc::clone(&config);
|
||||
mux.handle_async_func(crate::queue::types::FORTHWITH_RATE_TASK, move |t| {
|
||||
task::rate_task(t, Arc::clone(&rate_repos), Arc::clone(&rate_config))
|
||||
});
|
||||
|
||||
mux
|
||||
|
||||
@@ -4,7 +4,7 @@ use asynq::error::Result;
|
||||
use asynq::task::Task;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::queue::service::task::QuotaTaskLogic;
|
||||
use crate::queue::service::task::{QuotaTaskLogic, RateLogic};
|
||||
use crate::repository::Repositories;
|
||||
|
||||
pub async fn quota_task(task: Task, repos: Arc<Repositories>, config: Arc<Config>) -> Result<()> {
|
||||
@@ -13,3 +13,12 @@ pub async fn quota_task(task: Task, repos: Arc<Repositories>, config: Arc<Config
|
||||
.await
|
||||
.map_err(|e| asynq::error::Error::other(e.to_string()))
|
||||
}
|
||||
|
||||
/// Fetch the current exchange rate and persist it.
|
||||
/// Scheduled daily at 01:00 by the scheduler (mirrors `rateLogic.go`).
|
||||
pub async fn rate_task(_task: Task, repos: Arc<Repositories>, config: Arc<Config>) -> Result<()> {
|
||||
RateLogic::new(repos, config)
|
||||
.execute()
|
||||
.await
|
||||
.map_err(|e| asynq::error::Error::other(e.to_string()))
|
||||
}
|
||||
|
||||
@@ -250,3 +250,57 @@ impl QuotaTaskLogic {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// RateLogic — port of `server/queue/logic/task/rateLogic.go`
|
||||
// Fetches the current exchange rate for the site currency and caches it.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
pub struct RateLogic {
|
||||
repos: Arc<Repositories>,
|
||||
config: Arc<Config>,
|
||||
}
|
||||
|
||||
impl RateLogic {
|
||||
pub fn new(repos: Arc<Repositories>, config: Arc<Config>) -> Self {
|
||||
Self { repos, config }
|
||||
}
|
||||
|
||||
/// Fetch exchange rate from apilayer.com and cache it in Redis.
|
||||
///
|
||||
/// Skips silently when `Currency.AccessKey` is not configured.
|
||||
pub async fn execute(&self) -> anyhow::Result<()> {
|
||||
let access_key = &self.config.currency.access_key;
|
||||
if access_key.is_empty() {
|
||||
tracing::debug!("[RateLogic] skip: no Currency.AccessKey configured");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let from = &self.config.currency.unit;
|
||||
if from.is_empty() || from.to_uppercase() == "CNY" {
|
||||
// Already in base currency — rate is 1.0, nothing to fetch.
|
||||
tracing::debug!("[RateLogic] skip: currency unit is CNY or empty");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
match crate::exchange_rate::convert(from, "CNY", 1.0, access_key).await {
|
||||
Ok(rate) => {
|
||||
tracing::info!(
|
||||
"[RateLogic] exchange rate {from}→CNY = {rate:.6}"
|
||||
);
|
||||
// Persist rate to system config table.
|
||||
let _ = self
|
||||
.repos
|
||||
.system
|
||||
.update_value_by_category_key("currency", "exchange_rate", &rate.to_string())
|
||||
.await
|
||||
.map_err(|e| tracing::warn!("[RateLogic] persist rate failed: {e}"));
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("[RateLogic] fetch exchange rate failed: {e}");
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,3 +28,5 @@ pub const FORTHWITH_TRAFFIC_STATISTICS: &str = "forthwith:traffic:statistics";
|
||||
|
||||
// ── task / quota ───────────────────────────────────────────────────────
|
||||
pub const FORTHWITH_QUOTA_TASK: &str = "forthwith:quota:task";
|
||||
/// Daily exchange-rate refresh (mirrors Go `ForthwithRateTask`).
|
||||
pub const FORTHWITH_RATE_TASK: &str = "forthwith:rate:task";
|
||||
|
||||
Reference in New Issue
Block a user