skeleton for better RPC types

This commit is contained in:
Florian Dold 2017-05-30 18:33:28 +02:00
parent b6df47f25e
commit e5b88ee003
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
8 changed files with 195 additions and 156 deletions

View File

@ -1358,3 +1358,49 @@ export type CheckPayResult = "paid" | "payment-possible" | "insufficient-balance
* Possible results for confirmPay.
*/
export type ConfirmPayResult = "paid" | "insufficient-balance";
/**
* Level of detail at which a history
* entry should be shown.
*/
export enum HistoryLevel {
Trace = 1,
Developer = 2,
Expert = 3,
User = 4,
}
/*
* Activity history record.
*/
export interface HistoryRecord {
/**
* Type of the history event.
*/
type: string;
/**
* Time when the activity was recorded.
*/
timestamp: number;
/**
* Subject of the entry. Used to group multiple history records together.
* Only the latest history record with the same subjectId will be shown.
*/
subjectId?: string;
/**
* Details used when rendering the history record.
*/
detail: any;
/**
* Level of detail of the history entry.
*/
level: HistoryLevel;
}

View File

@ -60,6 +60,8 @@ import {
ExchangeHandle,
ExchangeRecord,
ExchangeWireFeesRecord,
HistoryLevel,
HistoryRecord,
Notifier,
OfferRecord,
PayCoinInfo,
@ -270,38 +272,6 @@ export class ConfirmReserveRequest {
}
/**
* Activity history record.
*/
export interface HistoryRecord {
/**
* Type of the history event.
*/
type: string;
/**
* Time when the activity was recorded.
*/
timestamp: number;
/**
* Subject of the entry. Used to group multiple history records together.
* Only the latest history record with the same subjectId will be shown.
*/
subjectId?: string;
/**
* Details used when rendering the history record.
*/
detail: any;
/**
* Level of detail of the history entry.
*/
level: HistoryLevel;
}
interface PayReq {
coins: CoinPaySig[];
merchant_pub: string;
@ -323,18 +293,6 @@ interface TransactionRecord {
}
/**
* Level of detail at which a history
* entry should be shown.
*/
export enum HistoryLevel {
Trace = 1,
Developer = 2,
Expert = 3,
User = 4,
}
/**
* Badge that shows activity for the wallet.
*/

64
src/webex/messages.ts Normal file
View File

@ -0,0 +1,64 @@
/*
This file is part of TALER
(C) 2017 Inria and GNUnet e.V.
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.
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
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* Type definitions for messages between content scripts/pages and backend.
*/
// Messages are already documented in wxApi.
/* tslint:disable:completed-docs */
import * as types from "../types";
export interface MessageMap {
"balances": { };
"dump-db": { };
"import-db": { dump: object };
"get-tab-cookie": { };
"ping": { };
"reset": { };
"create-reserve": { amount: types.AmountJson; exchange: string };
"confirm-reserve": { reservePub: string };
"generate-nonce": { };
"confirm-pay": { offer: types.OfferRecord; };
"check-pay": { offer: types.OfferRecord; };
"query-payment": { };
"exchange-info": { baseUrl: string };
"currency-info": { name: string };
"hash-contract": { contract: object };
"put-history-entry": { historyEntry: types.HistoryRecord };
"safe-offer": { offer: types.OfferRecord };
"reserve-creation-info": { baseUrl: string };
"get-history": { };
"get-offer": { offerId: number }
"get-currencies": { };
"update-currency": { currencyRecord: types.CurrencyRecord };
"get-reserves": { exchangeBaseUrl: string };
"get-payback-reserves": { };
"withdraw-payback-reserve": { reservePub: string };
"get-precoins": { exchangeBaseUrl: string };
"get-denoms": { exchangeBaseUrl: string };
"payback-coin": { coinPub: string };
"payment-failed": { contractTermsHash: string };
"payment-succeeded": { contractTermsHash: string; merchantSig: string };
}
export type MessageType = keyof MessageMap;
export class Message<T extends MessageType> {
constructor (public type: T, public detail: MessageMap[T]) {
}
}

View File

@ -27,6 +27,8 @@
*/
import URI = require("urijs");
import wxApi = require("./wxApi");
declare var cloneInto: any;
let logVerbose: boolean = false;
@ -40,29 +42,12 @@ if (document.documentElement.getAttribute("data-taler-nojs")) {
document.dispatchEvent(new Event("taler-probe-result"));
}
interface Handler {
type: string;
listener: (e: CustomEvent) => void|Promise<void>;
}
const handlers: Handler[] = [];
function hashContract(contract: string): Promise<string> {
const walletHashContractMsg = {
detail: {contract},
type: "hash-contract",
};
return new Promise<string>((resolve, reject) => {
chrome.runtime.sendMessage(walletHashContractMsg, (resp: any) => {
if (!resp.hash) {
console.log("error", resp);
reject(Error("hashing failed"));
}
resolve(resp.hash);
});
});
}
function queryPayment(url: string): Promise<any> {
const walletMsg = {
detail: { url },
@ -178,6 +163,8 @@ function handlePaymentResponse(walletResp: any) {
timeoutHandle = null;
err();
}
timeoutHandle = window.setTimeout(onTimeout, 200);
talerPaymentFailed(walletResp.H_contract).then(() => {
if (timeoutHandle !== null) {
clearTimeout(timeoutHandle);
@ -185,10 +172,8 @@ function handlePaymentResponse(walletResp: any) {
}
err();
});
timeoutHandle = window.setTimeout(onTimeout, 200);
}
logVerbose && console.log("handling taler-notify-payment: ", walletResp);
// Payment timeout in ms.
let timeout_ms = 1000;
@ -353,7 +338,7 @@ async function processProposal(proposal: any) {
return;
}
const contractHash = await hashContract(proposal.data);
const contractHash = await wxApi.hashContract(proposal.data);
if (contractHash !== proposal.hash) {
console.error("merchant-supplied contract hash is wrong");
@ -488,7 +473,7 @@ function registerHandlers() {
addHandler("taler-query-id", (msg: any, sendResponse: any) => {
// FIXME: maybe include this info in taoer-probe?
// FIXME: maybe include this info in taler-probe?
sendResponse({id: chrome.runtime.id});
});
@ -518,46 +503,21 @@ function registerHandlers() {
window.location.href = redirectUrl;
});
addHandler("taler-confirm-reserve", (msg: any, sendResponse: any) => {
const walletMsg = {
detail: {
reservePub: msg.reserve_pub,
},
type: "confirm-reserve",
};
chrome.runtime.sendMessage(walletMsg, (resp) => {
sendResponse();
});
});
addHandler("taler-confirm-contract", async(msg: any) => {
if (!msg.contract_wrapper) {
console.error("contract wrapper missing");
addHandler("taler-confirm-reserve", async (msg: any, sendResponse: any) => {
const reservePub = msg.reserve_pub;
if (typeof reservePub !== "string") {
console.error("taler-confirm-reserve expects parameter reserve_pub of type 'string'");
return;
}
const proposal = msg.contract_wrapper;
processProposal(proposal);
await wxApi.confirmReserve(msg.reserve_pub);
sendResponse();
});
addHandler("taler-pay", async(msg: any, sendResponse: any) => {
const resp = await talerPay(msg);
sendResponse(resp);
});
addHandler("taler-payment-failed", async(msg: any, sendResponse: any) => {
await talerPaymentFailed(msg.H_contract);
sendResponse();
});
addHandler("taler-payment-succeeded", async(msg: any, sendResponse: any) => {
await talerPaymentSucceeded(msg);
sendResponse();
});
}
logVerbose && console.log("loading Taler content script");
init();

View File

@ -30,13 +30,11 @@ import * as i18n from "../../i18n";
import {
AmountJson,
Amounts,
HistoryLevel,
HistoryRecord,
WalletBalance,
WalletBalanceEntry,
} from "../../types";
import {
HistoryLevel,
HistoryRecord,
} from "../../wallet";
import { abbrev } from "../renderHtml";

View File

@ -37,27 +37,6 @@ import {
} from "../types";
/**
* Query the wallet for the coins that would be used to withdraw
* from a given reserve.
*/
export function getReserveCreationInfo(baseUrl: string,
amount: AmountJson): Promise<ReserveCreationInfo> {
const m = { type: "reserve-creation-info", detail: { baseUrl, amount } };
return new Promise<ReserveCreationInfo>((resolve, reject) => {
chrome.runtime.sendMessage(m, (resp) => {
if (resp.error) {
console.error("error response", resp);
const e = Error("call to reserve-creation-info failed");
(e as any).errorResponse = resp;
reject(e);
return;
}
resolve(resp);
});
});
}
async function callBackend(type: string, detail?: any): Promise<any> {
return new Promise<any>((resolve, reject) => {
@ -72,35 +51,45 @@ async function callBackend(type: string, detail?: any): Promise<any> {
}
/**
* Query the wallet for the coins that would be used to withdraw
* from a given reserve.
*/
export function getReserveCreationInfo(baseUrl: string,
amount: AmountJson): Promise<ReserveCreationInfo> {
return callBackend("reserve-creation-info", { baseUrl, amount });
}
/**
* Get all exchanges the wallet knows about.
*/
export async function getExchanges(): Promise<ExchangeRecord[]> {
return await callBackend("get-exchanges");
export function getExchanges(): Promise<ExchangeRecord[]> {
return callBackend("get-exchanges");
}
/**
* Get all currencies the exchange knows about.
*/
export async function getCurrencies(): Promise<CurrencyRecord[]> {
return await callBackend("get-currencies");
export function getCurrencies(): Promise<CurrencyRecord[]> {
return callBackend("get-currencies");
}
/**
* Get information about a specific currency.
*/
export async function getCurrency(name: string): Promise<CurrencyRecord|null> {
return await callBackend("currency-info", {name});
export function getCurrency(name: string): Promise<CurrencyRecord|null> {
return callBackend("currency-info", {name});
}
/**
* Get information about a specific exchange.
*/
export async function getExchangeInfo(baseUrl: string): Promise<ExchangeRecord> {
return await callBackend("exchange-info", {baseUrl});
export function getExchangeInfo(baseUrl: string): Promise<ExchangeRecord> {
return callBackend("exchange-info", {baseUrl});
}
@ -108,72 +97,72 @@ export async function getExchangeInfo(baseUrl: string): Promise<ExchangeRecord>
* Replace an existing currency record with the one given. The currency to
* replace is specified inside the currency record.
*/
export async function updateCurrency(currencyRecord: CurrencyRecord): Promise<void> {
return await callBackend("update-currency", { currencyRecord });
export function updateCurrency(currencyRecord: CurrencyRecord): Promise<void> {
return callBackend("update-currency", { currencyRecord });
}
/**
* Get all reserves the wallet has at an exchange.
*/
export async function getReserves(exchangeBaseUrl: string): Promise<ReserveRecord[]> {
return await callBackend("get-reserves", { exchangeBaseUrl });
export function getReserves(exchangeBaseUrl: string): Promise<ReserveRecord[]> {
return callBackend("get-reserves", { exchangeBaseUrl });
}
/**
* Get all reserves for which a payback is available.
*/
export async function getPaybackReserves(): Promise<ReserveRecord[]> {
return await callBackend("get-payback-reserves");
export function getPaybackReserves(): Promise<ReserveRecord[]> {
return callBackend("get-payback-reserves");
}
/**
* Withdraw the payback that is available for a reserve.
*/
export async function withdrawPaybackReserve(reservePub: string): Promise<ReserveRecord[]> {
return await callBackend("withdraw-payback-reserve", { reservePub });
export function withdrawPaybackReserve(reservePub: string): Promise<ReserveRecord[]> {
return callBackend("withdraw-payback-reserve", { reservePub });
}
/**
* Get all coins withdrawn from the given exchange.
*/
export async function getCoins(exchangeBaseUrl: string): Promise<CoinRecord[]> {
return await callBackend("get-coins", { exchangeBaseUrl });
export function getCoins(exchangeBaseUrl: string): Promise<CoinRecord[]> {
return callBackend("get-coins", { exchangeBaseUrl });
}
/**
* Get all precoins withdrawn from the given exchange.
*/
export async function getPreCoins(exchangeBaseUrl: string): Promise<PreCoinRecord[]> {
return await callBackend("get-precoins", { exchangeBaseUrl });
export function getPreCoins(exchangeBaseUrl: string): Promise<PreCoinRecord[]> {
return callBackend("get-precoins", { exchangeBaseUrl });
}
/**
* Get all denoms offered by the given exchange.
*/
export async function getDenoms(exchangeBaseUrl: string): Promise<DenominationRecord[]> {
return await callBackend("get-denoms", { exchangeBaseUrl });
export function getDenoms(exchangeBaseUrl: string): Promise<DenominationRecord[]> {
return callBackend("get-denoms", { exchangeBaseUrl });
}
/**
* Start refreshing a coin.
*/
export async function refresh(coinPub: string): Promise<void> {
return await callBackend("refresh-coin", { coinPub });
export function refresh(coinPub: string): Promise<void> {
return callBackend("refresh-coin", { coinPub });
}
/**
* Request payback for a coin. Only works for non-refreshed coins.
*/
export async function payback(coinPub: string): Promise<void> {
return await callBackend("payback-coin", { coinPub });
export function payback(coinPub: string): Promise<void> {
return callBackend("payback-coin", { coinPub });
}
/**
@ -181,20 +170,41 @@ export async function payback(coinPub: string): Promise<void> {
* Note that the numeric offer id is not to be confused with
* the string order_id from the contract terms.
*/
export async function getOffer(offerId: number) {
return await callBackend("get-offer", { offerId });
export function getOffer(offerId: number) {
return callBackend("get-offer", { offerId });
}
/**
* Check if payment is possible or already done.
*/
export async function checkPay(offer: OfferRecord): Promise<CheckPayResult> {
return await callBackend("check-pay", { offer });
export function checkPay(offer: OfferRecord): Promise<CheckPayResult> {
return callBackend("check-pay", { offer });
}
/**
* Pay for an offer.
*/
export async function confirmPay(offer: OfferRecord): Promise<ConfirmPayResult> {
return await callBackend("confirm-pay", { offer });
export function confirmPay(offer: OfferRecord): Promise<ConfirmPayResult> {
return callBackend("confirm-pay", { offer });
}
/**
* Hash a contract. Throws if its not a valid contract.
*/
export function hashContract(contract: object): Promise<string> {
return callBackend("confirm-pay", { contract });
}
/**
* Save an offer in the wallet.
*/
export function saveOffer(offer: object): Promise<void> {
return callBackend("save-offer", { offer });
}
/**
* Mark a reserve as confirmed.
*/
export function confirmReserve(reservePub: string): Promise<void> {
return callBackend("confirm-reserve", { reservePub });
}

View File

@ -44,6 +44,7 @@ import {
} from "../wallet";
import { ChromeBadge } from "./chromeBadge";
import URI = require("urijs");
import Port = chrome.runtime.Port;
import MessageSender = chrome.runtime.MessageSender;
@ -300,9 +301,10 @@ function makeHandlers(db: IDBDatabase,
async function dispatch(handlers: any, req: any, sender: any, sendResponse: any): Promise<void> {
if (!(req.type in handlers)) {
console.error(`Request type ${JSON.stringify(req)} unknown, req ${req.type}`);
console.error(`Request type ${req.type} unknown`);
console.error(`Request was ${req}`);
try {
sendResponse({ error: "request unknown" });
sendResponse({ error: "request unknown", requestType: req.type });
} catch (e) {
// might fail if tab disconnected
}

View File

@ -50,6 +50,7 @@
"src/webex/background.ts",
"src/webex/chromeBadge.ts",
"src/webex/components.ts",
"src/webex/messages.ts",
"src/webex/notify.ts",
"src/webex/pages/add-auditor.tsx",
"src/webex/pages/auditors.tsx",