forked from baycom/node-red-contrib-emberplus
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathemberplus-server.js
executable file
·134 lines (120 loc) · 6.13 KB
/
emberplus-server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
const { EmberClient, EmberLib } = require('node-emberplus');
const reconnectDelay = 30 * 1000;
module.exports = function (RED) {
function EmberPlusServerNode(config) {
var statusCallbacks = [];
RED.nodes.createNode(this, config);
this.host = config.host;
this.port = config.port;
this.name = config.name;
this.configPaths = config.paths ? config.paths.split(",") : [];
var node = this;
node.shutdown = false;
//Send a message to the subscribed nodes (appears on the flow)
node.sendStatus = function (colour, message, extraInformation = "") {
for (var i = 0; i < statusCallbacks.length; i++) {
statusCallbacks[i](colour, message, extraInformation);
}
}
//Callback definitions
node.addStatusCallback = function (func) { statusCallbacks.push(func); }
function getFunctionDescriptor(func) {
return (func.description ? func.description : 'function') +
'args:' + func.arguments ? func.arguments.map(arg => {
const jarg = arg.toJSON();
return `${jarg.name}/${jarg.type}`;
}).join(",") : "";
}
/**
*
* @param {EmberLib.Element} element
*/
async function getEmberChildren(element) {
if (element.isParameter()) {
node.paths.push({ "path": element.path, "id": element.path + ":/" + element.identifier + "->" + (element.description ? element.description : element.value) });
} else if (element.isFunction()) {
node.paths.push({ "path": element.path, "id": element.path + ":/" + element.identifier + "->" + getFunctionDescriptor(element) });
}
const children = element.getChildren();
if (children && children.length) {
children.forEach(child => getEmberChildren(child));
}
}
async function getPath(path) {
try {
const element = await node.client.getElementByPathAsync(path);
await node.client.expandAsync(element);
await getEmberChildren(element);
} catch(e) {
console.log(e);
}
}
async function getCompleteTree() {
try {
const element = await node.client.expandAsync();
await getEmberChildren(node.client.root);
} catch(e) {
console.log(e);
}
}
async function reconnect() {
if (node.client) {
delete node.client;
}
var client = new EmberClient({
host: node.host,
port: node.port
});
node.client = client;
node.paths = [];
client.on("error", e => {
node.sendStatus("red", "Error", e)
});
client.on("connecting", () => {
node.sendStatus("yellow", "Connecting");
});
client.on("disconnected", () => {
node.sendStatus("red", "Disconnected");
if (!node.shutdown) {
setTimeout(() => reconnect().catch(e => console.log(e)), reconnectDelay);
}
});
client.on("connected", () => {
node.sendStatus("green", "Connected");
});
try {
await client.connectAsync();
if (node.configPaths.length) {
for(const path of node.configPaths) {
await getPath(path);
}
} else {
await getCompleteTree();
}
node.emit("clientready", node.paths, client);
} catch(e) {
console.log(e);
setTimeout(() => reconnect().catch(e => console.log(e)), reconnectDelay);
}
}
//On redeploy
node.on("close", function () {
node.shutdown = true;
node.client.disconnect();
});
reconnect().catch(e => console.log(e));
}
RED.httpAdmin.get('/emberplus/:node/paths', RED.auth.needsPermission('emberplus.read'), (req, res) => {
var node = RED.nodes.getNode(req.params.node);
if (node != null) {
if (node.paths.length) {
res.status(200).send(JSON.stringify(node.paths));
} else {
res.status(401).send(`401 Not found: no path data yet`);
}
} else {
res.status(401).send(`401 Invalid node id`);
}
});
RED.nodes.registerType("emberplus-server", EmberPlusServerNode);
}