jrgen
Version:
Generates docs, tests, clients and servers for json-rpc apis.
151 lines (133 loc) • 3.5 kB
JavaScript
const http = require("http");
module.exports = class RpcServer {
constructor() {
this.api = {};
this.httpServer = http.createServer((request, response) => {
this.process(request, response);
});
}
listen(port, ip, callback) {
this.httpServer.listen(port, ip, callback);
}
process(request, response) {
response.statusCode = 200;
response.setHeader("Content-Type", "application/json");
response.setHeader("Access-Control-Allow-Origin", "*");
if (request.method !== "POST") {
response.statusCode = 404;
response.end();
return;
}
this.loadBody(request)
.then((body) => {
this.parseRPCMessage(body)
.then((rpc) => {
new Promise((resolve, reject) => {
this.api[rpc.method](rpc.params, resolve, reject);
})
.then((result) => {
response.end(
JSON.stringify({
id: rpc.id,
jsonrpc: "2.0",
result: result,
})
);
})
.catch((error) => {
response.end(
JSON.stringify({
id: rpc.id,
jsonrpc: "2.0",
error: error,
})
);
});
})
.catch((error) => {
response.end(
JSON.stringify({
id: null,
jsonrpc: "2.0",
error: error,
})
);
});
})
.catch((error) => {
response.end(
JSON.stringify({
id: null,
jsonrpc: "2.0",
error: error,
})
);
});
}
loadBody(request) {
return new Promise((resolve, reject) => {
var requestBody = "";
request.on("data", (chunk) => {
requestBody += chunk;
});
request.on("end", () => {
resolve(requestBody);
});
});
}
parseRPCMessage(message) {
return new Promise((resolve, reject) => {
var rpc;
try {
rpc = JSON.parse(message);
} catch (e) {
return reject({
code: -32700,
message: "Parse error",
});
}
if (typeof rpc !== "object") {
return reject({
code: -32600,
message: "Invalid Request",
data: "rpc is not of type object.",
});
}
if (rpc.jsonrpc !== "2.0") {
return reject({
code: -32600,
message: "Invalid Request",
data: "jsonrpc has not been set or has an invalid value.",
});
}
if (
rpc.id &&
!(typeof rpc.id === "number" || typeof rpc.id === "string")
) {
return reject({
code: -32600,
message: "Invalid Request",
data: "id is not of type number or string.",
});
}
if (typeof rpc.method !== "string") {
return reject({
code: -32600,
message: "Invalid Request",
data: "method is not of type string.",
});
}
if (rpc.params && typeof rpc.params !== "object") {
return reject({
code: -32600,
message: "Invalid Request",
data: "params is not of type object.",
});
}
resolve(rpc);
});
}
expose(method, handler) {
this.api[method] = handler;
}
};