wallet-core: do not block when accepting a manual withdrawal
This commit is contained in:
parent
9811e19252
commit
72336b149b
@ -1378,6 +1378,7 @@ export interface DepositGroupFees {
|
|||||||
wire: AmountJson;
|
wire: AmountJson;
|
||||||
refresh: AmountJson;
|
refresh: AmountJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateDepositGroupRequest {
|
export interface CreateDepositGroupRequest {
|
||||||
depositPaytoUri: string;
|
depositPaytoUri: string;
|
||||||
amount: AmountString;
|
amount: AmountString;
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gnu-taler/taler-util": "workspace:*",
|
"@gnu-taler/taler-util": "workspace:*",
|
||||||
"@gnu-taler/taler-wallet-core": "workspace:*",
|
"@gnu-taler/taler-wallet-core": "workspace:*",
|
||||||
"axios": "^0.25.0",
|
"axios": "^0.27.2",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
"tslib": "^2.3.1"
|
"tslib": "^2.3.1"
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,11 @@
|
|||||||
import { GlobalTestState } from "../harness/harness.js";
|
import { GlobalTestState } from "../harness/harness.js";
|
||||||
import { createSimpleTestkudosEnvironment } from "../harness/helpers.js";
|
import { createSimpleTestkudosEnvironment } from "../harness/helpers.js";
|
||||||
import { WalletApiOperation, BankApi } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation, BankApi } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import {
|
||||||
|
AbsoluteTime,
|
||||||
|
Duration,
|
||||||
|
TalerProtocolTimestamp,
|
||||||
|
} from "@gnu-taler/taler-util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run test for basic, bank-integrated withdrawal.
|
* Run test for basic, bank-integrated withdrawal.
|
||||||
@ -38,6 +43,9 @@ export async function runTestWithdrawalManualTest(t: GlobalTestState) {
|
|||||||
exchangeBaseUrl: exchange.baseUrl,
|
exchangeBaseUrl: exchange.baseUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tStart = AbsoluteTime.now();
|
||||||
|
|
||||||
|
// We expect this to return immediately.
|
||||||
const wres = await wallet.client.call(
|
const wres = await wallet.client.call(
|
||||||
WalletApiOperation.AcceptManualWithdrawal,
|
WalletApiOperation.AcceptManualWithdrawal,
|
||||||
{
|
{
|
||||||
@ -46,9 +54,14 @@ export async function runTestWithdrawalManualTest(t: GlobalTestState) {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Check that the request did not go into long-polling.
|
||||||
|
const duration = AbsoluteTime.difference(tStart, AbsoluteTime.now());
|
||||||
|
if (duration.d_ms > 5 * 1000) {
|
||||||
|
throw Error("withdrawal took too long (longpolling issue)");
|
||||||
|
}
|
||||||
|
|
||||||
const reservePub: string = wres.reservePub;
|
const reservePub: string = wres.reservePub;
|
||||||
|
|
||||||
// Bug.
|
|
||||||
await BankApi.adminAddIncoming(bank, {
|
await BankApi.adminAddIncoming(bank, {
|
||||||
exchangeBankAccount,
|
exchangeBankAccount,
|
||||||
amount: "TESTKUDOS:10",
|
amount: "TESTKUDOS:10",
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
"@gnu-taler/idb-bridge": "workspace:*",
|
"@gnu-taler/idb-bridge": "workspace:*",
|
||||||
"@gnu-taler/taler-util": "workspace:*",
|
"@gnu-taler/taler-util": "workspace:*",
|
||||||
"@types/node": "^17.0.17",
|
"@types/node": "^17.0.17",
|
||||||
"axios": "^0.25.0",
|
"axios": "^0.27.2",
|
||||||
"big-integer": "^1.6.51",
|
"big-integer": "^1.6.51",
|
||||||
"fflate": "^0.7.3",
|
"fflate": "^0.7.3",
|
||||||
"source-map-support": "^0.5.21",
|
"source-map-support": "^0.5.21",
|
||||||
|
@ -127,6 +127,12 @@ export interface RecoupOperations {
|
|||||||
|
|
||||||
export type NotificationListener = (n: WalletNotification) => void;
|
export type NotificationListener = (n: WalletNotification) => void;
|
||||||
|
|
||||||
|
export interface ActiveLongpollInfo {
|
||||||
|
[opId: string]: {
|
||||||
|
cancel: () => void;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal, shard wallet state that is used by the implementation
|
* Internal, shard wallet state that is used by the implementation
|
||||||
* of wallet operations.
|
* of wallet operations.
|
||||||
@ -135,12 +141,10 @@ export type NotificationListener = (n: WalletNotification) => void;
|
|||||||
* as it's an opaque implementation detail.
|
* as it's an opaque implementation detail.
|
||||||
*/
|
*/
|
||||||
export interface InternalWalletState {
|
export interface InternalWalletState {
|
||||||
memoProcessReserve: AsyncOpMemoMap<void>;
|
/**
|
||||||
memoMakePlanchet: AsyncOpMemoMap<void>;
|
* Active longpoll operations.
|
||||||
memoGetPending: AsyncOpMemoSingle<PendingOperationsResponse>;
|
*/
|
||||||
memoGetBalance: AsyncOpMemoSingle<BalancesResponse>;
|
activeLongpoll: ActiveLongpollInfo;
|
||||||
memoProcessRefresh: AsyncOpMemoMap<void>;
|
|
||||||
memoProcessRecoup: AsyncOpMemoMap<void>;
|
|
||||||
|
|
||||||
cryptoApi: TalerCryptoInterface;
|
cryptoApi: TalerCryptoInterface;
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import {
|
|||||||
Amounts,
|
Amounts,
|
||||||
AmountString,
|
AmountString,
|
||||||
BankWithdrawDetails,
|
BankWithdrawDetails,
|
||||||
|
CancellationToken,
|
||||||
canonicalizeBaseUrl,
|
canonicalizeBaseUrl,
|
||||||
codecForBankWithdrawalOperationPostResponse,
|
codecForBankWithdrawalOperationPostResponse,
|
||||||
codecForReserveStatus,
|
codecForReserveStatus,
|
||||||
@ -106,7 +107,12 @@ import {
|
|||||||
WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
|
WALLET_BANK_INTEGRATION_PROTOCOL_VERSION,
|
||||||
WALLET_EXCHANGE_PROTOCOL_VERSION,
|
WALLET_EXCHANGE_PROTOCOL_VERSION,
|
||||||
} from "../versions.js";
|
} from "../versions.js";
|
||||||
import { makeCoinAvailable, storeOperationPending } from "../wallet.js";
|
import {
|
||||||
|
makeCoinAvailable,
|
||||||
|
runOperationWithErrorReporting,
|
||||||
|
storeOperationError,
|
||||||
|
storeOperationPending,
|
||||||
|
} from "../wallet.js";
|
||||||
import {
|
import {
|
||||||
getExchangeDetails,
|
getExchangeDetails,
|
||||||
getExchangePaytoUri,
|
getExchangePaytoUri,
|
||||||
@ -962,6 +968,7 @@ export async function updateWithdrawalDenoms(
|
|||||||
async function queryReserve(
|
async function queryReserve(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
withdrawalGroupId: string,
|
withdrawalGroupId: string,
|
||||||
|
cancellationToken: CancellationToken,
|
||||||
): Promise<{ ready: boolean }> {
|
): Promise<{ ready: boolean }> {
|
||||||
const withdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, {
|
const withdrawalGroup = await getWithdrawalGroupRecordTx(ws.db, {
|
||||||
withdrawalGroupId,
|
withdrawalGroupId,
|
||||||
@ -982,6 +989,7 @@ async function queryReserve(
|
|||||||
|
|
||||||
const resp = await ws.http.get(reserveUrl.href, {
|
const resp = await ws.http.get(reserveUrl.href, {
|
||||||
timeout: getReserveRequestTimeout(withdrawalGroup),
|
timeout: getReserveRequestTimeout(withdrawalGroup),
|
||||||
|
cancellationToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await readSuccessResponseJsonOrErrorCode(
|
const result = await readSuccessResponseJsonOrErrorCode(
|
||||||
@ -1044,6 +1052,16 @@ export async function processWithdrawalGroup(
|
|||||||
throw Error(`withdrawal group ${withdrawalGroupId} not found`);
|
throw Error(`withdrawal group ${withdrawalGroupId} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const retryTag = RetryTags.forWithdrawal(withdrawalGroup);
|
||||||
|
|
||||||
|
// We're already running!
|
||||||
|
if (ws.activeLongpoll[retryTag]) {
|
||||||
|
logger.info("withdrawal group already in long-polling, returning!");
|
||||||
|
return {
|
||||||
|
type: OperationAttemptResultType.Longpoll,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
switch (withdrawalGroup.status) {
|
switch (withdrawalGroup.status) {
|
||||||
case WithdrawalGroupStatus.RegisteringBank:
|
case WithdrawalGroupStatus.RegisteringBank:
|
||||||
await processReserveBankStatus(ws, withdrawalGroupId);
|
await processReserveBankStatus(ws, withdrawalGroupId);
|
||||||
@ -1051,15 +1069,45 @@ export async function processWithdrawalGroup(
|
|||||||
forceNow: true,
|
forceNow: true,
|
||||||
});
|
});
|
||||||
case WithdrawalGroupStatus.QueryingStatus: {
|
case WithdrawalGroupStatus.QueryingStatus: {
|
||||||
const res = await queryReserve(ws, withdrawalGroupId);
|
const doQueryAsync = async () => {
|
||||||
if (res.ready) {
|
if (ws.stopped) {
|
||||||
return await processWithdrawalGroup(ws, withdrawalGroupId, {
|
logger.info("not long-polling reserve, wallet already stopped");
|
||||||
forceNow: true,
|
await storeOperationPending(ws, retryTag);
|
||||||
});
|
return;
|
||||||
}
|
}
|
||||||
|
const cts = CancellationToken.create();
|
||||||
|
let res: { ready: boolean } | undefined = undefined;
|
||||||
|
try {
|
||||||
|
ws.activeLongpoll[retryTag] = {
|
||||||
|
cancel: () => {
|
||||||
|
logger.info("cancel of reserve longpoll requested");
|
||||||
|
cts.cancel();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
res = await queryReserve(ws, withdrawalGroupId, cts.token);
|
||||||
|
} catch (e) {
|
||||||
|
await storeOperationError(
|
||||||
|
ws,
|
||||||
|
retryTag,
|
||||||
|
getErrorDetailFromException(e),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete ws.activeLongpoll[retryTag];
|
||||||
|
logger.info(
|
||||||
|
`active longpoll keys (2) ${Object.keys(ws.activeLongpoll)}`,
|
||||||
|
);
|
||||||
|
if (!res.ready) {
|
||||||
|
await storeOperationPending(ws, retryTag);
|
||||||
|
}
|
||||||
|
ws.latch.trigger();
|
||||||
|
};
|
||||||
|
doQueryAsync();
|
||||||
|
logger.info(
|
||||||
|
"returning early from withdrawal for long-polling in background",
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
type: OperationAttemptResultType.Pending,
|
type: OperationAttemptResultType.Longpoll,
|
||||||
result: undefined,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case WithdrawalGroupStatus.WaitConfirmBank: {
|
case WithdrawalGroupStatus.WaitConfirmBank: {
|
||||||
@ -1912,10 +1960,16 @@ export async function createManualWithdrawal(
|
|||||||
return await getFundingPaytoUris(tx, withdrawalGroup.withdrawalGroupId);
|
return await getFundingPaytoUris(tx, withdrawalGroup.withdrawalGroupId);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start withdrawal in the background.
|
// Start withdrawal in the background (do not await!)
|
||||||
await processWithdrawalGroup(ws, withdrawalGroupId, { forceNow: true }).catch(
|
// FIXME: We could also interrupt the task look if it is waiting and
|
||||||
(err) => {
|
// rely on retry handling to re-process the withdrawal group.
|
||||||
logger.error("Processing withdrawal (after creation) failed:", err);
|
runOperationWithErrorReporting(
|
||||||
|
ws,
|
||||||
|
RetryTags.forWithdrawal(withdrawalGroup),
|
||||||
|
async () => {
|
||||||
|
return await processWithdrawalGroup(ws, withdrawalGroupId, {
|
||||||
|
forceNow: true,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -64,38 +64,37 @@ import {
|
|||||||
codecForSetWalletDeviceIdRequest,
|
codecForSetWalletDeviceIdRequest,
|
||||||
codecForTestPayArgs,
|
codecForTestPayArgs,
|
||||||
codecForTrackDepositGroupRequest,
|
codecForTrackDepositGroupRequest,
|
||||||
|
codecForTransactionByIdRequest,
|
||||||
codecForTransactionsRequest,
|
codecForTransactionsRequest,
|
||||||
codecForWithdrawFakebankRequest,
|
codecForWithdrawFakebankRequest,
|
||||||
codecForWithdrawTestBalance,
|
codecForWithdrawTestBalance,
|
||||||
CoinDumpJson,
|
CoinDumpJson,
|
||||||
CoreApiResponse,
|
CoreApiResponse,
|
||||||
|
DenominationInfo,
|
||||||
Duration,
|
Duration,
|
||||||
durationFromSpec,
|
durationFromSpec,
|
||||||
durationMin,
|
durationMin,
|
||||||
ExchangeFullDetails,
|
ExchangeFullDetails,
|
||||||
|
ExchangeListItem,
|
||||||
ExchangesListResponse,
|
ExchangesListResponse,
|
||||||
|
FeeDescription,
|
||||||
GetExchangeTosResult,
|
GetExchangeTosResult,
|
||||||
j2s,
|
j2s,
|
||||||
KnownBankAccounts,
|
KnownBankAccounts,
|
||||||
Logger,
|
Logger,
|
||||||
ManualWithdrawalDetails,
|
ManualWithdrawalDetails,
|
||||||
NotificationType,
|
NotificationType,
|
||||||
|
OperationMap,
|
||||||
parsePaytoUri,
|
parsePaytoUri,
|
||||||
PaytoUri,
|
|
||||||
RefreshReason,
|
RefreshReason,
|
||||||
TalerErrorCode,
|
TalerErrorCode,
|
||||||
URL,
|
|
||||||
WalletNotification,
|
|
||||||
WalletCoreVersion,
|
|
||||||
ExchangeListItem,
|
|
||||||
OperationMap,
|
|
||||||
FeeDescription,
|
|
||||||
TalerErrorDetail,
|
TalerErrorDetail,
|
||||||
codecForTransactionByIdRequest,
|
|
||||||
DenominationInfo,
|
|
||||||
KnownBankAccountsInfo,
|
KnownBankAccountsInfo,
|
||||||
codecForAddKnownBankAccounts,
|
codecForAddKnownBankAccounts,
|
||||||
codecForForgetKnownBankAccounts,
|
codecForForgetKnownBankAccounts,
|
||||||
|
URL,
|
||||||
|
WalletCoreVersion,
|
||||||
|
WalletNotification,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
|
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
|
||||||
import {
|
import {
|
||||||
@ -119,6 +118,7 @@ import {
|
|||||||
TalerError,
|
TalerError,
|
||||||
} from "./errors.js";
|
} from "./errors.js";
|
||||||
import {
|
import {
|
||||||
|
ActiveLongpollInfo,
|
||||||
ExchangeOperations,
|
ExchangeOperations,
|
||||||
InternalWalletState,
|
InternalWalletState,
|
||||||
MerchantInfo,
|
MerchantInfo,
|
||||||
@ -235,7 +235,6 @@ import {
|
|||||||
OperationAttemptResult,
|
OperationAttemptResult,
|
||||||
OperationAttemptResultType,
|
OperationAttemptResultType,
|
||||||
RetryInfo,
|
RetryInfo,
|
||||||
runOperationHandlerForResult,
|
|
||||||
} from "./util/retries.js";
|
} from "./util/retries.js";
|
||||||
import { TimerAPI, TimerGroup } from "./util/timer.js";
|
import { TimerAPI, TimerGroup } from "./util/timer.js";
|
||||||
import {
|
import {
|
||||||
@ -392,27 +391,21 @@ export async function storeOperationPending(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export async function runOperationWithErrorReporting(
|
||||||
* Execute one operation based on the pending operation info record.
|
|
||||||
*
|
|
||||||
* Store success/failure result in the database.
|
|
||||||
*/
|
|
||||||
async function processOnePendingOperation(
|
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
pending: PendingTaskInfo,
|
opId: string,
|
||||||
forceNow = false,
|
f: () => Promise<OperationAttemptResult>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
logger.trace(`running pending ${JSON.stringify(pending, undefined, 2)}`);
|
|
||||||
let maybeError: TalerErrorDetail | undefined;
|
let maybeError: TalerErrorDetail | undefined;
|
||||||
try {
|
try {
|
||||||
const resp = await callOperationHandler(ws, pending, forceNow);
|
const resp = await f();
|
||||||
switch (resp.type) {
|
switch (resp.type) {
|
||||||
case OperationAttemptResultType.Error:
|
case OperationAttemptResultType.Error:
|
||||||
return await storeOperationError(ws, pending.id, resp.errorDetail);
|
return await storeOperationError(ws, opId, resp.errorDetail);
|
||||||
case OperationAttemptResultType.Finished:
|
case OperationAttemptResultType.Finished:
|
||||||
return await storeOperationFinished(ws, pending.id);
|
return await storeOperationFinished(ws, opId);
|
||||||
case OperationAttemptResultType.Pending:
|
case OperationAttemptResultType.Pending:
|
||||||
return await storeOperationPending(ws, pending.id);
|
return await storeOperationPending(ws, opId);
|
||||||
case OperationAttemptResultType.Longpoll:
|
case OperationAttemptResultType.Longpoll:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -421,7 +414,7 @@ async function processOnePendingOperation(
|
|||||||
logger.warn("operation processed resulted in error");
|
logger.warn("operation processed resulted in error");
|
||||||
logger.warn(`error was: ${j2s(e.errorDetail)}`);
|
logger.warn(`error was: ${j2s(e.errorDetail)}`);
|
||||||
maybeError = e.errorDetail;
|
maybeError = e.errorDetail;
|
||||||
return await storeOperationError(ws, pending.id, maybeError!);
|
return await storeOperationError(ws, opId, maybeError!);
|
||||||
} else if (e instanceof Error) {
|
} else if (e instanceof Error) {
|
||||||
// This is a bug, as we expect pending operations to always
|
// This is a bug, as we expect pending operations to always
|
||||||
// do their own error handling and only throw WALLET_PENDING_OPERATION_FAILED
|
// do their own error handling and only throw WALLET_PENDING_OPERATION_FAILED
|
||||||
@ -435,7 +428,7 @@ async function processOnePendingOperation(
|
|||||||
},
|
},
|
||||||
`unexpected exception (message: ${e.message})`,
|
`unexpected exception (message: ${e.message})`,
|
||||||
);
|
);
|
||||||
return await storeOperationError(ws, pending.id, maybeError);
|
return await storeOperationError(ws, opId, maybeError);
|
||||||
} else {
|
} else {
|
||||||
logger.error("Uncaught exception, value is not even an error.");
|
logger.error("Uncaught exception, value is not even an error.");
|
||||||
maybeError = makeErrorDetail(
|
maybeError = makeErrorDetail(
|
||||||
@ -443,7 +436,7 @@ async function processOnePendingOperation(
|
|||||||
{},
|
{},
|
||||||
`unexpected exception (not even an error)`,
|
`unexpected exception (not even an error)`,
|
||||||
);
|
);
|
||||||
return await storeOperationError(ws, pending.id, maybeError);
|
return await storeOperationError(ws, opId, maybeError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,7 +453,10 @@ export async function runPending(
|
|||||||
if (!forceNow && !AbsoluteTime.isExpired(p.timestampDue)) {
|
if (!forceNow && !AbsoluteTime.isExpired(p.timestampDue)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
await processOnePendingOperation(ws, p, forceNow);
|
await runOperationWithErrorReporting(ws, p.id, async () => {
|
||||||
|
logger.trace(`running pending ${JSON.stringify(p, undefined, 2)}`);
|
||||||
|
return await callOperationHandler(ws, p, forceNow);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,7 +559,10 @@ async function runTaskLoop(
|
|||||||
if (!AbsoluteTime.isExpired(p.timestampDue)) {
|
if (!AbsoluteTime.isExpired(p.timestampDue)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
await processOnePendingOperation(ws, p);
|
await runOperationWithErrorReporting(ws, p.id, async () => {
|
||||||
|
logger.trace(`running pending ${JSON.stringify(p, undefined, 2)}`);
|
||||||
|
return await callOperationHandler(ws, p);
|
||||||
|
});
|
||||||
ws.notify({
|
ws.notify({
|
||||||
type: NotificationType.PendingOperationProcessed,
|
type: NotificationType.PendingOperationProcessed,
|
||||||
});
|
});
|
||||||
@ -1613,13 +1612,10 @@ export class Wallet {
|
|||||||
* This ties together all the operation implementations.
|
* This ties together all the operation implementations.
|
||||||
*/
|
*/
|
||||||
class InternalWalletStateImpl implements InternalWalletState {
|
class InternalWalletStateImpl implements InternalWalletState {
|
||||||
memoProcessReserve: AsyncOpMemoMap<void> = new AsyncOpMemoMap();
|
/**
|
||||||
memoMakePlanchet: AsyncOpMemoMap<void> = new AsyncOpMemoMap();
|
* @see {@link InternalWalletState.activeLongpoll}
|
||||||
memoGetPending: AsyncOpMemoSingle<PendingOperationsResponse> =
|
*/
|
||||||
new AsyncOpMemoSingle();
|
activeLongpoll: ActiveLongpollInfo = {};
|
||||||
memoGetBalance: AsyncOpMemoSingle<BalancesResponse> = new AsyncOpMemoSingle();
|
|
||||||
memoProcessRefresh: AsyncOpMemoMap<void> = new AsyncOpMemoMap();
|
|
||||||
memoProcessRecoup: AsyncOpMemoMap<void> = new AsyncOpMemoMap();
|
|
||||||
|
|
||||||
cryptoApi: TalerCryptoInterface;
|
cryptoApi: TalerCryptoInterface;
|
||||||
cryptoDispatcher: CryptoDispatcher;
|
cryptoDispatcher: CryptoDispatcher;
|
||||||
@ -1719,9 +1715,14 @@ class InternalWalletStateImpl implements InternalWalletState {
|
|||||||
* Stop ongoing processing.
|
* Stop ongoing processing.
|
||||||
*/
|
*/
|
||||||
stop(): void {
|
stop(): void {
|
||||||
|
logger.info("stopping (at internal wallet state)");
|
||||||
this.stopped = true;
|
this.stopped = true;
|
||||||
this.timerGroup.stopCurrentAndFutureTimers();
|
this.timerGroup.stopCurrentAndFutureTimers();
|
||||||
this.cryptoDispatcher.stop();
|
this.cryptoDispatcher.stop();
|
||||||
|
for (const key of Object.keys(this.activeLongpoll)) {
|
||||||
|
logger.info(`cancelling active longpoll ${key}`);
|
||||||
|
this.activeLongpoll[key].cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async runUntilDone(
|
async runUntilDone(
|
||||||
|
@ -197,7 +197,7 @@ importers:
|
|||||||
'@rollup/plugin-node-resolve': ^13.3.0
|
'@rollup/plugin-node-resolve': ^13.3.0
|
||||||
'@rollup/plugin-replace': ^4.0.0
|
'@rollup/plugin-replace': ^4.0.0
|
||||||
'@types/node': ^17.0.17
|
'@types/node': ^17.0.17
|
||||||
axios: ^0.25.0
|
axios: ^0.27.2
|
||||||
prettier: ^2.5.1
|
prettier: ^2.5.1
|
||||||
rimraf: ^3.0.2
|
rimraf: ^3.0.2
|
||||||
rollup: ^2.79.0
|
rollup: ^2.79.0
|
||||||
@ -210,7 +210,7 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@gnu-taler/taler-util': link:../taler-util
|
'@gnu-taler/taler-util': link:../taler-util
|
||||||
'@gnu-taler/taler-wallet-core': link:../taler-wallet-core
|
'@gnu-taler/taler-wallet-core': link:../taler-wallet-core
|
||||||
axios: 0.25.0
|
axios: 0.27.2
|
||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
tslib: 2.3.1
|
tslib: 2.3.1
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@ -237,7 +237,7 @@ importers:
|
|||||||
'@typescript-eslint/eslint-plugin': ^5.36.1
|
'@typescript-eslint/eslint-plugin': ^5.36.1
|
||||||
'@typescript-eslint/parser': ^5.36.1
|
'@typescript-eslint/parser': ^5.36.1
|
||||||
ava: ^4.0.1
|
ava: ^4.0.1
|
||||||
axios: ^0.25.0
|
axios: ^0.27.2
|
||||||
big-integer: ^1.6.51
|
big-integer: ^1.6.51
|
||||||
c8: ^7.11.0
|
c8: ^7.11.0
|
||||||
eslint: ^8.8.0
|
eslint: ^8.8.0
|
||||||
@ -262,7 +262,7 @@ importers:
|
|||||||
'@gnu-taler/idb-bridge': link:../idb-bridge
|
'@gnu-taler/idb-bridge': link:../idb-bridge
|
||||||
'@gnu-taler/taler-util': link:../taler-util
|
'@gnu-taler/taler-util': link:../taler-util
|
||||||
'@types/node': 17.0.17
|
'@types/node': 17.0.17
|
||||||
axios: 0.25.0
|
axios: 0.27.2
|
||||||
big-integer: 1.6.51
|
big-integer: 1.6.51
|
||||||
fflate: 0.7.3
|
fflate: 0.7.3
|
||||||
source-map-support: 0.5.21
|
source-map-support: 0.5.21
|
||||||
@ -4380,8 +4380,7 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/asynckit/0.4.0:
|
/asynckit/0.4.0:
|
||||||
resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=}
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/at-least-node/1.0.0:
|
/at-least-node/1.0.0:
|
||||||
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
|
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
|
||||||
@ -4550,10 +4549,11 @@ packages:
|
|||||||
- debug
|
- debug
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/axios/0.25.0:
|
/axios/0.27.2:
|
||||||
resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==}
|
resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.14.8
|
follow-redirects: 1.15.2
|
||||||
|
form-data: 4.0.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- debug
|
- debug
|
||||||
dev: false
|
dev: false
|
||||||
@ -5535,7 +5535,6 @@ packages:
|
|||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream: 1.0.0
|
delayed-stream: 1.0.0
|
||||||
dev: true
|
|
||||||
|
|
||||||
/commander/2.17.1:
|
/commander/2.17.1:
|
||||||
resolution: {integrity: sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==}
|
resolution: {integrity: sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==}
|
||||||
@ -6382,9 +6381,8 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/delayed-stream/1.0.0:
|
/delayed-stream/1.0.0:
|
||||||
resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=}
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/depd/1.1.2:
|
/depd/1.1.2:
|
||||||
resolution: {integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=}
|
resolution: {integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=}
|
||||||
@ -7627,6 +7625,17 @@ packages:
|
|||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
debug:
|
debug:
|
||||||
optional: true
|
optional: true
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/follow-redirects/1.15.2:
|
||||||
|
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
peerDependencies:
|
||||||
|
debug: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
debug:
|
||||||
|
optional: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/for-each/0.3.3:
|
/for-each/0.3.3:
|
||||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||||
@ -7687,6 +7696,15 @@ packages:
|
|||||||
mime-types: 2.1.34
|
mime-types: 2.1.34
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/form-data/4.0.0:
|
||||||
|
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
dependencies:
|
||||||
|
asynckit: 0.4.0
|
||||||
|
combined-stream: 1.0.8
|
||||||
|
mime-types: 2.1.35
|
||||||
|
dev: false
|
||||||
|
|
||||||
/formdata-polyfill/4.0.10:
|
/formdata-polyfill/4.0.10:
|
||||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||||
engines: {node: '>=12.20.0'}
|
engines: {node: '>=12.20.0'}
|
||||||
@ -9593,6 +9611,11 @@ packages:
|
|||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/mime-db/1.52.0:
|
||||||
|
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/mime-types/2.1.34:
|
/mime-types/2.1.34:
|
||||||
resolution: {integrity: sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==}
|
resolution: {integrity: sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@ -9600,6 +9623,13 @@ packages:
|
|||||||
mime-db: 1.51.0
|
mime-db: 1.51.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/mime-types/2.1.35:
|
||||||
|
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
|
||||||
|
engines: {node: '>= 0.6'}
|
||||||
|
dependencies:
|
||||||
|
mime-db: 1.52.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/mime/1.6.0:
|
/mime/1.6.0:
|
||||||
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
|
resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
Loading…
Reference in New Issue
Block a user