diff --git a/packages/core/src/database/database.js b/packages/core/src/database/database.js index 5a9a474..c95f698 100644 --- a/packages/core/src/database/database.js +++ b/packages/core/src/database/database.js @@ -41,9 +41,8 @@ class Database { } databaseInitialize(cb) { - // TODO: save in the db results by using a combination of concatMap and scan, to save results in batches fromEvent(this.events, "updateDB").subscribe(({eventKey, eventData}) => { - if (eventData.removed) { + if (eventData.removed) { this.deleteEvent(eventKey, eventData.id); return; } @@ -56,6 +55,25 @@ class Database { }); } + serialize() { + return this.db.serialize(); + } + + restore(serializedDb, forced) { + return new Promise((resolve, reject) => { + const collections = this.db.listCollections(); + if (!collections?.length || forced) { + this.db.loadJSON(serializedDb); + this.db.saveDatabase(err => { + if(err) { + reject(err); + } + resolve(); + }); + } + }); + } + getLastKnownEvent(eventKey) { const collection = this.db.getCollection(eventKey); if (collection?.count()) { @@ -99,9 +117,10 @@ class Database { deleteEvent(eventKey, eventId) { const collection = this.db.getCollection(eventKey); if (collection) - collection.chain() - .find({id: eventId}) - .remove(); + collection + .chain() + .find({id: eventId}) + .remove(); } deleteNewestBlocks(eventKey, gteBlockNum) { @@ -109,9 +128,10 @@ class Database { const collection = this.db.getCollection(eventKey); if (collection) - collection.chain() - .find({blockNumber: {$gte: gteBlockNum}}) - .remove(); + collection + .chain() + .find({blockNumber: {$gte: gteBlockNum}}) + .remove(); } } diff --git a/packages/core/src/subspace.js b/packages/core/src/subspace.js index 9e9fb46..f1ef647 100644 --- a/packages/core/src/subspace.js +++ b/packages/core/src/subspace.js @@ -33,6 +33,7 @@ export default class Subspace { this.options.callInterval = options.callInterval; this.options.dbFilename = options.dbFilename ?? "subspace.db"; this.options.disableDatabase = options.disableDatabase; + this.options.snapshot = options.snapshot; this.networkId = undefined; this.isWebsocketProvider = options.disableSubscriptions ? false : !!web3?.currentProvider?.on; @@ -44,6 +45,11 @@ export default class Subspace { } else { this._db = new Database(this.options.dbFilename, this.events); } + + if(this.options.snapshot) { + await this._db.restore(this.options.snapshot); + } + this.eventSyncer = new EventSyncer(this.web3.eth, this.events, this._db, this.isWebsocketProvider); this.logSyncer = new LogSyncer(this.web3.eth, this.events, this._db); @@ -308,4 +314,12 @@ export default class Subspace { close() { this.eventSyncer.close(); } + + snapshot() { + return this._db.serialize(); + } + + async loadSnapshot(serializedDb) { + return this._db.restore(serializedDb, true); + } } diff --git a/packages/core/types/index.d.ts b/packages/core/types/index.d.ts index 70a5a6a..d0eed02 100644 --- a/packages/core/types/index.d.ts +++ b/packages/core/types/index.d.ts @@ -19,6 +19,8 @@ export default class Subspace { trackGasPrice(): Observable; trackAverageBlocktime(): Observable; close(): void; + snapshot(): string; + async loadSnapshot(serializedDb: string): void; } export interface ContractLike {