mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-09 02:47:45 +08:00
refactor: 移除独立 hub/proxy/executor/gateway crate,统一为 gateway tunnel 架构
- 删除 aether-hub、aether-proxy 独立项目及其 Dockerfile/配置 - 删除 crates/aether-executor 和 crates/aether-gateway 全部模块 - 新增 apps/ 目录作为应用入口 - 将 hub 概念重构为 gateway tunnel transport - 将 executor 重构为 execution runtime - 新增 tunnel.rs 合约定义和 testkit tunnel/execution_runtime 模块 - 更新 Python 服务层和测试适配新架构命名
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
use super::*;
|
||||
|
||||
pub(super) async fn provider_checkin_schedule(
|
||||
data: &GatewayDataState,
|
||||
) -> Result<(u32, u32), aether_data::DataLayerError> {
|
||||
let configured =
|
||||
system_config_string(data, "provider_checkin_time", PROVIDER_CHECKIN_DEFAULT_TIME).await?;
|
||||
Ok(parse_hhmm_time(&configured).unwrap_or_else(|| {
|
||||
warn!(
|
||||
value = %configured,
|
||||
fallback = PROVIDER_CHECKIN_DEFAULT_TIME,
|
||||
"gateway provider checkin time invalid; falling back"
|
||||
);
|
||||
parse_hhmm_time(PROVIDER_CHECKIN_DEFAULT_TIME)
|
||||
.expect("default provider checkin time should parse")
|
||||
}))
|
||||
}
|
||||
|
||||
pub(super) fn maintenance_timezone() -> Tz {
|
||||
let configured = std::env::var("APP_TIMEZONE")
|
||||
.ok()
|
||||
.map(|value| value.trim().to_string())
|
||||
.filter(|value| !value.is_empty())
|
||||
.unwrap_or_else(|| MAINTENANCE_DEFAULT_TIMEZONE.to_string());
|
||||
configured.parse().unwrap_or_else(|_| {
|
||||
warn!(
|
||||
timezone = %configured,
|
||||
fallback = MAINTENANCE_DEFAULT_TIMEZONE,
|
||||
"gateway maintenance timezone invalid; falling back"
|
||||
);
|
||||
MAINTENANCE_DEFAULT_TIMEZONE
|
||||
.parse()
|
||||
.expect("default maintenance timezone should parse")
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn duration_until_next_db_maintenance_run(
|
||||
now_utc: DateTime<Utc>,
|
||||
timezone: Tz,
|
||||
) -> Duration {
|
||||
next_db_maintenance_run_after(now_utc, timezone)
|
||||
.signed_duration_since(now_utc)
|
||||
.to_std()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(super) fn next_db_maintenance_run_after(now_utc: DateTime<Utc>, timezone: Tz) -> DateTime<Utc> {
|
||||
let local_now = now_utc.with_timezone(&timezone);
|
||||
for day_offset in 0..=7 {
|
||||
let candidate_date = local_now.date_naive() + chrono::Duration::days(day_offset);
|
||||
if candidate_date.weekday() != DB_MAINTENANCE_WEEKDAY {
|
||||
continue;
|
||||
}
|
||||
let Some(candidate_naive) =
|
||||
candidate_date.and_hms_opt(DB_MAINTENANCE_HOUR, DB_MAINTENANCE_MINUTE, 0)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let candidate_local = resolve_local_scheduled_time(timezone, candidate_naive);
|
||||
let Some(candidate_local) = candidate_local else {
|
||||
continue;
|
||||
};
|
||||
if candidate_local > local_now {
|
||||
return candidate_local.with_timezone(&Utc);
|
||||
}
|
||||
}
|
||||
|
||||
let fallback_date = local_now.date_naive() + DB_MAINTENANCE_WEEKLY_INTERVAL;
|
||||
let fallback_naive = fallback_date
|
||||
.and_hms_opt(DB_MAINTENANCE_HOUR, DB_MAINTENANCE_MINUTE, 0)
|
||||
.expect("db maintenance fallback time should be valid");
|
||||
let fallback_local = resolve_local_scheduled_time(timezone, fallback_naive)
|
||||
.expect("db maintenance fallback local datetime should resolve");
|
||||
fallback_local.with_timezone(&Utc)
|
||||
}
|
||||
|
||||
pub(super) fn duration_until_next_daily_run(
|
||||
now_utc: DateTime<Utc>,
|
||||
timezone: Tz,
|
||||
hour: u32,
|
||||
minute: u32,
|
||||
) -> Duration {
|
||||
next_daily_run_after(now_utc, timezone, hour, minute)
|
||||
.signed_duration_since(now_utc)
|
||||
.to_std()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(super) fn duration_until_next_stats_aggregation_run(now_utc: DateTime<Utc>) -> Duration {
|
||||
next_stats_aggregation_run_after(now_utc)
|
||||
.signed_duration_since(now_utc)
|
||||
.to_std()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(super) fn duration_until_next_stats_hourly_aggregation_run(now_utc: DateTime<Utc>) -> Duration {
|
||||
next_stats_hourly_aggregation_run_after(now_utc)
|
||||
.signed_duration_since(now_utc)
|
||||
.to_std()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(super) fn next_daily_run_after(
|
||||
now_utc: DateTime<Utc>,
|
||||
timezone: Tz,
|
||||
hour: u32,
|
||||
minute: u32,
|
||||
) -> DateTime<Utc> {
|
||||
let local_now = now_utc.with_timezone(&timezone);
|
||||
for day_offset in 0..=1 {
|
||||
let candidate_date = local_now.date_naive() + chrono::Duration::days(day_offset);
|
||||
let Some(candidate_naive) = candidate_date.and_hms_opt(hour, minute, 0) else {
|
||||
continue;
|
||||
};
|
||||
let candidate_local = resolve_local_scheduled_time(timezone, candidate_naive);
|
||||
let Some(candidate_local) = candidate_local else {
|
||||
continue;
|
||||
};
|
||||
if candidate_local > local_now {
|
||||
return candidate_local.with_timezone(&Utc);
|
||||
}
|
||||
}
|
||||
|
||||
let fallback_date = local_now.date_naive() + chrono::Duration::days(1);
|
||||
let fallback_naive = fallback_date
|
||||
.and_hms_opt(hour, minute, 0)
|
||||
.expect("daily fallback time should be valid");
|
||||
let fallback_local = resolve_local_scheduled_time(timezone, fallback_naive)
|
||||
.expect("daily fallback local datetime should resolve");
|
||||
fallback_local.with_timezone(&Utc)
|
||||
}
|
||||
|
||||
pub(super) fn next_stats_aggregation_run_after(now_utc: DateTime<Utc>) -> DateTime<Utc> {
|
||||
next_daily_run_after(
|
||||
now_utc,
|
||||
chrono_tz::UTC,
|
||||
STATS_DAILY_AGGREGATION_HOUR,
|
||||
STATS_DAILY_AGGREGATION_MINUTE,
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn next_stats_hourly_aggregation_run_after(now_utc: DateTime<Utc>) -> DateTime<Utc> {
|
||||
let current_hour_slot = Utc.from_utc_datetime(
|
||||
&now_utc
|
||||
.date_naive()
|
||||
.and_hms_opt(now_utc.hour(), STATS_HOURLY_AGGREGATION_MINUTE, 0)
|
||||
.expect("stats hourly aggregation slot should be valid"),
|
||||
);
|
||||
if current_hour_slot > now_utc {
|
||||
return current_hour_slot;
|
||||
}
|
||||
|
||||
let next_hour = now_utc + chrono::Duration::hours(1);
|
||||
Utc.from_utc_datetime(
|
||||
&next_hour
|
||||
.date_naive()
|
||||
.and_hms_opt(next_hour.hour(), STATS_HOURLY_AGGREGATION_MINUTE, 0)
|
||||
.expect("stats hourly aggregation next slot should be valid"),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn stats_aggregation_target_day(now_utc: DateTime<Utc>) -> DateTime<Utc> {
|
||||
let previous_day = now_utc - chrono::Duration::days(1);
|
||||
Utc.from_utc_datetime(
|
||||
&previous_day
|
||||
.date_naive()
|
||||
.and_hms_opt(0, 0, 0)
|
||||
.expect("stats aggregation target day should be valid"),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn stats_hourly_aggregation_target_hour(now_utc: DateTime<Utc>) -> DateTime<Utc> {
|
||||
let previous_hour = now_utc - chrono::Duration::hours(1);
|
||||
Utc.from_utc_datetime(
|
||||
&previous_hour
|
||||
.date_naive()
|
||||
.and_hms_opt(previous_hour.hour(), 0, 0)
|
||||
.expect("stats hourly aggregation target hour should be valid"),
|
||||
)
|
||||
}
|
||||
|
||||
pub(super) fn wallet_daily_usage_aggregation_target(
|
||||
now_utc: DateTime<Utc>,
|
||||
timezone: Tz,
|
||||
) -> WalletDailyUsageAggregationTarget {
|
||||
let local_today = now_utc.with_timezone(&timezone).date_naive();
|
||||
let billing_date = local_today - chrono::Duration::days(1);
|
||||
let next_billing_date = billing_date + chrono::Duration::days(1);
|
||||
|
||||
WalletDailyUsageAggregationTarget {
|
||||
billing_date,
|
||||
billing_timezone: timezone.to_string(),
|
||||
window_start_utc: local_day_start_utc(billing_date, timezone),
|
||||
window_end_utc: local_day_start_utc(next_billing_date, timezone),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn local_day_start_utc(date: chrono::NaiveDate, timezone: Tz) -> DateTime<Utc> {
|
||||
let local_start = date
|
||||
.and_hms_opt(0, 0, 0)
|
||||
.and_then(|naive| resolve_local_scheduled_time(timezone, naive))
|
||||
.expect("local day start should resolve");
|
||||
local_start.with_timezone(&Utc)
|
||||
}
|
||||
|
||||
pub(super) fn resolve_local_scheduled_time(
|
||||
timezone: Tz,
|
||||
naive: chrono::NaiveDateTime,
|
||||
) -> Option<chrono::DateTime<Tz>> {
|
||||
match timezone.from_local_datetime(&naive) {
|
||||
chrono::LocalResult::Single(value) => Some(value),
|
||||
chrono::LocalResult::Ambiguous(first, second) => Some(first.min(second)),
|
||||
chrono::LocalResult::None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn parse_hhmm_time(value: &str) -> Option<(u32, u32)> {
|
||||
let (hour, minute) = value.trim().split_once(':')?;
|
||||
let hour = hour.parse::<u32>().ok()?;
|
||||
let minute = minute.parse::<u32>().ok()?;
|
||||
(hour <= 23 && minute <= 59).then_some((hour, minute))
|
||||
}
|
||||
Reference in New Issue
Block a user