"use strict"; const config = require('./config.json') const library = require('./jukebox/library'); const ScriptRunner = require('./jukebox/scripts')(config); const express = require('express'); const morgan = require('morgan'); const handlebars = require('express-handlebars'); const { createLogger, format, transports } = require('winston'); const { throttle } = require('throttle-debounce'); var logger = createLogger({ transports: [ new transports.Console() ] }); logger.level = config.debug ? 'debug' : 'info'; const MediaPlayer = require('./jukebox/media-player')(config, logger); const TagReader = require('./jukebox/tag-reader')(config, logger); const play_log = require('./jukebox/library/play-log'); const sqlite3 = require('sqlite3'); var db = new sqlite3.Database(config.db); const MediaLibrarySqliteBackend = require('./jukebox/library/sqlite-backend')(config, db); const MediaLibrary = new library.Library(config, MediaLibrarySqliteBackend); const PlayLog = new play_log.PlayLog(); var app = express(); var server = require('http').createServer(); const WebSocket = require('ws'); const WebSocketServer = WebSocket.Server; var wss = new WebSocketServer({server: server}); function exitHandler(options, err) { logger.debug('closing child tasks'); if (err) logger.debug(err.stack); // FIXME When do we actually need to call this? Adding these seems // to have fixed a problem with orphaned children, but not we get // two sets of "closing child tasks" messages when we shut down. TagReader.kill(); MediaPlayer.kill(); if (options.exit) { process.exit(); } }; process.on('exit', exitHandler.bind(null)); process.on('SIGINT', exitHandler.bind(null, {exit:true})); process.on('SIGUSR2', exitHandler.bind(null, {exit:true})); const throttledTag = throttle(config.global_throttle, true, tag => { ScriptRunner.find(tag).then((fulfilled) => { if (false === fulfilled) { MediaLibrary.find(tag) } }).catch(err => { logger.error("got an error handling the tag: " + err); }); }); TagReader.on('message', tag => { if (tag == 'E1' || tag == 'E2') { logger.debug("tagreader had rfid read error", { tag: tag }); return; } logger.debug("got tag from tagreader", { tag: tag }); throttledTag(tag); }); if (config.debug) { MediaPlayer.on('message', line => { logger.debug("mediaplayer sent message", { line: line }); }); } MediaPlayer.on('command', tag => { PlayLog.updateLog(tag); }); var hbs = handlebars.create({ extname: ".hbs", }); MediaLibrary.on('action', MediaPlayer.handleTag.bind(MediaPlayer)); app.engine(".hbs", hbs.engine); app.set('view engine', '.hbs'); app.set('views', __dirname + '/views'); app.use(morgan('dev')) app.use(express.static(__dirname + '/static')) PlayLog.on('update', tag => { app.render("log", { layout: false, play_log: PlayLog.getLog(), }, (err, html) => { var data = { html: html, tag: tag.tag }; wss.broadcast(JSON.stringify(data)); }); }); app.get('/', function (req, res, next) { res.render('index', { last_tag: PlayLog.getLastTag(), config: config, play_log: PlayLog.getLog(), }); }); app.get('/library', function (req, res, next) { db.all("SELECT * FROM tags", (err, rows) => { var content = views.library.render({ rows: rows, config: config, }); var html = views.base.render({ title: 'Library', content: content, }); res.send(html); }); }); wss.broadcast = function broadcast(data) { wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { client.send(data); } }); }; wss.on('connection', function (ws) { logger.info('websocket client connected'); ws.on('close', function () { logger.info('websocket client disconnected'); }); }); server.on('request', app); server.listen(config.port, function () { logger.info('express listening on http://localhost:' + config.port) }) // vim:ts=2 sw=2 et: