(options: ParseOptions)
| 117 | // ==================== 解析器实现 ==================== |
| 118 | |
| 119 | async function* parseTelegram(options: ParseOptions): AsyncGenerator<ParseEvent, void, unknown> { |
| 120 | const { filePath, batchSize = 5000, formatOptions, onProgress, onLog } = options |
| 121 | |
| 122 | // 获取目标聊天索引 |
| 123 | const chatIndex = (formatOptions?.chatIndex as number) ?? 0 |
| 124 | |
| 125 | const totalBytes = getFileSize(filePath) |
| 126 | let bytesRead = 0 |
| 127 | let messagesProcessed = 0 |
| 128 | |
| 129 | // 发送初始进度 |
| 130 | const initialProgress = createProgress('parsing', 0, totalBytes, 0, '') |
| 131 | yield { type: 'progress', data: initialProgress } |
| 132 | onProgress?.(initialProgress) |
| 133 | |
| 134 | onLog?.('info', `开始解析 Telegram JSON 文件,大小: ${(totalBytes / 1024 / 1024).toFixed(2)} MB`) |
| 135 | onLog?.('info', `目标聊天索引: ${chatIndex}`) |
| 136 | |
| 137 | // 使用 stream-json 流式解析目标聊天 |
| 138 | // 定位到 chats.list[chatIndex] 对象 |
| 139 | const chatPathFilter = `chats.list.${chatIndex}` |
| 140 | |
| 141 | const chatData = await new Promise<TelegramChat | null>((resolve, reject) => { |
| 142 | const readStream = fs.createReadStream(filePath, { encoding: 'utf-8' }) |
| 143 | |
| 144 | readStream.on('data', (chunk: string | Buffer) => { |
| 145 | bytesRead += typeof chunk === 'string' ? Buffer.byteLength(chunk) : chunk.length |
| 146 | }) |
| 147 | |
| 148 | const pipeline = chain([ |
| 149 | readStream, |
| 150 | parser(), |
| 151 | pick({ filter: new RegExp(`^${chatPathFilter.replace('.', '\\.')}$`) }), |
| 152 | streamValues(), |
| 153 | ]) |
| 154 | |
| 155 | let found = false |
| 156 | |
| 157 | pipeline.on('data', ({ value }: { value: TelegramChat }) => { |
| 158 | found = true |
| 159 | resolve(value) |
| 160 | }) |
| 161 | |
| 162 | pipeline.on('end', () => { |
| 163 | if (!found) resolve(null) |
| 164 | }) |
| 165 | |
| 166 | pipeline.on('error', reject) |
| 167 | }) |
| 168 | |
| 169 | if (!chatData) { |
| 170 | onLog?.('error', `未找到索引 ${chatIndex} 对应的聊天`) |
| 171 | yield { type: 'error', data: new Error(`未找到索引 ${chatIndex} 对应的聊天`) } |
| 172 | return |
| 173 | } |
| 174 | |
| 175 | onLog?.('info', `找到聊天: "${chatData.name}", 类型: ${chatData.type}, 消息数: ${chatData.messages?.length || 0}`) |
| 176 |
nothing calls this directly
no test coverage detected