From 3d76205c809a5e08af4178e97e67182436306318 Mon Sep 17 00:00:00 2001 From: Annika Backstrom Date: Sun, 9 Apr 2017 09:41:17 -0400 Subject: [PATCH] Move child process handling into its own module --- jukebox/children.js | 73 +++++++++++++++++++++++++++++++++++++++++++++ player.js | 70 ++++++++++++++----------------------------- 2 files changed, 96 insertions(+), 47 deletions(-) create mode 100644 jukebox/children.js diff --git a/jukebox/children.js b/jukebox/children.js new file mode 100644 index 0000000..7494517 --- /dev/null +++ b/jukebox/children.js @@ -0,0 +1,73 @@ +const spawn = require('child_process').spawn; + +const EventEmitter = require('events').EventEmitter; + +const TAGREADER = 'tagreader'; +const MP3PLAYER = 'mpg321'; + +const child_processes = new Map(); + +function launchChild(name, command) { + var cmd = command[0], + args = command.slice(1); + + return spawn(cmd, args); +} + +function setupEmitter(name, emitter, child) { + exports[name] = emitter; + + child.on('error', function(err) { + emitter.emit('process_error', err); + }); + + child.on('close', function(code, signal) { + emitter.emit('close', code, signal); + }); + + child.stdout.on('data', (data) => { + var s = data.toString(), lines = s.split(/\n/g); + for (var i = 0, l = lines.length; i < l; i++) { + emitter.emit('message', lines[i]); + } + }); + + child.stderr.on('data', (data) => { + emitter.emit('error', data); + }); + + return emitter; +} + +exports.init = function(config) { + // Set up tag reader + var tagreader = launchChild(TAGREADER, config.tag_reader); + var tagreader_emitter = new EventEmitter(); + setupEmitter(TAGREADER, tagreader_emitter, tagreader); + + child_processes.set(TAGREADER, tagreader); + exports.tagreader = tagreader_emitter; + + // set up mp3 player + var mp3player = launchChild(MP3PLAYER, config.mpg321); + var mp3player_emitter = new EventEmitter(); + setupEmitter(MP3PLAYER, mp3player_emitter, mp3player); + + child_processes.set(MP3PLAYER, mp3player); + exports.mp3player = mp3player_emitter; +}; + +exports.exitHandler = function(options, err) { + console.log('[player] closing children'); + if (err) console.log(err.stack); + + child_processes.forEach((p) => { + p.kill(); + }); + + if (options.exit) { + process.exit(); + } +}; + +// vim:set ts=2 sw=2 et: diff --git a/player.js b/player.js index 9de1f6e..df8c7b9 100644 --- a/player.js +++ b/player.js @@ -2,9 +2,6 @@ const config = require('./config.json') const glob = require('glob'); -const spawn = require('child_process').spawn; -const tag_reader = spawn(config.tag_reader[0], config.tag_reader.slice(1)); -const player = spawn(config.mpg321[0], config.mpg321.slice(1)); const express = require('express'); const logger = require('morgan') @@ -12,6 +9,8 @@ const mustache = require('mustache'); const readFileSync = require('fs').readFileSync; +const children = require('./jukebox/children'); + var app = express(); var server = require('http').createServer(); @@ -28,37 +27,32 @@ mustache.parse(log_tpl); var play_log = []; -function exitHandler(options, err) { - console.log('[player] closing children'); - if (err) console.log(err.stack); - tag_reader.kill(); - player.kill(); - if (options.exit) { - process.exit(); - } +children.init(config); + +process.on('exit', children.exitHandler.bind(null)); +process.on('SIGINT', children.exitHandler.bind(null, {exit:true})); + +function setupChildLogging(name, child) { + child.on('process_error', (err) => { + console.log(`[${name}] error=${err}`); + }); + + child.on('close', (code, signal) => { + console.log(`[${name}] process closed:code=${code} signal=${signal}`); + }); + + child.on('error', (data) => { + console.log(`[${name}] stderr: ${data}`); + }); } -process.on('exit', exitHandler.bind(null)); -process.on('SIGINT', exitHandler.bind(null, {exit:true})); +setupChildLogging('tagreader', children.tagreader); +setupChildLogging('mp3player', children.mp3player); -tag_reader.on('error', function(err) { - console.log(`[tag_reader] error=${err}`); +children.tagreader.on('message', (data) => { + processLine(data); }); -player.on('error', function(err) { - console.log(`[mpg321] error=${err}`); -}); - -tag_reader.on('close', function(code, signal) { - console.log(`[tag_reader] process closed:code=${code} signal=${signal}`); -}); - -player.on('close', function(code, signal) { - console.log(`[mpg321] process closed:code=${code} signal=${signal}`); -}); - -// player.stdin.write("GAIN 100"); - var last_tag = null; var debounce_until = 0; @@ -115,24 +109,6 @@ function processLine(data) { }); } -tag_reader.stdout.on('data', (data) => { - var s = data.toString(), lines = s.split(/\n/g); - for (var i = 0, l = lines.length; i < l; i++) { - processLine(lines[i]); - } -}); - -tag_reader.stderr.on('data', (data) => { - console.log(`[tag_reader:stderr] ${data}`); -}); - -player.stderr.on('data', (data) => { - if (String(data).substr(0, 3) === "@F ") { - return; - } - console.log(`[mpg321] stderr ${data}`); -}); - app.use(logger('dev')) app.use(express.static(__dirname + '/static'))