diff options
author | Florian Dold <florian.dold@gmail.com> | 2019-11-20 19:48:43 +0100 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2019-11-20 19:48:43 +0100 |
commit | 553da649902f71d5ca34c9a6289ab6b1ef0ba7cb (patch) | |
tree | 857c4eb2c39e4a92e71c8a623d3188e6dbbbd1e9 /src/headless | |
parent | faedf697626dd37f3ac74ad4cac1ec378598bbf3 (diff) | |
download | wallet-core-553da649902f71d5ca34c9a6289ab6b1ef0ba7cb.tar.xz |
WIP: simplify DB queries and error handling
Diffstat (limited to 'src/headless')
-rw-r--r-- | src/headless/clk.ts | 64 | ||||
-rw-r--r-- | src/headless/taler-wallet-cli.ts | 108 |
2 files changed, 128 insertions, 44 deletions
diff --git a/src/headless/clk.ts b/src/headless/clk.ts index 642a1bef3..f66d609e8 100644 --- a/src/headless/clk.ts +++ b/src/headless/clk.ts @@ -20,7 +20,6 @@ import process = require("process"); import path = require("path"); import readline = require("readline"); -import { symlinkSync } from "fs"; class Converter<T> {} @@ -54,6 +53,7 @@ interface ArgumentDef { name: string; conv: Converter<any>; args: ArgumentArgs<any>; + required: boolean; } interface SubcommandDef { @@ -181,7 +181,7 @@ export class CommandGroup<GN extends keyof any, TG> { return this as any; } - argument<N extends keyof any, V>( + requiredArgument<N extends keyof any, V>( name: N, conv: Converter<V>, args: ArgumentArgs<V> = {}, @@ -190,6 +190,22 @@ export class CommandGroup<GN extends keyof any, TG> { args: args, conv: conv, name: name as string, + required: true, + }; + this.arguments.push(argDef); + return this as any; + } + + maybeArgument<N extends keyof any, V>( + name: N, + conv: Converter<V>, + args: ArgumentArgs<V> = {}, + ): CommandGroup<GN, TG & SubRecord<GN, N, V | undefined>> { + const argDef: ArgumentDef = { + args: args, + conv: conv, + name: name as string, + required: false, }; this.arguments.push(argDef); return this as any; @@ -401,10 +417,25 @@ export class CommandGroup<GN extends keyof any, TG> { process.exit(-1); throw Error("not reached"); } + myArgs[d.name] = unparsedArgs[i]; posArgIndex++; } } + for (let i = posArgIndex; i < this.arguments.length; i++) { + const d = this.arguments[i]; + const n = this.name ?? progname; + if (d.required) { + if (d.args.default !== undefined) { + myArgs[d.name] = d.args.default; + } else { + console.error(`error: missing positional argument '${d.name}' for ${n}`); + process.exit(-1); + throw Error("not reached"); + } + } + } + for (let option of this.options) { if (option.isFlag == false && option.required == true) { if (!foundOptions[option.name]) { @@ -433,9 +464,7 @@ export class CommandGroup<GN extends keyof any, TG> { unparsedArgs.slice(i + 1), parsedArgs, ); - } - - if (this.myAction) { + } else if (this.myAction) { this.myAction(parsedArgs); } else { this.printHelp(progname, parents); @@ -513,18 +542,35 @@ export class Program<PN extends keyof any, T> { } /** - * Add a positional argument to the program. + * Add a required positional argument to the program. */ - argument<N extends keyof any, V>( + requiredArgument<N extends keyof any, V>( name: N, conv: Converter<V>, args: ArgumentArgs<V> = {}, ): Program<N, T & SubRecord<PN, N, V>> { - this.mainCommand.argument(name, conv, args); + this.mainCommand.requiredArgument(name, conv, args); + return this as any; + } + + /** + * Add an optional argument to the program. + */ + maybeArgument<N extends keyof any, V>( + name: N, + conv: Converter<V>, + args: ArgumentArgs<V> = {}, + ): Program<N, T & SubRecord<PN, N, V | undefined>> { + this.mainCommand.maybeArgument(name, conv, args); return this as any; } } +export type GetArgType<T> = + T extends Program<any, infer AT> ? AT : + T extends CommandGroup<any, infer AT> ? AT : + any; + export function program<PN extends keyof any>( argKey: PN, args: ProgramArgs = {}, @@ -532,6 +578,8 @@ export function program<PN extends keyof any>( return new Program(argKey as string, args); } + + export function prompt(question: string): Promise<string> { const stdinReadline = readline.createInterface({ input: process.stdin, diff --git a/src/headless/taler-wallet-cli.ts b/src/headless/taler-wallet-cli.ts index 41f68319a..06235d0b4 100644 --- a/src/headless/taler-wallet-cli.ts +++ b/src/headless/taler-wallet-cli.ts @@ -97,6 +97,28 @@ const walletCli = clk help: "Enable verbose output.", }); +type WalletCliArgsType = clk.GetArgType<typeof walletCli>; + +async function withWallet<T>( + walletCliArgs: WalletCliArgsType, + f: (w: Wallet) => Promise<T>, +): Promise<T> { + applyVerbose(walletCliArgs.wallet.verbose); + const wallet = await getDefaultNodeWallet({ + persistentStoragePath: walletDbPath, + }); + try { + await wallet.fillDefaults(); + const ret = await f(wallet); + return ret; + } catch (e) { + console.error("caught exception:", e); + process.exit(1); + } finally { + wallet.stop(); + } +} + walletCli .subcommand("testPayCmd", "test-pay", { help: "create contract and pay" }) .requiredOption("amount", ["-a", "--amount"], clk.STRING) @@ -135,15 +157,11 @@ walletCli walletCli .subcommand("", "balance", { help: "Show wallet balance." }) .action(async args => { - applyVerbose(args.wallet.verbose); console.log("balance command called"); - const wallet = await getDefaultNodeWallet({ - persistentStoragePath: walletDbPath, + withWallet(args, async (wallet) => { + const balance = await wallet.getBalances(); + console.log(JSON.stringify(balance, undefined, 2)); }); - console.log("got wallet"); - const balance = await wallet.getBalances(); - console.log(JSON.stringify(balance, undefined, 2)); - process.exit(0); }); walletCli @@ -153,29 +171,19 @@ walletCli .requiredOption("limit", ["--limit"], clk.STRING) .requiredOption("contEvt", ["--continue-with"], clk.STRING) .action(async args => { - applyVerbose(args.wallet.verbose); - console.log("history command called"); - const wallet = await getDefaultNodeWallet({ - persistentStoragePath: walletDbPath, + withWallet(args, async (wallet) => { + const history = await wallet.getHistory(); + console.log(JSON.stringify(history, undefined, 2)); }); - console.log("got wallet"); - const history = await wallet.getHistory(); - console.log(JSON.stringify(history, undefined, 2)); - process.exit(0); }); walletCli .subcommand("", "pending", { help: "Show pending operations." }) .action(async args => { - applyVerbose(args.wallet.verbose); - console.log("history command called"); - const wallet = await getDefaultNodeWallet({ - persistentStoragePath: walletDbPath, + withWallet(args, async (wallet) => { + const pending = await wallet.getPendingOperations(); + console.log(JSON.stringify(pending, undefined, 2)); }); - console.log("got wallet"); - const pending = await wallet.getPendingOperations(); - console.log(JSON.stringify(pending, undefined, 2)); - process.exit(0); }); async function asyncSleep(milliSeconds: number): Promise<void> { @@ -185,6 +193,16 @@ async function asyncSleep(milliSeconds: number): Promise<void> { } walletCli + .subcommand("runPendingOpt", "run-pending", { + help: "Run pending operations." + }) + .action(async (args) => { + withWallet(args, async (wallet) => { + await wallet.processPending(); + }); + }); + +walletCli .subcommand("testMerchantQrcodeCmd", "test-merchant-qrcode") .requiredOption("amount", ["-a", "--amount"], clk.STRING, { default: "TESTKUDOS:1", @@ -279,7 +297,7 @@ walletCli walletCli .subcommand("withdrawUriCmd", "withdraw-uri") - .argument("withdrawUri", clk.STRING) + .requiredArgument("withdrawUri", clk.STRING) .action(async args => { applyVerbose(args.wallet.verbose); const cmdArgs = args.withdrawUriCmd; @@ -318,7 +336,7 @@ walletCli walletCli .subcommand("tipUriCmd", "tip-uri") - .argument("uri", clk.STRING) + .requiredArgument("uri", clk.STRING) .action(async args => { applyVerbose(args.wallet.verbose); const tipUri = args.tipUriCmd.uri; @@ -334,7 +352,7 @@ walletCli walletCli .subcommand("refundUriCmd", "refund-uri") - .argument("uri", clk.STRING) + .requiredArgument("uri", clk.STRING) .action(async args => { applyVerbose(args.wallet.verbose); const refundUri = args.refundUriCmd.uri; @@ -346,20 +364,38 @@ walletCli wallet.stop(); }); -const exchangesCli = walletCli - .subcommand("exchangesCmd", "exchanges", { - help: "Manage exchanges." - }); - -exchangesCli.subcommand("exchangesListCmd", "list", { - help: "List known exchanges." +const exchangesCli = walletCli.subcommand("exchangesCmd", "exchanges", { + help: "Manage exchanges.", }); -exchangesCli.subcommand("exchangesListCmd", "update"); +exchangesCli + .subcommand("exchangesListCmd", "list", { + help: "List known exchanges.", + }) + .action(async args => { + console.log("Listing exchanges ..."); + withWallet(args, async (wallet) => { + const exchanges = await wallet.getExchanges(); + console.log("exchanges", exchanges); + }); + }); + +exchangesCli + .subcommand("exchangesUpdateCmd", "update", { + help: "Update or add an exchange by base URL.", + }) + .requiredArgument("url", clk.STRING, { + help: "Base URL of the exchange.", + }) + .action(async args => { + withWallet(args, async (wallet) => { + const res = await wallet.updateExchangeFromUrl(args.exchangesUpdateCmd.url); + }); + }); walletCli .subcommand("payUriCmd", "pay-uri") - .argument("url", clk.STRING) + .requiredArgument("url", clk.STRING) .flag("autoYes", ["-y", "--yes"]) .action(async args => { applyVerbose(args.wallet.verbose); @@ -374,7 +410,7 @@ walletCli }); const testCli = walletCli.subcommand("testingArgs", "testing", { - help: "Subcommands for testing GNU Taler deployments." + help: "Subcommands for testing GNU Taler deployments.", }); testCli |