UNPKG

@river-build/sdk

Version:

For more details, visit the following resources:

108 lines 5.08 kB
import { PersistedSyncedStreamSchema, } from '@river-build/proto'; import { Stream } from './stream'; import { bin_toHexString, dlog } from '@river-build/dlog'; import { isDefined } from './check'; import { create } from '@bufbuild/protobuf'; export class SyncedStream extends Stream { log; isUpToDate = false; persistenceStore; constructor(userId, streamId, clientEmitter, logEmitFromStream, persistenceStore) { super(userId, streamId, clientEmitter, logEmitFromStream); this.log = dlog('csb:syncedStream', { defaultEnabled: false }).extend(userId); this.persistenceStore = persistenceStore; } async initializeFromPersistence(persistedData) { const loadedStream = persistedData ?? (await this.persistenceStore.loadStream(this.streamId)); if (!loadedStream) { this.log('No persisted data found for stream', this.streamId, persistedData); return false; } try { super.initialize(loadedStream.persistedSyncedStream.syncCookie, loadedStream.persistedSyncedStream.minipoolEvents, loadedStream.snapshot, loadedStream.miniblocks, loadedStream.prependedMiniblocks, loadedStream.miniblocks[0].header.prevSnapshotMiniblockNum, loadedStream.cleartexts); } catch (e) { this.log('Error initializing from persistence', this.streamId, e); return false; } return true; } async initialize(nextSyncCookie, events, snapshot, miniblocks, prependedMiniblocks, prevSnapshotMiniblockNum, cleartexts) { super.initialize(nextSyncCookie, events, snapshot, miniblocks, prependedMiniblocks, prevSnapshotMiniblockNum, cleartexts); const cachedSyncedStream = create(PersistedSyncedStreamSchema, { syncCookie: nextSyncCookie, lastSnapshotMiniblockNum: miniblocks[0].header.miniblockNum, minipoolEvents: events, lastMiniblockNum: miniblocks[miniblocks.length - 1].header.miniblockNum, }); await this.persistenceStore.saveSyncedStream(this.streamId, cachedSyncedStream); await this.persistenceStore.saveMiniblocks(this.streamId, miniblocks, 'forward'); this.markUpToDate(); } async initializeFromResponse(response) { this.log('initializing from response', this.streamId); const cleartexts = await this.persistenceStore.getCleartexts(response.eventIds); await this.initialize(response.streamAndCookie.nextSyncCookie, response.streamAndCookie.events, response.snapshot, response.streamAndCookie.miniblocks, [], response.prevSnapshotMiniblockNum, cleartexts); this.markUpToDate(); } async appendEvents(events, nextSyncCookie, cleartexts) { await super.appendEvents(events, nextSyncCookie, cleartexts); for (const event of events) { const payload = event.event.payload; switch (payload.case) { case 'miniblockHeader': { await this.onMiniblockHeader(payload.value, event, event.hash); break; } default: break; } } this.markUpToDate(); } async onMiniblockHeader(miniblockHeader, miniblockEvent, hash) { this.log('Received miniblock header', miniblockHeader.miniblockNum.toString(), this.streamId); const eventHashes = miniblockHeader.eventHashes.map(bin_toHexString); const events = eventHashes .map((hash) => this.view.events.get(hash)?.remoteEvent) .filter(isDefined); if (events.length !== eventHashes.length) { throw new Error("Couldn't find event for hash in miniblock"); } const miniblock = { hash: hash, header: miniblockHeader, events: [...events, miniblockEvent], }; await this.persistenceStore.saveMiniblock(this.streamId, miniblock); const syncCookie = this.view.syncCookie; if (!syncCookie) { return; } const minipoolEvents = this.view.timeline .filter((e) => e.confirmedEventNum === undefined) .map((e) => e.remoteEvent) .filter(isDefined); const lastSnapshotMiniblockNum = miniblock.header.snapshot !== undefined ? miniblock.header.miniblockNum : miniblock.header.prevSnapshotMiniblockNum; const cachedSyncedStream = create(PersistedSyncedStreamSchema, { syncCookie: syncCookie, lastSnapshotMiniblockNum: lastSnapshotMiniblockNum, minipoolEvents: minipoolEvents, lastMiniblockNum: miniblock.header.miniblockNum, }); await this.persistenceStore.saveSyncedStream(this.streamId, cachedSyncedStream); } markUpToDate() { if (this.isUpToDate) { return; } this.isUpToDate = true; this.emit('streamUpToDate', this.streamId); } resetUpToDate() { this.isUpToDate = false; } } //# sourceMappingURL=syncedStream.js.map