2021-03-26 21:31:32 +01:00
|
|
|
const yargs = require('yargs');
|
|
|
|
const path = require('path');
|
2018-08-09 21:20:30 +02:00
|
|
|
const udp = require('dgram');
|
|
|
|
const server = udp.createSocket('udp4');
|
|
|
|
const http = require('http');
|
2021-03-26 21:31:32 +01:00
|
|
|
const YamahaYXC = require('yamaha-yxc-nodejs');
|
2018-08-09 21:20:30 +02:00
|
|
|
|
2021-03-24 22:40:49 +01:00
|
|
|
const LOCAL_IP = process.env.LOCAL_IP || "0.0.0.0";
|
2018-08-09 21:20:30 +02:00
|
|
|
const INCOMING_EVENT_SERVER_PORT = parseInt(process.env.PORT) || 41100;
|
|
|
|
|
2021-03-24 22:40:49 +01:00
|
|
|
const send = (host, path, headers) =>
|
2018-08-09 21:20:30 +02:00
|
|
|
http
|
|
|
|
.get(
|
|
|
|
{
|
|
|
|
localAddress: LOCAL_IP,
|
2021-03-24 22:40:49 +01:00
|
|
|
host: host,
|
2018-08-09 21:20:30 +02:00
|
|
|
path,
|
|
|
|
timeout: 3000,
|
|
|
|
headers: {
|
|
|
|
'User-Agent': 'yamaha-sound-program-by-source',
|
|
|
|
Accept: 'application/vnd.musiccast.v1+json',
|
|
|
|
...headers
|
|
|
|
}
|
|
|
|
},
|
|
|
|
resp => {
|
|
|
|
let data = '';
|
|
|
|
|
|
|
|
resp.on('data', chunk => {
|
|
|
|
data += chunk;
|
|
|
|
});
|
|
|
|
|
|
|
|
resp.on('end', () => {
|
|
|
|
// console.log(data);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
)
|
|
|
|
.on('error', err => {
|
2021-03-27 22:16:07 +01:00
|
|
|
console.error('Error on send(',host,path,headers,') :', err.message);
|
2018-08-09 21:20:30 +02:00
|
|
|
});
|
|
|
|
|
2021-03-27 22:16:07 +01:00
|
|
|
const sendEventServerAddress = (hostname,port) => {
|
|
|
|
console.debug("sendEventServerAddress",hostname,port);
|
|
|
|
send(hostname,
|
|
|
|
'/YamahaExtendedControl/v1', {
|
|
|
|
'X-AppName': 'MusicCast/1',
|
|
|
|
'X-AppPort': port
|
|
|
|
}
|
|
|
|
);
|
|
|
|
};
|
2018-08-09 21:20:30 +02:00
|
|
|
|
|
|
|
|
|
|
|
server.on('close', () => {
|
|
|
|
console.log('Server is closed!');
|
2021-03-26 21:31:32 +01:00
|
|
|
// TODO ? Notify the device not to send events anymore ?
|
2018-08-09 21:20:30 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
server.on('error', error => {
|
2021-03-27 22:16:07 +01:00
|
|
|
console.error('Socket error (',host,path,headers,') :', error);
|
2018-08-09 21:20:30 +02:00
|
|
|
server.close();
|
|
|
|
});
|
|
|
|
|
|
|
|
server.on('message', (msg, _info) => {
|
|
|
|
let body = '';
|
|
|
|
|
|
|
|
try {
|
|
|
|
body = JSON.parse(msg.toString('utf8'));
|
2021-03-26 21:31:32 +01:00
|
|
|
// console.log(body);
|
2018-08-09 21:20:30 +02:00
|
|
|
} catch (err) {
|
|
|
|
console.warn('Could not parse event', msg.toString());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-26 21:31:32 +01:00
|
|
|
// Runs each scenario on this event
|
|
|
|
for ( s=0 ; s<scenarii.length ; s++ ) {
|
|
|
|
scenarii[s].handler.onEvent(body);
|
|
|
|
}
|
2018-08-09 21:20:30 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
server.on('listening', () => {
|
|
|
|
const address = server.address();
|
|
|
|
const port = address.port;
|
|
|
|
const ipaddr = address.address;
|
|
|
|
|
|
|
|
console.log(
|
|
|
|
'Incoming event server is listening at port',
|
|
|
|
ipaddr + ':' + port
|
|
|
|
);
|
|
|
|
|
2021-03-26 21:31:32 +01:00
|
|
|
// Register at each configured 'source'
|
|
|
|
var sourcesDict = {};
|
|
|
|
for ( s=0 ; s<scenarii.length ; s++ ) {
|
|
|
|
var scenario = scenarii[s];
|
|
|
|
if ( scenario.conf && typeof scenario.conf !== 'undefined' &&
|
|
|
|
scenario.conf.source && typeof scenario.conf.source !== 'undefined' ) {
|
|
|
|
sourcesDict[scenario.conf.source] = true;
|
|
|
|
}
|
|
|
|
}
|
2021-03-27 22:16:07 +01:00
|
|
|
var sourcesList = Object.keys(sourcesDict);
|
|
|
|
for ( var s=0 ; s<sourcesList.length ; s++ ) {
|
|
|
|
var source = sourcesList[s];
|
|
|
|
console.log("Registering with port",port,"at ",source);
|
|
|
|
sendEventServerAddress(source,port);
|
2021-03-26 21:31:32 +01:00
|
|
|
|
|
|
|
// After 10 minutes the receiver will drop this server to be notified unless we
|
|
|
|
// say hi again, so to be on the safe side, ask again every 5 minutes.
|
2021-03-27 22:16:07 +01:00
|
|
|
setInterval(() => sendEventServerAddress(source,port), 5 * 60 * 1000);
|
2021-03-26 21:31:32 +01:00
|
|
|
}
|
2018-08-09 21:20:30 +02:00
|
|
|
});
|
|
|
|
|
2021-03-26 21:31:32 +01:00
|
|
|
// Command line parsing
|
|
|
|
const argv = yargs
|
|
|
|
.option('s', {
|
|
|
|
alias: ['scripts'],
|
|
|
|
describe: 'Load these .js files each implementing a scenario',
|
|
|
|
requiresArg: true,
|
|
|
|
type: 'array',
|
|
|
|
demandOption: true
|
|
|
|
})
|
|
|
|
// Configuration as a whole .json file
|
|
|
|
.config()
|
|
|
|
.help()
|
|
|
|
.alias('help', 'h')
|
|
|
|
.argv;
|
|
|
|
console.log("argv:", argv);
|
|
|
|
|
|
|
|
// Instanciates the handlers for each scenario
|
|
|
|
var scenarii = [];
|
|
|
|
const scripts = argv.scripts;
|
|
|
|
for ( var s=0 ; s<scripts.length ; s++ ) {
|
|
|
|
var scenarioModule = scripts[s];
|
|
|
|
|
|
|
|
console.log("Loading scenario :", scenarioModule);
|
|
|
|
var scenarioClass = require(scenarioModule);
|
|
|
|
|
|
|
|
var scenarioName = path.basename(scenarioModule, path.extname(scenarioModule));
|
|
|
|
console.log("Scenario name :", scenarioName);
|
|
|
|
var conf = Object.assign({}, argv, argv.conf[scenarioName]);
|
|
|
|
console.log("Scenario conf. :", conf);
|
|
|
|
|
|
|
|
scenarii.push({
|
|
|
|
name: scenarioName,
|
|
|
|
conf: conf,
|
|
|
|
handler: new scenarioClass(conf)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
console.log("Scenarii :", scenarii);
|
|
|
|
|
|
|
|
|
2018-08-09 21:20:30 +02:00
|
|
|
server.bind(INCOMING_EVENT_SERVER_PORT, LOCAL_IP);
|