From 16ecbc9f177f1f71048840edf9b7af20ace3aad8 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sun, 21 Jul 2019 23:50:10 +0200 Subject: [PATCH] headless wallet skeleton, type fixes --- gulpfile.js | 1 + package.json | 3 + packages/idb-bridge/package.json | 9 +- packages/idb-bridge/src/BridgeIDBFactory.ts | 2 +- packages/idb-bridge/src/MemoryBackend.ts | 2 - packages/idb-bridge/tsconfig.json | 1 + src/http.ts | 2 +- src/query.ts | 2 +- src/wallet.ts | 4 +- src/walletTypes.ts | 2 +- src/webex/pages/return-coins.tsx | 2 +- src/webex/wxBackend.ts | 142 +++----------------- tsconfig.json | 5 +- yarn.lock | 11 +- 14 files changed, 43 insertions(+), 145 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index cbcd366ea..fb99d0a73 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -110,6 +110,7 @@ const tsBaseArgs = { allowJs: true, checkJs: true, noUnusedLocals: true, + incremental: true, }; diff --git a/package.json b/package.json index 90f4ec580..42a2712bd 100644 --- a/package.json +++ b/package.json @@ -57,5 +57,8 @@ "webpack-bundle-analyzer": "^3.0.2", "webpack-cli": "^3.1.0", "webpack-merge": "^4.1.0" + }, + "dependencies": { + "commander": "^2.20.0" } } diff --git a/packages/idb-bridge/package.json b/packages/idb-bridge/package.json index 52396bfe9..940f1747b 100644 --- a/packages/idb-bridge/package.json +++ b/packages/idb-bridge/package.json @@ -2,15 +2,14 @@ "name": "idb-bridge", "version": "0.0.1", "description": "IndexedDB implementation that uses SQLite3 as storage", - "main": "index.js", + "main": "./build/index.js", + "types": "./build/index.d.ts", "author": "Florian Dold", "license": "AGPL-3.0-or-later", "private": false, - "dependencies": { - "sqlite3": "^4.0.8" - }, "scripts": { - "test": "tsc && ava" + "test": "tsc && ava", + "build": "tsc" }, "devDependencies": { "ava": "2.1.0", diff --git a/packages/idb-bridge/src/BridgeIDBFactory.ts b/packages/idb-bridge/src/BridgeIDBFactory.ts index ad02be461..f6234b49c 100644 --- a/packages/idb-bridge/src/BridgeIDBFactory.ts +++ b/packages/idb-bridge/src/BridgeIDBFactory.ts @@ -27,7 +27,7 @@ import queueTask from "./util/queueTask"; type DatabaseList = Array<{ name: string; version: number }>; -class BridgeIDBFactory { +export class BridgeIDBFactory { public cmp = compareKeys; private backend: Backend; private connections: BridgeIDBDatabase[] = []; diff --git a/packages/idb-bridge/src/MemoryBackend.ts b/packages/idb-bridge/src/MemoryBackend.ts index bd9b8996d..1a85a7397 100644 --- a/packages/idb-bridge/src/MemoryBackend.ts +++ b/packages/idb-bridge/src/MemoryBackend.ts @@ -881,8 +881,6 @@ export class MemoryBackend implements Backend { // if requested. if (req.resultLevel === ResultLevel.Full) { for (let i = 0; i < numResults; i++) { - console.log("getting value for index", i); - console.log("with key", primaryKeys[i]); const result = storeData.get(primaryKeys[i]); if (!result) { throw Error("invariant violated"); diff --git a/packages/idb-bridge/tsconfig.json b/packages/idb-bridge/tsconfig.json index 1b9102e40..9f076388e 100644 --- a/packages/idb-bridge/tsconfig.json +++ b/packages/idb-bridge/tsconfig.json @@ -6,6 +6,7 @@ "noImplicitAny": true, "sourceMap": false, "outDir": "build", + "declaration": true, "noEmitOnError": true, "strict": true, "incremental": true, diff --git a/src/http.ts b/src/http.ts index 895b10973..a102b3973 100644 --- a/src/http.ts +++ b/src/http.ts @@ -44,7 +44,7 @@ export interface HttpRequestLibrary { * An implementation of the [[HttpRequestLibrary]] using the * browser's XMLHttpRequest. */ -export class BrowserHttpLib { +export class BrowserHttpLib implements HttpRequestLibrary { private req(method: string, url: string, options?: any): Promise { diff --git a/src/query.ts b/src/query.ts index 68074ec03..5feb29a55 100644 --- a/src/query.ts +++ b/src/query.ts @@ -580,7 +580,7 @@ class IterQueryStream extends QueryStreamBase { */ export class QueryRoot { private work: Array<((t: IDBTransaction) => void)> = []; - private stores = new Set(); + private stores: Set = new Set(); private kickoffPromise: Promise; /** diff --git a/src/wallet.ts b/src/wallet.ts index 0dfb77554..fd7887a85 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -2727,14 +2727,14 @@ export class Wallet { exchangeWireTypes[e] = Array.from(m[e]); }); - const senderWiresSet = new Set(); + const senderWiresSet: Set = new Set(); await this.q() .iter(Stores.senderWires) .map(x => { senderWiresSet.add(x.paytoUri); }) .run(); - const senderWires = Array.from(senderWiresSet); + const senderWires: string[] = Array.from(senderWiresSet); return { exchangeWireTypes, diff --git a/src/walletTypes.ts b/src/walletTypes.ts index 73a72bbbf..f9d753f28 100644 --- a/src/walletTypes.ts +++ b/src/walletTypes.ts @@ -303,7 +303,7 @@ export interface SenderWireInfos { /** * Sender wire information stored in the wallet. */ - senderWires: object[]; + senderWires: string[]; } diff --git a/src/webex/pages/return-coins.tsx b/src/webex/pages/return-coins.tsx index 278f8af9d..b5d53c31e 100644 --- a/src/webex/pages/return-coins.tsx +++ b/src/webex/pages/return-coins.tsx @@ -55,7 +55,7 @@ interface ReturnSelectionItemProps extends ReturnSelectionListProps { interface ReturnSelectionItemState { selectedValue: string; - supportedWires: object[]; + supportedWires: string[]; selectedWire: string; currency: string; } diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index f2dbd68be..0baa7d414 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -26,10 +26,6 @@ */ import { BrowserHttpLib } from "../http"; import * as logging from "../logging"; -import { - Index, - Store, -} from "../query"; import { AmountJson } from "../amounts"; @@ -48,10 +44,11 @@ import { isFirefox } from "./compat"; import { PurchaseRecord, - Stores, WALLET_DB_VERSION, } from "../dbTypes"; +import { openTalerDb, exportDb, importDb, deleteDb } from "../db"; + import { ChromeBadge } from "./chromeBadge"; import { MessageType } from "./messages"; @@ -62,9 +59,6 @@ import Port = chrome.runtime.Port; import MessageSender = chrome.runtime.MessageSender; import { TipToken } from "../talerTypes"; - -const DB_NAME = "taler"; - const NeedsWallet = Symbol("NeedsWallet"); function handleMessage(sender: MessageSender, @@ -104,7 +98,7 @@ function handleMessage(sender: MessageSender, tx.objectStore(db.objectStoreNames[i]).clear(); } } - deleteDb(); + deleteDb(indexedDB); setBadgeText({ text: "" }); console.log("reset done"); if (!currentWallet) { @@ -688,6 +682,17 @@ let currentWallet: Wallet|undefined; */ let oldDbVersion: number|undefined; +function handleUpgradeUnsupported(oldDbVersion: number, newDbVersion: number) { + console.log("DB migration not supported"); + chrome.tabs.create({ + url: chrome.extension.getURL( + "/src/webex/pages/reset-required.html", + ), + }); + setBadgeText({ text: "err" }); + chrome.browserAction.setBadgeBackgroundColor({ color: "#F00" }); +} + async function reinitWallet() { if (currentWallet) { @@ -698,7 +703,7 @@ async function reinitWallet() { const badge = new ChromeBadge(); let db: IDBDatabase; try { - db = await openTalerDb(); + db = await openTalerDb(indexedDB, reinitWallet, handleUpgradeUnsupported); } catch (e) { console.error("could not open database", e); return; @@ -867,120 +872,3 @@ export async function wxMain() { } }, { urls: [""] }, ["responseHeaders", "blocking"]); } - - -/** - * Return a promise that resolves - * to the taler wallet db. - */ -function openTalerDb(): Promise { - return new Promise((resolve, reject) => { - const req = indexedDB.open(DB_NAME, WALLET_DB_VERSION); - req.onerror = (e) => { - console.log("taler database error", e); - reject(e); - }; - req.onsuccess = (e) => { - req.result.onversionchange = (evt: IDBVersionChangeEvent) => { - console.log(`handling live db version change from ${evt.oldVersion} to ${evt.newVersion}`); - req.result.close(); - reinitWallet(); - }; - resolve(req.result); - }; - req.onupgradeneeded = (e) => { - const db = req.result; - console.log(`DB: upgrade needed: oldVersion=${e.oldVersion}, newVersion=${e.newVersion}`); - switch (e.oldVersion) { - case 0: // DB does not exist yet - - for (const n in Stores) { - if ((Stores as any)[n] instanceof Store) { - const si: Store = (Stores as any)[n]; - const s = db.createObjectStore(si.name, si.storeParams); - for (const indexName in (si as any)) { - if ((si as any)[indexName] instanceof Index) { - const ii: Index = (si as any)[indexName]; - s.createIndex(ii.indexName, ii.keyPath, ii.options); - } - } - } - } - break; - default: - if (e.oldVersion !== WALLET_DB_VERSION) { - oldDbVersion = e.oldVersion; - chrome.tabs.create({ - url: chrome.extension.getURL("/src/webex/pages/reset-required.html"), - }); - setBadgeText({text: "err"}); - chrome.browserAction.setBadgeBackgroundColor({color: "#F00"}); - throw Error("incompatible DB"); - } - break; - } - }; - }); -} - - -function exportDb(db: IDBDatabase): Promise { - const dump = { - name: db.name, - stores: {} as {[s: string]: any}, - version: db.version, - }; - - return new Promise((resolve, reject) => { - - const tx = db.transaction(Array.from(db.objectStoreNames)); - tx.addEventListener("complete", () => { - resolve(dump); - }); - // tslint:disable-next-line:prefer-for-of - for (let i = 0; i < db.objectStoreNames.length; i++) { - const name = db.objectStoreNames[i]; - const storeDump = {} as {[s: string]: any}; - dump.stores[name] = storeDump; - tx.objectStore(name) - .openCursor() - .addEventListener("success", (e: Event) => { - const cursor = (e.target as any).result; - if (cursor) { - storeDump[cursor.key] = cursor.value; - cursor.continue(); - } - }); - } - }); -} - - -function importDb(db: IDBDatabase, dump: any): Promise { - console.log("importing db", dump); - return new Promise((resolve, reject) => { - const tx = db.transaction(Array.from(db.objectStoreNames), "readwrite"); - if (dump.stores) { - for (const storeName in dump.stores) { - const objects = []; - const dumpStore = dump.stores[storeName]; - for (const key in dumpStore) { - objects.push(dumpStore[key]); - } - console.log(`importing ${objects.length} records into ${storeName}`); - const store = tx.objectStore(storeName); - for (const obj of objects) { - store.put(obj); - } - } - } - tx.addEventListener("complete", () => { - resolve(); - }); - }); -} - - -function deleteDb() { - indexedDB.deleteDatabase(DB_NAME); -} diff --git a/tsconfig.json b/tsconfig.json index 081140fa3..db44f039d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,8 @@ "noImplicitAny": true, "allowJs": true, "checkJs": true, - "noUnusedLocals": true + "noUnusedLocals": true, + "incremental": true }, "files": [ "decl/chrome/chrome.d.ts", @@ -37,7 +38,9 @@ "src/crypto/nodeWorker.ts", "src/crypto/nodeWorkerEntry.ts", "src/crypto/startWorker.js", + "src/db.ts", "src/dbTypes.ts", + "src/headless/taler-wallet-cli.ts", "src/helpers-test.ts", "src/helpers.ts", "src/http.ts", diff --git a/yarn.lock b/yarn.lock index f624383b4..76c42889c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1671,6 +1671,11 @@ commander@^2.12.1, commander@^2.18.0, commander@^2.19.0, commander@~2.19.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +commander@^2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + common-path-prefix@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-1.0.0.tgz#cd52f6f0712e0baab97d6f9732874f22f47752c0" @@ -6323,9 +6328,9 @@ typescript@3.2.x: integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg== typescript@^3.3.4000: - version "3.3.4000" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.4000.tgz#76b0f89cfdbf97827e1112d64f283f1151d6adf0" - integrity sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA== + version "3.5.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" + integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== uglify-js@^3.0.27, uglify-js@^3.1.4: version "3.5.2"