diff --git a/core/listening_server.js b/core/listening_server.js index 8743d6ce..aa573fa1 100644 --- a/core/listening_server.js +++ b/core/listening_server.js @@ -2,11 +2,10 @@ 'use strict'; // ENiGMA½ -const logger = require('./logger.js'); -const { ErrorReasons } = require('./enig_error.js'); +const logger = require('./logger.js'); // deps -const async = require('async'); +const async = require('async'); const listeningServers = {}; // packageName -> info @@ -34,15 +33,22 @@ function startListening(cb) { const moduleInst = new module.getModule(); try { moduleInst.createServer(err => { - if(!moduleInst.listen()) { - throw new Error('Failed listening'); + if(err) { + return nextModule(err); } - listeningServers[module.moduleInfo.packageName] = { - instance : moduleInst, - info : module.moduleInfo, - }; - return nextModule(err); + moduleInst.listen( err => { + if(err) { + return nextModule(err); + } + + listeningServers[module.moduleInfo.packageName] = { + instance : moduleInst, + info : module.moduleInfo, + }; + + return nextModule(null); + }); }); } catch(e) { logger.log.error(e, 'Exception caught creating server!'); diff --git a/core/servers/content/gopher.js b/core/servers/content/gopher.js index 7553793e..ee889b8c 100644 --- a/core/servers/content/gopher.js +++ b/core/servers/content/gopher.js @@ -5,6 +5,7 @@ const Log = require('../../logger.js').log; const { ServerModule } = require('../../server_module.js'); const Config = require('../../config.js').get; +const { Errors } = require('../../enig_error.js'); const { splitTextAtTerms, isAnsi, @@ -100,19 +101,19 @@ exports.getModule = class GopherModule extends ServerModule { return cb(null); } - listen() { + listen(cb) { if(!this.enabled) { - return true; // nothing to do, but not an error + return cb(null); } const config = Config(); const port = parseInt(config.contentServers.gopher.port); if(isNaN(port)) { this.log.warn( { port : config.contentServers.gopher.port, server : ModuleInfo.name }, 'Invalid port' ); - return false; + return cb(Errors.Invalid(`Invalid port: ${config.contentServers.gopher.port}`)); } - return this.server.listen(port); + return this.server.listen(port, cb); } get enabled() { diff --git a/core/servers/content/nntp.js b/core/servers/content/nntp.js index 7f20cba7..41dda2e8 100644 --- a/core/servers/content/nntp.js +++ b/core/servers/content/nntp.js @@ -918,21 +918,26 @@ exports.getModule = class NNTPServerModule extends ServerModule { }); } - listen() { + listen(cb) { const config = Config(); - [ 'nntp', 'nntps' ].forEach( service => { + forEachSeries([ 'nntp', 'nntps' ], (service, nextService) => { const server = this[`${service}Server`]; if(server) { const port = config.contentServers.nntp[service].port; server.listen(this.listenURI(port, service)) .catch(e => { Log.warn( { error : e.message, port }, `${service.toUpperCase()} failed to listen`); + return nextService(null); // try next anyway + }).then( () => { + return nextService(null); }); + } else { + return nextService(null); } + }, + err => { + return cb(err); }); - - // :TODO: listen() needs to be async. I always should have been... - return true; } listenURI(port, service = 'nntp') { diff --git a/core/servers/content/web.js b/core/servers/content/web.js index f0e0d903..1a09aace 100644 --- a/core/servers/content/web.js +++ b/core/servers/content/web.js @@ -5,6 +5,7 @@ const Log = require('../../logger.js').log; const ServerModule = require('../../server_module.js').ServerModule; const Config = require('../../config.js').get; +const { Errors } = require('../../enig_error.js'); // deps const http = require('http'); @@ -13,6 +14,7 @@ const _ = require('lodash'); const fs = require('graceful-fs'); const paths = require('path'); const mimeTypes = require('mime-types'); +const forEachSeries = require('async/forEachSeries'); const ModuleInfo = exports.moduleInfo = { name : 'Web', @@ -125,23 +127,27 @@ exports.getModule = class WebServerModule extends ServerModule { return cb(null); } - listen() { - let ok = true; - + listen(cb) { const config = Config(); - [ 'http', 'https' ].forEach(service => { + forEachSeries([ 'http', 'https' ], (service, nextService) => { const name = `${service}Server`; if(this[name]) { const port = parseInt(config.contentServers.web[service].port); if(isNaN(port)) { - ok = false; - return Log.warn( { port : config.contentServers.web[service].port, server : ModuleInfo.name }, `Invalid port (${service})` ); + Log.warn( { port : config.contentServers.web[service].port, server : ModuleInfo.name }, `Invalid port (${service})` ); + return nextService(Errors.Invalid(`Invalid port: ${config.contentServers.web[service].port}`)); } - return this[name].listen(port); - } - }); - return ok; + this[name].listen(port, err => { + return nextService(err); + }); + } else { + return nextService(null); + } + }, + err => { + return cb(err); + }); } addRoute(route) { diff --git a/core/servers/login/ssh.js b/core/servers/login/ssh.js index 263a3929..d67bbafa 100644 --- a/core/servers/login/ssh.js +++ b/core/servers/login/ssh.js @@ -322,20 +322,23 @@ exports.getModule = class SSHServerModule extends LoginServerModule { return cb(null); } - listen() { + listen(cb) { const config = Config(); if(true != config.loginServers.ssh.enabled) { - return true; // no server, but not an error + return cb(null); } const port = parseInt(config.loginServers.ssh.port); if(isNaN(port)) { Log.error( { server : ModuleInfo.name, port : config.loginServers.ssh.port }, 'Cannot load server (invalid port)' ); - return false; + return cb(Errors.Invalid(`Invalid port: ${config.loginServers.ssh.port}`)); } - this.server.listen(port); - Log.info( { server : ModuleInfo.name, port : port }, 'Listening for connections' ); - return true; + this.server.listen(port, err => { + if(!err) { + Log.info( { server : ModuleInfo.name, port : port }, 'Listening for connections' ); + } + return cb(err); + }); } }; diff --git a/core/servers/login/telnet.js b/core/servers/login/telnet.js index ae1ecbe9..ff21b602 100644 --- a/core/servers/login/telnet.js +++ b/core/servers/login/telnet.js @@ -8,6 +8,7 @@ const LoginServerModule = require('../../login_server_module.js'); const Config = require('../../config.js').get; const EnigAssert = require('../../enigma_assert.js'); const { stringFromNullTermBuffer } = require('../../string_util.js'); +const { Errors } = require('../../enig_error.js'); // deps const net = require('net'); @@ -880,16 +881,19 @@ exports.getModule = class TelnetServerModule extends LoginServerModule { return cb(null); } - listen() { + listen(cb) { const config = Config(); const port = parseInt(config.loginServers.telnet.port); if(isNaN(port)) { Log.error( { server : ModuleInfo.name, port : config.loginServers.telnet.port }, 'Cannot load server (invalid port)' ); - return false; + return cb(Errors.Invalid(`Invalid port: ${config.loginServers.telnet.port}`)); } - this.server.listen(port); - Log.info( { server : ModuleInfo.name, port : port }, 'Listening for connections' ); - return true; + this.server.listen(port, err => { + if(!err) { + Log.info( { server : ModuleInfo.name, port : port }, 'Listening for connections' ); + } + return cb(err); + }); } }; diff --git a/core/servers/login/websocket.js b/core/servers/login/websocket.js index b27aaf6d..35bc0757 100644 --- a/core/servers/login/websocket.js +++ b/core/servers/login/websocket.js @@ -6,6 +6,7 @@ const Config = require('../../config.js').get; const TelnetClient = require('./telnet.js').TelnetClient; const Log = require('../../logger.js').log; const LoginServerModule = require('../../login_server_module.js'); +const { Errors } = require('../../enig_error.js'); // deps const _ = require('lodash'); @@ -14,6 +15,7 @@ const http = require('http'); const https = require('https'); const fs = require('graceful-fs'); const Writable = require('stream'); +const forEachSeries = require('async/forEachSeries'); const ModuleInfo = exports.moduleInfo = { name : 'WebSocket', @@ -165,31 +167,7 @@ exports.getModule = class WebSocketLoginServer extends LoginServerModule { return cb(null); } - listen() { - WSS_SERVER_TYPES.forEach(serverType => { - const server = this[serverType]; - if(!server) { - return; - } - - const serverName = `${ModuleInfo.name} (${serverType})`; - const port = parseInt(_.get(Config(), [ 'loginServers', 'webSocket', 'secure' === serverType ? 'wss' : 'ws', 'port' ] )); - - if(isNaN(port)) { - Log.error( { server : serverName, port : port }, 'Cannot load server (invalid port)' ); - return; - } - - server.httpServer.listen(port); - - server.wsServer.on('connection', (ws, req) => { - const webSocketClient = new WebSocketClient(ws, req, serverType); - this.handleNewClient(webSocketClient, webSocketClient.socketBridge, ModuleInfo); - }); - - Log.info( { server : serverName, port : port }, 'Listening for connections' ); - }); - + listen(cb) { // // Send pings every 30s // @@ -215,7 +193,38 @@ exports.getModule = class WebSocketLoginServer extends LoginServerModule { }); }, 30000); - return true; + forEachSeries(WSS_SERVER_TYPES, (serverType, nextServerType) => { + const server = this[serverType]; + if(!server) { + return nextServerType(null); + } + + const serverName = `${ModuleInfo.name} (${serverType})`; + const confPort = _.get(Config(), [ 'loginServers', 'webSocket', 'secure' === serverType ? 'wss' : 'ws', 'port' ] ); + const port = parseInt(confPort); + + if(isNaN(port)) { + Log.error( { server : serverName, port : confPort }, 'Cannot load server (invalid port)' ); + return nextServerType(Errors.Invalid(`Invalid port: ${confPort}`)); + } + + server.httpServer.listen(port, err => { + if(err) { + return nextServerType(err); + } + + server.wsServer.on('connection', (ws, req) => { + const webSocketClient = new WebSocketClient(ws, req, serverType); + this.handleNewClient(webSocketClient, webSocketClient.socketBridge, ModuleInfo); + }); + + Log.info( { server : serverName, port : port }, 'Listening for connections' ); + return nextServerType(null); + }); + }, + err => { + cb(err); + }); } webSocketConnection(conn) {