给 JVM 的多线程下载引擎
TurboDL 是一个用纯 Kotlin 从零写的下载内核:按 HTTP Range 分片并发、可断点续传,并把「不是 HTTP 的东西」做成插件框架。不依赖 Android,任何 JVM 应用都能直接用。
它能做什么
下载引擎真正要紧的六件事 —— 其余在 README 里。
分片并发下载
按 HTTP Range 并行下载分片,并复用连接(HTTP/2 多路复用 + keep-alive)。
动态分片 + 工作窃取
细粒度预分片 + 工作窃取:一条慢连接拖不垮整个传输,也消除了「最后一个分片单线程收尾」的长尾。
克制的自适应
**只在**遇到 429/503 或连续失败时才降低并发。普通抖动绝不改线程数 —— 不做 AIMD 来回震荡。
按真实进度续传
分片状态落盘;暂停/继续按磁盘上真实写完的字节接着下,而不是按记忆中的数字。
拒绝 Range 篡改
会核对服务端实际返回的字节是否就是请求的那段 Range —— 忽略 Range 直接回整文件的服务端会被识别出来,而不是把错位数据写进文件。
字节级完整性校验
合并完成后校验总大小;少了或多了都判为失败。
九项引擎能力
每一项都是公开的配置字段 —— 没有藏着的手法。
| 能力 | 配置项 | 说明 |
|---|---|---|
| 全局限速 | globalSpeedLimitBytesPerSec | 0 = 不限速 |
| 线程数 | maxConnectionsPerTask | 1..256 |
| 并发任务数 | maxConcurrentTasks | 1..64 |
| 最大重试 | maxRetries | 0..50 |
| 动态分片 | dynamicSegmentation | true / false |
| 代理 | proxy | 直连 / 系统 / 手动(HTTP,SOCKS,鉴权) / PAC |
| DNS | dns | 系统 / 静态 hosts / DoH(url) |
| 忽略 SSL | trustAllCerts | 抓包调试用 |
| 主题 | — | 由上层应用负责;SDK 不涉及界面 |
模块构成
只有 turbodl-core 是必需的。其余都是你主动加进来的插件。
| 构件 | 作用 | 必需? |
|---|---|---|
| turbodl-core | 下载引擎本体 分片并发下载、断点续传、重试、限速、DNS/代理。可单独使用,**不依赖**插件框架。 | 必需 |
| turbo-plugin-runtime | 插件运行时内核 生命周期、清理(disposer)、事件总线、服务注册表、扩展点、版本握手、诊断。对任何具体协议一无所知。 | 可选 |
| turbo-plugin-bootstrap | 基础装配 一次调用装配基础插件(Kotlin 加载器 + HTTP 后端),并桥接引擎的事件流。 | 可选 |
| turbo-plugin-hls | HLS VOD 适配 解析 M3U8 清单、分片并发下载(分片级重试)、AES-128 解密、支持 EXT-X-BYTERANGE。直播/DRM/fMP4 清单会被**明确拒绝**,而不是产出一个损坏的文件。 | 可选 |
| turbo-plugin-js | JavaScript 插件加载器 加载用 JavaScript 写的 TurboDL 插件。内嵌 QuickJS —— 每个脚本一个 runtime 与 context —— 并给脚本一套稳定的 `host`/`plugin` ABI。 | 可选 |
| turbodl-cli | 命令行工具 基于 SDK 的完整命令行工具:多线程、断点续传、批量、给脚本与 Agent 用的 NDJSON 输出。以 fat JAR 形式提供。 | 可选 |
快速开始
加一个依赖、提交一个请求、订阅事件。完整的 API(暂停 / 继续 / 取消 / 批量 / 诊断)见文档。
Kotlin
val client = TurboClient(
TurboConfig(
maxConnectionsPerTask = 16, // up to 256 / 最高 256
globalSpeedLimitBytesPerSec = 0, // 0 = unlimited / 不限速
dynamicSegmentation = true,
)
)
val id = client.submit(
DownloadRequest(url = "https://example.com/big.zip", destination = File("big.zip"))
)
client.events.collect { event ->
when (event) {
is TurboEvent.Progress -> println("${event.progress.percent}%")
is TurboEvent.Completed -> println("done: ${event.file}")
is TurboEvent.Failed -> println("failed: ${event.reason}")
else -> {}
}
}
val result = client.await(id) // Result<File>
client.shutdown()插件框架
TurboDL 既是独立的引擎,也是可选的插件平台。内核不认识任何协议:它只提供生命周期、清理、事件总线、服务注册表、扩展点、版本握手与诊断 —— 全部就这些。
Kotlin · bootstrap
val boot = TurboBootstrap.create(
config = TurboConfig(maxConnectionsPerTask = 16),
extraPlugins = listOf(HlsPlugin()),
)
boot.host.loadSource(
PluginSource(kind = "js", uri = "/opt/turbodl-plugins/acme-parser.js")
)写在文档里的东西
读者会想知道的每一件事 —— 插件怎么写、清单有哪些必填项、会连带引入哪些库、什么数据会离开你的机器、协议究竟写了什么 —— 在这里是一页,在仓库里是一个文件。两处由同一份源渲染,不会各说各话。