Implement node communication via Websocket
This commit is contained in:
43
package-lock.json
generated
43
package-lock.json
generated
@@ -10,7 +10,9 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.2.2",
|
"axios": "^1.2.2",
|
||||||
"express": "^4.18.2"
|
"express": "^4.18.2",
|
||||||
|
"uuid": "^9.0.0",
|
||||||
|
"ws": "^8.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nodemon": "^2.0.22"
|
"nodemon": "^2.0.22"
|
||||||
@@ -1020,6 +1022,14 @@
|
|||||||
"node": ">= 0.4.0"
|
"node": ">= 0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vary": {
|
"node_modules/vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
@@ -1027,6 +1037,26 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||||
|
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1769,10 +1799,21 @@
|
|||||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
|
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
|
||||||
},
|
},
|
||||||
|
"uuid": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg=="
|
||||||
|
},
|
||||||
"vary": {
|
"vary": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
|
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
|
||||||
|
},
|
||||||
|
"ws": {
|
||||||
|
"version": "8.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
|
||||||
|
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
|
||||||
|
"requires": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.2.2",
|
"axios": "^1.2.2",
|
||||||
"express": "^4.18.2"
|
"express": "^4.18.2",
|
||||||
|
"uuid": "^9.0.0",
|
||||||
|
"ws": "^8.13.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nodemon": "^2.0.22"
|
"nodemon": "^2.0.22"
|
||||||
|
|||||||
37
src/example/job.json
Normal file
37
src/example/job.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"remoteIdentifier": "AAAAA",
|
||||||
|
"callback": "undefined",
|
||||||
|
"type": "card",
|
||||||
|
"size": {
|
||||||
|
"width": 600,
|
||||||
|
"height": 1000
|
||||||
|
},
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"asset": "https://cdn.discordapp.com/attachments/1083687175998152714/1113486254953222205/rainbow_overlay.png",
|
||||||
|
"x": 0,
|
||||||
|
"y": 300,
|
||||||
|
"width": 600,
|
||||||
|
"height": 1000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"asset": "https://cdn.discordapp.com/attachments/1083687175998152714/1113486177002070126/template.png",
|
||||||
|
"x": 0,
|
||||||
|
"y": 300,
|
||||||
|
"width": 600,
|
||||||
|
"height": 1000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "Ninomae Ina'nis",
|
||||||
|
"fontSize": 55,
|
||||||
|
"x": 0,
|
||||||
|
"y": 700,
|
||||||
|
"width": 600,
|
||||||
|
"height": 300,
|
||||||
|
"horizontalAlignment": "center"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
66
src/index.js
66
src/index.js
@@ -1,11 +1,18 @@
|
|||||||
const express = require("express");
|
const express = require("express");
|
||||||
var crypto = require('crypto');
|
var crypto = require('crypto');
|
||||||
const { finished } = require("stream");
|
const { finished } = require("stream");
|
||||||
|
const uuid = require("uuid");
|
||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
|
const path = require("path")
|
||||||
|
const { WebSocketServer } = require("ws");
|
||||||
|
const { request } = require("http");
|
||||||
|
|
||||||
|
const PORT_WEB = 6968;
|
||||||
|
const PORT_WSS = 6980;
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
const wss = new WebSocketServer({ port: PORT_WSS });
|
||||||
const PORT = 6968;
|
console.log(`Websocket listening on port ${PORT_WSS}`);
|
||||||
|
|
||||||
let jobs = {
|
let jobs = {
|
||||||
queued: {},
|
queued: {},
|
||||||
@@ -13,12 +20,16 @@ let jobs = {
|
|||||||
finished: {}
|
finished: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let nodes = {};
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
res.send('Job handling server')
|
res.send('Job handling server')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.use('/example', express.static(path.join(__dirname, 'example')));
|
||||||
|
|
||||||
app.get('/jobs', (req, res) => {
|
app.get('/jobs', (req, res) => {
|
||||||
let queued = Object.values(jobs['queued']);
|
let queued = Object.values(jobs['queued']);
|
||||||
let waiting = Object.values(jobs['waiting']);
|
let waiting = Object.values(jobs['waiting']);
|
||||||
@@ -35,7 +46,14 @@ app.get('/jobs', (req, res) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/jobs", (req, res) => {
|
function ResolveJob(result){
|
||||||
|
let jobId = result["jobId"];
|
||||||
|
console.log(`Completed Job ${jobId}`);
|
||||||
|
delete jobs['queued'][jobId];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
app.post("/jobs", async (req, res) => {
|
||||||
const data = req.body;
|
const data = req.body;
|
||||||
let jobId = crypto.createHash('md5').update(JSON.stringify(req.body)).digest('hex');
|
let jobId = crypto.createHash('md5').update(JSON.stringify(req.body)).digest('hex');
|
||||||
|
|
||||||
@@ -47,7 +65,18 @@ app.post("/jobs", (req, res) => {
|
|||||||
jobs['queued'][jobId] = req.body;
|
jobs['queued'][jobId] = req.body;
|
||||||
jobs['queued'][jobId]['jobId'] = jobId;
|
jobs['queued'][jobId]['jobId'] = jobId;
|
||||||
console.log(`Queued Job ${jobId}`);
|
console.log(`Queued Job ${jobId}`);
|
||||||
res.json({ 'jobId': jobId });
|
var client = Array.from(wss.clients)[0];
|
||||||
|
if(!client) {
|
||||||
|
res.status(503).json({ 'message': 'No render nodes available', 'jobId': jobId });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
client.send(JSON.stringify({"job": req.body}));
|
||||||
|
let response = new Promise(function (resolve, reject){
|
||||||
|
jobs['queued'][jobId]['promise'] = {resolve: resolve, reject: reject};
|
||||||
|
});
|
||||||
|
console.log("Sent job to node", client.nodeID);
|
||||||
|
let result = await response.then(ResolveJob)
|
||||||
|
res.json({ 'jobId': jobId, "path": result["path"] });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/batch", async (req, res) => {
|
app.get("/batch", async (req, res) => {
|
||||||
@@ -104,6 +133,31 @@ app.post("/jobs/:jobId/completed", async (req, res) => {
|
|||||||
res.status(400).send({ 'message': `Job ${jobId} not found` });
|
res.status(400).send({ 'message': `Job ${jobId} not found` });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(PORT, () => {
|
|
||||||
console.log("Job Server running")
|
wss.on('connection', function connection(ws) {
|
||||||
|
var nodeID = uuid.v4();
|
||||||
|
ws.nodeID = nodeID;
|
||||||
|
nodes[nodeID] = ws
|
||||||
|
console.log("New connection from", nodeID)
|
||||||
|
ws.on('error', console.error);
|
||||||
|
|
||||||
|
ws.on('message', function message(data) {
|
||||||
|
let request = JSON.parse(data);
|
||||||
|
console.log('received: %s', data);
|
||||||
|
|
||||||
|
if(request["register"]){
|
||||||
|
ws.send(JSON.stringify({"welcome": { "clientId": nodeID }}));
|
||||||
|
console.log("Node registered", nodeID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(request["result"]) {
|
||||||
|
let jobResult = request["result"]
|
||||||
|
jobs['queued'][jobResult["jobId"]]['promise'].resolve(jobResult);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(PORT_WEB, () => {
|
||||||
|
console.log(`Job Server API running on ${PORT_WEB}`);
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user