From e03dce34c060d38be7835d222fd5d0ceb1f725a3 Mon Sep 17 00:00:00 2001 From: uonr Date: Mon, 9 Sep 2024 15:25:27 +0900 Subject: [PATCH] refactor(spa): expand the `BATCH` event --- apps/spa/hooks/useConnectionEffect.tsx | 23 ++++++++++++++++++----- apps/spa/state/chat.reducer.tsx | 25 +++---------------------- 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/apps/spa/hooks/useConnectionEffect.tsx b/apps/spa/hooks/useConnectionEffect.tsx index 66128746..be39484c 100644 --- a/apps/spa/hooks/useConnectionEffect.tsx +++ b/apps/spa/hooks/useConnectionEffect.tsx @@ -7,6 +7,7 @@ import { isUuid } from '@boluo/utils'; import { PING, PONG } from '../const'; import { chatAtom, type ChatDispatch, connectionStateAtom } from '../state/chat.atoms'; import { type ConnectionState } from '../state/connection.reducer'; +import { recordError } from '../error'; let lastPongTime = Date.now(); const RELOAD_TIMEOUT = 1000 * 60 * 30; @@ -70,11 +71,23 @@ const connect = ( return; } if (!isServerEvent(event)) return; - dispatch({ type: 'eventFromServer', payload: event }); - // The `event.id.node` field is currently unused, so we can ignore it. - if (event.id.timestamp < after.timestamp) return; - if (event.id.timestamp === after.timestamp && event.id.seq <= after.seq) return; - onEvent(event); + let eventList: ServerEvent[]; + if (event.body.type === 'BATCH') { + eventList = event.body.encodedEvents.flatMap((encodedEvent) => { + try { + return [JSON.parse(encodedEvent) as ServerEvent]; + } catch { + recordError('Failed to parse event', { event: encodedEvent }); + return []; + } + }); + } else { + eventList = [event]; + } + for (const event of eventList) { + dispatch({ type: 'eventFromServer', payload: event }); + onEvent(event); + } }; return newConnection; }; diff --git a/apps/spa/state/chat.reducer.tsx b/apps/spa/state/chat.reducer.tsx index 586f4cc2..47ee5622 100644 --- a/apps/spa/state/chat.reducer.tsx +++ b/apps/spa/state/chat.reducer.tsx @@ -1,4 +1,4 @@ -import type { EventId, ServerEvent } from '@boluo/api'; +import type { EventId } from '@boluo/api'; import type { Reducer } from 'react'; import { eventIdCompare } from '../sort'; import type { ChannelState } from './channel.reducer'; @@ -6,7 +6,6 @@ import { channelReducer, makeInitialChannelState } from './channel.reducer'; import { type ChatAction, type ChatActionUnion, eventToChatAction } from './chat.actions'; import type { ConnectionState } from './connection.reducer'; import { connectionReducer, initialConnectionState } from './connection.reducer'; -import { recordError } from '../error'; export interface ChatReducerContext { spaceId: string; @@ -105,26 +104,8 @@ const handleEventFromServer = ( { payload: event }: ChatAction<'eventFromServer'>, ): ChatSpaceState => { if (event.body.type === 'BATCH') { - const { encodedEvents } = event.body; - const events: Array = encodedEvents.map((encodedEvent) => { - try { - return JSON.parse(encodedEvent) as ServerEvent; - } catch { - recordError('Failed to parse event', { event: encodedEvent }); - return null; - } - }); - let nextState = state; - let lastEventId = state.lastEventId; - for (const event of events) { - if (event === null) continue; - if (eventIdCompare(event.id, state.lastEventId) <= 0) continue; - const chatAction = eventToChatAction(event); - if (chatAction === null) continue; - nextState = chatReducer(nextState, chatAction); - lastEventId = event.id; - } - return { ...nextState, lastEventId }; + // We do not handle batch events here + return state; } if (eventIdCompare(event.id, state.lastEventId) <= 0) return state; const lastEventId = event.id;