From fff5dcde90e3b10d8b33cb0c3f3cd50f0fb22021 Mon Sep 17 00:00:00 2001 From: Aaron Barnard Date: Fri, 20 Sep 2019 14:45:47 +1000 Subject: [PATCH] Try new sync state approach --- package-lock.json | 5 ++ package.json | 1 + rollup.config.js | 3 +- src/index.js | 16 ++--- src/services.js | 16 +++++ src/stores.js | 109 ++++++++++++++++++++++++++++++++- src/views/Onboard.svelte | 3 +- src/views/PrepareWallet.svelte | 7 ++- 8 files changed, 145 insertions(+), 15 deletions(-) create mode 100644 src/services.js diff --git a/package-lock.json b/package-lock.json index 8fd621f65..f8e57f5b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3609,6 +3609,11 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "promise-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/promise-cancelable/-/promise-cancelable-2.1.1.tgz", + "integrity": "sha512-tHjRM44/n6ktUY1BohLKl109rYDK6oZ+B/OyMUDQrIMTjDZBdCLvpu/vzv5UqqqLeOw5KfJnFFVmfDtzJtvVTw==" + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", diff --git a/package.json b/package.json index e3e40d78a..4ab3f5efe 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "bn-sdk": "github:blocknative/bn-sdk#master", "bowser": "^2.5.2", "ow": "^0.13.2", + "promise-cancelable": "^2.1.1", "rollup-plugin-node-globals": "^1.4.0", "svelte": "^3.0.0", "svelte-i18n": "^1.1.2-beta" diff --git a/rollup.config.js b/rollup.config.js index a1382bb27..bbdb3f7a2 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -42,7 +42,8 @@ export default [ "svelte", "svelte/store", "svelte/internal", - "svelte/transition" + "svelte/transition", + "promise-cancelable" ], plugins: [ svelte(), diff --git a/src/index.js b/src/index.js index 0474ca848..f9fe181aa 100644 --- a/src/index.js +++ b/src/index.js @@ -1,9 +1,9 @@ -import blocknativeApi from "bn-sdk" import Onboard from "./views/Onboard.svelte" import { app, address, network, balance, provider } from "./stores" import { selectWallet, prepareWallet, config, getState } from "./api" import { validateInit } from "./validation" import { getUserAgent } from "./utilities" +import { initializeBlocknative } from "./services" function init(initialization) { getUserAgent() @@ -12,19 +12,21 @@ function init(initialization) { const { subscriptions, ...rest } = initialization + const blocknative = initializeBlocknative( + initialization.dappId, + initialization.networkId + ) + app.update(store => ({ ...store, - ...rest, - blocknative: new blocknativeApi({ - dappId: initialization.dappId, - networkId: initialization.networkId - }) + ...rest })) new Onboard({ target: document.body, props: { - onboardingModules: initialization.modules.prepareWallet + onboardingModules: initialization.modules.prepareWallet, + blocknative } }) diff --git a/src/services.js b/src/services.js new file mode 100644 index 000000000..f4654c72e --- /dev/null +++ b/src/services.js @@ -0,0 +1,16 @@ +import blocknativeApi from "bn-sdk" + +let blocknative + +export function initializeBlocknative(dappId, networkId) { + blocknative = blocknativeApi({ + dappId, + networkId + }) + + return blocknative +} + +export function getBlocknative() { + return blocknative +} diff --git a/src/stores.js b/src/stores.js index c5ca04d51..8286d5744 100644 --- a/src/stores.js +++ b/src/stores.js @@ -1,5 +1,7 @@ import { writable } from "svelte/store" +import Cancelable from "promise-cancelable" import { validateWalletInterface } from "./validation" +import { getBlocknative } from "./services" export const app = writable({ dappId: null, @@ -9,18 +11,22 @@ export const app = writable({ selectWalletCompleted: false, prepareWallet: false, prepareWalletCompleted: false, - modules: null + modules: null, + blocknative: null }) export const configuration = writable({ darkMode: false }) -export let syncingState = false +export const balanceSyncStatus = { + syncing: false, + error: false +} export const address = createUserStateStore("address") export const network = createUserStateStore("network") -export const balance = createUserStateStore("balance") +export const balance = createBalanceStore() export const provider = writable(null) export const state = createState({ @@ -128,3 +134,100 @@ function createUserStateStore(parameter) { } } } + +function createBalanceStore() { + let stateSyncer + let emitter + + const { subscribe } = derived( + [address, network], + ([$address, $network], set) => { + if (stateSyncer) { + syncState(stateSyncer.get, set) + + emitter = getBlocknative().account($address) + + emitter.on("txConfirmed", () => { + syncState(stateSyncer.get, set) + }) + } + } + ) + + return { + subscribe, + setStateSyncer: syncer => { + if (!syncer || typeof syncer !== "object") { + throw new Error("setStateSyncer must be called with a valid interface") + } + + stateSyncer = syncer + } + } +} + +function syncState(func, set) { + const prom = makeQuerablePromise( + new Cancelable((resolve, reject, onCancel) => { + console.log("calling stateSyncer for:", parameter) + func() + .then(resolve) + .catch(reject) + + onCancel(resolve) + }) + ) + + balanceSyncStatus.syncing = prom + + prom + .then(result => { + set(result) + balanceSyncStatus.syncing = false + }) + .catch(err => { + throw new Error(`Error getting balance from state syncer: ${err}`) + }) + + const timedOut = wait(1000) + + timedOut.then(() => { + if (!prom.isFulfilled()) { + console.log("promise timed out") + prom.cancel() + + balanceSyncStatus.syncing = false + balanceSyncStatus.error = `There was a problem getting the ${parameter} of this wallet` + } + }) +} + +function wait(time) { + return new Promise(resolve => setTimeout(resolve, time)) +} + +function makeQuerablePromise(promise) { + let isResolved = false + let isRejected = false + + const result = promise.then( + function(v) { + isResolved = true + return v + }, + function(e) { + isRejected = true + throw e + } + ) + result.isFulfilled = function() { + return isResolved || isRejected + } + result.isResolved = function() { + return isResolved + } + result.isRejected = function() { + return isRejected + } + return result +} diff --git a/src/views/Onboard.svelte b/src/views/Onboard.svelte index 6d1e9ecd1..2c48526a0 100644 --- a/src/views/Onboard.svelte +++ b/src/views/Onboard.svelte @@ -4,6 +4,7 @@ import { app } from "../stores"; export let onboardingModules; + export let blocknative;