Skip to main content

btcli_lib/
lib.rs

1// Copyright (C) 2026 S.A. (@snoware)
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use lazy_static::lazy_static;
8use log::{Level, Log, Metadata, Record, SetLoggerError};
9use std::fs::OpenOptions;
10use std::sync::Mutex;
11
12lazy_static! {
13    pub static ref LOG_FILE: Mutex<std::fs::File> = {
14        Mutex::new(
15            OpenOptions::new()
16                .create(true)
17                .append(true)
18                .open("btcli_app.log")
19                .expect("无法创建日志文件"),
20        )
21    };
22}
23
24// 自定义日志宏 - 仅在启用调试时记录日志
25#[macro_export]
26macro_rules! log_to_file {
27    ($($arg:tt)*) => {
28        if let Ok(config) = crate::conf::try_init_conf() {
29            if config.enable_logging {
30                if let Ok(mut file) = crate::LOG_FILE.lock() {
31                    use std::io::Write;
32                    // 使用 write! 替代 writeln!,手动添加换行符和处理编码
33                    let log_msg = format!("[{}] {}\n", chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), format_args!($($arg)*));
34                    let _ = file.write_all(log_msg.as_bytes());
35                    let _ = file.flush(); // 确保立即写入
36                }
37            }
38        } else {
39            // 如果无法加载配置,也记录日志(这可能是早期阶段)
40            if let Ok(mut file) = crate::LOG_FILE.lock() {
41                use std::io::Write;
42                // 使用 write! 替代 writeln!,手动添加换行符和处理编码
43                let log_msg = format!("[{}] {}\n", chrono::Local::now().format("%Y-%m-%d %H:%M:%S"), format_args!($($arg)*));
44                let _ = file.write_all(log_msg.as_bytes());
45                let _ = file.flush(); // 确保立即写入
46            }
47        }
48    };
49}
50
51// 与 Rust 标准日志系统兼容的文件日志记录器
52pub struct FileLogger;
53
54impl Log for FileLogger {
55    fn enabled(&self, metadata: &Metadata) -> bool {
56        // 检查配置是否启用了日志记录
57        if let Ok(config) = crate::conf::try_init_conf() {
58            config.enable_logging && metadata.level() <= Level::Info
59        } else {
60            // 如果无法加载配置,默认启用
61            metadata.level() <= Level::Info
62        }
63    }
64
65    fn log(&self, record: &Record) {
66        if self.enabled(record.metadata()) {
67            if let Ok(mut file) = LOG_FILE.lock() {
68                use std::io::Write;
69                let log_msg = format!(
70                    "[{}] [{}] {}\n",
71                    chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
72                    record.level(),
73                    record.args()
74                );
75                let _ = file.write_all(log_msg.as_bytes());
76                let _ = file.flush();
77            }
78        }
79    }
80
81    fn flush(&self) {
82        if let Ok(file) = LOG_FILE.lock() {
83            let _ = file.sync_all();
84        }
85    }
86}
87
88impl FileLogger {
89    pub fn init() -> Result<(), SetLoggerError> {
90        log::set_boxed_logger(Box::new(FileLogger))
91            .map(|()| log::set_max_level(log::LevelFilter::Info))
92    }
93}
94
95// 导出必要的模块
96pub mod conf;
97pub mod expect_react;
98pub mod extract_help;
99pub mod fancy_egg;
100pub mod fycore;
101pub mod fyerrcodes;
102pub mod ui;