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' const app = express(); app.use(bodyParser.json()); app.use(basicAuth({ users: { admin: 'superPasswd' }, challenge: true })); //TODO is cors package necesary? basic middleware could suffice app.use(cors()); //TODO: set only safe origins const asyncExec = util.promisify(exec); const IROHA_ADMIN_PRIV = "f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70"; const IROHA_ADMIN = "admin@test"; const IROHA_ADDRESS = "localhost:50051"; const commandService = new CommandService(IROHA_ADDRESS, grpc.credentials.createInsecure()); 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 IROHA_API_HOST = process.env.IROHA_API_HOST || "http://localhost"; const IROHA_API_PORT = process.env.IROHA_API_PORT || 5000; const IROHA_DOMAIN = process.env.IROHA_DOMAIN || "test"; const IROHA_ASSET = process.env.IROHA_ASSET || "coin"; const DATA_OWNER = process.env.DATA_OWNER || "admin" const PRICE_MODIFIER: number = parseFloat(process.env.PRICE_MODIFIER || "0.5"); app.get("/", (req, res) => { res.send("Chain4All Blockchain service"); }); app.post("/price", (req, res) => { if (req.body && req.body.extent) { res.send({ price: getPrice(req.body.extent) }); } else { res.status(400); throw Error(JSON.stringify({ error: { name: "Error, request has no body with \"extent\" 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: Array> = JSON.parse(txDetail.description).extent as Array>; let dataFileId: string = Date.now().toString(); let dataCommand = CHAIN4ALL_RASTER_CLIP_SCRIPT_PATH + ' ' + extent[3][1] + ' ' + extent[3][0] + ' ' + extent[1][1] + ' ' + extent[1][0] + ' ' + 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); } }); 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 getArea(extent: Array>): number { let y1 = extent[0][1]; let y4 = extent[3][1]; let x1 = extent[0][0]; let x2 = extent[1][0]; let height = Math.abs(y1 - y4); let width = Math.abs(x1 - x2); return height * width; } function getPrice(extent: Array>): number { return getArea(extent) * 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}`) });