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