-
Notifications
You must be signed in to change notification settings - Fork 2
/
server.js
237 lines (209 loc) · 8.39 KB
/
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#!/usr/bin/env node
/* Copyright 2016 Streampunk Media Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var http = require('http');
var express = require("express");
var RED = require("node-red");
var fs = require('fs');
var dgram = require('dgram');
var ledger = require('nmos-ledger');
var util = require('util');
var hostname = require('os').hostname();
var shortHostname = hostname.match(/([^\.]*)\.?.*/)[1];
var pid = process.pid;
var properties = {
redPort : '8000',
ledgerPort : '3101',
userDir : 'reduser'
};
var flowFileSet = false;
for ( var i = 2 ; i < process.argv.length ; i++ ) {
var arg = /(\S+)=(\S+)/.exec(process.argv[i]);
if (arg) properties[arg[1]] = arg[2];
else console.error(`Could not process argument ${i - 1}: '${process.argv[i]}'`);
}
if (!properties.flowFile) {
properties.flowFile = `flows_${hostname}_${properties.redPort}.json`;
}
if (isNaN(+properties.redPort) || +properties.redPort > 65535 ||
properties.redPort < 0) {
console.error('Parameter redPort must be a number between 0 and 65535.');
process.exit(1);
}
if (isNaN(+properties.ledgerPort) || +properties.ledgerPort > 65535 ||
+properties.ledgerPort < 0) {
console.error('Parameter ledgerPort must be a number between 0 and 65535.');
process.exit(1);
}
if (!properties.flowFile.endsWith('.json')) {
console.error('Parameter flowFile must end with .json.');
process.exit(1);
}
var node = new ledger.Node(null, null, `Dynamorse ${shortHostname} ${pid}`,
`http://dynamorse-${shortHostname}-${pid}.local:${properties.ledgerPort}`,
`${hostname}`);
// Externally advertised ... sources etc are registered with discovered registration
// services
var device = new ledger.Device(null, null, `device-${shortHostname}-${pid}`,
ledger.deviceTypes.generic, node.id, null, null);
// Internal only ... sources etc are not pushed to external registration services
var pipelines = new ledger.Device(null, null, `pipelines-${shortHostname}-${pid}`,
ledger.deviceTypes.pipeline, node.id, null, null);
var store = new ledger.NodeRAMStore(node);
var nodeAPI = new ledger.NodeAPI(+properties.ledgerPort, store);
nodeAPI.init().start();
// Fixed identifiers for global config nodes
var deviceNodeID = 'f089bf72.0f764';
var pipelinesNodeID = 'da7405b8.258bf8';
var selfNodeID = 'd8044477.27fbb8';
var extDefNodeID = '30fb5980.cf04a6';
// Create an Express app
var app = express();
// Add a simple route for static content served from 'public'
app.use("/",express.static("public"));
// Create a server
var server = http.createServer(app);
// Debug levels
// Level of logging to be recorded. Options are:
// fatal - only those errors which make the application unusable should be recorded
// error - record errors which are deemed fatal for a particular request + fatal errors
// warn - record problems which are non fatal + errors + fatal errors
// info - record information about the general running of the application + warn + error + fatal errors
// debug - record information which is more verbose than info + info + warn + error + fatal errors
// trace - record very detailed logging + debug + info + warn + error + fatal errors
// Create the settings object - see default settings.js file for other options
var settings = {
httpAdminRoot: "/red",
httpNodeRoot: "/api",
userDir: properties.userDir,
flowFile: properties.flowFile,
nodesDir: __dirname + "/reduser/nodes/",
functionGlobalContext: {
node : node,
nodeAPI : nodeAPI,
ledger : ledger,
rtp_ext_id : extDefNodeID,
pipelinesID : pipelines.id,
genericID : device.id,
updated : false
}, // enables global context
paletteCategories: ['subflows', 'funnel', 'valve', 'fitting', 'spout', 'testing', 'input', 'output', 'function', 'social', 'mobile', 'storage', 'analysis', 'advanced'],
logging: { console : { level : "error", audit : false } }
};
// Initialise the runtime with a server and settings
RED.init(server,settings);
// Serve the editor UI from /red
app.use(settings.httpAdminRoot, RED.httpAdmin);
// Serve the http nodes UI from /api
app.use(settings.httpNodeRoot, RED.httpNode);
server.listen(+properties.redPort);
// Start the runtime - function can be used to do work after types are loaded
RED.start().then(function () {
RED.log.info("STARTED!");
});
// Run flow configurations once flows are loaded
var EE = require('events').EventEmitter;
var logger = new EE();
RED.log.addHandler(logger);
logger.on('log', function (x) { if (x.msg === 'Starting flows') {
RED.settings.functionGlobalContext.updated = false;
// logger.removeAllListeners();
nodeAPI.putResource(device).catch(RED.log.error);
nodeAPI.putResource(pipelines).then(function () {
RED.log.info('Devices and self registred with ledger.');
RED.nodes.updateFlow('global', {
configs: [ {
id: deviceNodeID,
type: 'device',
nmos_id: device.id,
version: device.version,
nmos_label: device.label,
nmos_type: device.type,
node_id: device.node_id,
node_ref: selfNodeID
}, {
id: pipelinesNodeID,
type: 'device',
nmos_id: pipelines.id,
version: pipelines.version,
nmos_label: pipelines.label,
nmos_type: pipelines.type,
node_id: pipelines.node_id,
node_ref: selfNodeID
}, {
id: selfNodeID,
type: 'self',
nmos_id: node.id,
version: node.version,
nmos_label: node.label,
href: node.href,
hostname: node.hostname,
nodeAPI: nodeAPI
}, {
id : extDefNodeID,
type : 'rtp-ext',
name : 'rtp-extensions-default',
origin_timestamp_id : 1,
smpte_tc_id : 2,
smpte_tc_param : '3600@90000/25',
flow_id_id: 3,
source_id_id : 4,
grain_flags_id : 5,
sync_timestamp_id : 7,
grain_duration_id : 9,
ts_refclk : 'ptp=IEEE1588-2008:dd-a9-3e-5d-c7-28-28-dc'
} ],
nodes: [] }
)}
).then(function () {
RED.log.info('Global flow updated with dynamorse configurations.');
if (!RED.nodes.getFlows().some(function (x) {
return x.label === 'Dynamorse'
})) {
RED.log.info("Creating dynamorse tab.")
return RED.nodes.addFlow({
label : 'Dynamorse',
configs: [ ],
nodes: [ {
id : RED.util.generateId(),
type: 'comment',
name: 'Streampunk Media',
info: 'Design and deploy professional media workflows with [_Dynamorse_](https://github.com/Streampunk/dynamorse/blob/master/README.md).\n\n' +
'For support, development or further information, please e-mail [Streampunk Media Ltd](http://www.streampunk.media) on [furnace@streampunk.media](mailto: furnace@streampunk.media).\n\n' +
'Dynamorse depends on [codecadon](https://github.com/Streampunk/codecadon) that incorprates binaries compiled from unmodified [LGPL v3 licensed code](https://github.com/Streampunk/codecadon/tree/master/licenses) from the FFMPEG project.',
x: 122,
y: 45,
wires: []
} ]
}).then(RED.nodes.loadFlows);
} else {
RED.log.info("Dynamorse tab already in place.");
}
}).then(
function () {
RED.settings.functionGlobalContext.updated = true;
RED.log.info('Dynamorse tab checked and created if required.')
},
RED.log.error
);
}} );
// Send process memory statistics to influxDB every couple of seconds
var hostname = require('os').hostname();
var pid = process.pid;
var soc = dgram.createSocket('udp4');
setInterval(function () {
var usage = process.memoryUsage();
var message = new Buffer(`remember,host=${hostname},pid=${pid},type=rss value=${usage.rss}\n` +
`remember,host=${hostname},pid=${pid},type=heapTotal value=${usage.heapTotal}\n` +
`remember,host=${hostname},pid=${pid},type=heapUsed value=${usage.heapUsed}`);
soc.send(message, 0, message.length, 8765, '192.168.99.100');
}, 2000);