diff options
Diffstat (limited to 'packages/taler-wallet-core')
| -rw-r--r-- | packages/taler-wallet-core/src/db.ts | 78 | ||||
| -rw-r--r-- | packages/taler-wallet-core/src/host-impl.node.ts | 11 | ||||
| -rw-r--r-- | packages/taler-wallet-core/src/host-impl.qtart.ts | 20 | ||||
| -rw-r--r-- | packages/taler-wallet-core/src/internal-wallet-state.ts | 4 | ||||
| -rw-r--r-- | packages/taler-wallet-core/src/util/query.ts | 2 | ||||
| -rw-r--r-- | packages/taler-wallet-core/src/wallet.ts | 50 | 
6 files changed, 103 insertions, 62 deletions
| diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index ba5295dda..efc0333f4 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -104,7 +104,7 @@ import { RetryInfo, TaskIdentifiers } from "./operations/common.js";   * for all previous versions must be written, which should be   * avoided.   */ -export const TALER_DB_NAME = "taler-wallet-main-v9"; +export const TALER_WALLET_MAIN_DB_NAME = "taler-wallet-main-v9";  /**   * Name of the metadata database.  This database is used @@ -112,7 +112,7 @@ export const TALER_DB_NAME = "taler-wallet-main-v9";   *   * (Minor migrations are handled via upgrade transactions.)   */ -export const TALER_META_DB_NAME = "taler-wallet-meta"; +export const TALER_WALLET_META_DB_NAME = "taler-wallet-meta";  export const CURRENT_DB_CONFIG_KEY = "currentMainDbName"; @@ -2806,25 +2806,36 @@ export interface DbDump {    };  } -export function exportDb(db: IDBDatabase): Promise<DbDump> { -  const dbDump: DbDump = { -    databases: {}, -  }; +export async function exportSingleDb( +  idb: IDBFactory, +  dbName: string, +): Promise<DbDumpDatabase> { +  const myDb = await openDatabase( +    idb, +    dbName, +    undefined, +    () => { +      // May not happen, since we're not requesting a specific version +      throw Error("unexpected version change"); +    }, +    () => { +      logger.info("unexpected onupgradeneeded"); +    }, +  ); -  const walletDb: DbDumpDatabase = { -    version: db.version, +  const singleDbDump: DbDumpDatabase = { +    version: myDb.version,      stores: {},    }; -  dbDump.databases[db.name] = walletDb;    return new Promise((resolve, reject) => { -    const tx = db.transaction(Array.from(db.objectStoreNames)); +    const tx = myDb.transaction(Array.from(myDb.objectStoreNames));      tx.addEventListener("complete", () => { -      resolve(dbDump); +      resolve(singleDbDump);      });      // tslint:disable-next-line:prefer-for-of -    for (let i = 0; i < db.objectStoreNames.length; i++) { -      const name = db.objectStoreNames[i]; +    for (let i = 0; i < myDb.objectStoreNames.length; i++) { +      const name = myDb.objectStoreNames[i];        const store = tx.objectStore(name);        const storeDump: DbStoreDump = {          autoIncrement: store.autoIncrement, @@ -2842,7 +2853,7 @@ export function exportDb(db: IDBDatabase): Promise<DbDump> {            unique: index.unique,          };        } -      walletDb.stores[name] = storeDump; +      singleDbDump.stores[name] = storeDump;        store.openCursor().addEventListener("success", (e: Event) => {          const cursor = (e.target as any).result;          if (cursor) { @@ -2862,6 +2873,23 @@ export function exportDb(db: IDBDatabase): Promise<DbDump> {    });  } +export async function exportDb(idb: IDBFactory): Promise<DbDump> { +  const dbDump: DbDump = { +    databases: {}, +  }; + +  dbDump.databases[TALER_WALLET_META_DB_NAME] = await exportSingleDb( +    idb, +    TALER_WALLET_META_DB_NAME, +  ); +  dbDump.databases[TALER_WALLET_MAIN_DB_NAME] = await exportSingleDb( +    idb, +    TALER_WALLET_MAIN_DB_NAME, +  ); + +  return dbDump; +} +  export interface DatabaseDump {    name: string;    stores: { [s: string]: any }; @@ -2902,13 +2930,13 @@ export async function importDb(db: IDBDatabase, object: any): Promise<void> {      // looks like a IDBDatabase      const someDatabase = object.databases; -    if (TALER_META_DB_NAME in someDatabase) { +    if (TALER_WALLET_META_DB_NAME in someDatabase) {        //looks like a taler database        const currentMainDbValue = -        someDatabase[TALER_META_DB_NAME].objectStores.metaConfig.records[0] -          .value.value; +        someDatabase[TALER_WALLET_META_DB_NAME].objectStores.metaConfig +          .records[0].value.value; -      if (currentMainDbValue !== TALER_DB_NAME) { +      if (currentMainDbValue !== TALER_WALLET_MAIN_DB_NAME) {          console.log("not the current database version");        } @@ -3236,7 +3264,7 @@ export async function openTalerDatabase(  ): Promise<DbAccess<typeof WalletStoresV1>> {    const metaDbHandle = await openDatabase(      idbFactory, -    TALER_META_DB_NAME, +    TALER_WALLET_META_DB_NAME,      1,      () => {},      onMetaDbUpgradeNeeded, @@ -3249,17 +3277,17 @@ export async function openTalerDatabase(      .runReadWrite(async (tx) => {        const dbVersionRecord = await tx.metaConfig.get(CURRENT_DB_CONFIG_KEY);        if (!dbVersionRecord) { -        currentMainVersion = TALER_DB_NAME; +        currentMainVersion = TALER_WALLET_MAIN_DB_NAME;          await tx.metaConfig.put({            key: CURRENT_DB_CONFIG_KEY, -          value: TALER_DB_NAME, +          value: TALER_WALLET_MAIN_DB_NAME,          });        } else {          currentMainVersion = dbVersionRecord.value;        }      }); -  if (currentMainVersion !== TALER_DB_NAME) { +  if (currentMainVersion !== TALER_WALLET_MAIN_DB_NAME) {      switch (currentMainVersion) {        case "taler-wallet-main-v2":        case "taler-wallet-main-v3": @@ -3275,7 +3303,7 @@ export async function openTalerDatabase(            .runReadWrite(async (tx) => {              await tx.metaConfig.put({                key: CURRENT_DB_CONFIG_KEY, -              value: TALER_DB_NAME, +              value: TALER_WALLET_MAIN_DB_NAME,              });            });          break; @@ -3288,7 +3316,7 @@ export async function openTalerDatabase(    const mainDbHandle = await openDatabase(      idbFactory, -    TALER_DB_NAME, +    TALER_WALLET_MAIN_DB_NAME,      WALLET_DB_MINOR_VERSION,      onVersionChange,      onTalerDbUpgradeNeeded, @@ -3305,7 +3333,7 @@ export async function deleteTalerDatabase(    idbFactory: IDBFactory,  ): Promise<void> {    return new Promise((resolve, reject) => { -    const req = idbFactory.deleteDatabase(TALER_DB_NAME); +    const req = idbFactory.deleteDatabase(TALER_WALLET_MAIN_DB_NAME);      req.onerror = () => reject(req.error);      req.onsuccess = () => resolve();    }); diff --git a/packages/taler-wallet-core/src/host-impl.node.ts b/packages/taler-wallet-core/src/host-impl.node.ts index 6a4f21d79..0b6539306 100644 --- a/packages/taler-wallet-core/src/host-impl.node.ts +++ b/packages/taler-wallet-core/src/host-impl.node.ts @@ -139,13 +139,6 @@ export async function createNativeWalletHost2(      });    } -  const myVersionChange = (): Promise<void> => { -    logger.error("version change requested, should not happen"); -    throw Error( -      "BUG: wallet DB version change event can't happen with memory IDB", -    ); -  }; -    let dbResp: MakeDbResult;    if (args.persistentStoragePath &&args.persistentStoragePath.endsWith(".json")) { @@ -160,8 +153,6 @@ export async function createNativeWalletHost2(    shimIndexedDB(dbResp.idbFactory); -  const myDb = await openTalerDatabase(myIdbFactory, myVersionChange); -    let workerFactory;    const cryptoWorkerType = args.cryptoWorkerType ?? "node-worker-thread";    if (cryptoWorkerType === "sync") { @@ -189,7 +180,7 @@ export async function createNativeWalletHost2(    const timer = new SetTimeoutTimerAPI();    const w = await Wallet.create( -    myDb, +    myIdbFactory,      myHttpLib,      timer,      workerFactory, diff --git a/packages/taler-wallet-core/src/host-impl.qtart.ts b/packages/taler-wallet-core/src/host-impl.qtart.ts index 720f5affb..81dbe0acd 100644 --- a/packages/taler-wallet-core/src/host-impl.qtart.ts +++ b/packages/taler-wallet-core/src/host-impl.qtart.ts @@ -110,7 +110,7 @@ async function makeSqliteDb(        return {          ...myBackend.accessStats,          primitiveStatements: numStmt, -      } +      };      },      idbFactory: myBridgeIdbFactory,    }; @@ -167,12 +167,15 @@ export async function createNativeWalletHost2(    let dbResp: MakeDbResult; -  if (args.persistentStoragePath && args.persistentStoragePath.endsWith(".json")) { +  if ( +    args.persistentStoragePath && +    args.persistentStoragePath.endsWith(".json") +  ) {      logger.info("using JSON file DB backend (slow!)");      dbResp = await makeFileDb(args);    } else {      logger.info("using sqlite3 DB backend (experimental!)"); -    dbResp = await makeSqliteDb(args) +    dbResp = await makeSqliteDb(args);    }    const myIdbFactory: IDBFactory = dbResp.idbFactory as any as IDBFactory; @@ -189,22 +192,13 @@ export async function createNativeWalletHost2(      });    } -  const myVersionChange = (): Promise<void> => { -    logger.error("version change requested, should not happen"); -    throw Error( -      "BUG: wallet DB version change event can't happen with memory IDB", -    ); -  }; - -  const myDb = await openTalerDatabase(myIdbFactory, myVersionChange); -    let workerFactory;    workerFactory = new SynchronousCryptoWorkerFactoryPlain();    const timer = new SetTimeoutTimerAPI();    const w = await Wallet.create( -    myDb, +    myIdbFactory,      myHttpLib,      timer,      workerFactory, diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts b/packages/taler-wallet-core/src/internal-wallet-state.ts index 76aee05bd..a189c9cb3 100644 --- a/packages/taler-wallet-core/src/internal-wallet-state.ts +++ b/packages/taler-wallet-core/src/internal-wallet-state.ts @@ -54,6 +54,7 @@ import {  } from "./util/query.js";  import { TimerGroup } from "./util/timer.js";  import { WalletConfig } from "./wallet-api-types.js"; +import { IDBFactory } from "@gnu-taler/idb-bridge";  export const EXCHANGE_COINS_LOCK = "exchange-coins-lock";  export const EXCHANGE_RESERVES_LOCK = "exchange-reserves-lock"; @@ -203,6 +204,9 @@ export interface InternalWalletState {      denomPubHash: string,    ): Promise<DenominationInfo | undefined>; +  ensureWalletDbOpen(): Promise<void>; + +  idb: IDBFactory;    db: DbAccess<typeof WalletStoresV1>;    http: HttpRequestLibrary; diff --git a/packages/taler-wallet-core/src/util/query.ts b/packages/taler-wallet-core/src/util/query.ts index 71f80f8aa..eb2bddec1 100644 --- a/packages/taler-wallet-core/src/util/query.ts +++ b/packages/taler-wallet-core/src/util/query.ts @@ -239,7 +239,7 @@ class ResultStream<T> {  export function openDatabase(    idbFactory: IDBFactory,    databaseName: string, -  databaseVersion: number, +  databaseVersion: number | undefined,    onVersionChange: () => void,    onUpgradeNeeded: (      db: IDBDatabase, diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index c9ccda20d..9f754ed69 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -139,6 +139,7 @@ import {    clearDatabase,    exportDb,    importDb, +  openTalerDatabase,  } from "./db.js";  import { DevExperimentHttpLib, applyDevExperiment } from "./dev-experiments.js";  import { @@ -315,6 +316,7 @@ import {    getMaxPeerPushAmount,    convertWithdrawalAmount,  } from "./util/instructedAmountConversion.js"; +import { IDBFactory } from "@gnu-taler/idb-bridge";  const logger = new Logger("wallet.ts"); @@ -1539,7 +1541,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(        return {};      }      case WalletApiOperation.ExportDb: { -      const dbDump = await exportDb(ws.db.idbHandle()); +      const dbDump = await exportDb(ws.idb);        return dbDump;      }      case WalletApiOperation.ImportDb: { @@ -1654,14 +1656,14 @@ export class Wallet {    private _client: WalletCoreApiClient | undefined;    private constructor( -    db: DbAccess<typeof WalletStoresV1>, +    idb: IDBFactory,      http: HttpRequestLibrary,      timer: TimerAPI,      cryptoWorkerFactory: CryptoWorkerFactory,      config?: WalletConfigParameter,    ) {      this.ws = new InternalWalletStateImpl( -      db, +      idb,        http,        timer,        cryptoWorkerFactory, @@ -1677,13 +1679,13 @@ export class Wallet {    }    static async create( -    db: DbAccess<typeof WalletStoresV1>, +    idb: IDBFactory,      http: HttpRequestLibrary,      timer: TimerAPI,      cryptoWorkerFactory: CryptoWorkerFactory,      config?: WalletConfigParameter,    ): Promise<Wallet> { -    const w = new Wallet(db, http, timer, cryptoWorkerFactory, config); +    const w = new Wallet(idb, http, timer, cryptoWorkerFactory, config);      w._client = await getClientFromWalletState(w.ws);      return w;    } @@ -1725,19 +1727,22 @@ export class Wallet {      this.ws.stop();    } -  runPending(): Promise<void> { +  async runPending(): Promise<void> { +    await this.ws.ensureWalletDbOpen();      return runPending(this.ws);    } -  runTaskLoop(opts?: RetryLoopOpts): Promise<TaskLoopResult> { +  async runTaskLoop(opts?: RetryLoopOpts): Promise<TaskLoopResult> { +    await this.ws.ensureWalletDbOpen();      return runTaskLoop(this.ws, opts);    } -  handleCoreApiRequest( +  async handleCoreApiRequest(      operation: string,      id: string,      payload: unknown,    ): Promise<CoreApiResponse> { +    await this.ws.ensureWalletDbOpen();      return handleCoreApiRequest(this.ws, operation, id, payload);    }  } @@ -1801,12 +1806,17 @@ class InternalWalletStateImpl implements InternalWalletState {    config: Readonly<WalletConfig>; +  private _db: DbAccess<typeof WalletStoresV1> | undefined = undefined; + +  get db(): DbAccess<typeof WalletStoresV1> { +    if (!this._db) { +      throw Error("db not initialized"); +    } +    return this._db; +  } +    constructor( -    // FIXME: Make this a getter and make -    // the actual value nullable. -    // Check if we are in a DB migration / garbage collection -    // and throw an error in that case. -    public db: DbAccess<typeof WalletStoresV1>, +    public idb: IDBFactory,      public http: HttpRequestLibrary,      public timer: TimerAPI,      cryptoWorkerFactory: CryptoWorkerFactory, @@ -1821,6 +1831,20 @@ class InternalWalletStateImpl implements InternalWalletState {      }    } +  async ensureWalletDbOpen(): Promise<void> { +    if (this._db) { +      return; +    } +    const myVersionChange = (): Promise<void> => { +      logger.error("version change requested, should not happen"); +      throw Error( +        "BUG: wallet DB version change event can't happen with memory IDB", +      ); +    }; +    const myDb = await openTalerDatabase(this.idb, myVersionChange); +    this._db = myDb; +  } +    async getTransactionState(      ws: InternalWalletState,      tx: GetReadOnlyAccess<typeof WalletStoresV1>, | 
