Skip to content

Commit 572749a

Browse files
committed
feat: add transfer controls and background services
1 parent ec41fd4 commit 572749a

38 files changed

Lines changed: 1598 additions & 66 deletions

CHANGELOG.en.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
All notable changes to `ii` are documented here. The default Chinese version is [CHANGELOG.md](CHANGELOG.md).
44

5+
## Unreleased
6+
7+
### Added
8+
9+
- `ii send` and `ii recv` support `--checksum md5|sha256`; checksums are calculated and printed locally only, never stored in tickets or compared automatically.
10+
- `ii send <file> --preserve-metadata` uses the existing tar payload to retain single-file mtime, permissions, and read-only metadata; directory and multi-path archives support `--symlinks follow|preserve|reject`.
11+
- Added process-local FIFO `ii queue` and polling `ii watch`, including delay, repeat, stability detection, and existing sending backends.
12+
- `ii send`, `ii recv`, `ii watch`, and `ii queue` support `--quic-port` to fix the P2P Iroh UDP port; `ii doctor --nat` reports a short-lived UDP, NAT, and relay probe.
13+
- `ii web --once` exits after the first complete ordinary-file download; directory pages, HEAD, Range, uploads, and failed requests do not stop it.
14+
515
## 0.3.4 - 2026-08-06
616

717
### Changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
本文件记录 `ii` 的重要变更。默认中文版本在这里,英文版本见 [CHANGELOG.en.md](CHANGELOG.en.md)
44

5+
## Unreleased
6+
7+
### 新增
8+
9+
- `ii send``ii recv` 支持 `--checksum md5|sha256`;校验和仅在本地计算和输出,不写入 ticket,也不自动比较。
10+
- `ii send <file> --preserve-metadata` 可用现有 tar 载荷保留单文件的 mtime、权限和只读属性;目录和多路径归档支持 `--symlinks follow|preserve|reject`
11+
- 新增进程内 FIFO `ii queue` 与轮询式 `ii watch`,支持延迟、定时、稳定检测和现有发送后端。
12+
- `ii send``ii recv``ii watch``ii queue` 支持 `--quic-port` 固定 P2P Iroh UDP 端口;`ii doctor --nat` 输出短生命周期的 UDP、NAT 和 relay 探测结果。
13+
- `ii web --once` 在第一次完整普通文件下载后关闭;目录页、HEAD、Range、上传和失败请求不会触发关闭。
14+
515
## 0.3.4 - 2026-08-06
616

717
### 变更

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ unused-async = "warn"
1818

1919
[package]
2020
name = "ii"
21-
version = "0.3.4"
21+
version = "0.3.5"
2222
edition.workspace = true
2323
rust-version.workspace = true
2424
license.workspace = true
@@ -30,7 +30,7 @@ base64 = "0.22"
3030
futures-util = "0.3"
3131
glob = "0.3.3"
3232
hmac = "0.12"
33-
iroh = { path = "vendor/iroh/iroh", default-features = false, features = ["tls-ring"] }
33+
iroh = { path = "vendor/iroh/iroh", default-features = false, features = ["tls-ring", "unstable-net-report"] }
3434
iroh-relay = { path = "vendor/iroh/iroh-relay", default-features = false, features = ["server-minimal"] }
3535
md5 = { package = "md-5", version = "0.10" }
3636
percent-encoding = "2"

README.en.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
`ii` is a CLI for temporary file transfer: it connects peer-to-peer by default, discovers services on the LAN, and automatically falls back to Iroh's default n0 relay when direct connectivity is unavailable.
2323

2424
- Send files, folders, multiple paths, or piped data. Receives resume, skip matching MD5 files, and overwrite conflicts.
25+
- Compute local checksums, preserve single-file metadata, choose symlink behavior, and run FIFO queues or directory watches.
2526
- Use generic S3, Cloudflare R2, Azure Blob, WebDAV, FTP, or SFTP as optional backends, with cleanup after receiving.
2627
- It also provides LAN web sharing, WebDAV, browser transfer, TCP tunnels, and self-hosted relays.
2728

@@ -112,10 +113,29 @@ ii send .\video.mp4 -o recv.txt
112113
113114
# JSON Lines for automation
114115
ii send .\video.mp4 --json
116+
117+
# Print a checksum of the bytes being sent
118+
ii send .\video.mp4 --checksum sha256
119+
120+
# Preserve mtime, permissions, and read-only metadata for one file
121+
ii send .\video.mp4 --preserve-metadata
115122
```
116123

117124
Plain `ii send` exits after its first successful transfer. `-t` serves up to 16 receivers concurrently and queues up to 1,000 more in first-in, first-out order. Concurrent receivers share sender bandwidth; retry later when the queue is full. With `--json`, stdout contains JSON Lines only.
118125

126+
`--checksum md5|sha256` computes and prints the local payload checksum. It is not stored in the ticket and is not compared automatically. `--preserve-metadata` accepts one regular file only and wraps it in the existing tar payload; it rejects stdin and `--web`, and disables resume and MD5 skip for that send.
127+
128+
### Queues and Directory Watches
129+
130+
```powershell
131+
ii queue .\a.zip .\b.zip
132+
ii queue .\report.pdf --after 10s
133+
ii queue .\folder --every 1h
134+
ii watch .\incoming --interval 2s --stabilize 2s
135+
```
136+
137+
`queue` and `watch` are process-local and non-persistent. They accept `--rate`, storage backends, relay, `--local`, `--no-relay`, `--checksum`, `--preserve-metadata`, and `--symlinks`; they reject `-t`, `-c`, `-o`, `--web`, and `--json`. `--quic-port <1..65535>` fixes the Iroh UDP port for P2P jobs.
138+
119139
### Storage Backends
120140

121141
| Backend | Send command | Notes |
@@ -144,6 +164,8 @@ ii recv ii1k7v...x9a --json
144164

145165
If the network drops halfway, run the same `ii recv` command again and it continues receiving. If the target file already exists with the same content, it is skipped. If the name matches but the content differs, it is overwritten. `ii send` and `ii recv` show progress, speed, and elapsed time; `--trace` prints connection diagnostics. `--stdout` cannot be combined with `--json`.
146166

167+
`--checksum md5|sha256` computes the received file or directory tar stream after completion and cannot be combined with `--stdout`. `--quic-port` applies only to P2P tickets.
168+
147169
## Extended Capabilities
148170

149171
### LAN Web Sharing and WebDAV
@@ -167,6 +189,8 @@ ii dav .\shared --port 8443 --username alice --password secret --tls --domain da
167189

168190
`--port 8080` fixes the port, `--bind ::` listens on IPv6 only, and bare `--token` generates a path token while `--token <value>` uses the supplied token. A path token is not account authentication.
169191

192+
`ii web --once` exits only after the first complete ordinary-file `GET 200`. HEAD, Range, directory pages, 404 responses, and uploads do not consume the one-shot lifetime, and `--once` conflicts with `--upload`.
193+
170194
### LAN Discovery
171195

172196
```powershell
@@ -231,9 +255,12 @@ ii recv ii1k7v...x9a --trace
231255
232256
# Check local networking, ports, permissions, and version
233257
ii doctor
258+
ii doctor --nat
234259
ii version
235260
```
236261

262+
`ii doctor --nat` runs a short-lived UDP/NAT/relay probe and reports bound UDP sockets, IPv4/IPv6, NAT mapping behavior, the preferred relay, and relay reachability. Hairpin is explicitly unavailable because Iroh does not expose that probe.
263+
237264
## Full Manual
238265

239266
Full command, configuration, and troubleshooting reference: [ii.md](ii.md).

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
`ii` 是临时文件传输命令行工具:默认 P2P 直连,局域网可发现;无法直连时自动降级到 Iroh 默认的 n0 relay。
2323

2424
- 发送文件、目录、多文件和管道数据;接收支持断点续传、同 MD5 跳过和冲突覆盖。
25+
- 支持发送端校验和、单文件 metadata 保留、符号链接策略、FIFO 队列和目录监视。
2526
- 可选通用 S3、Cloudflare R2、Azure Blob、WebDAV、FTP、SFTP 中转;传完可删除中转对象。
2627
- 另有局域网网页、WebDAV、浏览器直传、TCP 隧道和自建 relay。
2728

@@ -112,10 +113,29 @@ ii send .\video.mp4 -o recv.txt
112113
113114
# 面向自动化的 JSON Lines
114115
ii send .\video.mp4 --json
116+
117+
# 输出实际发送字节的校验和
118+
ii send .\video.mp4 --checksum sha256
119+
120+
# 单文件保留 mtime、权限和只读属性
121+
ii send .\video.mp4 --preserve-metadata
115122
```
116123

117124
普通 `ii send` 在首次成功发送后退出。`-t` 最多同时服务 16 个接收端,另有最多 1000 个 FIFO 排队连接;并发接收共享发送端带宽,满队列时稍后重试。`--json` 时 stdout 只输出 JSON Lines。
118125

126+
`--checksum md5|sha256` 只在本地计算并输出实际发送字节,不写入 ticket,也不自动和接收端比较。`--preserve-metadata` 只适用于单个常规文件,会使用现有 tar 载荷,因此不支持 stdin、`--web`、断点续传和 MD5 秒传。
127+
128+
### 队列与目录监视
129+
130+
```powershell
131+
ii queue .\a.zip .\b.zip
132+
ii queue .\report.pdf --after 10s
133+
ii queue .\folder --every 1h
134+
ii watch .\incoming --interval 2s --stabilize 2s
135+
```
136+
137+
`queue``watch` 只在当前进程内排队,不持久化;它们接受 `--rate`、后端、relay、`--local``--no-relay``--checksum``--preserve-metadata``--symlinks`,不接受 `-t``-c``-o``--web``--json``--quic-port <1..65535>` 可固定 P2P 的 Iroh UDP 端口。
138+
119139
### 后端中转
120140

121141
| 后端 | 发送命令 | 说明 |
@@ -144,6 +164,8 @@ ii recv ii1k7v...x9a --json
144164

145165
断网或传到一半失败后,重新执行同一条 `ii recv` 就会继续接收;如果目标文件已经完整且内容相同,会直接跳过;如果同名但内容不同,会覆盖。`ii send``ii recv` 都会显示传输进度、速率和完成耗时;`--trace` 输出连接诊断。`--stdout` 不能与 `--json` 同用。
146166

167+
`--checksum md5|sha256` 在接收完成后计算实际文件或目录 tar 流;不能与 `--stdout` 同用。`--quic-port` 只适用于 P2P ticket。
168+
147169
## 扩展能力
148170

149171
### 局域网网页与 WebDAV
@@ -167,6 +189,8 @@ ii dav .\shared --port 8443 --username alice --password secret --tls --domain da
167189

168190
`--port 8080` 固定端口,`--bind ::` 只监听 IPv6;裸 `--token` 生成路径令牌,`--token <value>` 使用指定令牌。路径 token 不是账号鉴权。
169191

192+
`ii web --once` 只在第一次完整的普通文件 `GET 200` 后退出;HEAD、Range、目录页、404 和上传不会消耗这次机会,且不能和 `--upload` 同用。
193+
170194
### 局域网发现
171195

172196
```powershell
@@ -231,9 +255,12 @@ ii recv ii1k7v...x9a --trace
231255
232256
# 检查本机网络、端口、权限和版本
233257
ii doctor
258+
ii doctor --nat
234259
ii version
235260
```
236261

262+
`ii doctor --nat` 会运行一次短生命周期 UDP/NAT/relay 探测,输出实际 UDP socket、IPv4/IPv6、NAT 映射、首选 relay 和 relay 在线结果;Iroh 未公开 hairpin 探测时会明确标记为不可用。
263+
237264
## 详细手册
238265

239266
完整命令、配置和故障排查见 [ii.md](ii.md)

SIZE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ All measurements use `cargo build -p ii --release --locked` followed by UPX
3434
| `ii webrtc` text messages | 6,124,544 | 2,204,672 | +512 | Compared with the same `0.2.2` tunnel baseline (6,120,448 / 2,204,160); `cargo test -p ii --locked` (104 tests), `cargo build -p ii --release --locked`, UPX `5.1.0 --best --lzma`, `upx -t` |
3535
| Seven extension plan: multi-send, filters, rate, JSON, discover, bind, DAV | 6,315,008 | 2,265,600 | +60,928 | `cargo test -p ii --offline --no-fail-fast -- --test-threads=1` (121 tests), workspace check, `cargo build -p ii --release --locked`, `cargo bloat --crates`, UPX `5.1.0 --best --lzma`, `upx -t` |
3636
| Generic S3/R2 split and Azure Blob backend | 6,413,312 | 2,436,608 | +171,008 | `cargo test -p ii --locked` (131 tests), `cargo check -p ii-gui --locked`, `cargo bloat --crates`, UPX `5.1.0 --best --lzma`, `upx -t` |
37+
| Nine low-volume extensions: checksums, metadata, queue/watch, NAT probe, symlink policy, QUIC port, and `web --once` | 6,650,368 | 2,353,152 | -83,456 | `cargo test -p ii --locked` (146 tests), fmt check, diff check, `cargo bloat -p ii --release --crates -n 15`, standard `cargo build -p ii --release --locked`, UPX `5.1.0 --best --lzma`, `upx -t` |
3738

3839
Equivalent release rebuilds have varied by up to `1,536` UPX bytes; the latest
3940
measurement is recorded with the pinned `5.1.0` packer.

ii.md

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,22 @@
1010

1111
```text
1212
ii help [<command>]
13-
ii send [<path>...] [--name <name>] [--include <glob>] [--exclude <glob>] [--rate <bytes/s>] [--json] [-t] [-c] [-o <path>] [--web [--port <port>] [--bind <ip>] [--token [<value>]] [--upload] [--path <path>] | --s3 | --r2 | --azure | --webdav | --ftp | --sftp] [--profile <name>] [-d] [-p] [--local] [--relay <url> [-k]] [--no-relay]
14-
ii web [<目录>] [--port <port>] [--bind <ip>] [--token [<value>]] [--upload] [--path <目录>]
13+
ii send [<path>...] [--name <name>] [--include <glob>] [--exclude <glob>] [--rate <bytes/s>] [--json] [--checksum <md5|sha256>] [--preserve-metadata] [--symlinks <follow|preserve|reject>] [--quic-port <port>] [-t] [-c] [-o <path>] [--web [--port <port>] [--bind <ip>] [--token [<value>]] [--upload] [--path <path>] | --s3 | --r2 | --azure | --webdav | --ftp | --sftp] [--profile <name>] [-d] [-p] [--local] [--relay <url> [-k]] [--no-relay]
14+
ii watch <目录> [--interval <duration>] [--stabilize <duration>] [发送选项]
15+
ii queue <path...> [--after <duration>|--every <duration>] [发送选项]
16+
ii web [<目录>] [--port <port>] [--bind <ip>] [--token [<value>]] [--upload] [--path <目录>] [--once]
1517
ii dav [<目录>] [--port <port>] [--bind <ip>] [--token [<value>]] [--read-only] [--username <username> --password <password>] [--tls [--domain <name>] [--cert <path> --key <path>]]
1618
ii webrtc [--port <port>] [--bind <ip>] [--token [<value>]]
1719
ii tunnel -s <target-host:port> [--relay <url> [-k]]
1820
ii tunnel -c <ticket> [--listen <ip:port>]
19-
ii recv <ticket> [-o <dir>] [--stdout] [--overwrite] [--resume] [--local] [--trace]
21+
ii recv <ticket> [-o <dir>] [--stdout] [--overwrite] [--resume] [--local] [--trace] [--checksum <md5|sha256>] [--quic-port <port>]
2022
ii relay [--port <port>] [--tls [--domain <name>] [--cert <path> --key <path>]]
2123
ii discover [--json]
22-
ii doctor
24+
ii doctor [--nat]
2325
ii version
2426
```
2527

26-
`ii help` 显示命令总览;`ii help send``ii help web``ii help webrtc``ii help tunnel``ii help recv``ii help relay``ii help doctor``ii help version` 显示对应命令帮助,内容与 `<command> --help` 相同。
28+
`ii help` 显示命令总览;`ii help send``ii help watch``ii help queue``ii help web``ii help dav``ii help webrtc``ii help tunnel``ii help recv``ii help relay``ii help discover``ii help doctor``ii help version` 显示对应命令帮助,内容与 `<command> --help` 相同。
2729

2830
## 核心规则
2931

@@ -110,6 +112,18 @@ tar czf - .\project | ii send --name project.tar.gz
110112
`--rate <bytes/s>`
111113
: 限制发送端总带宽,支持正整数 bytes/s 以及 `KiB``MiB``GiB` 后缀;多接收端共享同一个上限。
112114

115+
`--checksum md5|sha256`
116+
: 只在本地计算实际发送字节并输出,不写入 ticket,也不自动比较。目录和多文件输出 tar 流校验和。
117+
118+
`--preserve-metadata`
119+
: 只允许一个常规文件;将其包装为现有 tar 载荷,保留 mtime、权限和只读属性。它不支持 stdin、`--web`、断点续传或 MD5 秒传。
120+
121+
`--symlinks <follow|preserve|reject>`
122+
: 目录和多路径归档中的符号链接策略,默认 `follow``preserve` 保留链接条目,`reject` 发现链接即失败。`watch``queue` 也接受此参数。
123+
124+
`--quic-port <1..65535>`
125+
: 固定 P2P Iroh UDP 端口;未指定时仍随机。端口占用或无法绑定直接失败。
126+
113127
`--json`
114128
: 输出稳定 JSON Lines;stdout 只输出事件,诊断和错误走 stderr。`recv --stdout --json` 不允许使用;JSON 后端缺 profile 时直接失败,不弹配置提示。
115129

@@ -212,6 +226,29 @@ Azure SAS 模式把 `auth` 改为 `"sas"`,移除 `account_key`,加入具有
212226
- 指定 `--relay http://...``--relay https://...` 后,当前发送会强制走 relay-only,不使用默认公网 relay。
213227
- 手工证书 relay 不带 `-k`;自签 relay 必须带 `-k`
214228

229+
## `ii queue`
230+
231+
```powershell
232+
ii queue .\a.zip .\b.zip
233+
ii queue .\report.pdf --after 10s
234+
ii queue .\folder --every 1h
235+
```
236+
237+
每个位置参数是一个独立发送任务,按 FIFO 顺序执行,不会像 `ii send a b` 那样打成一个集合。`--after` 延迟一次执行;`--every` 在上一轮全部完成后等待再重复,二者互斥。duration 只接受正整数和 `ms``s``m``h` 后缀。队列只存在于当前进程,失败任务会报错后继续;`Ctrl+C` 会停止当前队列。
238+
239+
`queue` 接受 `--rate`、后端、relay、`--local``--no-relay``--checksum``--preserve-metadata``--symlinks``--quic-port`;拒绝 `-t``-c``-o``--web``--json`
240+
241+
## `ii watch`
242+
243+
```powershell
244+
ii watch .\incoming
245+
ii watch .\incoming --interval 500ms --stabilize 2s --checksum sha256
246+
```
247+
248+
`watch` 递归扫描普通文件,默认每 2 秒扫描;启动时已有文件只建立基线,不会立即发送。启动后的新增或变化文件在连续扫描中保持路径、大小和 mtime 不变达到 `--stabilize` 后入队,逐个生成独立 ticket 并按 FIFO 等待任务完成。它不使用文件系统监听器,进程退出后队列丢失。
249+
250+
`watch` 接受 `--rate`、后端、relay、`--local``--no-relay``--checksum``--preserve-metadata``--symlinks``--quic-port`;拒绝 `-t``-c``-o``--web``--json`
251+
215252
## `ii web`
216253

217254
```powershell
@@ -224,6 +261,8 @@ ii web .\shared --port 8080 --token A1b2C3d4E5f6G7h8 --upload --path .\uploads
224261

225262
命令行会在主 IPv4 LAN URL 上方打印根页二维码,并在 `other:` 下打印其他物理和虚拟网卡 URL;网页不显示二维码。`--bind <ip>` 可固定 IPv4 或 IPv6 listener;显式 bind 只打印该地址。按 `Ctrl+C` 关闭服务。
226263

264+
`--once` 只在第一次完整的普通文件 `GET 200` 后关闭服务;HEAD、Range、目录页、404 和上传不会消耗单次机会,且不能与 `--upload` 同用。
265+
227266
`--port <port>` 指定 `1``65535` 的 HTTP 监听端口,未提供时随机选择。裸 `--token` 自动生成 32 字符路径令牌;`--token <value>``--token=<value>` 使用指定令牌,把目录、文件和已启用的上传 URL 固定到 `/<value>/` 下;遗漏或写错返回 `404`。显式令牌必须为 16 到 128 个 ASCII 字母、数字、`-``_``--upload` 才显示上传控件并开放上传接口;`--path <目录>` 指定上传文件直接写入的目录,相对路径按启动目录解析,首次上传才创建目录,未指定时写入启动目录下的 `./ii/`,未提供 `--upload` 时会被忽略。`-p` 不适用于 `ii web`,仍仅用于 WebDAV、FTP、SFTP 的便携 ticket。
228267

229268
## `ii dav`
@@ -347,6 +386,12 @@ ii recv ii1k7v...x9a --local --trace
347386
`--trace`
348387
: 输出接收过程的分段耗时、地址统计、写入字节数和平均速度,便于排查为什么慢。
349388

389+
`--checksum md5|sha256`
390+
: 接收完成后计算并输出实际文件或目录 tar 流;不与发送端自动比对,且不能与 `--stdout` 同用。
391+
392+
`--quic-port <1..65535>`
393+
: 固定 P2P Iroh UDP 端口;后端 ticket 不能使用该参数。
394+
350395
### 接收规则
351396

352397
- `--stdout``--resume` 不同时用。
@@ -489,7 +534,22 @@ ii relay --port 8443
489534
ii doctor
490535
```
491536

492-
`doctor` 用来查:
537+
`doctor` 默认只读取本地配置和运行环境,不创建网络服务、不修改配置,也不改变端口或 relay 设置。
538+
539+
```powershell
540+
ii doctor --nat
541+
```
542+
543+
`--nat` 会创建一个短生命周期的默认 Iroh endpoint,报告:
544+
545+
- 实际绑定的 UDP socket 及 IPv4/IPv6 可用性
546+
- Iroh net-report 的 UDP 探测结果和 NAT 映射是否随目标变化
547+
- 首选 relay 与 relay 在线结果
548+
- `hairpin` 明确显示为 `unavailable`,因为当前 Iroh 公开 API 没有 hairpin 探测字段
549+
550+
探测结束后 endpoint 立即关闭;该命令不保存网络状态,也不伪造缺失的 hairpin 结果。
551+
552+
默认 `doctor` 会输出:
493553

494554
- 网络连通性
495555
- 直连是否可用

0 commit comments

Comments
 (0)