proxy.js
1 const httpProxy = require('http-proxy'); 2 const http = require('http'); 3 const constants = require('../../constants.json'); 4 const utils = require('../../utils/utils'); 5 6 let commList = {}; 7 let transactions = {}; 8 let receipts = {}; 9 10 const {canonicalHost, defaultHost} = require('../../utils/host'); 11 12 const parseRequest = function (reqBody) { 13 let jsonO; 14 try { 15 jsonO = JSON.parse(reqBody); 16 } catch (e) { 17 return; // Request is not a json. Do nothing 18 } 19 if (jsonO.method === "eth_sendTransaction") { 20 commList[jsonO.id] = { 21 type: 'contract-log', 22 address: jsonO.params[0].to, 23 data: jsonO.params[0].data 24 }; 25 } else if (jsonO.method === "eth_getTransactionReceipt") { 26 if (transactions[jsonO.params[0]]) { 27 transactions[jsonO.params[0]].receiptId = jsonO.id; 28 receipts[jsonO.id] = transactions[jsonO.params[0]].commListId; 29 } 30 } 31 }; 32 33 const parseResponse = function (ipc, resBody) { 34 let jsonO; 35 try { 36 jsonO = JSON.parse(resBody); 37 } catch (e) { 38 return; // Response is not a json. Do nothing 39 } 40 if (commList[jsonO.id]) { 41 commList[jsonO.id].transactionHash = jsonO.result; 42 transactions[jsonO.result] = {commListId: jsonO.id}; 43 } else if (receipts[jsonO.id] && jsonO.result && jsonO.result.blockNumber) { 44 // TODO find out why commList[receipts[jsonO.id]] is sometimes not defined 45 if (!commList[receipts[jsonO.id]]) { 46 commList[receipts[jsonO.id]] = {}; 47 } 48 commList[receipts[jsonO.id]].blockNumber = jsonO.result.blockNumber; 49 commList[receipts[jsonO.id]].gasUsed = jsonO.result.gasUsed; 50 commList[receipts[jsonO.id]].status = jsonO.result.status; 51 52 if (ipc.connected && !ipc.connecting) { 53 ipc.request('log', commList[receipts[jsonO.id]]); 54 } else { 55 const message = commList[receipts[jsonO.id]]; 56 ipc.connecting = true; 57 ipc.connect(() => { 58 ipc.connecting = false; 59 ipc.request('log', message); 60 }); 61 } 62 63 delete transactions[commList[receipts[jsonO.id]].transactionHash]; 64 delete commList[receipts[jsonO.id]]; 65 delete receipts[jsonO.id]; 66 } 67 }; 68 69 exports.serve = async function (ipc, host, port, ws, origin) { 70 const _origin = origin ? origin.split(',')[0] : undefined; 71 const start = Date.now(); 72 73 function awaitTarget() { 74 return new Promise(resolve => { 75 utils.pingEndpoint( 76 canonicalHost(host), port, ws ? 'ws': false, 'http', _origin, async (err) => { 77 if (!err || (Date.now() - start > 10000)) { 78 return resolve(); 79 } 80 await utils.timer(250).then(awaitTarget).then(resolve); 81 } 82 ); 83 }); 84 } 85 86 await awaitTarget(); 87 88 let proxy = httpProxy.createProxyServer({ 89 target: { 90 host: canonicalHost(host), 91 port: port 92 }, 93 ws: ws 94 }); 95 96 proxy.on('error', function (e) { 97 console.error(__("Error forwarding requests to blockchain/simulator"), e.message); 98 }); 99 100 proxy.on('proxyRes', (proxyRes) => { 101 let resBody = []; 102 proxyRes.on('data', (b) => resBody.push(b)); 103 proxyRes.on('end', function () { 104 resBody = Buffer.concat(resBody).toString(); 105 if (resBody) { 106 parseResponse(ipc, resBody); 107 } 108 }); 109 }); 110 111 let server = http.createServer((req, res) => { 112 let reqBody = []; 113 req.on('data', (b) => { 114 reqBody.push(b); 115 }) 116 .on('end', () => { 117 reqBody = Buffer.concat(reqBody).toString(); 118 if (reqBody) { 119 parseRequest(reqBody); 120 } 121 }); 122 123 if (!ws) { 124 proxy.web(req, res); 125 } 126 }); 127 128 if (ws) { 129 const WsParser = require('simples/lib/parsers/ws'); // npm install simples 130 131 server.on('upgrade', function (req, socket, head) { 132 proxy.ws(req, socket, head); 133 }); 134 135 proxy.on('open', (proxySocket) => { 136 proxySocket.on('data', (data) => { 137 parseResponse(ipc, data.toString().substr(data.indexOf("{"))); 138 }); 139 }); 140 141 proxy.on('proxyReqWs', (proxyReq, req, socket) => { 142 var parser = new WsParser(0, false); 143 socket.pipe(parser); 144 parser.on('frame', function (frame) { 145 parseRequest(frame.data); 146 }); 147 148 }); 149 } 150 const listenPort = port - constants.blockchain.servicePortOnProxy; 151 return new Promise(resolve => { 152 server.listen(listenPort, defaultHost, () => { 153 resolve(server); 154 }); 155 }); 156 };