moving libs to web utils, apply new mock api to backoffice
This commit is contained in:
parent
b9c24772f5
commit
c5c00e4da7
@ -71,16 +71,19 @@ export class ApiMockEnvironment extends MockEnvironment {
|
|||||||
request: options.data,
|
request: options.data,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
const status = mocked.expectedQuery?.query.code ?? 200;
|
||||||
|
const requestPayload = mocked.expectedQuery?.params?.request;
|
||||||
|
const responsePayload = mocked.expectedQuery?.params?.response;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ok: true,
|
ok: true,
|
||||||
data: (!mocked ? undefined : mocked.payload) as T,
|
data: responsePayload as T,
|
||||||
loading: false,
|
loading: false,
|
||||||
clientError: false,
|
clientError: false,
|
||||||
serverError: false,
|
serverError: false,
|
||||||
info: {
|
info: {
|
||||||
hasToken: !!options.token,
|
hasToken: !!options.token,
|
||||||
status: !mocked ? 200 : mocked.status,
|
status,
|
||||||
url: _url.href,
|
url: _url.href,
|
||||||
payload: options.data,
|
payload: options.data,
|
||||||
options: {},
|
options: {},
|
||||||
|
@ -1,203 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of GNU Taler
|
|
||||||
(C) 2022 Taler Systems S.A.
|
|
||||||
|
|
||||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3, or (at your option) any later version.
|
|
||||||
|
|
||||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Imports.
|
|
||||||
*/
|
|
||||||
import {
|
|
||||||
Logger,
|
|
||||||
RequestThrottler,
|
|
||||||
TalerErrorCode,
|
|
||||||
TalerError,
|
|
||||||
} from "@gnu-taler/taler-util";
|
|
||||||
|
|
||||||
import {
|
|
||||||
HttpRequestLibrary,
|
|
||||||
HttpRequestOptions,
|
|
||||||
HttpResponse,
|
|
||||||
Headers,
|
|
||||||
} from "@gnu-taler/taler-util/http";
|
|
||||||
|
|
||||||
const logger = new Logger("browserHttpLib");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implementation of the [[HttpRequestLibrary]] using the
|
|
||||||
* browser's XMLHttpRequest.
|
|
||||||
*/
|
|
||||||
export class BrowserHttpLib implements HttpRequestLibrary {
|
|
||||||
private throttle = new RequestThrottler();
|
|
||||||
private throttlingEnabled = true;
|
|
||||||
|
|
||||||
fetch(
|
|
||||||
requestUrl: string,
|
|
||||||
options?: HttpRequestOptions,
|
|
||||||
): Promise<HttpResponse> {
|
|
||||||
const requestMethod = options?.method ?? "GET";
|
|
||||||
const requestBody = options?.body;
|
|
||||||
|
|
||||||
if (this.throttlingEnabled && this.throttle.applyThrottle(requestUrl)) {
|
|
||||||
const parsedUrl = new URL(requestUrl);
|
|
||||||
throw TalerError.fromDetail(
|
|
||||||
TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
|
|
||||||
{
|
|
||||||
requestMethod,
|
|
||||||
requestUrl,
|
|
||||||
throttleStats: this.throttle.getThrottleStats(requestUrl),
|
|
||||||
},
|
|
||||||
`request to origin ${parsedUrl.origin} was throttled`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise<HttpResponse>((resolve, reject) => {
|
|
||||||
const myRequest = new XMLHttpRequest();
|
|
||||||
myRequest.open(requestMethod, requestUrl);
|
|
||||||
if (options?.headers) {
|
|
||||||
for (const headerName in options.headers) {
|
|
||||||
myRequest.setRequestHeader(headerName, options.headers[headerName]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
myRequest.responseType = "arraybuffer";
|
|
||||||
if (requestBody) {
|
|
||||||
if (requestBody instanceof ArrayBuffer) {
|
|
||||||
myRequest.send(requestBody);
|
|
||||||
} else if (ArrayBuffer.isView(requestBody)) {
|
|
||||||
myRequest.send(requestBody);
|
|
||||||
} else if (typeof requestBody === "string") {
|
|
||||||
myRequest.send(requestBody);
|
|
||||||
} else {
|
|
||||||
myRequest.send(JSON.stringify(requestBody));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
myRequest.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
myRequest.onerror = (e) => {
|
|
||||||
logger.error("http request error");
|
|
||||||
reject(
|
|
||||||
TalerError.fromDetail(
|
|
||||||
TalerErrorCode.WALLET_NETWORK_ERROR,
|
|
||||||
{
|
|
||||||
requestUrl,
|
|
||||||
requestMethod,
|
|
||||||
},
|
|
||||||
"Could not make request",
|
|
||||||
),
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
myRequest.addEventListener("readystatechange", (e) => {
|
|
||||||
if (myRequest.readyState === XMLHttpRequest.DONE) {
|
|
||||||
if (myRequest.status === 0) {
|
|
||||||
const exc = TalerError.fromDetail(
|
|
||||||
TalerErrorCode.WALLET_NETWORK_ERROR,
|
|
||||||
{
|
|
||||||
requestUrl,
|
|
||||||
requestMethod,
|
|
||||||
},
|
|
||||||
"HTTP request failed (status 0, maybe URI scheme was wrong?)",
|
|
||||||
);
|
|
||||||
reject(exc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const makeText = async (): Promise<string> => {
|
|
||||||
const td = new TextDecoder();
|
|
||||||
return td.decode(myRequest.response);
|
|
||||||
};
|
|
||||||
const makeJson = async (): Promise<any> => {
|
|
||||||
let responseJson;
|
|
||||||
try {
|
|
||||||
const td = new TextDecoder();
|
|
||||||
const responseString = td.decode(myRequest.response);
|
|
||||||
responseJson = JSON.parse(responseString);
|
|
||||||
} catch (e) {
|
|
||||||
throw TalerError.fromDetail(
|
|
||||||
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
|
|
||||||
{
|
|
||||||
requestUrl,
|
|
||||||
requestMethod,
|
|
||||||
httpStatusCode: myRequest.status,
|
|
||||||
},
|
|
||||||
"Invalid JSON from HTTP response",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (responseJson === null || typeof responseJson !== "object") {
|
|
||||||
throw TalerError.fromDetail(
|
|
||||||
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
|
|
||||||
{
|
|
||||||
requestUrl,
|
|
||||||
requestMethod,
|
|
||||||
httpStatusCode: myRequest.status,
|
|
||||||
},
|
|
||||||
"Invalid JSON from HTTP response",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return responseJson;
|
|
||||||
};
|
|
||||||
|
|
||||||
const headers = myRequest.getAllResponseHeaders();
|
|
||||||
const arr = headers.trim().split(/[\r\n]+/);
|
|
||||||
|
|
||||||
// Create a map of header names to values
|
|
||||||
const headerMap: Headers = new Headers();
|
|
||||||
arr.forEach(function (line) {
|
|
||||||
const parts = line.split(": ");
|
|
||||||
const headerName = parts.shift();
|
|
||||||
if (!headerName) {
|
|
||||||
logger.warn("skipping invalid header");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const value = parts.join(": ");
|
|
||||||
headerMap.set(headerName, value);
|
|
||||||
});
|
|
||||||
const resp: HttpResponse = {
|
|
||||||
requestUrl: requestUrl,
|
|
||||||
status: myRequest.status,
|
|
||||||
headers: headerMap,
|
|
||||||
requestMethod: requestMethod,
|
|
||||||
json: makeJson,
|
|
||||||
text: makeText,
|
|
||||||
bytes: async () => myRequest.response,
|
|
||||||
};
|
|
||||||
resolve(resp);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
|
|
||||||
return this.fetch(url, {
|
|
||||||
method: "GET",
|
|
||||||
...opt,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
postJson(
|
|
||||||
url: string,
|
|
||||||
body: any,
|
|
||||||
opt?: HttpRequestOptions,
|
|
||||||
): Promise<HttpResponse> {
|
|
||||||
return this.fetch(url, {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify(body),
|
|
||||||
...opt,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
stop(): void {
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of GNU Taler
|
|
||||||
(C) 2022 Taler Systems S.A.
|
|
||||||
|
|
||||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3, or (at your option) any later version.
|
|
||||||
|
|
||||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* API to access the Taler crypto worker thread.
|
|
||||||
* @author Florian Dold
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {
|
|
||||||
CryptoWorker,
|
|
||||||
CryptoWorkerFactory,
|
|
||||||
SynchronousCryptoWorkerPlain,
|
|
||||||
} from "@gnu-taler/taler-wallet-core";
|
|
||||||
|
|
||||||
export class SynchronousCryptoWorkerFactory implements CryptoWorkerFactory {
|
|
||||||
startWorker(): CryptoWorker {
|
|
||||||
return new SynchronousCryptoWorkerPlain();
|
|
||||||
}
|
|
||||||
|
|
||||||
getConcurrency(): number {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,205 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of GNU Taler
|
|
||||||
(C) 2022 Taler Systems S.A.
|
|
||||||
|
|
||||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
|
||||||
terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 3, or (at your option) any later version.
|
|
||||||
|
|
||||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Imports.
|
|
||||||
*/
|
|
||||||
import {
|
|
||||||
RequestThrottler,
|
|
||||||
TalerErrorCode,
|
|
||||||
TalerError,
|
|
||||||
} from "@gnu-taler/taler-util";
|
|
||||||
|
|
||||||
import {
|
|
||||||
Headers,
|
|
||||||
HttpRequestLibrary,
|
|
||||||
HttpRequestOptions,
|
|
||||||
HttpResponse,
|
|
||||||
} from "@gnu-taler/taler-util/http";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An implementation of the [[HttpRequestLibrary]] using the
|
|
||||||
* browser's XMLHttpRequest.
|
|
||||||
*/
|
|
||||||
export class ServiceWorkerHttpLib implements HttpRequestLibrary {
|
|
||||||
private throttle = new RequestThrottler();
|
|
||||||
private throttlingEnabled = true;
|
|
||||||
|
|
||||||
async fetch(
|
|
||||||
requestUrl: string,
|
|
||||||
options?: HttpRequestOptions,
|
|
||||||
): Promise<HttpResponse> {
|
|
||||||
const requestMethod = options?.method ?? "GET";
|
|
||||||
const requestBody = options?.body;
|
|
||||||
const requestHeader = options?.headers;
|
|
||||||
const requestTimeout = options?.timeout ?? { d_ms: 2 * 1000 };
|
|
||||||
|
|
||||||
if (this.throttlingEnabled && this.throttle.applyThrottle(requestUrl)) {
|
|
||||||
const parsedUrl = new URL(requestUrl);
|
|
||||||
throw TalerError.fromDetail(
|
|
||||||
TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
|
|
||||||
{
|
|
||||||
requestMethod,
|
|
||||||
requestUrl,
|
|
||||||
throttleStats: this.throttle.getThrottleStats(requestUrl),
|
|
||||||
},
|
|
||||||
`request to origin ${parsedUrl.origin} was throttled`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let myBody: BodyInit | undefined = undefined;
|
|
||||||
if (requestBody != null) {
|
|
||||||
if (typeof requestBody === "string") {
|
|
||||||
myBody = requestBody;
|
|
||||||
} else if (requestBody instanceof ArrayBuffer) {
|
|
||||||
myBody = requestBody;
|
|
||||||
} else if (ArrayBuffer.isView(requestBody)) {
|
|
||||||
myBody = requestBody;
|
|
||||||
} else if (typeof requestBody === "object") {
|
|
||||||
myBody = JSON.stringify(requestBody);
|
|
||||||
} else {
|
|
||||||
throw Error("unsupported request body type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const controller = new AbortController();
|
|
||||||
let timeoutId: any | undefined;
|
|
||||||
if (requestTimeout.d_ms !== "forever") {
|
|
||||||
timeoutId = setTimeout(() => {
|
|
||||||
controller.abort(TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT);
|
|
||||||
}, requestTimeout.d_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch(requestUrl, {
|
|
||||||
headers: requestHeader,
|
|
||||||
body: myBody,
|
|
||||||
method: requestMethod,
|
|
||||||
signal: controller.signal,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (timeoutId) {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerMap = new Headers();
|
|
||||||
response.headers.forEach((value, key) => {
|
|
||||||
headerMap.set(key, value);
|
|
||||||
});
|
|
||||||
return {
|
|
||||||
headers: headerMap,
|
|
||||||
status: response.status,
|
|
||||||
requestMethod,
|
|
||||||
requestUrl,
|
|
||||||
json: makeJsonHandler(response, requestUrl, requestMethod),
|
|
||||||
text: makeTextHandler(response, requestUrl, requestMethod),
|
|
||||||
bytes: async () => (await response.blob()).arrayBuffer(),
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
if (controller.signal) {
|
|
||||||
throw TalerError.fromDetail(
|
|
||||||
controller.signal.reason,
|
|
||||||
{},
|
|
||||||
`request to ${requestUrl} timed out`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get(url: string, opt?: HttpRequestOptions): Promise<HttpResponse> {
|
|
||||||
return this.fetch(url, {
|
|
||||||
method: "GET",
|
|
||||||
...opt,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
postJson(
|
|
||||||
url: string,
|
|
||||||
body: any,
|
|
||||||
opt?: HttpRequestOptions,
|
|
||||||
): Promise<HttpResponse> {
|
|
||||||
return this.fetch(url, {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify(body),
|
|
||||||
...opt,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
stop(): void {
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeTextHandler(
|
|
||||||
response: Response,
|
|
||||||
requestUrl: string,
|
|
||||||
requestMethod: string,
|
|
||||||
) {
|
|
||||||
return async function getJsonFromResponse(): Promise<any> {
|
|
||||||
let respText;
|
|
||||||
try {
|
|
||||||
respText = await response.text();
|
|
||||||
} catch (e) {
|
|
||||||
throw TalerError.fromDetail(
|
|
||||||
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
|
|
||||||
{
|
|
||||||
requestUrl,
|
|
||||||
requestMethod,
|
|
||||||
httpStatusCode: response.status,
|
|
||||||
},
|
|
||||||
"Invalid JSON from HTTP response",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return respText;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function makeJsonHandler(
|
|
||||||
response: Response,
|
|
||||||
requestUrl: string,
|
|
||||||
requestMethod: string,
|
|
||||||
) {
|
|
||||||
return async function getJsonFromResponse(): Promise<any> {
|
|
||||||
let responseJson;
|
|
||||||
try {
|
|
||||||
responseJson = await response.json();
|
|
||||||
} catch (e) {
|
|
||||||
throw TalerError.fromDetail(
|
|
||||||
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
|
|
||||||
{
|
|
||||||
requestUrl,
|
|
||||||
requestMethod,
|
|
||||||
httpStatusCode: response.status,
|
|
||||||
},
|
|
||||||
"Invalid JSON from HTTP response",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (responseJson === null || typeof responseJson !== "object") {
|
|
||||||
throw TalerError.fromDetail(
|
|
||||||
TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE,
|
|
||||||
{
|
|
||||||
requestUrl,
|
|
||||||
requestMethod,
|
|
||||||
httpStatusCode: response.status,
|
|
||||||
},
|
|
||||||
"Invalid JSON from HTTP response",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return responseJson;
|
|
||||||
};
|
|
||||||
}
|
|
@ -33,10 +33,15 @@ import {
|
|||||||
setGlobalLogLevelFromString,
|
setGlobalLogLevelFromString,
|
||||||
setLogLevelFromString,
|
setLogLevelFromString,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import {
|
||||||
|
ServiceWorkerHttpLib,
|
||||||
|
BrowserHttpLib,
|
||||||
|
} from "@gnu-taler/web-util/lib/index.browser";
|
||||||
import {
|
import {
|
||||||
DbAccess,
|
DbAccess,
|
||||||
OpenedPromise,
|
OpenedPromise,
|
||||||
SetTimeoutTimerAPI,
|
SetTimeoutTimerAPI,
|
||||||
|
SynchronousCryptoWorkerFactoryPlain,
|
||||||
Wallet,
|
Wallet,
|
||||||
WalletOperations,
|
WalletOperations,
|
||||||
WalletStoresV1,
|
WalletStoresV1,
|
||||||
@ -46,15 +51,12 @@ import {
|
|||||||
openPromise,
|
openPromise,
|
||||||
openTalerDatabase,
|
openTalerDatabase,
|
||||||
} from "@gnu-taler/taler-wallet-core";
|
} from "@gnu-taler/taler-wallet-core";
|
||||||
import { BrowserHttpLib } from "./browserHttpLib.js";
|
|
||||||
import {
|
import {
|
||||||
MessageFromBackend,
|
MessageFromBackend,
|
||||||
MessageFromFrontend,
|
MessageFromFrontend,
|
||||||
MessageResponse,
|
MessageResponse,
|
||||||
} from "./platform/api.js";
|
} from "./platform/api.js";
|
||||||
import { platform } from "./platform/background.js";
|
import { platform } from "./platform/background.js";
|
||||||
import { SynchronousCryptoWorkerFactory } from "./serviceWorkerCryptoWorkerFactory.js";
|
|
||||||
import { ServiceWorkerHttpLib } from "./serviceWorkerHttpLib.js";
|
|
||||||
import { ExtensionOperations } from "./taler-wallet-interaction-loader.js";
|
import { ExtensionOperations } from "./taler-wallet-interaction-loader.js";
|
||||||
import { BackgroundOperations } from "./wxApi.js";
|
import { BackgroundOperations } from "./wxApi.js";
|
||||||
|
|
||||||
@ -308,14 +310,14 @@ async function reinitWallet(): Promise<void> {
|
|||||||
|
|
||||||
if (platform.useServiceWorkerAsBackgroundProcess()) {
|
if (platform.useServiceWorkerAsBackgroundProcess()) {
|
||||||
httpLib = new ServiceWorkerHttpLib();
|
httpLib = new ServiceWorkerHttpLib();
|
||||||
cryptoWorker = new SynchronousCryptoWorkerFactory();
|
cryptoWorker = new SynchronousCryptoWorkerFactoryPlain();
|
||||||
timer = new SetTimeoutTimerAPI();
|
timer = new SetTimeoutTimerAPI();
|
||||||
} else {
|
} else {
|
||||||
httpLib = new BrowserHttpLib();
|
httpLib = new BrowserHttpLib();
|
||||||
// We could (should?) use the BrowserCryptoWorkerFactory here,
|
// We could (should?) use the BrowserCryptoWorkerFactory here,
|
||||||
// but right now we don't, to have less platform differences.
|
// but right now we don't, to have less platform differences.
|
||||||
// cryptoWorker = new BrowserCryptoWorkerFactory();
|
// cryptoWorker = new BrowserCryptoWorkerFactory();
|
||||||
cryptoWorker = new SynchronousCryptoWorkerFactory();
|
cryptoWorker = new SynchronousCryptoWorkerFactoryPlain();
|
||||||
timer = new SetTimeoutTimerAPI();
|
timer = new SetTimeoutTimerAPI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user