diff --git a/Cargo.lock b/Cargo.lock index 7683955..592e645 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,6 +10,7 @@ dependencies = [ "colored", "cxx", "cxx-build", + "encoding_rs", "env_logger", "fern", "futures-util", @@ -18,6 +19,7 @@ dependencies = [ "log", "reqwest", "tokio", + "tracing-appender", ] [[package]] @@ -234,6 +236,21 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + [[package]] name = "cxx" version = "1.0.192" @@ -296,6 +313,15 @@ dependencies = [ "syn", ] +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -313,6 +339,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + [[package]] name = "env_filter" version = "0.1.4" @@ -793,6 +828,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.180" @@ -869,6 +910,12 @@ dependencies = [ "tempfile", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" version = "0.2.19" @@ -1005,6 +1052,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro2" version = "1.0.105" @@ -1205,6 +1258,15 @@ dependencies = [ "syn", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1308,6 +1370,66 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" + +[[package]] +name = "time-macros" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinystr" version = "0.8.2" @@ -1424,6 +1546,18 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-core" version = "0.1.36" @@ -1433,6 +1567,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + [[package]] name = "try-lock" version = "0.2.5" diff --git a/Cargo.toml b/Cargo.toml index 3e57c89..99e5c67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ tokio = { version = "1.49.0", features = ["rt-multi-thread", "full"] } chrono = "0.4.43" colored = "3.1.1" env_logger = "0.11.8" +encoding_rs = "0.8.35" +tracing-appender = "0.2.4" [build-dependencies] cxx-build = "1.0.192" diff --git a/src/lib.rs b/src/lib.rs index b690e66..13f56e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ use ::log::{debug, error, info, trace, warn}; +use encoding_rs::Encoding; use tokio::runtime::Runtime; mod log; @@ -7,41 +8,46 @@ mod network; #[cxx::bridge] mod ffi { extern "Rust" { - fn download_file(url: &str, path: &str) -> Result<()>; + fn download_file(url: &CxxString, path: &CxxString) -> Result<()>; - fn http_get(url: &str) -> Result; + fn http_get(url: &CxxString) -> Result; fn init_log(is_debug: bool); - fn log_trace(msg: &str); + fn log_trace(msg: &CxxString); - fn log_debug(msg: &str); + fn log_debug(msg: &CxxString); - fn log_info(msg: &str); + fn log_info(msg: &CxxString); - fn log_warning(msg: &str); + fn log_warning(msg: &CxxString); - fn log_error(msg: &str); + fn log_error(msg: &CxxString); } } -fn log_error(msg: &str) { +fn log_error(msg: &cxx::CxxString) { + let msg = cxx_string_to_string(msg); error!("{}", msg); } -fn log_warning(msg: &str) { +fn log_warning(msg: &cxx::CxxString) { + let msg = cxx_string_to_string(msg); warn!("{}", msg); } -fn log_info(msg: &str) { +fn log_info(msg: &cxx::CxxString) { + let msg = cxx_string_to_string(msg); info!("{}", msg); } -fn log_debug(msg: &str) { +fn log_debug(msg: &cxx::CxxString) { + let msg = cxx_string_to_string(msg); debug!("{}", msg); } -fn log_trace(msg: &str) { +fn log_trace(msg: &cxx::CxxString) { + let msg = cxx_string_to_string(msg); trace!("{}", msg); } @@ -53,13 +59,47 @@ fn get_runtime() -> Runtime { Runtime::new().expect("创建Tokio运行时失败") } -fn download_file(url: &str, path: &str) -> Result<(), Box> { +fn download_file( + url: &cxx::CxxString, + path: &cxx::CxxString, +) -> Result<(), Box> { let rt = get_runtime(); - rt.block_on(network::download_file(url, path))?; + let url = cxx_string_to_string(url); + let path = cxx_string_to_string(path); + rt.block_on(network::download_file(&url, &path))?; Ok(()) } -fn http_get(url: &str) -> Result> { +fn http_get(url: &cxx::CxxString) -> Result> { let rt = get_runtime(); - rt.block_on(network::http_get(url)) + let url = cxx_string_to_string(url); + rt.block_on(network::http_get(&url)) +} + +fn cxx_string_to_string(s: &cxx::CxxString) -> String { + match s.to_str() { + Ok(s) => return s.to_string(), + Err(_) => {} + }; + + // 不是UTF-8,尝试转换 + let candidates = [ + "gb18030", // 覆盖 GBK/GB2312 的常见场景 + "windows-1252", // 西欧常见 + "shift_jis", // 日文常见 + "big5", // 繁体中文常见 + ]; + + let bytes = s.as_bytes(); + + for label in candidates { + let enc = Encoding::for_label(label.as_bytes()).unwrap(); + let (cow, _actual_used, had_errors) = enc.decode(bytes); + if !had_errors { + return cow.into_owned(); + } + } + + /// 编码全部没有命中的话,则丢弃无法解析的部分 + s.to_string_lossy().into_owned() } diff --git a/src/log.rs b/src/log.rs index d5044a8..0beb07e 100644 --- a/src/log.rs +++ b/src/log.rs @@ -30,20 +30,6 @@ fn get_time() -> String { } pub fn init_log(is_debug: bool) { - let mut file_dispatch = Dispatch::new() - .chain(fern::log_file(get_log_path().join("app.log")).expect("无法写入日志文件")) - .format(|out, message, record| { - let title = match record.level() { - Level::Error => "Error", - Level::Warn => "Warning", - Level::Info => "Info", - Level::Debug => "Debug", - Level::Trace => "Trace", - }; - - out.finish(format_args!("[{} {}]\t{}", get_time(), title, message)) - }); - let mut console_dispatch = Dispatch::new() .format(|out, message, record| { let (color, title) = match record.level() { @@ -61,28 +47,13 @@ pub fn init_log(is_debug: bool) { message )) }) + .chain(fern::log_file(get_log_path().join("app.log")).expect("无法写入日志文件")) .chain(std::io::stdout()); if is_debug { console_dispatch = console_dispatch.level(log::LevelFilter::Trace); - file_dispatch = file_dispatch.level(log::LevelFilter::Trace); } else { console_dispatch = console_dispatch.level(log::LevelFilter::Info); - file_dispatch = file_dispatch.level(log::LevelFilter::Debug); } - - /* - #[cfg(debug_assertions)] - let console_dispatch = console_dispatch.level(log::LevelFilter::Debug); - #[cfg(debug_assertions)] - let file_dispatch = file_dispatch.level(log::LevelFilter::Off); - #[cfg(not(debug_assertions))] - let console_dispatch = console_dispatch.level(log::LevelFilter::Info); - #[cfg(not(debug_assertions))] - let file_dispatch = file_dispatch.level(log::LevelFilter::Debug); - */ - console_dispatch - .chain(file_dispatch) - .apply() - .expect("写入日志失败"); + console_dispatch.apply().expect("写入日志失败"); }