xiaoshuai f158377742 fix(compat): Windows 兼容性修复 + 跨平台兼容分析
终端在 Windows 上起不来 (打包规则漏解包)
- 根因: build.asarUnpack 写的是 "**/node_modules/@lydell/node-pty-*/*", 只匹配一层,
  于是 prebuilds/<plat>/ 下的文件没被解包, 留在 app.asar 里
- Windows 上这些必须是磁盘上的真实文件: conpty.dll (OS loader 加载)、
  OpenConsole.exe (CreateProcess)、以及 node-pty 用 worker_threads.Worker 起的
  conoutSocketWorker.js —— node-pty 本身就写了
  __dirname.replace('node_modules.asar', 'node_modules.asar.unpacked') 来适配
- Linux 上看不出来: 只需要一个 pty.node, Electron 的 asar 层能 dlopen 归档里的 .node
- 修复: 规则递归化为 "**/node_modules/@lydell/node-pty-*/**/*"
- 验证: 重新打包后 pty.node 已落到 app.asar.unpacked, 安装版真实 spawn 成功

Windows 保留设备名 / 尾部点空格导致落盘写错
- 新增 src/main/safe-name.ts 的 safeFileName()
- Win32 把 CON/PRN/AUX/NUL/COM1-9/LPT1-9 (带扩展名也算) 当设备, open() 打开的不是文件;
  还会悄悄吃掉文件名结尾的点和空格, 导致 existsSync 判断和实际落盘对不上
- 两处落盘都接上: file-server.ts 的 targetPath()、drive.ts 的 downloadDriveFile()
  (后者名字来自对端共享目录, 属不可信输入)
- 策略是"最小必要": 非法字符全平台都清, 保留名和尾点空格只在 win32 上改写,
  避免动到 Linux 上合法的文件名

其他
- 终端 cwd: Windows 优先用 USERPROFILE (装了 Git Bash 时 HOME 可能是 POSIX 路径, Win32 下不存在)
- USB 面板空列表提示按平台给, 不再一律说"Linux 用户需要在 dialout 组"

分析文档与自测
- 新增 docs/windows-compat.md: 各原生模块的 N-API 情况、已有 win32 分支的位置、
  已知限制 (ConPTY 需 Win10 1809+、防火墙首次弹窗、USB 需 WinUSB 驱动等)、
  以及一份 Windows 真机验证清单
- 自测新增 S1-S8 组: 保留名改写、尾部点空格、非法字符、跨平台不过度清洗、
  超长截断、默认 shell/cwd、asarUnpack 规则回归护栏、上传落盘 + 路径穿越
- 全部 38 条用例通过
2026-10-20 16:59:26 +08:00

LocalNetMsg

局域网即时通讯工具,飞书/微信聊天风格。基于 Electron + Vue 3 + TypeScript。

功能

  • 局域网自动发现 (UDP 广播)
  • 1 对 1 私聊,消息持久化 (SQLite)
  • 富文本消息:Markdown / 代码高亮 / @提醒 / 表情
  • 图片消息:粘贴板、拖拽、本地选择
  • 文件传输:任意类型,大文件流式上传
  • 飞书式三栏 UI,消息气泡、时间分组、发送状态
  • 系统托盘最小化,后台新消息系统级通知
  • 接收文件按 设置目录/YYYY-MM/ 自动归档

开发

环境要求: Node.js >= 20

npm install
npm run dev        # 启动 Electron + 热更新

第一次启动时:

  • 默认接收目录: ~/Documents/LocalNetMsg
  • 默认设备名: 操作系统主机名
  • 两个端口自动分配 (UDP 发现 47800 / WebSocket 47900 / 文件 47901)

要测试多设备,在同一局域网的不同机器上各跑一个实例即可。

项目结构

src/
├── main/          Electron 主进程
│   ├── index.ts     入口: 窗口、托盘、IPC
│   ├── discovery.ts UDP 局域网发现
│   ├── chat-server  WebSocket 服务端
│   ├── chat-client  WebSocket 客户端
│   ├── file-server  HTTP 文件服务
│   ├── db.ts        SQLite 持久化
│   ├── settings.ts  electron-store
│   ├── notify.ts    系统通知
│   └── protocol.ts  消息协议定义
├── preload/       contextBridge 桥接
└── renderer/      Vue 3 渲染层
    ├── src/
    │   ├── views/      ChatView, SettingsView
    │   ├── components/ Sidebar, MessageList, MessageItem, MessageInput
    │   ├── stores/     Pinia
    │   ├── api/        IPC 桥接
    │   └── utils/      markdown, format
    └── index.html

配置

~/AppData/Roaming/local-net-msg/config.json (electron-store):

  • deviceName: 本机在网络中的显示名
  • downloadDir: 接收文件保存目录
  • notifications: 是否启用系统通知

端口

用途 端口 协议
局域网发现 47800 UDP
聊天 47900 WebSocket
文件传输 47901 HTTP

被占用时自动顺延。

S
Description
No description provided
Readme 1.4 MiB
Languages
TypeScript 70.8%
Vue 23.6%
JavaScript 5.3%
CSS 0.2%