add typecheck to background operations
This commit is contained in:
parent
8a98a5f880
commit
7873571d22
@ -34,7 +34,10 @@ export function useAutoOpenPermissions(): ToggleHandler {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getValue(): Promise<void> {
|
async function getValue(): Promise<void> {
|
||||||
const res = await api.background.containsHeaderListener();
|
const res = await api.background.call(
|
||||||
|
"containsHeaderListener",
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
setEnabled(res.newValue);
|
setEnabled(res.newValue);
|
||||||
}
|
}
|
||||||
getValue();
|
getValue();
|
||||||
@ -63,12 +66,12 @@ async function handleAutoOpenPerm(
|
|||||||
onChange(false);
|
onChange(false);
|
||||||
throw lastError;
|
throw lastError;
|
||||||
}
|
}
|
||||||
const res = await background.toggleHeaderListener(granted);
|
const res = await background.call("toggleHeaderListener", granted);
|
||||||
onChange(res.newValue);
|
onChange(res.newValue);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
await background
|
await background
|
||||||
.toggleHeaderListener(false)
|
.call("toggleHeaderListener", false)
|
||||||
.then((r) => onChange(r.newValue));
|
.then((r) => onChange(r.newValue));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
|
@ -35,7 +35,10 @@ export function useClipboardPermissions(): ToggleHandler {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getValue(): Promise<void> {
|
async function getValue(): Promise<void> {
|
||||||
const res = await api.background.containsHeaderListener();
|
const res = await api.background.call(
|
||||||
|
"containsHeaderListener",
|
||||||
|
undefined,
|
||||||
|
);
|
||||||
setEnabled(res.newValue);
|
setEnabled(res.newValue);
|
||||||
}
|
}
|
||||||
getValue();
|
getValue();
|
||||||
@ -71,7 +74,7 @@ async function handleClipboardPerm(
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
await background
|
await background
|
||||||
.toggleHeaderListener(false)
|
.call("toggleHeaderListener", false)
|
||||||
.then((r) => onChange(r.newValue));
|
.then((r) => onChange(r.newValue));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
|
@ -34,7 +34,7 @@ export function useDiagnostics(): [WalletDiagnostics | undefined, boolean] {
|
|||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
const doFetch = async (): Promise<void> => {
|
const doFetch = async (): Promise<void> => {
|
||||||
const d = await api.background.getDiagnostics();
|
const d = await api.background.call("getDiagnostics", undefined);
|
||||||
gotDiagnostics = true;
|
gotDiagnostics = true;
|
||||||
setDiagnostics(d);
|
setDiagnostics(d);
|
||||||
};
|
};
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CoreApiResponse, NotificationType } from "@gnu-taler/taler-util";
|
import { CoreApiResponse, NotificationType } from "@gnu-taler/taler-util";
|
||||||
|
import { WalletOperations } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import { BackgroundOperations } from "../wxApi.js";
|
||||||
|
|
||||||
export interface Permissions {
|
export interface Permissions {
|
||||||
/**
|
/**
|
||||||
@ -50,6 +52,30 @@ export type MessageFromBackend = {
|
|||||||
type: NotificationType;
|
type: NotificationType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type MessageFromFrontend<
|
||||||
|
Op extends BackgroundOperations | WalletOperations,
|
||||||
|
> = Op extends BackgroundOperations
|
||||||
|
? MessageFromFrontendBackground<keyof BackgroundOperations>
|
||||||
|
: Op extends WalletOperations
|
||||||
|
? MessageFromFrontendWallet<keyof WalletOperations>
|
||||||
|
: never;
|
||||||
|
|
||||||
|
export type MessageFromFrontendBackground<
|
||||||
|
Op extends keyof BackgroundOperations,
|
||||||
|
> = {
|
||||||
|
channel: "background";
|
||||||
|
operation: Op;
|
||||||
|
payload: BackgroundOperations[Op]["request"];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MessageFromFrontendWallet<Op extends keyof WalletOperations> = {
|
||||||
|
channel: "wallet";
|
||||||
|
operation: Op;
|
||||||
|
payload: WalletOperations[Op]["request"];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MessageResponse = CoreApiResponse;
|
||||||
|
|
||||||
export interface WalletWebExVersion {
|
export interface WalletWebExVersion {
|
||||||
version_name?: string | undefined;
|
version_name?: string | undefined;
|
||||||
version: string;
|
version: string;
|
||||||
@ -183,10 +209,9 @@ export interface PlatformAPI {
|
|||||||
*
|
*
|
||||||
* @return response from the backend
|
* @return response from the backend
|
||||||
*/
|
*/
|
||||||
sendMessageToWalletBackground(
|
sendMessageToBackground<Op extends WalletOperations | BackgroundOperations>(
|
||||||
operation: string,
|
message: MessageFromFrontend<Op>,
|
||||||
payload: any,
|
): Promise<MessageResponse>;
|
||||||
): Promise<CoreApiResponse>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used from the frontend to receive notifications about new information
|
* Used from the frontend to receive notifications about new information
|
||||||
@ -204,11 +229,9 @@ export interface PlatformAPI {
|
|||||||
* @param onNewMessage
|
* @param onNewMessage
|
||||||
*/
|
*/
|
||||||
listenToAllChannels(
|
listenToAllChannels(
|
||||||
onNewMessage: (
|
notifyNewMessage: <Op extends WalletOperations | BackgroundOperations>(
|
||||||
message: any,
|
message: MessageFromFrontend<Op> & { id: string },
|
||||||
sender: any,
|
) => Promise<MessageResponse>,
|
||||||
sendResponse: (r: CoreApiResponse) => void,
|
|
||||||
) => void,
|
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,9 +20,13 @@ import {
|
|||||||
Logger,
|
Logger,
|
||||||
TalerUriType,
|
TalerUriType,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletOperations } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import { BackgroundOperations } from "../wxApi.js";
|
||||||
import {
|
import {
|
||||||
CrossBrowserPermissionsApi,
|
CrossBrowserPermissionsApi,
|
||||||
MessageFromBackend,
|
MessageFromBackend,
|
||||||
|
MessageFromFrontend,
|
||||||
|
MessageResponse,
|
||||||
Permissions,
|
Permissions,
|
||||||
PlatformAPI,
|
PlatformAPI,
|
||||||
} from "./api.js";
|
} from "./api.js";
|
||||||
@ -41,11 +45,11 @@ const api: PlatformAPI = {
|
|||||||
redirectTabToWalletPage,
|
redirectTabToWalletPage,
|
||||||
registerAllIncomingConnections,
|
registerAllIncomingConnections,
|
||||||
registerOnInstalled,
|
registerOnInstalled,
|
||||||
listenToAllChannels,
|
listenToAllChannels: listenToAllChannels as any,
|
||||||
registerReloadOnNewVersion,
|
registerReloadOnNewVersion,
|
||||||
registerTalerHeaderListener,
|
registerTalerHeaderListener,
|
||||||
sendMessageToAllChannels,
|
sendMessageToAllChannels,
|
||||||
sendMessageToWalletBackground,
|
sendMessageToBackground,
|
||||||
useServiceWorkerAsBackgroundProcess,
|
useServiceWorkerAsBackgroundProcess,
|
||||||
containsTalerHeaderListener,
|
containsTalerHeaderListener,
|
||||||
keepAlive,
|
keepAlive,
|
||||||
@ -302,21 +306,14 @@ function openWalletPageFromPopup(page: string): void {
|
|||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
async function sendMessageToWalletBackground(
|
async function sendMessageToBackground<
|
||||||
operation: string,
|
Op extends WalletOperations | BackgroundOperations,
|
||||||
payload: any,
|
>(message: MessageFromFrontend<Op>): Promise<MessageResponse> {
|
||||||
): Promise<any> {
|
const messageWithId = { ...message, id: `id_${i++ % 1000}` };
|
||||||
return new Promise<any>((resolve, reject) => {
|
|
||||||
logger.trace("send operation to the wallet background", operation);
|
|
||||||
chrome.runtime.sendMessage(
|
|
||||||
{ operation, payload, id: `id_${i++ % 1000}` },
|
|
||||||
(backgroundResponse) => {
|
|
||||||
logger.trace(
|
|
||||||
"BUG: got response from background",
|
|
||||||
backgroundResponse,
|
|
||||||
chrome.runtime.lastError,
|
|
||||||
);
|
|
||||||
|
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
logger.trace("send operation to the wallet background", message);
|
||||||
|
chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => {
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
reject(chrome.runtime.lastError.message);
|
reject(chrome.runtime.lastError.message);
|
||||||
} else {
|
} else {
|
||||||
@ -324,8 +321,7 @@ async function sendMessageToWalletBackground(
|
|||||||
}
|
}
|
||||||
// return true to keep the channel open
|
// return true to keep the channel open
|
||||||
return true;
|
return true;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,20 +373,26 @@ function registerAllIncomingConnections(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function listenToAllChannels(
|
function listenToAllChannels(
|
||||||
cb: (
|
notifyNewMessage: <Op extends WalletOperations | BackgroundOperations>(
|
||||||
message: any,
|
message: MessageFromFrontend<Op> & { id: string },
|
||||||
sender: any,
|
) => Promise<MessageResponse>,
|
||||||
callback: (r: CoreApiResponse) => void,
|
|
||||||
) => void,
|
|
||||||
): void {
|
): void {
|
||||||
chrome.runtime.onMessage.addListener((m, s, c) => {
|
chrome.runtime.onMessage.addListener((message, sender, reply) => {
|
||||||
cb(m, s, (apiResponse) => {
|
notifyNewMessage(message)
|
||||||
logger.trace("BUG: sending response to client", apiResponse);
|
.then((apiResponse) => {
|
||||||
try {
|
try {
|
||||||
c(apiResponse);
|
reply(apiResponse);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("wallet operation ended with error", e);
|
logger.error(
|
||||||
|
"sending response to frontend failed",
|
||||||
|
message,
|
||||||
|
apiResponse,
|
||||||
|
e,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
logger.error("notify to background failed", e);
|
||||||
});
|
});
|
||||||
|
|
||||||
// keep the connection open
|
// keep the connection open
|
||||||
|
@ -15,7 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CoreApiResponse } from "@gnu-taler/taler-util";
|
import { CoreApiResponse } from "@gnu-taler/taler-util";
|
||||||
import { MessageFromBackend, PlatformAPI } from "./api.js";
|
import { WalletOperations } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import { BackgroundOperations } from "../wxApi.js";
|
||||||
|
import {
|
||||||
|
MessageFromBackend,
|
||||||
|
MessageFromFrontend,
|
||||||
|
MessageResponse,
|
||||||
|
PlatformAPI,
|
||||||
|
} from "./api.js";
|
||||||
|
|
||||||
const frames = ["popup", "wallet"];
|
const frames = ["popup", "wallet"];
|
||||||
|
|
||||||
@ -121,12 +128,17 @@ const api: PlatformAPI = {
|
|||||||
window.parent.removeEventListener("message", listener);
|
window.parent.removeEventListener("message", listener);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
sendMessageToWalletBackground: async (operation: string, payload: any) => {
|
|
||||||
|
sendMessageToBackground: async <
|
||||||
|
Op extends WalletOperations | BackgroundOperations,
|
||||||
|
>(
|
||||||
|
payload: MessageFromFrontend<Op>,
|
||||||
|
): Promise<MessageResponse> => {
|
||||||
const replyMe = `reply-${Math.floor(Math.random() * 100000)}`;
|
const replyMe = `reply-${Math.floor(Math.random() * 100000)}`;
|
||||||
const message: IframeMessageCommand = {
|
const message: IframeMessageCommand = {
|
||||||
type: "command",
|
type: "command",
|
||||||
header: { replyMe },
|
header: { replyMe },
|
||||||
body: { operation, payload, id: "(none)" },
|
body: payload,
|
||||||
};
|
};
|
||||||
window.parent.postMessage(message);
|
window.parent.postMessage(message);
|
||||||
|
|
||||||
@ -150,6 +162,7 @@ type IframeMessageType =
|
|||||||
| IframeMessageNotification
|
| IframeMessageNotification
|
||||||
| IframeMessageResponse
|
| IframeMessageResponse
|
||||||
| IframeMessageCommand;
|
| IframeMessageCommand;
|
||||||
|
|
||||||
interface IframeMessageNotification {
|
interface IframeMessageNotification {
|
||||||
type: "notification";
|
type: "notification";
|
||||||
header: Record<string, never>;
|
header: Record<string, never>;
|
||||||
@ -160,7 +173,7 @@ interface IframeMessageResponse {
|
|||||||
header: {
|
header: {
|
||||||
responseId: string;
|
responseId: string;
|
||||||
};
|
};
|
||||||
body: CoreApiResponse;
|
body: MessageResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IframeMessageCommand {
|
interface IframeMessageCommand {
|
||||||
@ -168,11 +181,7 @@ interface IframeMessageCommand {
|
|||||||
header: {
|
header: {
|
||||||
replyMe: string;
|
replyMe: string;
|
||||||
};
|
};
|
||||||
body: {
|
body: MessageFromFrontend<any>;
|
||||||
operation: any;
|
|
||||||
id: string;
|
|
||||||
payload: any;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
@ -177,7 +177,7 @@ export function View({
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
confirmReset(
|
confirmReset(
|
||||||
i18n.str`Do you want to IRREVOCABLY DESTROY everything inside your wallet and LOSE ALL YOUR COINS?`,
|
i18n.str`Do you want to IRREVOCABLY DESTROY everything inside your wallet and LOSE ALL YOUR COINS?`,
|
||||||
() => api.background.resetDb(),
|
() => api.background.call("resetDb", undefined),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@ -190,7 +190,7 @@ export function View({
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
confirmReset(
|
confirmReset(
|
||||||
i18n.str`TESTING: This may delete all your coin, proceed with caution`,
|
i18n.str`TESTING: This may delete all your coin, proceed with caution`,
|
||||||
() => api.background.runGarbageCollector(),
|
() => api.background.call("runGarbageCollector", undefined),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -34,70 +34,72 @@ import {
|
|||||||
WalletCoreRequestType,
|
WalletCoreRequestType,
|
||||||
WalletCoreResponseType,
|
WalletCoreResponseType,
|
||||||
} from "@gnu-taler/taler-wallet-core";
|
} from "@gnu-taler/taler-wallet-core";
|
||||||
import { MessageFromBackend, platform } from "./platform/api.js";
|
import {
|
||||||
import { nullFunction } from "./test-utils.js";
|
MessageFromBackend,
|
||||||
|
MessageFromFrontendBackground,
|
||||||
|
MessageFromFrontendWallet,
|
||||||
|
platform,
|
||||||
|
} from "./platform/api.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Florian Dold
|
|
||||||
* @author sebasjm
|
* @author sebasjm
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const logger = new Logger("wxApi");
|
||||||
|
|
||||||
export interface ExtendedPermissionsResponse {
|
export interface ExtendedPermissionsResponse {
|
||||||
newValue: boolean;
|
newValue: boolean;
|
||||||
}
|
}
|
||||||
const logger = new Logger("wxApi");
|
|
||||||
|
|
||||||
/**
|
export interface BackgroundOperations {
|
||||||
* Response with information about available version upgrades.
|
resetDb: {
|
||||||
*/
|
request: void;
|
||||||
export interface UpgradeResponse {
|
response: void;
|
||||||
/**
|
};
|
||||||
* Is a reset required because of a new DB version
|
containsHeaderListener: {
|
||||||
* that can't be automatically upgraded?
|
request: void;
|
||||||
*/
|
response: ExtendedPermissionsResponse;
|
||||||
dbResetRequired: boolean;
|
};
|
||||||
|
getDiagnostics: {
|
||||||
/**
|
request: void;
|
||||||
* Current database version.
|
response: WalletDiagnostics;
|
||||||
*/
|
};
|
||||||
currentDbVersion: string;
|
toggleHeaderListener: {
|
||||||
|
request: boolean;
|
||||||
/**
|
response: ExtendedPermissionsResponse;
|
||||||
* Old db version (if applicable).
|
};
|
||||||
*/
|
runGarbageCollector: {
|
||||||
oldDbVersion: string;
|
request: void;
|
||||||
|
response: void;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export interface BackgroundApiClient {
|
||||||
* @deprecated Use {@link WxWalletCoreApiClient} instead.
|
call<Op extends keyof BackgroundOperations>(
|
||||||
*/
|
|
||||||
async function callBackend(operation: string, payload: any): Promise<any> {
|
|
||||||
let response: CoreApiResponse;
|
|
||||||
try {
|
|
||||||
response = await platform.sendMessageToWalletBackground(operation, payload);
|
|
||||||
} catch (e) {
|
|
||||||
console.log("Error calling backend");
|
|
||||||
throw new Error(`Error contacting backend: ${e}`);
|
|
||||||
}
|
|
||||||
logger.info("got response", response);
|
|
||||||
if (response.type === "error") {
|
|
||||||
throw TalerError.fromUncheckedDetail(response.error);
|
|
||||||
}
|
|
||||||
return response.result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WxWalletCoreApiClient implements WalletCoreApiClient {
|
|
||||||
async call<Op extends WalletCoreOpKeys>(
|
|
||||||
operation: Op,
|
operation: Op,
|
||||||
payload: WalletCoreRequestType<Op>,
|
payload: BackgroundOperations[Op]["request"],
|
||||||
): Promise<WalletCoreResponseType<Op>> {
|
): Promise<BackgroundOperations[Op]["response"]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BackgroundApiClient integration with browser platform
|
||||||
|
*/
|
||||||
|
class BackgroundApiClientImpl implements BackgroundApiClient {
|
||||||
|
async call<Op extends keyof BackgroundOperations>(
|
||||||
|
operation: Op,
|
||||||
|
payload: BackgroundOperations[Op]["request"],
|
||||||
|
): Promise<BackgroundOperations[Op]["response"]> {
|
||||||
let response: CoreApiResponse;
|
let response: CoreApiResponse;
|
||||||
try {
|
|
||||||
response = await platform.sendMessageToWalletBackground(
|
const message: MessageFromFrontendBackground<Op> = {
|
||||||
|
channel: "background",
|
||||||
operation,
|
operation,
|
||||||
payload,
|
payload,
|
||||||
);
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = await platform.sendMessageToBackground(message);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Error calling backend");
|
console.log("Error calling backend");
|
||||||
throw new Error(`Error contacting backend: ${e}`);
|
throw new Error(`Error contacting backend: ${e}`);
|
||||||
@ -110,29 +112,34 @@ export class WxWalletCoreApiClient implements WalletCoreApiClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class BackgroundApiClient {
|
/**
|
||||||
public resetDb(): Promise<void> {
|
* WalletCoreApiClient integration with browser platform
|
||||||
return callBackend("reset-db", {});
|
*/
|
||||||
|
class WalletApiClientImpl implements WalletCoreApiClient {
|
||||||
|
async call<Op extends WalletCoreOpKeys>(
|
||||||
|
operation: Op,
|
||||||
|
payload: WalletCoreRequestType<Op>,
|
||||||
|
): Promise<WalletCoreResponseType<Op>> {
|
||||||
|
let response: CoreApiResponse;
|
||||||
|
try {
|
||||||
|
const message: MessageFromFrontendWallet<Op> = {
|
||||||
|
channel: "wallet",
|
||||||
|
operation,
|
||||||
|
payload,
|
||||||
|
};
|
||||||
|
response = await platform.sendMessageToBackground(message);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Error calling backend");
|
||||||
|
throw new Error(`Error contacting backend: ${e}`);
|
||||||
|
}
|
||||||
|
logger.info("got response", response);
|
||||||
|
if (response.type === "error") {
|
||||||
|
throw TalerError.fromUncheckedDetail(response.error);
|
||||||
|
}
|
||||||
|
return response.result as any;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
|
|
||||||
return callBackend("containsHeaderListener", {});
|
|
||||||
}
|
|
||||||
|
|
||||||
public getDiagnostics(): Promise<WalletDiagnostics> {
|
|
||||||
return callBackend("wxGetDiagnostics", {});
|
|
||||||
}
|
|
||||||
|
|
||||||
public toggleHeaderListener(
|
|
||||||
value: boolean,
|
|
||||||
): Promise<ExtendedPermissionsResponse> {
|
|
||||||
return callBackend("toggleHeaderListener", { value });
|
|
||||||
}
|
|
||||||
|
|
||||||
public runGarbageCollector(): Promise<void> {
|
|
||||||
return callBackend("run-gc", {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function onUpdateNotification(
|
function onUpdateNotification(
|
||||||
messageTypes: Array<NotificationType>,
|
messageTypes: Array<NotificationType>,
|
||||||
doCallback: undefined | (() => void),
|
doCallback: undefined | (() => void),
|
||||||
@ -160,8 +167,8 @@ export type WxApiType = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const wxApi = {
|
export const wxApi = {
|
||||||
wallet: new WxWalletCoreApiClient(),
|
wallet: new WalletApiClientImpl(),
|
||||||
background: new BackgroundApiClient(),
|
background: new BackgroundApiClientImpl(),
|
||||||
listener: {
|
listener: {
|
||||||
onUpdateNotification,
|
onUpdateNotification,
|
||||||
},
|
},
|
||||||
|
@ -25,8 +25,6 @@
|
|||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
classifyTalerUri,
|
classifyTalerUri,
|
||||||
CoreApiResponse,
|
|
||||||
CoreApiResponseSuccess,
|
|
||||||
Logger,
|
Logger,
|
||||||
TalerErrorCode,
|
TalerErrorCode,
|
||||||
TalerUriType,
|
TalerUriType,
|
||||||
@ -36,20 +34,27 @@ import {
|
|||||||
DbAccess,
|
DbAccess,
|
||||||
deleteTalerDatabase,
|
deleteTalerDatabase,
|
||||||
exportDb,
|
exportDb,
|
||||||
|
getErrorDetailFromException,
|
||||||
importDb,
|
importDb,
|
||||||
makeErrorDetail,
|
makeErrorDetail,
|
||||||
OpenedPromise,
|
OpenedPromise,
|
||||||
openPromise,
|
openPromise,
|
||||||
openTalerDatabase,
|
openTalerDatabase,
|
||||||
|
SetTimeoutTimerAPI,
|
||||||
Wallet,
|
Wallet,
|
||||||
|
WalletOperations,
|
||||||
WalletStoresV1,
|
WalletStoresV1,
|
||||||
} from "@gnu-taler/taler-wallet-core";
|
} from "@gnu-taler/taler-wallet-core";
|
||||||
import { SetTimeoutTimerAPI } from "@gnu-taler/taler-wallet-core";
|
|
||||||
import { BrowserCryptoWorkerFactory } from "./browserCryptoWorkerFactory.js";
|
|
||||||
import { BrowserHttpLib } from "./browserHttpLib.js";
|
import { BrowserHttpLib } from "./browserHttpLib.js";
|
||||||
import { MessageFromBackend, platform } from "./platform/api.js";
|
import {
|
||||||
|
MessageFromBackend,
|
||||||
|
MessageFromFrontend,
|
||||||
|
MessageResponse,
|
||||||
|
platform,
|
||||||
|
} from "./platform/api.js";
|
||||||
import { SynchronousCryptoWorkerFactory } from "./serviceWorkerCryptoWorkerFactory.js";
|
import { SynchronousCryptoWorkerFactory } from "./serviceWorkerCryptoWorkerFactory.js";
|
||||||
import { ServiceWorkerHttpLib } from "./serviceWorkerHttpLib.js";
|
import { ServiceWorkerHttpLib } from "./serviceWorkerHttpLib.js";
|
||||||
|
import { BackgroundOperations, ExtendedPermissionsResponse } from "./wxApi.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Currently active wallet instance. Might be unloaded and
|
* Currently active wallet instance. Might be unloaded and
|
||||||
@ -107,70 +112,92 @@ async function getDiagnostics(): Promise<WalletDiagnostics> {
|
|||||||
return diagnostics;
|
return diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function dispatch(
|
type BackendHandlerType = {
|
||||||
req: any,
|
[Op in keyof BackgroundOperations]: (
|
||||||
sender: any,
|
req: BackgroundOperations[Op]["request"],
|
||||||
sendResponse: any,
|
) => Promise<BackgroundOperations[Op]["response"]>;
|
||||||
): Promise<void> {
|
|
||||||
let r: CoreApiResponse;
|
|
||||||
|
|
||||||
const wrapResponse = (result: unknown): CoreApiResponseSuccess => {
|
|
||||||
return {
|
|
||||||
type: "response",
|
|
||||||
id: req.id,
|
|
||||||
operation: req.operation,
|
|
||||||
result,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
async function containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
|
||||||
switch (req.operation) {
|
const result = await platform.containsTalerHeaderListener();
|
||||||
case "wxGetDiagnostics": {
|
return { newValue: result };
|
||||||
r = wrapResponse(await getDiagnostics());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case "reset-db": {
|
|
||||||
|
async function resetDb(): Promise<void> {
|
||||||
await deleteTalerDatabase(indexedDB as any);
|
await deleteTalerDatabase(indexedDB as any);
|
||||||
r = wrapResponse(await reinitWallet());
|
await reinitWallet();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case "run-gc": {
|
|
||||||
logger.info("gc");
|
async function runGarbageCollector(): Promise<void> {
|
||||||
const dump = await exportDb(currentDatabase!.idbHandle());
|
const dbBeforeGc = currentDatabase;
|
||||||
|
if (!dbBeforeGc) {
|
||||||
|
throw Error("no current db before running gc");
|
||||||
|
}
|
||||||
|
const dump = await exportDb(dbBeforeGc.idbHandle());
|
||||||
|
|
||||||
await deleteTalerDatabase(indexedDB as any);
|
await deleteTalerDatabase(indexedDB as any);
|
||||||
logger.info("cleaned");
|
logger.info("cleaned");
|
||||||
await reinitWallet();
|
await reinitWallet();
|
||||||
logger.info("init");
|
logger.info("init");
|
||||||
await importDb(currentDatabase!.idbHandle(), dump);
|
|
||||||
|
const dbAfterGc = currentDatabase;
|
||||||
|
if (!dbAfterGc) {
|
||||||
|
throw Error("no current db before running gc");
|
||||||
|
}
|
||||||
|
await importDb(dbAfterGc.idbHandle(), dump);
|
||||||
logger.info("imported");
|
logger.info("imported");
|
||||||
r = wrapResponse({ result: true });
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case "containsHeaderListener": {
|
|
||||||
const res = await platform.containsTalerHeaderListener();
|
async function toggleHeaderListener(
|
||||||
r = wrapResponse({ newValue: res });
|
newVal: boolean,
|
||||||
break;
|
): Promise<ExtendedPermissionsResponse> {
|
||||||
}
|
|
||||||
//FIXME: implement type checked api like WalletCoreApi
|
|
||||||
case "toggleHeaderListener": {
|
|
||||||
const newVal = req.payload.value;
|
|
||||||
logger.trace("new extended permissions value", newVal);
|
logger.trace("new extended permissions value", newVal);
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
platform.registerTalerHeaderListener(parseTalerUriAndRedirect);
|
platform.registerTalerHeaderListener(parseTalerUriAndRedirect);
|
||||||
r = wrapResponse({ newValue: true });
|
return { newValue: true };
|
||||||
} else {
|
}
|
||||||
const rem = await platform
|
|
||||||
.getPermissionsApi()
|
const rem = await platform.getPermissionsApi().removeHostPermissions();
|
||||||
.removeHostPermissions();
|
|
||||||
logger.trace("permissions removed:", rem);
|
logger.trace("permissions removed:", rem);
|
||||||
r = wrapResponse({ newVal: false });
|
return { newValue: false };
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
const backendHandlers: BackendHandlerType = {
|
||||||
|
containsHeaderListener,
|
||||||
|
getDiagnostics,
|
||||||
|
resetDb,
|
||||||
|
runGarbageCollector,
|
||||||
|
toggleHeaderListener,
|
||||||
|
};
|
||||||
|
|
||||||
|
async function dispatch<Op extends WalletOperations | BackgroundOperations>(
|
||||||
|
req: MessageFromFrontend<Op> & { id: string },
|
||||||
|
): Promise<MessageResponse> {
|
||||||
|
if (req.channel === "background") {
|
||||||
|
const handler = backendHandlers[req.operation] as (req: any) => any;
|
||||||
|
if (!handler) {
|
||||||
|
return {
|
||||||
|
type: "error",
|
||||||
|
id: req.id,
|
||||||
|
operation: String(req.operation),
|
||||||
|
error: getErrorDetailFromException(
|
||||||
|
Error(`unknown background operation`),
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
default: {
|
const result = await handler(req.payload);
|
||||||
|
return {
|
||||||
|
type: "response",
|
||||||
|
id: req.id,
|
||||||
|
operation: String(req.operation),
|
||||||
|
result,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.channel === "wallet") {
|
||||||
const w = currentWallet;
|
const w = currentWallet;
|
||||||
if (!w) {
|
if (!w) {
|
||||||
r = {
|
return {
|
||||||
type: "error",
|
type: "error",
|
||||||
id: req.id,
|
id: req.id,
|
||||||
operation: req.operation,
|
operation: req.operation,
|
||||||
@ -180,19 +207,20 @@ async function dispatch(
|
|||||||
"wallet core not available",
|
"wallet core not available",
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
break;
|
|
||||||
}
|
|
||||||
r = await w.handleCoreApiRequest(req.operation, req.id, req.payload);
|
|
||||||
console.log("response received from wallet", r);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sendResponse(r);
|
return await w.handleCoreApiRequest(req.operation, req.id, req.payload);
|
||||||
} catch (e) {
|
|
||||||
logger.error(`Error sending operation: ${req.operation}`, e);
|
|
||||||
// might fail if tab disconnected
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const anyReq = req as any;
|
||||||
|
return {
|
||||||
|
type: "error",
|
||||||
|
id: anyReq.id,
|
||||||
|
operation: String(anyReq.operation),
|
||||||
|
error: getErrorDetailFromException(
|
||||||
|
Error(`unknown channel ${anyReq.channel}`),
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reinitWallet(): Promise<void> {
|
async function reinitWallet(): Promise<void> {
|
||||||
@ -328,12 +356,11 @@ export async function wxMain(): Promise<void> {
|
|||||||
|
|
||||||
// Handlers for messages coming directly from the content
|
// Handlers for messages coming directly from the content
|
||||||
// script on the page
|
// script on the page
|
||||||
platform.listenToAllChannels((message, sender, callback) => {
|
platform.listenToAllChannels(async (message) => {
|
||||||
afterWalletIsInitialized.then(() => {
|
//wait until wallet is initialized
|
||||||
dispatch(message, sender, (response: CoreApiResponse) => {
|
await afterWalletIsInitialized;
|
||||||
callback(response);
|
const result = await dispatch(message);
|
||||||
});
|
return result;
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
platform.registerAllIncomingConnections();
|
platform.registerAllIncomingConnections();
|
||||||
|
Loading…
Reference in New Issue
Block a user