Skip to content

Latest commit

 

History

History
621 lines (440 loc) · 20.6 KB

README.md

File metadata and controls

621 lines (440 loc) · 20.6 KB

feiq-cli

feiq-cli 是一个使用 Go 实现的 IP Messenger/飞秋兼容工具,可通过命令行或内嵌 Web 界面完成文本消息、普通文件和递归目录的发送与接收。

  • UDP 2425:文本消息与附件通知
  • TCP 2425:文件和目录数据传输
  • 字符编码:优先调用系统 iconv 使用 GBK;不可用时回退到 UTF-8

环境要求

  • Go 1.25 或更高版本
  • macOS 或 Linux
  • 本机 UDP/TCP 2425 端口未被其他飞秋、IP Messenger 或 feiq-cli 进程占用
  • 建议安装 iconv,以确保中文名称、消息和文件名兼容传统飞秋客户端
  • 只有修改 Web 源码时才需要 Node.js 24;普通编译和运行不需要 Node.js

检查 Go 环境:

go version

拉取项目

git clone git@github.com:X-for/feiq-cli.git
cd feiq-cli

如果没有配置 GitHub SSH 密钥,也可以使用 HTTPS:

git clone https://github.com/X-for/feiq-cli.git
cd feiq-cli

测试与编译

先运行测试:

go test ./...

编译命令行程序:

go build -o feiq-cli ./cmd/feiq-cli

Web 页面已经作为静态资源嵌入 Go 二进制,因此编译后不需要单独安装或启动前端。

确认程序可以运行:

./feiq-cli help
./feiq-cli version

也可以将它安装到 Go 的二进制目录:

go install ./cmd/feiq-cli

安装后请确认 Go 的二进制目录已经加入 PATH:

command -v feiq-cli
feiq-cli version

下文使用 ./feiq-cli 表示仓库根目录构建出的程序;通过 go install 安装后,可以直接将它替换为 feiq-cli。

配置文件

程序启动时默认尝试读取:

~/.feiq-cli/config.json

默认配置文件不存在时不会报错,也不会自动创建,程序会继续使用内置默认值。仓库根目录的 config.example.json 只是模板,不会被自动加载。可以复制模板后再修改:

mkdir -p ~/.feiq-cli
cp config.example.json ~/.feiq-cli/config.json

配置文件可以只填写需要修改的字段。例如只修改接收文件的保存目录:

{
  "output": "~/Downloads/飞秋接收"
}

完整配置示例:

{
  "bind": "192.168.110.25",
  "port": 2425,
  "output": "~/Downloads/飞秋接收",
  "history_file": "~/.feiq-cli/history.jsonl",
  "web_roots": ["~/", "/Volumes/data"],
  "name": "CLI 客户端",
  "host": "feiq-cli",
  "version": "1",
  "color": "auto",
  "message_wait": "5s",
  "transfer_wait": "30m"
}

支持的字段:

字段 内置默认值 适用范围
bind 0.0.0.0 所有运行模式的本地 IPv4 监听地址
port 2425 所有运行模式的 IP Messenger UDP/TCP 端口,范围 1–65535
name 当前系统主机名 所有运行模式中向对方显示的名称
host 当前系统主机名 所有运行模式中写入协议包的主机名
version 1 所有运行模式的 IP Messenger 版本字段
output ./downloads 交互模式和 receive 自动接收文件、目录的保存路径
history_file ~/.feiq-cli/history.jsonl 交互模式的本地聊天记录路径
web_roots 当前用户的 $HOME Web 页面可以浏览并发送的本机目录列表
color auto 交互模式颜色,可设为 auto、always 或 never
message_wait 交互模式 5s;send-message 为 3s 消息回执等待时间
transfer_wait 5m 交互模式、send-file 和 send-dir 的附件等待接收时间

message_wait 和 transfer_wait 使用 Go 时间格式且必须大于零,例如 500ms、5s、30m 或 1h。

配置中的 output、history_file、web_roots 以及 --config 路径支持以 ~/ 开头。其他相对路径以启动程序时的当前工作目录为基准。web_roots 中的路径必须是已存在的目录;可以配置多个目录,重复或被更宽目录包含的项会自动合并。

默认情况下,Web 页面只能浏览当前用户的 $HOME。如果确实需要浏览整台电脑,可以明确配置:

{
  "web_roots": ["/"]
}

配置 / 会允许 Web 操作者选择本机文件系统中的任意可读文件或目录。与 --allow-remote 同时使用时,局域网中能访问 Web 端口的设备也会获得该能力,请谨慎启用。

所有命令均可使用其他配置文件:

./feiq-cli --config ./config.json
./feiq-cli receive --config ./config.json
./feiq-cli send-message --config ./config.json --to 192.168.110.150 --text "测试"

显式指定的配置文件不存在时,程序会报错退出。配置采用严格 JSON 格式,不支持注释、尾随逗号或未定义字段;字段拼写错误也会直接报告。

命令行参数的优先级高于配置文件。例如配置中设置了 output,仍可在本次运行中临时覆盖:

./feiq-cli --output /tmp/received

配置字段与命令行参数的对应关系:

bind           --bind
port           --port
name           --name
host           --host
version        --version
output         --output
history_file   --history-file
color          --color
message_wait   --message-wait(交互模式)或 --wait(send-message)
transfer_wait  --transfer-wait(交互模式)或 --wait(send-file/send-dir)

快速开始

直接启动程序会进入推荐的常驻交互模式:

./feiq-cli

启动后会同时监听 UDP/TCP 2425。先选择联系人,然后可以像聊天窗口一样直接输入消息:

feiq> /to 郑安其
当前联系人: 郑安其 (192.168.110.150)
feiq[郑安其]> 你好
feiq[郑安其]> /file ./example.txt
feiq[郑安其]> /dir ./example-directory
feiq[郑安其]> /image

/to 支持用户名、主机名、完整 IP 或 IP 片段。输入 /to 郑 或 /to 150 时,当前输入行右侧会显示匹配联系人,按 Tab 补全为对应 IP。输入 / 时,命令候选同样显示在当前行右侧,不会在终端中不断产生新行。

交互输入支持以下快捷操作:

  • ← / →:移动输入光标,可在消息中间插入或删除中文、Emoji 和普通字符
  • ↑ / ↓:切换之前提交过的完整输入,并在回到末尾时恢复尚未提交的草稿
  • Tab:补全命令、/to 联系人,以及 /file、/dir 的本地路径;候选较多时可连续按 Tab 逐个切换

发送单行消息时不需要命令前缀;引号和反斜杠会作为普通消息内容原样发送。也可以明确使用:

/msg 包含 "引号" 和 \反斜杠 的消息

发送多行消息:

/compose
第一行
第二行
.send

多行模式使用 .send 发送、.cancel 取消。

文件路径包含空格时可以使用双引号:

/file "/Users/me/My Files/report.pdf"

交互模式的文件和目录路径支持 ~ 和 ~/,例如:

/dir ~/Desktop/Project/dataset/images

macOS 下可以先复制一张截图或图片,再执行 /image。程序会将剪贴板图片临时保存为 PNG,并通过普通文件协议发送;临时文件在传输结束后自动删除。对方收到的是普通 PNG 文件,不是飞秋聊天窗口中的原生图片消息。其他系统可以先将图片保存为文件,再使用 /file。

交互消息默认使用不同颜色区分收发、附件、状态和错误。颜色模式可设置为:

./feiq-cli --color auto
./feiq-cli --color always
./feiq-cli --color never

默认 auto 仅在交互终端启用颜色,并遵循 NO_COLOR 环境变量。

其他交互命令:

/users
/users 张三
/history
/history 张三
/help
/exit

程序启动后会通过 IP Messenger 广播自动发现同一局域网中的在线用户,并每分钟刷新一次。/users 会同时显示当前在线用户和聊天记录中的本地联系人;可以使用用户名、主机名或 IP 片段过滤。

/history 显示当前联系人的最近 50 条文本、文件和目录收发记录,也可以使用 /history <用户名或 IP> 查询其他联系人。历史默认保存在:

~/.feiq-cli/history.jsonl

可以在启动时修改历史文件位置:

./feiq-cli --history-file ./data/history.jsonl

旧版 /send msg|file|dir|image <IP> ... 和 /search user ... 命令仍然兼容。也支持 exit、quit 和 /quit 退出。退出时程序会停止监听、取消未完成任务并恢复终端状态。

指定监听地址、显示名称和下载目录:

./feiq-cli \
  --bind 192.168.110.25 \
  --name "CLI 客户端" \
  --output ./downloads

交互模式收到消息时会显示:

[12:30:01] [张三 192.168.110.150] 消息: 你好
[12:30:10] [张三 192.168.110.150] 收到文件: report.pdf -> downloads/report.pdf

自己发送的内容和后续状态也会显示在输入栏上方:

[12:31:00] [我 -> 192.168.110.150] 消息: 收到
[12:31:00] [已送达 -> 192.168.110.150] 对方已确认接收

交互模式会自动接受并下载附件,建议仅在受信任的局域网内使用。

独立收发命令

原有的一次性命令仍然保留。以下示例假设目标地址为 192.168.110.150。

启动接收端

接收端先启动常驻监听:

./feiq-cli receive --output ./downloads

该命令会:

  • 监听 UDP 2425
  • 在终端输出收到的文本消息
  • 自动接受文件和目录附件
  • 通过 TCP 连接发送方下载数据
  • 将内容保存到当前目录下的 downloads 目录
  • 普通文件中断后保留 partial,并在发送方再次提供相同文件时从已有字节继续

按 Ctrl+C 停止接收。也可以在交互模式中使用 exit 安全退出。

receive 当前会自动下载附件,建议仅在受信任的局域网内使用。

普通文件断点续传

普通文件接收使用 IP Messenger 标准 GETFILEDATA offset。下载未完成时,已收到的数据保存在接收目录的隐藏子目录:

downloads/.feiq-cli-partials/

partial 身份由发送方 IP、文件名、文件大小和修改时间共同确定。网络恢复或程序重启后,只要发送方再次提供相同元数据的文件,接收端就会从 partial 当前大小继续请求;成功后再移动为正常文件名,并继续使用同名文件自动重命名规则。发送端会在短暂断线后继续保留附件,允许接收端重新连接。

如果确定某项传输不再需要,可以在没有正在进行的接收任务时删除对应接收目录下的 .feiq-cli-partials。目录传输使用标准 GETDIRFILES 流,该协议没有兼容的 offset 字段,因此目录中断后仍需重新传输;程序不会使用私有扩展破坏与飞秋/IP Messenger 客户端的互操作。

目录接收会先写入接收目录下以 .feiq-cli-directory- 开头的隐藏暂存目录,完整接收后才一次性显示为正式目录名;失败时自动清理暂存内容。不要在传输完成提示出现前移动或修改隐藏暂存目录。

标准目录协议不能保留 pnpm 等工具创建的软链接、目录链接或硬链接关系。部分 Windows 飞秋客户端会沿链接展开整个 node_modules,导致实际网络流量和接收体积远大于资源管理器显示的目录大小。传输 Node.js 项目时,建议排除 node_modules 后发送源码和 lockfile,或先压缩为单个归档文件再发送。

Web 图形界面

执行一个命令即可同时启动 IP Messenger 会话、HTTP API、内嵌 Vue 页面和终端交互界面:

./feiq-cli web

浏览器访问 http://127.0.0.1:2426。Web 界面支持联系人发现与搜索、历史记录、实时消息、服务端本机路径选择、文件和目录收发以及已接收附件下载。同时可以继续在启动它的终端中使用 /to、/msg、/file、/dir、/users、/history 等 CLI 命令;Web 和 CLI 共用同一个 IP Messenger 会话、聊天记录和接收目录。输入 exit 会同时停止 CLI 和 Web 服务。

在另一个 Bash/Zsh 终端中,也可以使用位置参数短命令调用这个正在运行的会话,不会再次占用 2425:

feiq-cli msg  192.168.110.150 "你好"
feiq-cli file 192.168.110.150 ~/Desktop/photo.png
feiq-cli dir  192.168.110.150 ~/Desktop/dataset

短命令默认连接 http://127.0.0.1:2426。如果 Web/API 使用了其他本机端口,把 --api 放在目标地址前,例如 feiq-cli msg --api http://127.0.0.1:2430 192.168.110.150 "你好"。file 和 dir 的路径仍须位于服务端配置的 web_roots 中。Web/API 未运行时,短命令会明确报连接失败,不会退回到另一个独立 IP Messenger 会话。

Web 聊天记录的时间使用本机时区,并显示完整的 YYYY-MM-DD HH:mm,因此跨天、跨月和跨年的记录可以直接区分。

如果从脚本、后台服务或没有交互终端的环境启动,CLI 会自动停用。也可以显式只启动 Web/API:

./feiq-cli web --no-cli

发送文件或目录时,点击聊天标题栏的“选择本机路径”。选择器默认从当前用户的 $HOME 开始,支持允许目录切换、面包屑导航、进入子目录、选择当前目录和手动输入路径;手动定位目录成功后会自动选中该目录并启用发送按钮。浏览和手动输入都会由服务端按 web_roots 重新校验,不能通过 .. 或符号链接访问未授权目录。

附件状态从 offered 开始:接收完成后显示 completed,接收方明确拒收时显示 rejected,其他传输错误或等待超时显示 failed。

默认只允许本机访问。需要让局域网内其他设备打开页面时,必须明确启用:

./feiq-cli web --listen 0.0.0.0:2426 --allow-remote

Web 服务尚无身份认证,启用远程访问后,同一网络中能访问该端口的设备可以操作本机发送消息,并浏览、发送 web_roots 内的文件和目录,因此只应在受信任局域网中使用。

Web UI 二次开发

Vue 3 + TypeScript 源码位于 web/,Go 服务代码位于 cmd/feiq-cli/,两部分在同一仓库中保持目录分离。前端开发时:

cd web
npm install
npm run dev

Vite 页面运行在 http://127.0.0.1:5173,并将 /api 代理到 http://127.0.0.1:2426。另一个终端启动后端:

go run ./cmd/feiq-cli web

修改前端后运行 cd web && npm run build,将最新资源更新到 web/dist。api 子命令仍然保留,可在不提供页面时单独启动 HTTP API;跨域前端需要使用 --allow-origin。

发送消息

./feiq-cli send-message \
  --to 192.168.110.150 \
  --text "来自 feiq-cli 的消息"

发送后程序会等待 IPMSG_RECVMSG 回执,并报告对方是否确认接收。可调整等待时间:

./feiq-cli send-message \
  --to 192.168.110.150 \
  --text "测试消息" \
  --wait 8s

发送文件

./feiq-cli send-file \
  --to 192.168.110.150 \
  --path ./example.txt

发送方会先发送附件通知,然后等待接收方通过 TCP 回连下载。因此命令必须保持运行,直到传输完成或超时。

调整最长等待时间:

./feiq-cli send-file \
  --to 192.168.110.150 \
  --path ./example.zip \
  --wait 10m

发送目录

./feiq-cli send-dir \
  --to 192.168.110.150 \
  --path ./example-directory

目录会递归发送,保留内部子目录结构。符号链接和特殊文件不会发送。

指定接收目录

相对路径:

./feiq-cli receive --output ./received-files

绝对路径:

./feiq-cli receive --output /path/to/received-files

同名文件或目录不会覆盖,程序会自动追加数字后缀:

example.txt
example-1.txt
example-2.txt

通用参数

所有子命令均支持:

--config PATH      JSON 配置文件
--bind 0.0.0.0    本地 IPv4 监听地址
--port 2425       IP Messenger UDP/TCP 端口
--name feiq-cli   向对方显示的名称
--host HOST       协议包中的主机名
--version 1       IP Messenger 版本字段

指定本地网卡地址和显示名称:

./feiq-cli receive \
  --bind 192.168.110.25 \
  --name "CLI 接收端" \
  --output ./downloads

端口与运行限制

  • 默认同时使用 UDP 2425 和 TCP 2425。
  • Web/API 默认监听本机 TCP 2426;它不替代 IP Messenger 使用的 UDP/TCP 2425。
  • 交互模式和 web 模式在一个进程中共享 UDP/TCP 监听,可以同时收发。
  • 同一地址上的 UDP/TCP 2425 只能由一个常驻 IP Messenger 会话占用。feiq-cli web 已经运行时,不要再启动第二个交互模式或 receive。
  • feiq-cli msg/file/dir 是 HTTP 客户端,只调用当前运行的 Web/API,不会再次监听 2425。
  • 如果桌面版飞秋正在监听 2425,请先退出桌面版飞秋。
  • 使用自定义端口时,通信双方必须使用相同端口。
  • 防火墙必须允许 UDP/TCP 2425 入站和出站通信。

遇到 address already in use 时,可以分别查看占用 2425、Web 端口 2426 或自定义测试端口的进程:

lsof -nP -iTCP:2425 -iUDP:2425
lsof -nP -iTCP:2426
lsof -nP -iTCP:2525 -iUDP:2525

输出中的 PID 是占用端口的进程号。先用只读命令确认它的程序文件、工作目录和全部监听端口:

lsof -nP -a -p <PID> -d cwd,txt
lsof -nP -a -p <PID> -iTCP -iUDP

确认是自己遗留的测试进程后,再正常终止并复查端口;不要直接结束来源不明的进程:

kill <PID>
lsof -nP -iTCP:2525 -iUDP:2525

2525 不是程序默认端口,只会在显式传入 --port 2525 时使用。它通常用于本机隔离测试;使用该端口的实例不能与仍使用 2425 的飞秋设备直接通信。

当前支持范围

已支持:

  • 指定 IPv4 地址发送和接收文本消息
  • 消息接收回执
  • 普通文件发送和接收
  • 普通文件断点续传,包括重连和进程重启后继续
  • 嵌套目录递归发送和接收
  • GBK 中文兼容
  • 同名文件自动重命名
  • 接收路径安全检查
  • 常驻交互命令行及输入行实时重绘
  • 交互模式中并发发送消息和附件
  • IP Messenger 局域网在线用户自动发现
  • 本地 JSONL 聊天历史与用户检索
  • 彩色事件输出、Unicode 光标编辑和完整输入历史
  • 命令、联系人、文件与目录路径 Tab 补全
  • 当前联系人会话和多行消息编辑
  • macOS 剪贴板图片转普通 PNG 文件发送
  • 单进程 Web UI、HTTP API 和终端交互模式
  • 通过运行中 Web/API 会话执行 msg、file、dir Shell 短命令
  • Web 服务端路径选择与 web_roots 访问控制
  • Web 历史记录按本机时区显示完整年月日和时分

暂未支持:

  • 群聊及多目标群发
  • 一次发送多个附件
  • 加密、签名和密封消息
  • 飞秋原生图片、截图与表情扩展协议(普通图片文件收发不受影响)
  • 文件哈希校验和目录断点续传(标准 GETDIRFILES 不提供 offset)

开发验证

执行完整测试:

go test -race ./...
go vet ./...

发布 GitHub Release

项目已经配置 .github/workflows/release.yml。推荐通过语义化版本标签触发自动发布,本机不需要安装 GitHub CLI。

发布前先确认 main 已经提交并推送:

git switch main
git pull --ff-only
git status

创建带说明的版本标签并推送。首次发布可以使用 v0.1.0:

git tag -a v0.1.0 -m "feiq-cli v0.1.0"
git push origin v0.1.0

标签推送后,GitHub Actions 会自动:

  1. 运行 go test -race ./...。
  2. 构建 macOS amd64、macOS arm64、Linux amd64 和 Linux arm64。
  3. 将二进制、README.md、LICENSE 和配置示例打成 .tar.gz。
  4. 生成 checksums.txt。
  5. 创建 GitHub Release 并自动生成 Release Notes。

可以在仓库的 Actions → Release 查看进度,在 Releases 页面下载产物。

发布前也可以在本机预演构建:

./scripts/build-release.sh v0.1.0

产物会写入:

dist/v0.1.0/

同一版本目录已经存在时脚本会停止,避免意外覆盖已有产物。正式 Release 应当使用尚未发布的新版本号,例如 v0.1.1。

Release 二进制包含标签版本、Git 提交和构建时间:

./feiq-cli version

协议核心位于 ipmsg 包,常驻会话位于 ipmsg/session.go,交互终端位于 internal/console,CLI 入口位于 cmd/feiq-cli。可以在此基础上继续开发好友发现和传输任务管理等功能。

License

本项目采用 GNU GPL v3.0 开源协议发布。

  • 你可以使用、复制、修改和分发本项目代码。
  • 如果你分发了修改版或基于本项目的衍生作品,通常需要继续以 GPL 兼容方式公开对应源码。
  • 协议完整条款以仓库根目录的 LICENSE 为准。