feat: 迁移所有配置到数据库,并支持运行时重载 (#364)

This commit is contained in:
ᴀᴍᴛᴏᴀᴇʀ
2025-06-17 02:15:11 +08:00
committed by GitHub
parent a46c2572b1
commit 4539e9379d
46 changed files with 1055 additions and 715 deletions

View File

@@ -1,9 +1,8 @@
use std::sync::Arc;
use anyhow::{Context, Result};
use axum::body::Body;
use axum::extract::Request;
use axum::http::{Response, Uri, header};
use axum::http::{Uri, header};
use axum::response::IntoResponse;
use axum::routing::get;
use axum::{Extension, Router, ServiceExt, middleware};
@@ -16,7 +15,7 @@ use utoipa_swagger_ui::{Config, SwaggerUi};
use crate::api::auth;
use crate::api::handler::{ApiDoc, api_router};
use crate::bilibili::BiliClient;
use crate::config::CONFIG;
use crate::config::VersionedConfig;
#[derive(RustEmbed)]
#[preserve_source = false]
@@ -41,10 +40,11 @@ pub async fn http_server(database_connection: Arc<DatabaseConnection>, bili_clie
.layer(Extension(database_connection))
.layer(Extension(bili_client))
.layer(middleware::from_fn(auth::auth));
let listener = tokio::net::TcpListener::bind(&CONFIG.bind_address)
let config = VersionedConfig::get().load_full();
let listener = tokio::net::TcpListener::bind(&config.bind_address)
.await
.context("bind address failed")?;
info!("开始运行管理页: http://{}", CONFIG.bind_address);
info!("开始运行管理页: http://{}", config.bind_address);
Ok(axum::serve(listener, ServiceExt::<Request>::into_make_service(app)).await?)
}
@@ -56,16 +56,21 @@ async fn frontend_files(uri: Uri) -> impl IntoResponse {
let Some(content) = Asset::get(path) else {
return (StatusCode::NOT_FOUND, "404 Not Found").into_response();
};
Response::builder()
.status(StatusCode::OK)
.header(
header::CONTENT_TYPE,
content.mime_type().as_deref().unwrap_or("application/octet-stream"),
let mime_type = content.mime_type();
let content_type = mime_type.as_deref().unwrap_or("application/octet-stream");
if cfg!(debug_assertions) {
(
[(header::CONTENT_TYPE, content_type)],
// safety: `RustEmbed` returns uncompressed files directly from the filesystem in debug mode
content.data().unwrap(),
)
.header(header::CONTENT_ENCODING, "br")
// safety: `RustEmbed` will always generate br-compressed files if the feature is enabled
.body(Body::from(content.data_br().unwrap()))
.unwrap_or_else(|_| {
return (StatusCode::INTERNAL_SERVER_ERROR, "500 Internal Server Error").into_response();
})
.into_response()
} else {
(
[(header::CONTENT_TYPE, content_type), (header::CONTENT_ENCODING, "br")],
// safety: `RustEmbed` will always generate br-compressed files if the feature is enabled
content.data_br().unwrap(),
)
.into_response()
}
}

View File

@@ -4,16 +4,22 @@ use sea_orm::DatabaseConnection;
use tokio::time;
use crate::bilibili::{self, BiliClient};
use crate::config::CONFIG;
use crate::config::{DOWNLOADER_RUNNING, VersionedConfig};
use crate::utils::model::get_enabled_video_sources;
use crate::workflow::process_video_source;
/// 启动周期下载视频的任务
pub async fn video_downloader(connection: Arc<DatabaseConnection>, bili_client: Arc<BiliClient>) {
let mut anchor = chrono::Local::now().date_naive();
let video_sources = CONFIG.as_video_sources();
loop {
info!("开始执行本轮视频下载任务..");
DOWNLOADER_RUNNING.store(true, std::sync::atomic::Ordering::Relaxed);
let config = VersionedConfig::get().load_full();
'inner: {
if let Err(e) = config.check() {
error!("配置检查失败,跳过本轮执行:\n{:#}", e);
break 'inner;
}
match bili_client.wbi_img().await.map(|wbi_img| wbi_img.into()) {
Ok(Some(mixin_key)) => bilibili::set_global_mixin_key(mixin_key),
Ok(_) => {
@@ -26,19 +32,28 @@ pub async fn video_downloader(connection: Arc<DatabaseConnection>, bili_client:
}
};
if anchor != chrono::Local::now().date_naive() {
if let Err(e) = bili_client.check_refresh().await {
if let Err(e) = bili_client.check_refresh(&connection).await {
error!("检查刷新 Credential 遇到错误:{:#},等待下一轮执行", e);
break 'inner;
}
anchor = chrono::Local::now().date_naive();
}
for (args, path) in &video_sources {
if let Err(e) = process_video_source(*args, &bili_client, path, &connection).await {
error!("处理过程遇到错误:{:#}", e);
let Ok(video_sources) = get_enabled_video_sources(&connection).await else {
error!("获取视频源列表失败,等待下一轮执行");
break 'inner;
};
if video_sources.is_empty() {
info!("没有可用的视频源,等待下一轮执行");
break 'inner;
}
for video_source in video_sources {
if let Err(e) = process_video_source(video_source, &bili_client, &connection).await {
error!("处理 {} 时遇到错误:{:#},等待下一轮执行", "test", e);
}
}
info!("本轮任务执行完毕,等待下一轮执行");
}
time::sleep(time::Duration::from_secs(CONFIG.interval)).await;
DOWNLOADER_RUNNING.store(false, std::sync::atomic::Ordering::Relaxed);
time::sleep(time::Duration::from_secs(config.interval)).await;
}
}