(options: ParseOptions)
| 274 | } |
| 275 | |
| 276 | async function* parseGoogleChat(options: ParseOptions): AsyncGenerator<ParseEvent, void, unknown> { |
| 277 | const { filePath, batchSize = 5000, onProgress, onLog } = options |
| 278 | const { manifest, userInfoPath, groupInfoPath, messagesPath } = readManifest(filePath) |
| 279 | const userInfo = readJson<GoogleChatUserInfo>(userInfoPath) |
| 280 | const groupInfo = readJson<GoogleChatGroupInfo>(groupInfoPath) |
| 281 | const owner = userInfo.user ? normalizeIdentity(userInfo.user) : null |
| 282 | const totalBytes = getFileSize(messagesPath) |
| 283 | |
| 284 | const initialProgress = createProgress('parsing', 0, totalBytes, 0, '') |
| 285 | yield { type: 'progress', data: initialProgress } |
| 286 | onProgress?.(initialProgress) |
| 287 | |
| 288 | yield { |
| 289 | type: 'meta', |
| 290 | data: { |
| 291 | name: deriveChatName(manifest, groupInfo, owner?.platformId), |
| 292 | platform: KNOWN_PLATFORMS.GOOGLE_CHAT, |
| 293 | type: manifest.chatType === 'group' ? ChatType.GROUP : ChatType.PRIVATE, |
| 294 | ...(manifest.chatType === 'group' ? { groupId: manifest.chatId } : {}), |
| 295 | ownerId: owner?.platformId, |
| 296 | }, |
| 297 | } |
| 298 | |
| 299 | const memberMap = new Map<string, ParsedMember>() |
| 300 | for (const member of groupInfo.members ?? []) { |
| 301 | const identity = normalizeIdentity(member) |
| 302 | memberMap.set(identity.platformId, { |
| 303 | platformId: identity.platformId, |
| 304 | accountName: identity.name, |
| 305 | }) |
| 306 | } |
| 307 | if (owner && !memberMap.has(owner.platformId)) { |
| 308 | memberMap.set(owner.platformId, { |
| 309 | platformId: owner.platformId, |
| 310 | accountName: owner.name, |
| 311 | }) |
| 312 | } |
| 313 | yield { type: 'members', data: Array.from(memberMap.values()) } |
| 314 | |
| 315 | const readStream = fs.createReadStream(messagesPath, { encoding: 'utf8' }) |
| 316 | let bytesRead = 0 |
| 317 | let messagesProcessed = 0 |
| 318 | readStream.on('data', (chunk: string | Buffer) => { |
| 319 | bytesRead += typeof chunk === 'string' ? Buffer.byteLength(chunk) : chunk.length |
| 320 | }) |
| 321 | |
| 322 | const pipeline = chain([readStream, parser(), pick({ filter: /^messages\.\d+$/ }), streamValues()]) |
| 323 | const messageBatch: ParsedMessage[] = [] |
| 324 | |
| 325 | try { |
| 326 | for await (const item of pipeline as AsyncIterable<{ value: GoogleChatMessage }>) { |
| 327 | const message = item.value |
| 328 | const sender = normalizeIdentity(message.creator) |
| 329 | messageBatch.push({ |
| 330 | platformMessageId: message.message_id ? String(message.message_id) : undefined, |
| 331 | senderPlatformId: sender.platformId, |
| 332 | senderAccountName: sender.name, |
| 333 | timestamp: parseGoogleChatDate(message.created_date ?? message.updated_date ?? '') ?? Number.NaN, |
nothing calls this directly
no test coverage detected