@ceramicnetwork/core
Version:
Typescript implementation of the Ceramic protocol
127 lines • 5.93 kB
JavaScript
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _MonotonicKey_previous, _MonotonicKey_counter, _FeedAggregationStore_keyGenerator, _FeedAggregationStore_interval;
import { ObjectStore } from './object-store.js';
import { StreamID } from '@ceramicnetwork/streamid';
import { TaskQueue } from '../ancillary/task-queue.js';
import { firstValueFrom, Subject } from 'rxjs';
function serializeStreamID(streamID) {
return streamID.toString();
}
function deserializeStreamID(input) {
return StreamID.fromString(input);
}
const DEFAULT_STALE_DURATION = 604800000;
const DEFAULT_CLEANUP_INTERVAL = 600000;
export class MonotonicKey {
constructor() {
_MonotonicKey_previous.set(this, Date.now());
_MonotonicKey_counter.set(this, 0);
}
next(now = Date.now()) {
var _a, _b;
if (__classPrivateFieldGet(this, _MonotonicKey_previous, "f") === now) {
const counter = (__classPrivateFieldSet(this, _MonotonicKey_counter, (_b = __classPrivateFieldGet(this, _MonotonicKey_counter, "f"), _a = _b++, _b), "f"), _a);
return `${__classPrivateFieldGet(this, _MonotonicKey_previous, "f")}${counter.toString().padStart(6, '0')}`;
}
else {
__classPrivateFieldSet(this, _MonotonicKey_counter, 1, "f");
__classPrivateFieldSet(this, _MonotonicKey_previous, now, "f");
return `${__classPrivateFieldGet(this, _MonotonicKey_previous, "f")}000000`;
}
}
}
_MonotonicKey_previous = new WeakMap(), _MonotonicKey_counter = new WeakMap();
export class FeedAggregationStore extends ObjectStore {
constructor(logger, staleDuration = DEFAULT_STALE_DURATION, cleanupInterval = DEFAULT_CLEANUP_INTERVAL) {
super(String, serializeStreamID, deserializeStreamID);
this.logger = logger;
this.useCaseName = 'feed-aggregation';
_FeedAggregationStore_keyGenerator.set(this, new MonotonicKey());
_FeedAggregationStore_interval.set(this, void 0);
this.staleDuration = staleDuration;
this.cleanupInterval = cleanupInterval;
this.tasks = new TaskQueue();
__classPrivateFieldSet(this, _FeedAggregationStore_interval, undefined, "f");
this.find = this.find.bind(this);
this.onWrite = new Subject();
}
findKeys(params) {
return this.store.findKeys(params);
}
find(params) {
return this.store.find(params);
}
async deleteStale(lessThanMs) {
const keys = await this.store.findKeys({ lt: String(lessThanMs * 1000) });
if (keys.length > 0) {
let batch = this.store.batch();
for (const k of keys) {
batch = batch.del(k);
}
await batch.write();
}
return keys.length;
}
async put(streamId, key = __classPrivateFieldGet(this, _FeedAggregationStore_keyGenerator, "f").next()) {
await this.save(key, streamId);
this.logger.verbose(`Inserting this streamId from LevelDB ${streamId} at ${Date.now()}`);
this.onWrite.next();
}
async open(factory) {
await super.open(factory);
if (this.cleanupInterval) {
__classPrivateFieldSet(this, _FeedAggregationStore_interval, setInterval(() => {
if (this.tasks.size > 0)
return;
this.tasks.add(async () => {
const threshold = Date.now() - this.staleDuration;
await this.deleteStale(threshold);
});
}, this.cleanupInterval), "f");
}
}
streamIDs(gt) {
const source = new StreamIDFeedSource(this.find, this.onWrite.asObservable(), this.logger, gt);
return new ReadableStream(source);
}
async close() {
clearInterval(__classPrivateFieldGet(this, _FeedAggregationStore_interval, "f"));
await this.tasks.onIdle();
await super.close();
}
}
_FeedAggregationStore_keyGenerator = new WeakMap(), _FeedAggregationStore_interval = new WeakMap();
class StreamIDFeedSource {
constructor(find, onWrite, logger, token = new MonotonicKey().next()) {
this.find = find;
this.onWrite = onWrite;
this.logger = logger;
this.token = token;
}
async pull(controller) {
const entries = await this.find({ limit: controller.desiredSize, gt: this.token });
if (entries.length === 0) {
await firstValueFrom(this.onWrite);
return this.pull(controller);
}
for (const entry of entries) {
this.logger.verbose(`Sending this streamId from LevelDB ${entry.value} at ${Date.now()}`);
controller.enqueue({
resumeToken: entry.key,
streamID: entry.value,
});
}
this.token = entries[entries.length - 1].key;
}
}
//# sourceMappingURL=feed-aggregation-store.js.map