| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- import 'dotenv/config'
- import grpc from "grpc"
- import express from "express"
- import bodyParser from "body-parser"
- import basicAuth from "express-basic-auth"
- import {
- CommandService_v1Client as CommandService,
- QueryService_v1Client as QueryService
- } from 'iroha-helpers/lib/proto/endpoint_grpc_pb'
- import { queries } from 'iroha-helpers'
- import util from 'util'
- import { exec } from 'child_process'
- import cors from 'cors'
- import * as sql from 'sqlite3'
- import fs from 'fs'
- const app = express();
- app.use(bodyParser.json());
- //TODO is cors package necesary? basic middleware could suffice
- app.use(cors()); //TODO: set only safe origins
- app.use(basicAuth({
- users: { admin: 'superPasswd' }
- }));
- const asyncExec = util.promisify(exec);
- const IROHA_ADMIN_PRIV = "f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70";
- const IROHA_ADMIN = "admin@test";
- const IROHA_ADDRESS = process.env.IROHA_ADDRESS || "localhost:50051";
- const queryService = new QueryService(IROHA_ADDRESS, grpc.credentials.createInsecure());
- const CHAIN4ALL_RASTER_CLIP_SCRIPT_PATH = process.env.CHAIN4ALL_RASTER_CLIP_SCRIPT_PATH || '/home/kunickyd/Documents/chain4all/chain4all_raster_clip.sh';
- const CHAIN4ALL_SERVICE_PORT = process.env.CHAIN4ALL_SERVICE_PORT || 3000;
- const PRICE_MODIFIER: number = parseFloat(process.env.PRICE_MODIFIER || "0.5");
- const DB_FILE_NAME: string = "data/transfers.db";
- app.get("/", (req, res) => {
- res.send("Chain4All Blockchain service");
- });
- app.get("/transfers/:userId", async (req, res, next) => {
- let db = await getDbConnection();
- db.all(
- "SELECT hash " +
- "FROM transfers " +
- "WHERE user=? " +
- "ORDER BY id DESC " +
- "LIMIT 10;",
- [req.params.userId],
- (err, rows) => {
- if (err) {
- next(err);
- return;
- }
-
- res.send(rows);
- }
- );
- db.close();
- });
- app.post("/transfer", async (req, res, next) => {
- try {
- if (!req.body) {
- res.status(400);
- throw Error(JSON.stringify({ error: { name: "Error, request has no body!" } }));
- }
- if (!req.body.txHash) {
- res.status(400);
- throw Error(JSON.stringify({ error: { name: "Error, request body has no \"txHash\" property!" } }));
- }
- if (!req.body.user) {
- res.status(400);
- throw Error(JSON.stringify({ error: { name: "Error, request body has no \"user\" property!" } }));
- }
- let db = await getDbConnection();
- db.run(
- "INSERT INTO transfers (hash, user)" +
- "VALUES (?, ?);",
- [req.body.txHash, req.body.user],
- (err) => {
- if (err) {
- next(err);
- return;
- }
- res.status(201);
- res.send();
- }
- );
- db.close();
- }
- catch (err) {
- next(err);
- }
- });
- app.post("/price", (req, res) => { //add caching of same requests
- if (req.body && req.body.area) {
- res.send({ price: getPrice(req.body.area) });
- }
- else {
- res.status(400);
- throw Error(JSON.stringify({ error: { name: "Error, request has no body with \"area\" property!" } }));
- }
- });
- app.post("/buy", async (req, res, next) => {
- try {
- if (!req.body) {
- res.status(400);
- throw Error(JSON.stringify({ error: { name: "Error, request has no body!" } }));
- }
- if (!req.body.txHash) {
- res.status(400);
- throw Error(JSON.stringify({ error: { name: "Error, request body has no \"txHash\" property!" } }));
- }
- //TODO load from http headers, or something like that??
- if (!req.body.user) {
- res.status(400);
- throw Error(JSON.stringify({ error: { name: "Error, request body has no \"user\" property!" } }));
- }
- //TODO validate this properly
- let txDetail = await getTransactionDetail(req.body.txHash, req.body.user);
- let extent: number[] = JSON.parse(txDetail.description).extent as number[];
- let dataFileId: string = Date.now().toString();
- let dataCommand = CHAIN4ALL_RASTER_CLIP_SCRIPT_PATH + ' ' + extent[0] + ' ' + extent[1] + ' ' + extent[2] + ' ' + extent[3] + ' ' + dataFileId;
- console.debug(dataCommand);
- const { stdout, stderr } = await asyncExec(dataCommand);
- console.debug(stdout);
- if (stderr) {
- console.warn(stderr);
- }
- res.send({ dataUrl: "https://gis.lesprojekt.cz/chain4all/raster_" + dataFileId + ".tif" });
- }
- catch (err) {
- next(err);
- }
- });
- function getDbConnection(): Promise<sql.Database> {
- return new Promise<sql.Database>((resolve, reject) => {
- if(!fs.existsSync("./data")){
- fs.mkdirSync("data");
- };
-
- let db = new sql.Database(DB_FILE_NAME);
- db.run(
- "CREATE TABLE IF NOT EXISTS transfers( " +
- "id INTEGER PRIMARY KEY, " +
- "hash TEXT NOT NULL, " +
- "user TEXT NOT NULL " +
- ");",
- (err) => {
- if (err) {
- reject(err);
- }
- else{
- resolve(db);
- }
- }
- );
- });
- }
- async function getTransactionDetail(txHash: string, user: string) {
- let quer: any = await queries.getAccountTransactions({
- privateKey: IROHA_ADMIN_PRIV,
- creatorAccountId: IROHA_ADMIN,
- queryService,
- timeoutLimit: 5000
- }, {
- accountId: user,
- pageSize: 10,
- firstTxHash: txHash,
- ordering: {
- field: undefined,
- direction: undefined
- },
- firstTxTime: undefined,
- lastTxTime: undefined,
- firstTxHeight: 1,
- lastTxHeight: 3
- });
- //TODO find better way to look for transferAssets command in transaction
- return quer.transactionsList[0].payload.reducedPayload.commandsList[0].transferAsset;
- }
- function getPrice(area: number): number {
- return area * PRICE_MODIFIER;
- }
- function errorMiddleware(err: any, req: any, res: any, next: any): void { //TODO: add custom Exception class
- console.log(err);
- res.status(500);
- res.send(err);
- }
- app.use(errorMiddleware);
- app.listen(CHAIN4ALL_SERVICE_PORT, () => {
- console.log(`Listening at http://localhost:${CHAIN4ALL_SERVICE_PORT}`)
- });
|