feat: 添加日志功能

This commit is contained in:
zhushenwudi 2025-01-06 23:13:20 +08:00
parent 5a0f888000
commit ee2e8dd1c6
11 changed files with 125 additions and 52 deletions

View File

@ -31,3 +31,5 @@ serde = { version = "1.0.215", features = ["derive"] }
futures = "0.3.31" futures = "0.3.31"
mime_guess = "2.0.5" mime_guess = "2.0.5"
actix-files = "0.6.6" actix-files = "0.6.6"
simplelog = "0.12.2"
log = "0.4.22"

67
src/logger.rs Normal file
View File

@ -0,0 +1,67 @@
use log::{debug, error, info, warn, LevelFilter};
use simplelog::*;
use std::fs::{create_dir_all, File, OpenOptions};
use std::path::Path;
const MAX_LOG_SIZE: u64 = 50 * 1024 * 1024;
const LOG_FILE_PATH: &str = "data/rust.log";
pub fn init_logger() {
let mut builder = ConfigBuilder::new();
builder.set_time_offset_to_local().unwrap();
let config = builder.build();
// 获取文件的目录路径
let dir = Path::new(LOG_FILE_PATH).parent().unwrap();
// 检查并创建目录
if !dir.exists() {
create_dir_all(dir).unwrap();
}
let file = OpenOptions::new()
.write(true)
.append(true)
.create(true)
.open(LOG_FILE_PATH).unwrap();
CombinedLogger::init(
vec![
TermLogger::new(LevelFilter::Info, config.clone(), TerminalMode::Mixed, ColorChoice::Auto),
WriteLogger::new(LevelFilter::Info, config.clone(), file),
]
).unwrap();
}
// 检查文件大小并清空文件(如果超出限制)
fn check_and_clear_log_file() {
let metadata = std::fs::metadata(LOG_FILE_PATH).unwrap();
if metadata.len() > MAX_LOG_SIZE {
// 清空文件
File::create(LOG_FILE_PATH).expect(&format!("Can't re-create file {}", LOG_FILE_PATH));
}
}
#[allow(dead_code)]
pub fn debug(message: &str) {
check_and_clear_log_file();
debug!("{}", message);
}
#[allow(dead_code)]
pub fn info(message: &str) {
check_and_clear_log_file();
info!("{}", message);
}
#[allow(dead_code)]
pub fn warn(message: &str) {
check_and_clear_log_file();
warn!("{}", message);
}
#[allow(dead_code)]
pub fn error(message: &str) {
check_and_clear_log_file();
error!("{}", message);
}

View File

@ -1,6 +1,7 @@
mod encryption; mod encryption;
mod router; mod router;
mod sql; mod sql;
mod logger;
use actix_web::{ use actix_web::{
rt, rt,
@ -42,7 +43,7 @@ pub struct Args {
#[arg(short, long, default_value_t = 8000, help = "Assets port to listen on")] #[arg(short, long, default_value_t = 8000, help = "Assets port to listen on")]
asset_port: u16, asset_port: u16,
#[arg(long, default_value = "./", help = "Path to store database files")] #[arg(long, default_value = "./data/", help = "Path to store database files")]
path: String, path: String,
#[arg(long, default_value = "./asset/", help = "Path to store database files")] #[arg(long, default_value = "./asset/", help = "Path to store database files")]
@ -110,43 +111,45 @@ async fn run_server(in_thread: bool) -> std::io::Result<()> {
let asset_port = args.asset_port; let asset_port = args.asset_port;
if args.purge { if args.purge {
println!("Purging accounts..."); logger::debug("Purging accounts...");
let ct = crate::router::userdata::purge_accounts(); let ct = router::userdata::purge_accounts();
println!("Purged {} accounts", ct); logger::warn(&format!("Purged {} accounts", ct));
} }
let webui_server = HttpServer::new(|| App::new() let webui_server = HttpServer::new(|| {
.wrap_fn(|req, srv| { App::new()
println!("WebUI Request: {}", req.path()); .wrap_fn(|req, srv| {
srv.call(req) logger::info(&format!("WebUI Request: {}", req.path())); // 使用日志记录
}) srv.call(req)
.app_data(web::PayloadConfig::default().limit(1024 * 1024 * 25)) })
.service(css) .app_data(web::PayloadConfig::default().limit(1024 * 1024 * 25))
.service(js) .service(css)
.default_service(web::route().to(router::request)) .service(js)
).bind(("0.0.0.0", port))?.run(); .default_service(web::route().to(router::request))
}).bind(("0.0.0.0", port))?.run();
println!("WebUI Server started: http://0.0.0.0:{}", port); logger::info(&format!("WebUI Server started: http://0.0.0.0:{}", port));
println!("Database path is set to {}", args.path); logger::info(&format!("Database path is set to {}", args.path));
println!("Sif1 transfer requests will attempt to contact NPPS4 at {}", args.npps4); logger::debug(&format!("Sif1 transfer requests will attempt to contact NPPS4 at {}", args.npps4));
let mut asset_server: Option<Server> = None; let mut asset_server: Option<Server> = None;
if enable_asset_server { if enable_asset_server {
asset_server = Some(HttpServer::new(|| App::new() asset_server = Some(HttpServer::new(|| {
.wrap_fn(|req, srv| { App::new()
println!("Assets Request: {}", req.path()); .wrap_fn(|req, srv| {
srv.call(req) logger::info(&format!("Assets Request: {}", req.path()));
}) srv.call(req)
.app_data(web::PayloadConfig::default().limit(1024 * 1024 * 1024)) })
.default_service(web::route().to(router::asset_request)) .app_data(web::PayloadConfig::default().limit(1024 * 1024 * 1024))
).bind(("0.0.0.0", asset_port))?.run()); .default_service(web::route().to(router::asset_request))
}).bind(("0.0.0.0", asset_port))?.run());
println!("Assets Server started: http://0.0.0.0:{}", asset_port); logger::info(&format!("Assets Server started: http://0.0.0.0:{}", asset_port));
println!("Assets path is set to {}", args.asset_path); logger::info(&format!("Assets path is set to {}", args.asset_path));
} }
if args.https { if args.https {
println!("Note: gree is set to https mode. http requests will fail on jp clients."); logger::warn("Note: gree is set to https mode. http requests will fail on jp clients.");
} }
if in_thread { if in_thread {
@ -161,13 +164,13 @@ async fn run_server(in_thread: bool) -> std::io::Result<()> {
} }
while get_running().await { while get_running().await {
actix_web::rt::time::sleep(Duration::from_millis(100)).await; rt::time::sleep(Duration::from_millis(100)).await;
} }
handle.stop(false).await; handle.stop(false).await;
if handle2.is_some() { if handle2.is_some() {
handle2.unwrap().stop(false).await; handle2.unwrap().stop(false).await;
} }
println!("Stopped"); logger::info("Stopped");
return Ok(()); return Ok(());
} }
if asset_server.is_some() { if asset_server.is_some() {
@ -181,10 +184,11 @@ async fn run_server(in_thread: bool) -> std::io::Result<()> {
#[actix_web::main] #[actix_web::main]
async fn stop_server() { async fn stop_server() {
set_running(false).await; set_running(false).await;
println!("Stopping"); logger::error("Stopping");
} }
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
logger::init_logger();
run_server(false) run_server(false)
} }

View File

@ -30,13 +30,13 @@ pub mod event_ranking;
use actix_web::{HttpResponse, HttpRequest, http::header::HeaderValue, http::header::HeaderMap, Responder}; use actix_web::{HttpResponse, HttpRequest, http::header::HeaderValue, http::header::HeaderMap, Responder};
use json::{JsonValue, object}; use json::{JsonValue, object};
use crate::encryption; use crate::{encryption, logger};
fn unhandled(req: HttpRequest, body: String) -> Option<JsonValue> { fn unhandled(req: HttpRequest, body: String) -> Option<JsonValue> {
if body != String::new() { if body != String::new() {
println!("{}", encryption::decrypt_packet(&body).unwrap_or(body)); logger::error(&format!("{}", encryption::decrypt_packet(&body).unwrap_or(body)));
} }
println!("Unhandled request: {}", req.path()); logger::error(&format!("Unhandled request: {}", req.path()));
None None
} }

View File

@ -2,7 +2,7 @@ use json::{object, array, JsonValue};
use actix_web::{HttpRequest}; use actix_web::{HttpRequest};
use crate::router::{global, items, userdata, databases}; use crate::router::{global, items, userdata, databases};
use crate::encryption; use crate::{encryption, logger};
pub fn add_chat(id: i64, num: i64, chats: &mut JsonValue) -> bool { pub fn add_chat(id: i64, num: i64, chats: &mut JsonValue) -> bool {
for data in chats.members() { for data in chats.members() {
@ -23,7 +23,7 @@ pub fn add_chat(id: i64, num: i64, chats: &mut JsonValue) -> bool {
pub fn add_chat_from_chapter_id(chapter_id: i64, chats: &mut JsonValue) -> bool { pub fn add_chat_from_chapter_id(chapter_id: i64, chats: &mut JsonValue) -> bool {
let chapter = &databases::CHAPTERS_MASTER[chapter_id.to_string()]; let chapter = &databases::CHAPTERS_MASTER[chapter_id.to_string()];
if chapter.is_empty() { if chapter.is_empty() {
println!("Attempted to give unknown chapter id {}", chapter_id); logger::info(&format!("Attempted to give unknown chapter id {}", chapter_id));
return false; return false;
} }
add_chat(chapter["masterChatId"].as_i64().unwrap(), chapter["roomId"].as_i64().unwrap(), chats) add_chat(chapter["masterChatId"].as_i64().unwrap(), chapter["roomId"].as_i64().unwrap(), chats)

View File

@ -1,12 +1,12 @@
use json::{JsonValue, object}; use json::{JsonValue, object};
use actix_web::{HttpRequest}; use actix_web::{HttpRequest};
use crate::encryption; use crate::{encryption, logger};
pub fn error(_req: HttpRequest, body: String) -> Option<JsonValue> { pub fn error(_req: HttpRequest, body: String) -> Option<JsonValue> {
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap(); let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
println!("client error: {}", body["code"]); logger::error(&format!("client error: {}", body["code"]));
Some(object!{}) Some(object!{})
} }

View File

@ -1,7 +1,7 @@
use json::{array, object, JsonValue}; use json::{array, object, JsonValue};
use rand::Rng; use rand::Rng;
use actix_web::{HttpRequest, http::header::{HeaderMap, HeaderValue}}; use actix_web::{HttpRequest, http::header::{HeaderMap, HeaderValue}};
use crate::encryption; use crate::{encryption, logger};
use crate::router::{userdata, global, databases}; use crate::router::{userdata, global, databases};
@ -113,7 +113,7 @@ pub fn use_item(item: &JsonValue, multiplier: i64, user: &mut JsonValue) {
} else if item["consumeType"] == 4 { } else if item["consumeType"] == 4 {
use_itemm(item["value"].as_i64().unwrap(), item["amount"].as_i64().unwrap() * multiplier, user); use_itemm(item["value"].as_i64().unwrap(), item["amount"].as_i64().unwrap() * multiplier, user);
} else { } else {
println!("Unknown consume type {}", item["consumeType"]); logger::error(&format!("Unknown consume type {}", item["consumeType"]));
} }
} }
@ -142,7 +142,7 @@ pub fn give_gift(data: &JsonValue, user: &mut JsonValue, missions: &mut JsonValu
} }
return false; return false;
} }
println!("Redeeming reward not implemented for reward type {}", data["reward_type"]); logger::error(&format!("Redeeming reward not implemented for reward type {}", data["reward_type"]));
false false
} }
pub fn give_gift_basic(ty_pe: i32, id: i64, amount: i64, user: &mut JsonValue, missions: &mut JsonValue, clear_missions: &mut JsonValue, chats: &mut JsonValue) -> bool { pub fn give_gift_basic(ty_pe: i32, id: i64, amount: i64, user: &mut JsonValue, missions: &mut JsonValue, clear_missions: &mut JsonValue, chats: &mut JsonValue) -> bool {
@ -279,7 +279,7 @@ pub fn get_rarity(id: i64) -> i32 {
pub fn give_character(id: i64, user: &mut JsonValue, missions: &mut JsonValue, clear_missions: &mut JsonValue, chats: &mut JsonValue) -> bool { pub fn give_character(id: i64, user: &mut JsonValue, missions: &mut JsonValue, clear_missions: &mut JsonValue, chats: &mut JsonValue) -> bool {
let character_rarity = get_rarity(id); let character_rarity = get_rarity(id);
if character_rarity == 0 { if character_rarity == 0 {
println!("Attempted to give user undefined card!! Card id: {}", id); logger::error(&format!("Attempted to give user undefined card!! Card id: {}", id));
return false; return false;
} }
@ -498,7 +498,7 @@ pub fn use_item_req(req: HttpRequest, body: String) -> Option<JsonValue> {
if item["effectType"].as_i32().unwrap() == 1 { if item["effectType"].as_i32().unwrap() == 1 {
lp_modification(&mut user, item["effectValue"].as_u64().unwrap() * (amount as u64), false); lp_modification(&mut user, item["effectValue"].as_u64().unwrap() * (amount as u64), false);
} else { } else {
println!("Use item not implemented for effect type {}", item["effectType"]); logger::error(&format!("Use item not implemented for effect type {}", item["effectType"]));
} }
use_item(&object!{ use_item(&object!{
value: body["id"].as_i64().unwrap(), value: body["id"].as_i64().unwrap(),

View File

@ -1,12 +1,12 @@
use json::{JsonValue, object}; use json::{JsonValue, object};
use actix_web::{HttpRequest, http::header::HeaderValue}; use actix_web::{HttpRequest, http::header::HeaderValue};
use crate::encryption; use crate::{encryption, logger};
use crate::router::{userdata, global}; use crate::router::{userdata, global};
fn get_asset_hash(req: &HttpRequest, body: &JsonValue) -> String { fn get_asset_hash(req: &HttpRequest, body: &JsonValue) -> String {
if body["asset_version"] != global::ASSET_VERSION && body["asset_version"] != global::ASSET_VERSION_JP { if body["asset_version"] != global::ASSET_VERSION && body["asset_version"] != global::ASSET_VERSION_JP {
println!("Warning! Asset version is not what was expected. (Did the app update?)"); logger::warn("Warning! Asset version is not what was expected. (Did the app update?)");
} }
let blank_header = HeaderValue::from_static(""); let blank_header = HeaderValue::from_static("");
@ -29,7 +29,7 @@ pub fn start(req: HttpRequest, body: String) -> Option<JsonValue> {
let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap(); let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap();
let mut user = userdata::get_acc(&key); let mut user = userdata::get_acc(&key);
println!("Signin from uid: {}", user["user"]["id"].clone()); logger::info(&format!("Signin from uid: {}", user["user"]["id"].clone()));
user["user"]["last_login_time"] = global::timestamp().into(); user["user"]["last_login_time"] = global::timestamp().into();

View File

@ -2,7 +2,7 @@ use json::{array, object, JsonValue};
use actix_web::{HttpRequest}; use actix_web::{HttpRequest};
use sha1::{Sha1, Digest}; use sha1::{Sha1, Digest};
use crate::encryption; use crate::{encryption, logger};
use crate::router::{userdata, global, items}; use crate::router::{userdata, global, items};
use crate::include_file; use crate::include_file;
@ -329,7 +329,7 @@ async fn npps4_req(sha_id: String) -> Option<JsonValue> {
host.pop(); host.pop();
} }
let url = format!("{}/ewexport?sha1={}", host, sha_id); let url = format!("{}/ewexport?sha1={}", host, sha_id);
println!("Polling NPPS4 at {}", host); logger::debug(&format!("Polling NPPS4 at {}", host));
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let response = client.get(url); let response = client.get(url);

View File

@ -8,7 +8,7 @@ use base64::{Engine as _, engine::general_purpose};
use crate::router::global; use crate::router::global;
use crate::router::items; use crate::router::items;
use crate::sql::SQLite; use crate::sql::SQLite;
use crate::include_file; use crate::{include_file, logger};
lazy_static! { lazy_static! {
static ref DATABASE: SQLite = SQLite::new("userdata.db", setup_tables); static ref DATABASE: SQLite = SQLite::new("userdata.db", setup_tables);
@ -625,7 +625,7 @@ pub fn purge_accounts() -> usize {
)).unwrap(); )).unwrap();
for uid in dead_uids.members() { for uid in dead_uids.members() {
let user_id = uid.as_i64().unwrap(); let user_id = uid.as_i64().unwrap();
println!("Removing dead UID: {}", user_id); logger::error(&format!("Removing dead UID: {}", user_id));
crate::router::gree::delete_uuid(user_id); crate::router::gree::delete_uuid(user_id);
DATABASE.lock_and_exec("DELETE FROM userdata WHERE user_id=?1", params!(user_id)); DATABASE.lock_and_exec("DELETE FROM userdata WHERE user_id=?1", params!(user_id));
DATABASE.lock_and_exec("DELETE FROM userhome WHERE user_id=?1", params!(user_id)); DATABASE.lock_and_exec("DELETE FROM userhome WHERE user_id=?1", params!(user_id));

View File

@ -1,4 +1,4 @@
import { useState, useParams, useEffect } from 'react' import { useState, useEffect } from 'react'
import './Home.css' import './Home.css'
import Request from '../Request.jsx' import Request from '../Request.jsx'
let bonusItems = []; let bonusItems = [];