headless wallet skeleton, type fixes

This commit is contained in:
Florian Dold 2019-07-21 23:50:10 +02:00
parent cfa1df7343
commit 16ecbc9f17
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
14 changed files with 43 additions and 145 deletions

View File

@ -110,6 +110,7 @@ const tsBaseArgs = {
allowJs: true, allowJs: true,
checkJs: true, checkJs: true,
noUnusedLocals: true, noUnusedLocals: true,
incremental: true,
}; };

View File

@ -57,5 +57,8 @@
"webpack-bundle-analyzer": "^3.0.2", "webpack-bundle-analyzer": "^3.0.2",
"webpack-cli": "^3.1.0", "webpack-cli": "^3.1.0",
"webpack-merge": "^4.1.0" "webpack-merge": "^4.1.0"
},
"dependencies": {
"commander": "^2.20.0"
} }
} }

View File

@ -2,15 +2,14 @@
"name": "idb-bridge", "name": "idb-bridge",
"version": "0.0.1", "version": "0.0.1",
"description": "IndexedDB implementation that uses SQLite3 as storage", "description": "IndexedDB implementation that uses SQLite3 as storage",
"main": "index.js", "main": "./build/index.js",
"types": "./build/index.d.ts",
"author": "Florian Dold", "author": "Florian Dold",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"private": false, "private": false,
"dependencies": {
"sqlite3": "^4.0.8"
},
"scripts": { "scripts": {
"test": "tsc && ava" "test": "tsc && ava",
"build": "tsc"
}, },
"devDependencies": { "devDependencies": {
"ava": "2.1.0", "ava": "2.1.0",

View File

@ -27,7 +27,7 @@ import queueTask from "./util/queueTask";
type DatabaseList = Array<{ name: string; version: number }>; type DatabaseList = Array<{ name: string; version: number }>;
class BridgeIDBFactory { export class BridgeIDBFactory {
public cmp = compareKeys; public cmp = compareKeys;
private backend: Backend; private backend: Backend;
private connections: BridgeIDBDatabase[] = []; private connections: BridgeIDBDatabase[] = [];

View File

@ -881,8 +881,6 @@ export class MemoryBackend implements Backend {
// if requested. // if requested.
if (req.resultLevel === ResultLevel.Full) { if (req.resultLevel === ResultLevel.Full) {
for (let i = 0; i < numResults; i++) { 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]); const result = storeData.get(primaryKeys[i]);
if (!result) { if (!result) {
throw Error("invariant violated"); throw Error("invariant violated");

View File

@ -6,6 +6,7 @@
"noImplicitAny": true, "noImplicitAny": true,
"sourceMap": false, "sourceMap": false,
"outDir": "build", "outDir": "build",
"declaration": true,
"noEmitOnError": true, "noEmitOnError": true,
"strict": true, "strict": true,
"incremental": true, "incremental": true,

View File

@ -44,7 +44,7 @@ export interface HttpRequestLibrary {
* An implementation of the [[HttpRequestLibrary]] using the * An implementation of the [[HttpRequestLibrary]] using the
* browser's XMLHttpRequest. * browser's XMLHttpRequest.
*/ */
export class BrowserHttpLib { export class BrowserHttpLib implements HttpRequestLibrary {
private req(method: string, private req(method: string,
url: string, url: string,
options?: any): Promise<HttpResponse> { options?: any): Promise<HttpResponse> {

View File

@ -580,7 +580,7 @@ class IterQueryStream<T> extends QueryStreamBase<T> {
*/ */
export class QueryRoot { export class QueryRoot {
private work: Array<((t: IDBTransaction) => void)> = []; private work: Array<((t: IDBTransaction) => void)> = [];
private stores = new Set(); private stores: Set<string> = new Set();
private kickoffPromise: Promise<void>; private kickoffPromise: Promise<void>;
/** /**

View File

@ -2727,14 +2727,14 @@ export class Wallet {
exchangeWireTypes[e] = Array.from(m[e]); exchangeWireTypes[e] = Array.from(m[e]);
}); });
const senderWiresSet = new Set(); const senderWiresSet: Set<string> = new Set();
await this.q() await this.q()
.iter(Stores.senderWires) .iter(Stores.senderWires)
.map(x => { .map(x => {
senderWiresSet.add(x.paytoUri); senderWiresSet.add(x.paytoUri);
}) })
.run(); .run();
const senderWires = Array.from(senderWiresSet); const senderWires: string[] = Array.from(senderWiresSet);
return { return {
exchangeWireTypes, exchangeWireTypes,

View File

@ -303,7 +303,7 @@ export interface SenderWireInfos {
/** /**
* Sender wire information stored in the wallet. * Sender wire information stored in the wallet.
*/ */
senderWires: object[]; senderWires: string[];
} }

View File

@ -55,7 +55,7 @@ interface ReturnSelectionItemProps extends ReturnSelectionListProps {
interface ReturnSelectionItemState { interface ReturnSelectionItemState {
selectedValue: string; selectedValue: string;
supportedWires: object[]; supportedWires: string[];
selectedWire: string; selectedWire: string;
currency: string; currency: string;
} }

View File

@ -26,10 +26,6 @@
*/ */
import { BrowserHttpLib } from "../http"; import { BrowserHttpLib } from "../http";
import * as logging from "../logging"; import * as logging from "../logging";
import {
Index,
Store,
} from "../query";
import { AmountJson } from "../amounts"; import { AmountJson } from "../amounts";
@ -48,10 +44,11 @@ import { isFirefox } from "./compat";
import { import {
PurchaseRecord, PurchaseRecord,
Stores,
WALLET_DB_VERSION, WALLET_DB_VERSION,
} from "../dbTypes"; } from "../dbTypes";
import { openTalerDb, exportDb, importDb, deleteDb } from "../db";
import { ChromeBadge } from "./chromeBadge"; import { ChromeBadge } from "./chromeBadge";
import { MessageType } from "./messages"; import { MessageType } from "./messages";
@ -62,9 +59,6 @@ import Port = chrome.runtime.Port;
import MessageSender = chrome.runtime.MessageSender; import MessageSender = chrome.runtime.MessageSender;
import { TipToken } from "../talerTypes"; import { TipToken } from "../talerTypes";
const DB_NAME = "taler";
const NeedsWallet = Symbol("NeedsWallet"); const NeedsWallet = Symbol("NeedsWallet");
function handleMessage(sender: MessageSender, function handleMessage(sender: MessageSender,
@ -104,7 +98,7 @@ function handleMessage(sender: MessageSender,
tx.objectStore(db.objectStoreNames[i]).clear(); tx.objectStore(db.objectStoreNames[i]).clear();
} }
} }
deleteDb(); deleteDb(indexedDB);
setBadgeText({ text: "" }); setBadgeText({ text: "" });
console.log("reset done"); console.log("reset done");
if (!currentWallet) { if (!currentWallet) {
@ -688,6 +682,17 @@ let currentWallet: Wallet|undefined;
*/ */
let oldDbVersion: number|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() { async function reinitWallet() {
if (currentWallet) { if (currentWallet) {
@ -698,7 +703,7 @@ async function reinitWallet() {
const badge = new ChromeBadge(); const badge = new ChromeBadge();
let db: IDBDatabase; let db: IDBDatabase;
try { try {
db = await openTalerDb(); db = await openTalerDb(indexedDB, reinitWallet, handleUpgradeUnsupported);
} catch (e) { } catch (e) {
console.error("could not open database", e); console.error("could not open database", e);
return; return;
@ -867,120 +872,3 @@ export async function wxMain() {
} }
}, { urls: ["<all_urls>"] }, ["responseHeaders", "blocking"]); }, { urls: ["<all_urls>"] }, ["responseHeaders", "blocking"]);
} }
/**
* Return a promise that resolves
* to the taler wallet db.
*/
function openTalerDb(): Promise<IDBDatabase> {
return new Promise<IDBDatabase>((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<any> = (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<any, any> = (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<any> {
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<void> {
console.log("importing db", dump);
return new Promise<void>((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);
}

View File

@ -19,7 +19,8 @@
"noImplicitAny": true, "noImplicitAny": true,
"allowJs": true, "allowJs": true,
"checkJs": true, "checkJs": true,
"noUnusedLocals": true "noUnusedLocals": true,
"incremental": true
}, },
"files": [ "files": [
"decl/chrome/chrome.d.ts", "decl/chrome/chrome.d.ts",
@ -37,7 +38,9 @@
"src/crypto/nodeWorker.ts", "src/crypto/nodeWorker.ts",
"src/crypto/nodeWorkerEntry.ts", "src/crypto/nodeWorkerEntry.ts",
"src/crypto/startWorker.js", "src/crypto/startWorker.js",
"src/db.ts",
"src/dbTypes.ts", "src/dbTypes.ts",
"src/headless/taler-wallet-cli.ts",
"src/helpers-test.ts", "src/helpers-test.ts",
"src/helpers.ts", "src/helpers.ts",
"src/http.ts", "src/http.ts",

View File

@ -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" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== 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: common-path-prefix@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-1.0.0.tgz#cd52f6f0712e0baab97d6f9732874f22f47752c0" 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== integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==
typescript@^3.3.4000: typescript@^3.3.4000:
version "3.3.4000" version "3.5.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.4000.tgz#76b0f89cfdbf97827e1112d64f283f1151d6adf0" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
integrity sha512-jjOcCZvpkl2+z7JFn0yBOoLQyLoIkNZAs/fYJkUG6VKy6zLPHJGfQJYFHzibB6GJaF/8QrcECtlQ5cpvRHSMEA== integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
uglify-js@^3.0.27, uglify-js@^3.1.4: uglify-js@^3.0.27, uglify-js@^3.1.4:
version "3.5.2" version "3.5.2"