use ::log::{debug, error, info, trace, warn}; use encoding_rs::Encoding; use tokio::runtime::Runtime; mod log; mod network; #[cxx::bridge] mod ffi { extern "Rust" { fn download_file(url: &CxxString, path: &CxxString) -> Result<()>; fn http_get(url: &CxxString) -> Result; fn init_log(is_debug: bool); fn log_trace(msg: &CxxString); fn log_debug(msg: &CxxString); fn log_info(msg: &CxxString); fn log_warning(msg: &CxxString); fn log_error(msg: &CxxString); } } fn log_error(msg: &cxx::CxxString) { let msg = cxx_string_to_string(msg); error!("{}", msg); } fn log_warning(msg: &cxx::CxxString) { let msg = cxx_string_to_string(msg); warn!("{}", msg); } fn log_info(msg: &cxx::CxxString) { let msg = cxx_string_to_string(msg); info!("{}", msg); } fn log_debug(msg: &cxx::CxxString) { let msg = cxx_string_to_string(msg); debug!("{}", msg); } fn log_trace(msg: &cxx::CxxString) { let msg = cxx_string_to_string(msg); trace!("{}", msg); } fn init_log(is_debug: bool) { log::init_log(is_debug); } fn get_runtime() -> Runtime { Runtime::new().expect("创建Tokio运行时失败") } fn download_file( url: &cxx::CxxString, path: &cxx::CxxString, ) -> Result<(), Box> { let rt = get_runtime(); 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: &cxx::CxxString) -> Result> { let rt = get_runtime(); 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() }