npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nv-file-watch

v1.0.7

Published

基于 `nd-file-notify` 的高性能文件监控服务,带 Web UI 和 SSE 实时推送。

Downloads

614

Readme

nv-file-watch

基于 nd-file-notify 的高性能文件监控服务,带 Web UI 和 SSE 实时推送。

✨ 功能特性

  • 🚀 高性能监控 - 基于 Linux fanotify API,零轮询开销
  • 🔄 重命名检测 - 内核 5.17+ 支持原子重命名事件(包含源和目标路径)
  • 🔗 符号链接识别 - 自动检测符号链接并解析目标路径
  • 🌐 Web UI - 实时事件可视化,分类显示
  • 📡 SSE 推送 - 服务器发送事件(Server-Sent Events)实时通知
  • 🔌 Nginx 集成 - 支持 Unix socket,轻松集成到 Nginx
  • 🔐 HTTPS 支持 - 可配置 SSL/TLS
  • ⚡ 内核兼容 - 自动降级支持低版本内核
  • 🎯 智能过滤 - 嵌套删除过滤,只报告顶层事件

📋 系统要求

  • 操作系统: Linux
  • 内核版本:
    • 推荐: 5.17+ (完整 FAN_RENAME 支持)
    • 最低: 5.9+ (FAN_REPORT_DFID_NAME 支持)
    • 兼容性: < 5.17 自动降级为 moved_from/moved_to 事件
  • 权限: root 或 CAP_SYS_ADMIN
  • Node.js: 14+ (需要 N-API 支持)

📦 安装

npm install nv-file-watch

🚀 快速开始

基本用法(控制台输出)

const createWatch = require("nv-file-watch");

// 监控目录,输出到控制台
const srv = await createWatch("/path/to/watch");

启用 Web UI

const createWatch = require("nv-file-watch");

// 监控目录,启动 Web UI 在 http://localhost:3000
const srv = await createWatch("/path/to/watch", "http://127.0.0.1:3000");

// 访问 http://127.0.0.1:3000 查看实时事件

自定义回调

const createWatch = require("nv-file-watch");

const srv = await createWatch(
    "/home/user",
    undefined, // 不启动 SSE 服务
    (ftype, event_name, path, path2) => {
        if (event_name === "renamed") {
            // 内核 5.17+ 支持
            console.log(`[RENAME] ${ftype}: ${path} -> ${path2}`);
        } else if (event_name === "moved_from") {
            // 内核 < 5.17 降级
            console.log(`[MOVE FROM] ${ftype}: ${path}`);
        } else if (event_name === "moved_to") {
            // 内核 < 5.17 降级
            console.log(`[MOVE TO] ${ftype}: ${path}`);
        } else if (ftype === "link" && event_name === "created") {
            console.log(`[SYMLINK] ${path} -> ${path2}`);
        } else {
            console.log(`[${event_name.toUpperCase()}] ${ftype}: ${path}`);
        }
    }
);

🔧 API 文档

主函数

async function createWatch(
    watch_dir?: string,      // 监控目录,默认 "/"
    listen_on?: string,      // SSE 服务地址,undefined 则不启动
    callback?: Function,     // 事件回调
    chown_to_user?: string,  // Unix socket 所有者
    key_buf?: Buffer,        // HTTPS 私钥
    cert_buf?: Buffer        // HTTPS 证书
): Promise<Srv>

参数说明:

  • watch_dir: 要监控的目录路径(绝对或相对路径)
  • listen_on:
    • HTTP/HTTPS: "http://127.0.0.1:3000""https://0.0.0.0:3443"
    • Unix socket: "___socket_name___" (配合 Nginx)
    • undefined: 不启动 SSE 服务
  • callback: 事件回调函数 (ftype, event_name, path, path2) => void
    • ftype: "dire" | "file" | "link"
    • event_name: "created" | "deleted" | "modified" | "renamed" | "moved_from" | "moved_to" | "attr"
    • path: 文件路径(renamed 时为源路径,link 时为链接路径)
    • path2: 第二路径(renamed 时为目标路径,link 时为目标路径)
  • chown_to_user: Unix socket 文件所有者,如 "www-data"(仅 Unix socket 有效)
  • key_buf: HTTPS 私钥 Buffer
  • cert_buf: HTTPS 证书 Buffer

返回值:

interface Srv {
    mon: {
        start(): void;
        stop(): void;
        add(path: string): boolean;
        del(path: string): boolean;
        has(path: string): boolean;
        list(): string[];
    };
    sse: any;  // SSE 服务器实例(如果启用)
}

Nginx 配置生成器

const { creat_ngx_srv } = require("nv-file-watch");

const config = creat_ngx_srv(
    "/var/www",           // 监控目录
    "/opt/app",           // 工作目录(socket 位置)
    8847                  // 端口
);

console.log(config.ngx);   // Nginx 配置
console.log(config.code);  // Node.js 启动代码

🌐 Web UI 使用

启动服务

const srv = await require("nv-file-watch")(
    "/path/to/watch",
    "http://0.0.0.0:3000"  // 监听所有网卡
);

访问界面

打开浏览器访问 http://服务器IP:3000

功能:

  • 📊 实时事件统计
  • 📝 按类型分类的事件日志
  • 🎨 事件类型颜色编码:
    • 🟢 绿色:创建
    • 🟡 黄色:修改
    • 🔴 红色:删除
    • 🔵 青色:重命名
    • 🟠 橙色:移出 (moved_from)
    • 🟢 青绿:移入 (moved_to)
    • 🟣 紫色:属性
  • 🔗 符号链接显示目标路径
  • 🔄 重命名显示源和目标路径

🔌 Nginx 集成

1. 生成配置

const { creat_ngx_srv } = require("nv-file-watch");

const config = creat_ngx_srv("/var/www", "/opt/app", 8847);

// 保存配置
const fs = require("fs");
fs.writeFileSync("/etc/nginx/conf.d/filewatch.conf", config.ngx);
fs.writeFileSync("/opt/app/start.js", config.code);

2. 生成的 Nginx 配置示例

server {
    listen 8847;
    
    # 根路径返回 HTML
    location = / {
        proxy_pass http://unix:/opt/app/___nv_file_watch___:/NvSSEClient.html;
    }
    
    # SSE 和静态资源
    location / {
        proxy_pass http://unix:/opt/app/___nv_file_watch___;
    }
}

3. 启动服务

# 启动 Node.js 服务(使用 www-data 用户)
sudo -u www-data node /opt/app/start.js

# 重载 Nginx
sudo nginx -s reload

# 访问 http://your-server:8847

4. 使用 systemd 管理

# /etc/systemd/system/filewatch.service
[Unit]
Description=File Watch Service
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/app
ExecStart=/usr/bin/node /opt/app/start.js
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl enable filewatch
sudo systemctl start filewatch
sudo systemctl status filewatch

📝 事件类型说明

内核 5.17+ (推荐)

| 事件 | 说明 | ftype | path | path2 | |------|------|-------|------|-------| | created | 文件/目录创建 | file/dire | 新建路径 | - | | created | 符号链接创建 | link | 链接路径 | 目标路径 | | deleted | 文件/目录删除 | file/dire | 删除路径 | - | | modified | 文件/目录修改 | file/dire | 修改路径 | - | | renamed | 文件/目录重命名 | file/dire | 源路径 | 目标路径 | | attr | 属性变化 | file/dire | 路径 | - |

内核 5.9-5.16 (降级模式)

重命名操作会产生两个独立事件:

| 事件 | 说明 | ftype | path | path2 | |------|------|-------|------|-------| | moved_from | 从原位置移出 | file/dire | 源路径 | undefined | | moved_to | 移入新位置 | file/dire | 目标路径 | undefined |

注意: 低版本内核无法将 moved_frommoved_to 关联起来,需要在应用层自行匹配。

🔬 高级特性

1. 嵌套删除过滤

删除包含文件的目录时,只报告顶层目录删除事件,不报告内部文件/子目录的删除:

// 删除 /data/dir1 (包含 file1.txt 和 subdir/)
// 只产生一个事件:
// { ftype: 'dire', event_name: 'deleted', path: '/data/dir1' }

2. LRU 路径缓存

自动缓存文件句柄到路径的映射,显著提升性能(10-100倍加速):

  • 缓存大小: 65536 entries
  • 自动过期: ESTALE 错误时清理
  • 级联清理: 父目录删除时清理子项

3. 符号链接检测

创建符号链接时自动检测并解析目标路径:

// ln -s /target/path /link/path
// 产生事件:
// { ftype: 'link', event_name: 'created', path: '/link/path', target: '/absolute/target/path' }

4. 动态监控管理

const srv = await createWatch("/", "http://127.0.0.1:3000");

// 添加监控目录
srv.mon.add("/new/path");

// 移除监控
srv.mon.del("/old/path");

// 检查是否监控
const watching = srv.mon.has("/some/path");

// 列出所有监控目录
const dirs = srv.mon.list();

// 停止监控
srv.mon.stop();

// 重启监控
srv.mon.start();

🛡️ 安全考虑

  1. 权限要求: 需要 root 或 CAP_SYS_ADMIN
  2. 性能影响: fanotify 在高负载下可能影响系统性能(已优化,使用 LRU 缓存)
  3. 路径泄露: Web UI 会暴露文件系统路径,建议使用 Unix socket + Nginx 并配置访问控制
  4. 资源限制: 内核对 fanotify 实例数和标记数有限制

🐛 故障排查

权限错误

Error: fanotify_init failed: Operation not permitted

解决: 使用 sudo 运行或添加 CAP_SYS_ADMIN 能力

sudo node app.js
# 或
sudo setcap 'cap_sys_admin+ep' $(which node)

内核版本不支持

Error: FAN_REPORT_DFID_NAME not supported

解决: 升级内核到 5.9+ 或使用传统的 inotify 方案

事件丢失

检查内核日志:

dmesg | grep fanotify

增加内核限制:

# /etc/sysctl.conf
fs.fanotify.max_user_marks = 1048576
fs.fanotify.max_user_groups = 128

sudo sysctl -p

Web UI 无法访问

检查防火墙:

sudo ufw allow 3000/tcp
# 或
sudo firewall-cmd --add-port=3000/tcp --permanent
sudo firewall-cmd --reload

📚 相关项目

📄 License

ANY