chore: auto-commit after quick-task

GSD-Unit: Q3
pull/43/head
David Li 2026-05-13 17:19:09 +08:00
parent 7d2a54c416
commit 107af74a72
3 changed files with 41 additions and 67 deletions

View File

@ -114,6 +114,8 @@ pub fn ensure_daemon(tcp_addr: Option<&str>) -> Result<()> {
}
/// 启动 daemon 进程(自身二进制,设置 WX_DAEMON_MODE=1
///
/// tracing 已在子进程 main() 中直接写入 daemon.log无需重定向 stdout/stderr。
fn start_daemon() -> Result<()> {
let exe = std::env::current_exe().context("无法获取当前可执行文件路径")?;
@ -124,23 +126,11 @@ fn start_daemon() -> Result<()> {
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
// 日志文件:~/.wx-cli/daemon.log
let log_path = config::log_path();
// 确保父目录存在
if let Some(parent) = log_path.parent() {
let _ = std::fs::create_dir_all(parent);
}
let (stdout_stdio, stderr_stdio) = std::fs::OpenOptions::new()
.create(true).append(true)
.open(&log_path)
.and_then(|f| f.try_clone().map(|g| (f, g)))
.map(|(f, g)| (std::process::Stdio::from(f), std::process::Stdio::from(g)))
.unwrap_or_else(|_| (std::process::Stdio::null(), std::process::Stdio::null()));
let mut cmd = std::process::Command::new(&exe);
cmd.env("WX_DAEMON_MODE", "1")
.stdin(std::process::Stdio::null())
.stdout(stdout_stdio)
.stderr(stderr_stdio);
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null());
// SAFETY: setsid() 在 fork 后的子进程中调用,使 daemon 脱离控制终端
unsafe { cmd.pre_exec(|| { libc::setsid(); Ok(()) }); }
let _ = cmd.spawn().context("无法启动 daemon 进程")?;
@ -149,50 +139,16 @@ fn start_daemon() -> Result<()> {
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
let log_path = config::log_path();
if let Some(parent) = log_path.parent() {
let _ = std::fs::create_dir_all(parent);
}
let (stdout_stdio, stderr_stdio) = std::fs::OpenOptions::new()
.create(true).append(true)
.open(&log_path)
.and_then(|f| f.try_clone().map(|g| (f, g)))
.map(|(f, g)| (std::process::Stdio::from(f), std::process::Stdio::from(g)))
.unwrap_or_else(|_| (std::process::Stdio::null(), std::process::Stdio::null()));
let _ = std::process::Command::new(&exe)
.env("WX_DAEMON_MODE", "1")
.stdin(std::process::Stdio::null())
.stdout(stdout_stdio)
.stderr(stderr_stdio)
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.creation_flags(0x00000008) // DETACHED_PROCESS
.spawn()
.context("无法启动 daemon 进程")?;
}
// 等待 daemon 就绪(最多 STARTUP_TIMEOUT_SECS 秒)
let deadline = std::time::Instant::now() + Duration::from_secs(STARTUP_TIMEOUT_SECS);
while std::time::Instant::now() < deadline {
std::thread::sleep(Duration::from_millis(300));
if is_alive(None) {
return Ok(());
}
}
bail!(
"wx-daemon 启动超时(>{}s\n请查看日志: {}",
STARTUP_TIMEOUT_SECS,
config::log_path().display()
)
}
/// 启动 daemon 前检查 `~/.wx-cli/` 可写,给出比"超时"更明确的错误。
///
/// 典型坑:旧版本 `sudo wx init` 把目录留成 root 属主,非 root 的 daemon
/// 连 socket/log 都建不了,会静默失败 15s 超时。
fn preflight_cli_dir_writable() -> Result<()> {
let cli_dir = config::cli_dir();
std::fs::create_dir_all(&cli_dir)
.with_context(|| format!("创建 {} 失败", cli_dir.display()))?;
let probe = cli_dir.join(".daemon_probe");
match std::fs::File::create(&probe) {

View File

@ -23,21 +23,15 @@ pub fn run() {
/// 从 CLI `wx daemon start [--tcp ADDR]` 调用
///
/// 查找当前可执行文件路径,设置 WX_DAEMON_MODE=1后台启动新进程。
/// tracing 已在子进程 main() 中直接写入 daemon.log无需重定向 stdout/stderr。
pub fn run_start(tcp_addr: Option<String>) -> Result<()> {
let exe = std::env::current_exe()?;
let log = config::log_path();
let mut cmd = std::process::Command::new(&exe);
cmd.env("WX_DAEMON_MODE", "1");
if let Some(addr) = &tcp_addr {
cmd.env("WX_DAEMON_TCP_ADDR", addr);
}
// 日志重定向
let log_file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&log)?;
cmd.stdout(log_file.try_clone()?).stderr(log_file);
#[cfg(unix)]
{
@ -88,7 +82,7 @@ pub async fn start_daemon(tcp_addr: Option<String>) -> Result<()> {
// 收集消息 DB 列表
let msg_db_keys: Vec<String> = all_keys.keys()
.filter(|k| {
let k = k.replace('\\', "/");
let k = k.replace('\', "/");
k.contains("message/message_") && k.ends_with(".db")
&& !k.contains("_fts") && !k.contains("_resource")
})
@ -154,7 +148,7 @@ fn extract_keys(json: &serde_json::Value) -> HashMap<String, String> {
};
if !enc_key.is_empty() {
// 统一路径分隔符
let rel = k.replace('\\', "/");
let rel = k.replace('\', "/");
result.insert(rel, enc_key);
}
}

View File

@ -7,8 +7,8 @@ mod cli;
pub mod transport;
fn main() {
init_logging();
if std::env::var("WX_DAEMON_MODE").is_ok() {
init_logging();
daemon::run();
} else {
cli::run();
@ -17,14 +17,38 @@ fn main() {
fn init_logging() {
use tracing_subscriber::EnvFilter;
// 默认只输出 WARN+ 到 stderr不污染用户可见的 stdout
// 通过 `RUST_LOG=info` 或 `RUST_LOG=debug` 开启详细日志。
// CLI 路径不需要 tracing — 只输出用户可见的 stdout/stderr。
// daemon 路径tracing 直接写入 ~/.wx-cli/daemon.log
// 不依赖父进程的 stderr 重定向(避免重复写入)。
let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| {
EnvFilter::new("info")
});
tracing_subscriber::fmt()
.with_target(false)
.with_level(true)
.with_env_filter(env_filter)
.init();
let _ = std::fs::create_dir_all(config::cli_dir());
let log_file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(config::log_path())
.ok();
match log_file {
Some(file) => {
tracing_subscriber::fmt()
.with_target(false)
.with_level(true)
.with_env_filter(env_filter)
.with_writer(file)
.init();
}
None => {
// 文件打开失败时退回到 stderr确保日志不会静默丢失
tracing_subscriber::fmt()
.with_target(false)
.with_level(true)
.with_env_filter(env_filter)
.with_writer(std::io::stderr)
.init();
}
}
}