UNPKG

@river-build/sdk

Version:

For more details, visit the following resources:

93 lines 4.33 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { PersistedObservable, persistedObservable } from '../../../observable/persistedObservable'; import { LoadPriority } from '../../../store/store'; import { dlogger } from '@river-build/dlog'; import { makeUserStreamId, streamIdAsBytes } from '../../../id'; // Define a class that will manage the data model, decorate it to give it store properties let RiverChain = class RiverChain extends PersistedObservable { riverRegistryDapp; userId; log; sessionStartMs = Date.now(); stopped = false; // The constructor is where we set up the class, we pass in the store and any other dependencies constructor(store, riverRegistryDapp, userId, logId) { // pass a default value to the parent class, this is what will be used if the data is not loaded // set the load priority to high, this will load first super({ id: '0', urls: { value: '' }, streamExists: {} }, store, LoadPriority.high); this.riverRegistryDapp = riverRegistryDapp; this.userId = userId; this.log = dlogger(`csb:agent:riverChain:${logId}`); } // implement start function then wire it up from parent onLoaded() { this.log.info('riverChain onLoaded'); this.withInfiniteRetries(() => this.fetchUrls()); this.withInfiniteRetries(() => this.fetchStreamExists(makeUserStreamId(this.userId))); } stop() { this.stopped = true; } async urls() { // urls is returning the cached data if it exists, otherwise waiting for the data to be fetched // if the cached data returns a stale node url, the startup will fail // nodes almost never exit the network, so this is a very rare case await this.when((x) => x.data.urls.fetchedAtMs !== undefined, { timeoutMs: 15000 }); return this.data.urls.value; } async userStreamExists() { // user stream exists is returning the cached data if it exists, // otherwise waiting for new data to be fetched by comparing fetchedAtMs against sessionStartMs const streamId = makeUserStreamId(this.userId); await this.when((x) => { const entry = x.data.streamExists[streamId]; return entry && (entry.exists || entry.fetchedAtMs >= this.sessionStartMs); }); return this.data.streamExists[streamId]?.exists; } async fetchUrls() { const now = Date.now(); const urls = await this.riverRegistryDapp.getOperationalNodeUrls(); // here we are fetching the node urls this.setData({ urls: { value: urls, fetchedAtMs: now } }); // if the data is new, update our own state return urls; } async fetchStreamExists(streamId) { if (this.data.streamExists[streamId]?.exists === true) { return true; } const streamIdBytes = streamIdAsBytes(streamId); const now = Date.now(); const exists = await this.riverRegistryDapp.streamExists(streamIdBytes); this.setData({ streamExists: { ...this.data.streamExists, [streamId]: { exists, fetchedAtMs: now }, }, }); return exists; } withInfiniteRetries(fn, delayMs = 5000) { if (this.stopped) { return; } fn().catch((e) => { this.log.error(e); this.log.info(`retrying in ${delayMs / 1000} seconds`); setTimeout(() => { this.withInfiniteRetries(fn, delayMs); }, delayMs); }); } }; RiverChain = __decorate([ persistedObservable({ tableName: 'riverChain', // this is the name of the table in the database }) ], RiverChain); export { RiverChain }; //# sourceMappingURL=riverChain.js.map