@river-build/sdk
Version:
For more details, visit the following resources:
108 lines • 5.08 kB
JavaScript
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