Skip to content

Commit

Permalink
Add possibility to filter a request
Browse files Browse the repository at this point in the history
  • Loading branch information
panleone authored and Duddino committed Apr 7, 2023
1 parent a4ecfa3 commit 7ebec86
Show file tree
Hide file tree
Showing 4 changed files with 2,177 additions and 103 deletions.
2 changes: 1 addition & 1 deletion .env.mpw.sample
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
RPC_CREDENTIALS=name:password
ALLOWED_RPCS=listmasternodes,relaymasternodebroadcast,getbudgetprojection,mnbudgetrawvote,getbudgetinfo
ALLOWED_RPCS=listmasternodes,relaymasternodebroadcast,getbudgetprojection,mnbudgetrawvote,getbudgetinfo,getbudgetvotes
PORT=3000
RPC_PORT=51473
TESTNET_RPC_PORT=51463 # Remove if you don't want testnet
178 changes: 93 additions & 85 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import cors from "cors";
import http from "http";
import https from "https";
import fs from "fs";

import jq from "node-jq";

const app = express();
app.use(cors());
Expand All @@ -17,107 +17,115 @@ const testnetRpcPort = process.env["TESTNET_RPC_PORT"];
const allowedRpcs = process.env["ALLOWED_RPCS"].split(",");

function setupServer(app) {
const certificatePath = process.env["HTTPS_CERTIFICATE_PATH"];
const keyPath = process.env["HTTPS_KEY_PATH"];
if (!certificatePath || !keyPath) {
return http.createServer(app);
}
const cert = fs.readFileSync(certificatePath);
const key = fs.readFileSync(keyPath);
return https.createServer({cert, key}, app);
const certificatePath = process.env["HTTPS_CERTIFICATE_PATH"];
const keyPath = process.env["HTTPS_KEY_PATH"];
if (!certificatePath || !keyPath) {
return http.createServer(app);
}
const cert = fs.readFileSync(certificatePath);
const key = fs.readFileSync(keyPath);
return https.createServer({ cert, key }, app);
}

function checkEnv() {
if(!process.env["ALLOWED_RPCS"]) throw new Error("Environment variable ALLOWED_RPCS was not set");
if(!process.env["RPC_CREDENTIALS"]) throw new Error("Environment variable RPC_CREDENTIALS was not set");
if (!process.env["ALLOWED_RPCS"])
throw new Error("Environment variable ALLOWED_RPCS was not set");
if (!process.env["RPC_CREDENTIALS"])
throw new Error("Environment variable RPC_CREDENTIALS was not set");
}

const encodeBase64 = (data) => {
return Buffer.from(data).toString('base64');
}
return Buffer.from(data).toString("base64");
};

async function makeRpc(isTestnet, name, ...params){
try{
const output = await fetch(`http://127.0.0.1:${isTestnet ? testnetRpcPort : rpcPort}/`, {
method: 'POST',
headers: {
'content-type': 'text/plain;',
'Authorization': 'Basic ' + encodeBase64(process.env["RPC_CREDENTIALS"])
},
body: JSON.stringify({
jsonrpc: "1.0",
id: "pivxRerouter",
method: name,
params,
}),
});
async function makeRpc(isTestnet, name, ...params) {
try {
const output = await fetch(
`http://127.0.0.1:${isTestnet ? testnetRpcPort : rpcPort}/`,
{
method: "POST",
headers: {
"content-type": "text/plain;",
Authorization:
"Basic " + encodeBase64(process.env["RPC_CREDENTIALS"]),
},
body: JSON.stringify({
jsonrpc: "1.0",
id: "pivxRerouter",
method: name,
params,
}),
}
);

const obj = await output.json();
if(obj.error) {
const imATeapot = 418;
return { status: imATeapot, response: obj.error.message };
} else {
const ok = 200;
return { status: ok, response: JSON.stringify(obj.result) };
}
} catch(error) {
if (error.errno === "ECONNREFUSED") {
return { status: 503, response: "PIVX node was not responsive."};
}
console.error(error);
if (error.name === 'AbortError') {
return "brequbest was aborted'";
}else{
return "non u sac";
}
const obj = await output.json();
if (obj.error) {
const imATeapot = 418;
return { status: imATeapot, response: obj.error.message };
} else {
const ok = 200;
return { status: ok, response: JSON.stringify(obj.result) };
}
} catch (error) {
if (error.errno === "ECONNREFUSED") {
return { status: 503, response: "PIVX node was not responsive." };
}
console.error(error);
if (error.name === "AbortError") {
return "brequbest was aborted'";
} else {
return "non u sac";
}
}
}

function parseParams(params) {
return (params ? params.split(",") : [])
.map(v=>isNaN(v) ? v : parseInt(v))
.map(v=>v === "true" ? true : v)
.map(v=>v === "false" ? false : v);
return (params ? params.split(",") : [])
.map((v) => (isNaN(v) ? v : parseInt(v)))
.map((v) => (v === "true" ? true : v))
.map((v) => (v === "false" ? false : v));
}

app.get('/mainnet/:rpc', async function(req, res) {
try {
if (allowedRpcs.includes(req.params["rpc"])) {

const params = parseParams(req.query.params);
const { status, response } = await makeRpc(false, req.params["rpc"], ...params);
res.status(status).send(response + "");
} else {
const forbiddenStatus = 403;
res.status(forbiddenStatus).send("Invalid RPC");
}
} catch (e) {
console.error(e);
const internalError = 500;
res.status(internalError).send("Internal app error");
async function handleRequest(isTestnet, req, res) {
try {
if (allowedRpcs.includes(req.params["rpc"])) {
const filter = req.query.filter;
const params = parseParams(req.query.params);
const { status, response } = await makeRpc(
isTestnet,
req.params["rpc"],
...params
);
try {
res
.status(status)
.send(
filter
? await jq.run(filter, response, { input: "string" })
: response
);
} catch (e) {
const badRequest = 400;
res.status(badRequest).send("Bad filter request");
}
} else {
const forbiddenStatus = 403;
res.status(forbiddenStatus).send("Invalid RPC");
}
});
if(testnetRpcPort) {
app.get('/testnet/:rpc', async function(req, res) {
try {
if (allowedRpcs.includes(req.params["rpc"])) {

const params = parseParams(req.query.params);
const { status, response } = await makeRpc(true, req.params["rpc"], ...params);
res.status(status).send(response + "");
} else {
const forbiddenStatus = 403;
res.status(forbiddenStatus).send("Invalid RPC");
}
} catch (e) {
const internalError = 500;
res.status(internalError).send("Internal app error");
}
});
} catch (e) {
console.error(e);
const internalError = 500;
res.status(internalError).send("Internal app error");
}
}

app.get("/mainnet/:rpc", async (req, res) => handleRequest(false, req, res));
if (testnetRpcPort) {
app.get("/testnet/:rpc", async (req, res) => handleRequest(true, req, res));
}

const server = setupServer(app);

server.listen(port, () => {
console.log(`Pivx node controller listening on port ${port}`)
})
console.log(`Pivx node controller listening on port ${port}`);
});
Loading

0 comments on commit 7ebec86

Please sign in to comment.