# zmodem2-js **中文文档** | [English](README.md) > **注意:** > > 本项目是对 [zmodem2](https://codeberg.org/jarkko/zmodem2) Rust crate 的 JavaScript/TypeScript 移植。部分代码由 KiloCode 的 GLM5 模型 (z.ai) 生成。 > > **所有的原始作者署名归属于 Jarkko Sakkinen。** 这是一个面向 JavaScript/TypeScript 的现代 ZMODEM 文件传输协议库。该库提供类似流的状态机,用于通过 ZMODEM 协议发送和接收文件,适用于 Node.js 和浏览器环境。 ## 功能特性 - **跨平台**:同时支持 Node.js 与浏览器环境 - **原生 TypeScript 支持**:提供完整的类型声明文件 - **多种模块格式**:提供 ESM、CommonJS 与打包后的一体化版本 - **可摇树优化(tree-shakeable)**:ESM 输出支持摇树优化以减小包体积 - **零运行时依赖**:轻量且自包含 - **流式 API**:通过流式操作高效处理大文件 ## 安装 ```bash npm install zmodem2 ``` ## 模块格式 本包提供多种输出格式以适应不同的使用场景: | 格式 | 路径 | 说明 | |------|------|------| | ESM | `dist/esm/` | ES 模块,支持摇树优化,无捆绑依赖 | | CommonJS | `dist/cjs/` | CommonJS 模块,无捆绑依赖 | | CommonJS Full | `dist/cjs-full/` | 所有代码打包到单一文件的 CommonJS 版本 | | Browser | `dist/browser/` | 供浏览器直接使用的 IIFE 格式 | ## 使用方法 ### ES 模块 (ESM) — 推荐用于打包器 适用于支持摇树优化的现代打包器(如 webpack、rollup、vite 等): ```javascript import { Sender, Receiver, ZmodemError } from 'zmodem2' ``` // 创建用于发送的 Sender const sender = new Sender() // 创建用于接收的 Receiver const receiver = new Receiver() ### CommonJS - Node.js 在 Node.js 中使用 `require()` 时: ```javascript const { Sender, Receiver, ZmodemError } = require('zmodem2') // 创建用于发送的 Sender const sender = new Sender() // 创建用于接收的 Receiver const receiver = new Receiver() ``` ### CommonJS 完整包 - Node.js(一体化) 适用于希望将所有代码打包到单一文件的环境: ```javascript const zmodem2 = require('zmodem2/cjs-full') const { Sender, Receiver } = zmodem2 // 使用 Sender 与 Receiver const sender = new Sender() ``` ### 浏览器 (IIFE/UMD) 无需打包器即可直接在浏览器中使用: ```html ``` 或通过 CDN: ```html ``` ## API 概览 ### 核心类 #### `Sender` 用于通过 ZMODEM 协议发送文件。 ```javascript const sender = new Sender() // 获取要发送到对端的字节 const outgoingBytes = sender.drainOutgoing() // 写入字节后推进发送状态 sender.advanceOutgoing() // 向 Sender 提供从远端接收的字节 sender.feedIncoming(bytes) // 发起发送文件请求 const fileRequest = sender.pollFile() if (fileRequest) { sender.feedFile(fileData) } // 检查事件 const event = sender.pollEvent() ``` #### `Receiver` 用于通过 ZMODEM 协议接收文件。 ```javascript const receiver = new Receiver() // 获取要发送到对端的字节 const outgoingBytes = receiver.drainOutgoing() // 写入字节后推进接收状态 receiver.advanceOutgoing() // 向 Receiver 提供从远端接收的字节 receiver.feedIncoming(bytes) // 获取接收到的文件字节 const fileBytes = receiver.drainFile() if (fileBytes) { // 写入存储 receiver.advanceFile() } // 检查事件 const event = receiver.pollEvent() ``` ### 事件 `Sender` 与 `Receiver` 通过 `pollEvent()` 发出事件: ```typescript enum SenderEvent { Ready = 'ready', FileRequest = 'fileRequest', Sent = 'sent', Error = 'error', Complete = 'complete' } enum ReceiverEvent { Ready = 'ready', FileStart = 'fileStart', FileData = 'fileData', FileEnd = 'fileEnd', Error = 'error', Complete = 'complete' } ``` ### 错误处理 ```javascript import { ZmodemError, NotConnectedError, ReadError, WriteError } from 'zmodem2' try { // ZMODEM 操作 } catch (error) { if (error instanceof ZmodemError) { console.error('ZMODEM 错误:', error.message) } } ``` ### 常量与工具函数 ```javascript import { // 常量 ZPAD, ZDLE, XON, SUBPACKET_MAX_SIZE, SUBPACKET_PER_ACK, // CRC 工具 crc16Xmodem, crc32IsoHdlc, Crc16, Crc32, // ZDLE 编码表 ZDLE_TABLE, UNZDLE_TABLE, escapeByte, unescapeByte, // 头部类型 Encoding, Frame, Zrinit, Header, decodeHeader, createZrinit } from 'zmodem2' ``` ## TypeScript 支持 本包包含 TypeScript 类型声明文件,无需额外的 `@types/` 包。 ```typescript import { Sender, Receiver, SenderEvent, ReceiverEvent, FileRequest, ZmodemError } from 'zmodem2' const sender: Sender = new Sender() const event: SenderEvent | null = sender.pollEvent() ``` ## 从源码构建 ```bash # 克隆仓库 git clone https://github.com/zxdong262/zmodem2-js.git cd zmodem2-js # 安装依赖 npm install # 构建所有格式 npm run build # 构建指定格式 npm run build:esm # 仅 ESM npm run build:cjs # 仅 CommonJS npm run build:types # 仅声明文件 ``` ### 构建输出结构 ``` dist/ esm/ # ES 模块(支持摇树优化) index.js index.d.ts ... cjs/ # CommonJS 模块 index.cjs index.d.ts ... cjs-full/ # 打包后的 CommonJS index.cjs index.d.ts browser/ # 浏览器包 zmodem2.js zmodem2.min.js index.d.ts ``` ## 测试 ```bash # 运行单元测试 npm test # 运行集成测试 npm run test:upload npm run test:download # 监听模式 npm run test:watch ``` ## 许可证 MIT 许可证 - 详细信息见 [LICENSE](LICENSE)。 ## 演示(Demo) 本项目包含一个演示应用,用于展示 ZMODEM 文件传输功能。演示应用由以下部分组成: - **演示服务器**:位于 `src/server/index.mjs` 的 Node.js 服务器,提供用于终端仿真和 ZMODEM 文件传输的 WebSocket 连接 - **演示客户端**:位于 `src/client/` 的基于 React 的 Web 客户端,提供具有 ZMODEM 支持的终端界面 ### 运行演示 1. **安装依赖**(如果尚未安装): ```bash npm install ``` 2. **配置 SSH 连接**: 在项目根目录创建一个 `.env` 文件,包含您的 SSH 连接详细信息: ``` TEST_HOST=localhost TEST_PORT=22 TEST_USER=您的用户名 TEST_PASS=您的密码 # 或使用 SSH 密钥 # TEST_KEY_PATH=/path/to/your/ssh/key ``` 3. **启动演示**: ```bash npm start ``` 这将同时启动演示服务器和客户端的开发服务器。 4. **访问演示**: 打开浏览器并导航到 `http://localhost:5173` 以访问演示客户端。 ### 演示功能 - **终端仿真**:通过 SSH 连接进行完整的终端仿真 - **ZMODEM 文件传输**:支持使用 ZMODEM 协议发送和接收文件 - **WebSocket 通信**:客户端和服务器之间的实时通信 - **WASM 支持**:使用 WebAssembly 进行高性能 CRC 计算 ### 演示服务器代码 演示服务器代码位于 `src/server/index.mjs`,提供: - 用于终端连接的 WebSocket 端点 - SSH 连接管理 - 日志功能 - 跨域请求的 CORS 支持 ### 演示客户端代码 演示客户端代码位于 `src/client/`,包括: - 使用 xterm.js 的基于 React 的终端界面 - 用于文件传输功能的 ZMODEM 插件 - 用于与服务器通信的 WebSocket 客户端 - 用于发送文件的文件选择对话框 ## 相关项目 - [zmodem2-wasm](https://www.npmjs.com/package/zmodem2-wasm) - 使用 WebAssembly 提供高性能 CRC 计算的实现 - [electerm](https://github.com/electerm/electerm) - 支持 ZMODEM 的终端应用,使用本库进行 ZMODEM 文件传输