From d43df0a952b0aa843d0e26dba8d0fba981811938 Mon Sep 17 00:00:00 2001 From: sentialx Date: Thu, 2 Apr 2020 15:27:35 +0200 Subject: [PATCH] fix: history saving race conditions --- src/main/services/storage.ts | 1 + src/main/view.ts | 68 +++++++++++++++++++++--------------- src/utils/queue.ts | 50 ++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 29 deletions(-) create mode 100644 src/utils/queue.ts diff --git a/src/main/services/storage.ts b/src/main/services/storage.ts index 58f73fd7a..941b98275 100644 --- a/src/main/services/storage.ts +++ b/src/main/services/storage.ts @@ -17,6 +17,7 @@ import { import { countVisitedTimes } from '~/utils/history'; import { windowsManager } from '..'; import { promises } from 'fs'; +import { Queue } from '~/utils/queue'; interface Databases { [key: string]: Datastore; diff --git a/src/main/view.ts b/src/main/view.ts index 2be747da6..de195f2f1 100644 --- a/src/main/view.ts +++ b/src/main/view.ts @@ -13,6 +13,7 @@ import { ZOOM_FACTOR_INCREMENT, } from '~/constants/web-contents'; import { TabEvent } from '~/interfaces/tabs'; +import { Queue } from '~/utils/queue'; export class View extends BrowserView { public title = ''; @@ -32,6 +33,8 @@ export class View extends BrowserView { public bookmark: IBookmark; + private historyQueue = new Queue(); + public constructor(window: AppWindow, url: string, incognito: boolean) { super({ webPreferences: { @@ -273,18 +276,22 @@ export class View extends BrowserView { date: new Date().getTime(), }; - this.lastHistoryId = ( - await storage.insert({ - scope: 'history', - item: historyItem, - }) - )._id; + await this.historyQueue.enqueue(async () => { + this.lastHistoryId = ( + await storage.insert({ + scope: 'history', + item: historyItem, + }) + )._id; - historyItem._id = this.lastHistoryId; + historyItem._id = this.lastHistoryId; - storage.history.push(historyItem); + storage.history.push(historyItem); + }); } else if (!inPage) { - this.lastHistoryId = ''; + await this.historyQueue.enqueue(async () => { + this.lastHistoryId = ''; + }); } } @@ -311,29 +318,32 @@ export class View extends BrowserView { public async updateData() { if (!this.incognito) { - if (this.lastHistoryId) { + const id = this.lastHistoryId; + if (id) { const { title, url, favicon } = this; - storage.update({ - scope: 'history', - query: { - _id: this.lastHistoryId, - }, - value: { - title, - url, - favicon, - }, - multi: false, + this.historyQueue.enqueue(async () => { + await storage.update({ + scope: 'history', + query: { + _id: id, + }, + value: { + title, + url, + favicon, + }, + multi: false, + }); + + const item = storage.history.find(x => x._id === id); + + if (item) { + item.title = title; + item.url = url; + item.favicon = favicon; + } }); - - const item = storage.history.find(x => x._id === this.lastHistoryId); - - if (item) { - item.title = title; - item.url = url; - item.favicon = favicon; - } } } } diff --git a/src/utils/queue.ts b/src/utils/queue.ts new file mode 100644 index 000000000..aa3b038f3 --- /dev/null +++ b/src/utils/queue.ts @@ -0,0 +1,50 @@ +export class Queue { + private queue: { + promise: () => Promise; + reject: any; + resolve: any; + }[] = []; + private pendingPromise = false; + + public enqueue(promise: () => Promise): Promise { + return new Promise((resolve, reject) => { + this.queue.push({ + promise, + resolve, + reject, + }); + + this.dequeue(); + }); + } + + public dequeue() { + if (this.pendingPromise) { + return false; + } + const item = this.queue.shift(); + if (!item) { + return false; + } + try { + this.pendingPromise = true; + item + .promise() + .then(value => { + this.pendingPromise = false; + item.resolve(value); + this.dequeue(); + }) + .catch(err => { + this.pendingPromise = false; + item.reject(err); + this.dequeue(); + }); + } catch (err) { + this.pendingPromise = false; + item.reject(err); + this.dequeue(); + } + return true; + } +}