106 lines
2.4 KiB
Rust
106 lines
2.4 KiB
Rust
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<String>;
|
||
|
||
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<dyn std::error::Error>> {
|
||
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<String, Box<dyn std::error::Error>> {
|
||
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()
|
||
}
|