From 30a64a3795c378ef22efe2c209b81bcaa26b4dc9 Mon Sep 17 00:00:00 2001 From: thecodrr Date: Mon, 24 Aug 2020 11:14:16 +0500 Subject: [PATCH] feat: add sse support --- packages/core/api/index.js | 39 ++++++++++++++++++++++++---- packages/core/models/user.js | 16 ++++++++++++ packages/core/package.json | 3 ++- packages/core/utils/event-manager.js | 6 +++++ packages/core/yarn.lock | 5 ++++ 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/packages/core/api/index.js b/packages/core/api/index.js index b481f1c20..3c99a0111 100644 --- a/packages/core/api/index.js +++ b/packages/core/api/index.js @@ -11,6 +11,8 @@ import Content from "../collections/content"; import Conflicts from "./sync/conflicts"; import EventManager from "../utils/event-manager"; import Session from "./session"; +import { EventSourcePolyfill } from "event-source-polyfill"; +import { HOST } from "../utils/constants"; class Database { constructor(context) { @@ -28,6 +30,7 @@ class Database { } async init() { + this.ev = new EventManager(); this.session = new Session(this.context); this._validate(); @@ -38,7 +41,6 @@ class Database { this.vault = new Vault(this); this.conflicts = new Conflicts(this); this.lookup = new Lookup(this); - this.ev = new EventManager(); // collections /** @type {Notes} */ @@ -56,10 +58,37 @@ class Database { /** @type {Content} */ this.text = await Content.new(this, "text", false); - if (this._syncInterval) clearInterval(this._syncInterval); - this._syncInterval = setInterval(async () => { - this.ev.publish("sync"); - }, 60 * 1000 * 3); + this.ev.subscribeMulti( + ["user:loggedIn", "user:loggedOut", "user:tokenRefreshed", "user:synced"], + this._onUserStateChanged.bind(this) + ); + } + + _onUserStateChanged(user) { + if (this.evtSource) { + this.evtSource.close(); + } + + if (!user) return; + + this.evtSource = new EventSourcePolyfill(`${HOST}/events`, { + headers: { Authorization: `Bearer ${user.accessToken}` }, + }); + + this.evtSource.onmessage = async (event) => { + const { type, data } = JSON.parse(event.data); + switch (type) { + case "upgrade": + await this.user.set({ + notesnook: { ...user.notesnook, subscription: data }, + }); + this.ev.publish("user:upgraded"); + break; + case "sync": + this.ev.publish("db:sync"); + break; + } + }; } sync() { diff --git a/packages/core/models/user.js b/packages/core/models/user.js index 26216566c..66d186520 100644 --- a/packages/core/models/user.js +++ b/packages/core/models/user.js @@ -15,6 +15,9 @@ export default class User { if (!user) return; user = await authRequest.call(this, "users", undefined, true, true); await this.set(user); + + // propogate event + this._db.ev.publish("user:synced", user); } get() { @@ -43,6 +46,9 @@ export default class User { const key = await this._context.deriveKey(password, response.payload.salt); let user = userFromResponse(response, key); await this._context.write("user", user); + + // propogate event + this._db.ev.publish("user:loggedIn", user); } async token() { @@ -67,10 +73,17 @@ export default class User { expiry: Date.now() + response.expiry * 100, }; await this._context.write("user", user); + + // propogate event + this._db.ev.publish("user:tokenRefreshed", user); } logout() { this._db.ev.publish("clear"); + + // propogate event + this._db.ev.publish("user:loggedOut", null); + return this._context.clear(); } @@ -84,6 +97,9 @@ export default class User { const key = await this._context.deriveKey(password, response.payload.salt); let user = userFromResponse(response, key); await this._context.write("user", user); + + // propogate event + this._db.ev.publish("user:loggedIn", user); } } diff --git a/packages/core/package.json b/packages/core/package.json index 780d85773..aa11d8728 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -24,6 +24,7 @@ "fuzzysearch": "^1.0.3", "no-internet": "^1.5.2", "qclone": "^1.0.4", + "event-source-polyfill": "^1.0.16", "transfun": "^1.0.2" } -} +} \ No newline at end of file diff --git a/packages/core/utils/event-manager.js b/packages/core/utils/event-manager.js index 661f7d44d..7dd8cfeab 100644 --- a/packages/core/utils/event-manager.js +++ b/packages/core/utils/event-manager.js @@ -3,6 +3,12 @@ class EventManager { this._registry = {}; } + subscribeMulti(names, handler) { + names.forEach((name) => { + this.subscribe(name, handler); + }); + } + subscribe(name, handler) { if (!name || !handler) throw new Error("name and handler are required."); if (!this._registry[name]) this._registry[name] = []; diff --git a/packages/core/yarn.lock b/packages/core/yarn.lock index 017302d23..903de6178 100644 --- a/packages/core/yarn.lock +++ b/packages/core/yarn.lock @@ -2327,6 +2327,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +event-source-polyfill@^1.0.16: + version "1.0.17" + resolved "https://registry.yarnpkg.com/event-source-polyfill/-/event-source-polyfill-1.0.17.tgz#850a5103c8fbc5c2c0640ca8e545224e3be9614d" + integrity sha512-eLZQQpKZahOH5sFaqfrbLNXJKz+JawiDQVrl6lZmQHHSamIn5PlNV3HXAY9+ZRaQC5YTIBRDd8jeTxjuEveJnQ== + exec-sh@^0.3.2: version "0.3.4" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5"