使用 Rust 在 Windows 系统实现一个服务

最近我的 C 盘由蓝色变为红色(磁盘可用空间只有15GB),心里很郁闷,我最近没有安装新软件,磁盘为什么就会满,经过了一番排查后,发现有一个软件会偷偷截屏并存为图片文件,而且几乎每隔两分钟就截屏一次,非常恶心。

为了解决这个问题:

1、需要监控某个文件夹,如果文件夹里面新增了文件,则删除。

2、服务需要运行在后台。

3、服务需要开机自启动。

恰好我最近在学 Rust,所以我就使用 Rust 来练练手。

监控文件夹

rust 复制代码
// 监控的文件夹路径
let folder_to_watch = Path::new("D:\\test");

// 创建一个通道用于接收文件系统事件
let (tx, rx) = channel();

// 创建一个文件监控器
let mut watcher = RecommendedWatcher::new(tx, NotifyConfig::default()).expect("无法创建文件监控器");

// 监听指定文件夹的更改事件
watcher.watch(folder_to_watch, RecursiveMode::NonRecursive).expect("无法监听文件夹");

// 进入事件监听循环
loop {
    match rx.recv() {
        Ok(event) => match event {
            Ok(event) => {
                if event.kind == EventKind::Create(CreateKind::Any) {
                    for path in event.paths {
                        remove_file(&path);
                    }
                }
            }
            Err(e) => error!("错误: {}", e),
        },
        Err(e) => error!("监控文件错误: {}", e),
    }
}

fn remove_file(path: &PathBuf) {
    if path.is_file() {
        // 尝试删除文件
        sleep(Duration::from_secs(1));
        match fs::remove_file(&path) {
            Ok(_) => info!("成功删除文件: {:?}", path),
            Err(e) => {
                error!("删除文件失败: {:?}, 错误: {}", path, e)
            }
        }
    }
}

info!error! 宏来自 log crate。

实现服务

实现服务依赖了 windows-service

服务的主体结构是这样的:

rust 复制代码
use log::error;
use std::ffi::OsString;
use windows_service::service_dispatcher;

#[macro_use]
extern crate windows_service;
define_windows_service!(ffi_service_main, my_service_main);

const SERVICE_NAME: &str = "FolderMonitor";

fn my_service_main(arguments: Vec<OsString>) {
    if let Err(e) = run_service(arguments) {
        error!("运行服务错误:{:?}", e);
    }
}

fn run_service(_args: Vec<OsString>) -> Result<(), windows_service::Error> {
    // 服务入口
    // @TODO 监控文件夹
    // @TODO 服务运行时,把服务状态改为运行中
    // @TODO 服务停止运行时,退出事件监听循环、停止监控文件夹、把服务状态为已停止
    Ok(())
}

fn main() -> Result<(), windows_service::Error> {
    service_dispatcher::start(SERVICE_NAME, ffi_service_main)?;
    Ok(())
}

完整的run_service代码如下

rust 复制代码
fn run_service(_args: Vec<OsString>) -> Result<(), windows_service::Error> {
    // 初始化日志系统,将日志写入 LOG_FILE
    let log_file = OpenOptions::new()
        .create(true)
        .append(true)
        .open(LOG_FILE)
        .expect("无法打开日志文件");

    // 自定义日志格式:包含日期和时间
    let config = ConfigBuilder::new().set_time_format_rfc3339().build();

    CombinedLogger::init(vec![
        TermLogger::new(
            LevelFilter::Warn,
            Config::default(),
            TerminalMode::Mixed,
            ColorChoice::Auto,
        ),
        WriteLogger::new(LevelFilter::Info, config, log_file),
    ])
    .unwrap();

    info!("Windows 服务已启动");

    // 用于控制主循环的退出
    let running = Arc::new(AtomicBool::new(true));
    let running_clone = Arc::clone(&running);

    // 监控的文件夹路径
    let folder_to_watch = Path::new(MONITOR_PATH);

    // 创建一个通道用于接收文件系统事件
    let (tx, rx) = channel();

    // 创建一个文件监控器
    let mut watcher =
        RecommendedWatcher::new(tx, NotifyConfig::default()).expect("无法创建文件监控器");

    // 监听指定文件夹的更改事件
    watcher
        .watch(folder_to_watch, RecursiveMode::NonRecursive)
        .expect("无法监听文件夹");

    // 设定 Windows 服务控制处理器
    let status_handle =
        service_control_handler::register(SERVICE_NAME, move |control| match control {
            ServiceControl::Stop => {
                info!("收到服务停止命令");
                running_clone.store(false, Ordering::Relaxed); // 更新状态,让主循环退出
                return ServiceControlHandlerResult::NoError;
            }
            ServiceControl::Interrogate => ServiceControlHandlerResult::NoError,
            _ => ServiceControlHandlerResult::NotImplemented,
        })
        .unwrap();

    status_handle
        .set_service_status(ServiceStatus {
            service_type: ServiceType::OWN_PROCESS,
            current_state: ServiceState::Running,
            controls_accepted: ServiceControlAccept::STOP,
            exit_code: ServiceExitCode::Win32(0),
            checkpoint: 0,
            wait_hint: Duration::default(),
            process_id: None,
        })
        .unwrap();

    info!("开始监控文件夹: {}", folder_to_watch.to_string_lossy());

    // 进入事件监听循环
    while running.load(Ordering::Relaxed) {
        match rx.recv_timeout(Duration::from_secs(1)) {
            Ok(event) => match event {
                Ok(event) => {
                    if event.kind == EventKind::Create(CreateKind::Any) {
                        for path in event.paths {
                            remove_file(&path);
                        }
                    }
                }
                Err(e) => error!("错误: {}", e),
            },
            Err(_) => {}
        }
    }

    // 停止监听文件夹变动
    if let Err(e) = watcher.unwatch(folder_to_watch) {
        error!("停止监控文件夹失败: {}", e);
    } else {
        info!("已停止监控文件夹: {}", folder_to_watch.to_string_lossy());
    }

    status_handle
        .set_service_status(ServiceStatus {
            service_type: ServiceType::OWN_PROCESS,
            current_state: ServiceState::Stopped,
            controls_accepted: ServiceControlAccept::empty(),
            exit_code: ServiceExitCode::Win32(0),
            checkpoint: 0,
            wait_hint: Duration::default(),
            process_id: None,
        })
        .unwrap();

    info!("服务已停止");

    Ok(())
}

安装服务

以管理员身份运行命令行提示符应用

cmd 复制代码
sc create FolderMonitor binPath= "D:\Program Files\folder-monitor\folder_monitor_service.exe" # 创建服务

sc start FolderMonitor # 启动服务

sc stop FolderMonitor # 停止服务

参考

注:以上研究成果是在ChatGPT帮助下完成。

notify

windows-service

log

simplelog

相关推荐
aimmon22 分钟前
Rust从入门到精通之精通篇:25.过程宏高级应用
开发语言·后端·rust
aimmon1 小时前
Rust从入门到精通之精通篇:24.高级异步编程
开发语言·算法·rust
用户96715113916722 小时前
Rust 与 FFmpeg 实现视频水印添加:技术解析与应用实践
rust·ffmpeg
aimmon5 小时前
Rust从入门到精通之进阶篇:19.Rust 生态系统
开发语言·后端·rust
amirth7 小时前
在 Rust 基于 Juniper GraphQL 库实现 Relay 分页规范
rust
Bigger19 小时前
Tauri(十六)——为托盘菜单添加快捷键提示
前端·rust·app
Hello.Reader19 小时前
初探 Dubbo Rust SDK打造现代微服务的新可能
微服务·rust·dubbo
yezipi耶不耶21 小时前
Rust 入门之闭包(Closures)
开发语言·后端·rust
勇敢牛牛_21 小时前
【Rust基础】使用Rust和WASM开发的图片压缩工具
开发语言·rust·wasm·图片压缩
amirth1 天前
在 Tauri 中使用 GraphQL
rust