Pull out Webserver

This commit is contained in:
Simon Warta 2020-02-10 12:58:18 +01:00
parent 3f8ab89877
commit 1280c2f8cf
6 changed files with 97 additions and 73 deletions

View File

@ -1,16 +1,11 @@
import cors = require("@koa/cors");
import { createCosmWasmConnector } from "@cosmwasm/bcp";
import Koa from "koa";
import bodyParser from "koa-bodyparser";
import { isValidAddress } from "../../addresses";
import { Webserver } from "../../api/webserver";
import * as constants from "../../constants";
import { logAccountsState } from "../../debugging";
import { Faucet } from "../../faucet";
import { availableTokensFromHolder } from "../../multichainhelpers";
import { createUserProfile } from "../../profile";
import { HttpError } from "./httperror";
import { RequestParser } from "./requestparser";
export async function start(args: ReadonlyArray<string>): Promise<void> {
if (args.length < 1) {
@ -57,71 +52,6 @@ export async function start(args: ReadonlyArray<string>): Promise<void> {
setInterval(async () => faucet.refill(), 60_000); // ever 60 seconds
console.info("Creating webserver ...");
const api = new Koa();
api.use(cors());
api.use(bodyParser());
api.use(async context => {
switch (context.path) {
case "/":
case "/healthz":
context.response.body =
"Welcome to the faucet!\n" +
"\n" +
"Check the full status via the /status endpoint.\n" +
"You can get tokens from here by POSTing to /credit.\n" +
"See https://github.com/iov-one/iov-faucet for all further information.\n";
break;
case "/status": {
const updatedAccounts = await faucet.loadAccounts();
context.response.body = {
status: "ok",
nodeUrl: blockchainBaseUrl,
chainId: connection.chainId(),
chainTokens: chainTokens,
availableTokens: availableTokens,
holder: updatedAccounts[0],
distributors: updatedAccounts.slice(1),
};
break;
}
case "/credit": {
if (context.request.method !== "POST") {
throw new HttpError(405, "This endpoint requires a POST request");
}
if (context.request.type !== "application/json") {
throw new HttpError(415, "Content-type application/json expected");
}
// context.request.body is set by the bodyParser() plugin
const requestBody = context.request.body;
const { address, ticker } = RequestParser.parseCreditBody(requestBody);
if (!isValidAddress(address)) {
throw new HttpError(400, "Address is not in the expected format for this chain.");
}
if (availableTokens.indexOf(ticker) === -1) {
const tokens = JSON.stringify(availableTokens);
throw new HttpError(422, `Token is not available. Available tokens are: ${tokens}`);
}
try {
await faucet.credit(address, ticker);
} catch (e) {
console.error(e);
throw new HttpError(500, "Sending tokens failed");
}
context.response.body = "ok";
break;
}
default:
// koa sends 404 by default
}
});
const port = constants.port;
console.info(`Starting webserver on port ${port} ...`);
api.listen(port);
const server = new Webserver(faucet, { nodeUrl: blockchainBaseUrl, chainId: connection.chainId() });
server.start(constants.port);
}

View File

@ -0,0 +1,94 @@
import Koa from "koa";
import cors = require("@koa/cors");
import { ChainId } from "@iov/bcp";
import bodyParser from "koa-bodyparser";
import { isValidAddress } from "../addresses";
import { Faucet } from "../faucet";
import { availableTokensFromHolder } from "../multichainhelpers";
import { HttpError } from "./httperror";
import { RequestParser } from "./requestparser";
/** This will be passed 1:1 to the user */
export interface ChainConstants {
readonly nodeUrl: string;
readonly chainId: ChainId;
}
export class Webserver {
private readonly api = new Koa();
constructor(faucet: Faucet, chainChinstants: ChainConstants) {
this.api.use(cors());
this.api.use(bodyParser());
this.api.use(async context => {
switch (context.path) {
case "/":
case "/healthz":
context.response.body =
"Welcome to the faucet!\n" +
"\n" +
"Check the full status via the /status endpoint.\n" +
"You can get tokens from here by POSTing to /credit.\n" +
"See https://github.com/iov-one/iov-faucet for all further information.\n";
break;
case "/status": {
const [holder, ...distributors] = await faucet.loadAccounts();
const availableTokens = availableTokensFromHolder(holder);
const chainTokens = await faucet.loadTokenTickers();
context.response.body = {
status: "ok",
...chainChinstants,
chainTokens: chainTokens,
availableTokens: availableTokens,
holder: holder,
distributors: distributors,
};
break;
}
case "/credit": {
if (context.request.method !== "POST") {
throw new HttpError(405, "This endpoint requires a POST request");
}
if (context.request.type !== "application/json") {
throw new HttpError(415, "Content-type application/json expected");
}
// context.request.body is set by the bodyParser() plugin
const requestBody = context.request.body;
const { address, ticker } = RequestParser.parseCreditBody(requestBody);
if (!isValidAddress(address)) {
throw new HttpError(400, "Address is not in the expected format for this chain.");
}
const [holder] = await faucet.loadAccounts();
const availableTokens = availableTokensFromHolder(holder);
if (availableTokens.indexOf(ticker) === -1) {
const tokens = JSON.stringify(availableTokens);
throw new HttpError(422, `Token is not available. Available tokens are: ${tokens}`);
}
try {
await faucet.credit(address, ticker);
} catch (e) {
console.error(e);
throw new HttpError(500, "Sending tokens failed");
}
context.response.body = "ok";
break;
}
default:
// koa sends 404 by default
}
});
}
public start(port: number): void {
console.info(`Starting webserver on port ${port} ...`);
this.api.listen(port);
}
}