From 8a22874ce4635b6ab5f16f31f8c0672fc64d6be2 Mon Sep 17 00:00:00 2001 From: Olivier Penhoat Date: Fri, 29 Jul 2016 14:22:28 +0200 Subject: [PATCH 1/3] allow to use main without shell script --- bin/naught | 3 +++ lib/main.js | 2 -- package.json | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100755 bin/naught diff --git a/bin/naught b/bin/naught new file mode 100755 index 0000000..fd7bdad --- /dev/null +++ b/bin/naught @@ -0,0 +1,3 @@ +#!/usr/bin/env node + +require('../lib/main'); diff --git a/lib/main.js b/lib/main.js index d686bed..df9ed9b 100755 --- a/lib/main.js +++ b/lib/main.js @@ -1,5 +1,3 @@ -#!/usr/bin/env node - var fs = require('fs'); var os = require('os'); var net = require('net'); diff --git a/package.json b/package.json index 93dc535..53e5626 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "test": "node test/test.js" }, "bin": { - "naught": "./lib/main.js" + "naught": "./bin/naught" }, "repository": { "type": "git", From 7f489f103a8839e65f3cb031982ad969ce132f3b Mon Sep 17 00:00:00 2001 From: Olivier Penhoat Date: Fri, 29 Jul 2016 15:23:29 +0200 Subject: [PATCH 2/3] allow to use main without shell script --- lib/main.js | 290 ++---------------------------------------------- lib/naught.js | 298 ++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 +- 3 files changed, 309 insertions(+), 282 deletions(-) create mode 100755 lib/naught.js diff --git a/lib/main.js b/lib/main.js index df9ed9b..b7fc42d 100755 --- a/lib/main.js +++ b/lib/main.js @@ -3,12 +3,12 @@ var os = require('os'); var net = require('net'); var assert = require('assert'); var json_socket = require('./json_socket'); -var spawn = require('child_process').spawn; var path = require('path'); var DEFAULT_IPC_FILE = 'naught.ipc'; var DEFAULT_PID_FILE = 'naught.pid'; var CWD = process.cwd(); var daemon = require('./daemon'); +var naught = require('./naught'); var packageJson = require('../package.json'); var cmds = { @@ -64,7 +64,7 @@ var cmds = { 'cwd': CWD, 'daemon-mode': 'true', 'remove-old-ipc': 'false', - 'node-args': '', + 'node-args': '' }; var arr = chompArgv(options, argv) , err = arr[0] @@ -76,7 +76,7 @@ var cmds = { if (isNaN(options['worker-count'])) return false; options['max-log-size'] = parseInt(options['max-log-size'], 10); if (isNaN(options['max-log-size'])) return false; - startScript(options, script, argv); + naught.start(options, script, argv); return true; } else { return false; @@ -112,7 +112,7 @@ var cmds = { if (isNaN(options.timeout)) { options.timeout = null; } - stopScript(options, ipcFile); + naught.stop(options, ipcFile); return true; } else { return false; @@ -128,7 +128,7 @@ var cmds = { return false; } var ipcFile = argv[0] || DEFAULT_IPC_FILE; - displayStatus(ipcFile); + naught.status(ipcFile); return true; } }, @@ -198,7 +198,7 @@ var cmds = { options['worker-count'] = parseInt(options['worker-count'], 10); if (isNaN(options['worker-count'])) return false; - deploy(options, ipcFile); + naught.deploy(options, ipcFile); return true; } else { return false; @@ -220,7 +220,7 @@ var cmds = { fn: function(argv){ if (argv.length > 1) return false; var ipcFile = argv[0] || DEFAULT_IPC_FILE; - deployAbort(ipcFile); + naught.deployAbort(ipcFile); return true; } }, @@ -234,7 +234,7 @@ var cmds = { console.log(packageJson.version); return true; } - }, + } }, help: { help: "naught help [cmd]\n\n" + @@ -252,7 +252,7 @@ var cmds = { } }; -var cmd = cmds[process.argv[2]] +var cmd = cmds[process.argv[2]]; if (cmd) { if (!cmd.fn(process.argv.slice(3))) { console.error(cmd.help); @@ -287,12 +287,6 @@ function connectToDaemon(socket_path, cbs){ return socket; } -function assertErrorIsFromInvalidSocket(error){ - if (error.code !== 'ENOENT') { - throw error; - } -} - function exitWithConnRefusedMsg(socket_path){ fs.writeSync(process.stderr.fd, "unable to connect to ipc-file `" + socket_path + "`\n\n" + @@ -301,28 +295,6 @@ function exitWithConnRefusedMsg(socket_path){ process.exit(1); } -function getDaemonMessages(socket_path, cbs){ - var socket = connectToDaemon(socket_path, cbs); - socket.on('error', function(error){ - if (error.code === 'ENOENT') { - fs.writeSync(process.stderr.fd, "server not running\n"); - if(cbs.serverNotRunning) { - // Caller wants to handle the condition of server not running, - // so let them do it. - cbs.serverNotRunning(); - } else { - // Caller isn't prepared to deal with server not running, so die. - process.exit(1); - } - } else if (error.code === 'ECONNREFUSED') { - exitWithConnRefusedMsg(socket_path); - } else { - throw error; - } - }); - return socket; -} - function printUsage(){ for (var name in cmds) { var cmd = cmds[name]; @@ -330,250 +302,6 @@ function printUsage(){ } } -function startScript(options, script, argv){ - var ipcFile = options['ipc-file']; - var socket = connectToDaemon(ipcFile, { - ready: function(){ - json_socket.send(socket, { - action: 'NaughtStatus' - }); - }, - event: function(msg){ - if (msg.event === 'Status') { - fs.writeSync(process.stdout.fd, statusMsg(msg)); - process.exit(1); - } else { - printDaemonMsg(msg); - } - } - }); - socket.on('error', onSocketError); - - function onSocketError(error) { - socket.end(); - if (error.code === 'ECONNREFUSED') { - if(options['remove-old-ipc']) { - fs.writeSync(process.stderr.fd, - "unable to connect to ipc-file `" + ipcFile + "`\n\n" + - "removing the ipc-file and attempting to continue\n"); - fs.unlinkSync(ipcFile); - startDaemon(); - } else { - exitWithConnRefusedMsg(ipcFile); - } - } else if (error.code === 'ENOENT') { - // no server running - startDaemon(); - } else { - throw error; - } - } - - function startDaemon(){ - var args = [ - options['worker-count'], - path.resolve(CWD, ipcFile), - resolveLogPath(options.log), - resolveLogPath(options.stderr), - resolveLogPath(options.stdout), - options['max-log-size'], - path.resolve(CWD, script), - options['node-args'], - options['pid-file'] - ].concat(argv); - if (options['daemon-mode']) { - startDaemonChild(args); - } else { - startBlockingMaster(args); - } - } - - function startBlockingMaster(args) { - daemon.start(args); - } - - function startDaemonChild(args) { - var modulePath = path.resolve(__dirname, "start_daemon.js"); - var child = spawn(process.execPath, [modulePath].concat(args), { - env: process.env, - stdio: ['ignore', 'ignore', 'ignore', 'ipc'], - detached: true, - cwd: options.cwd, - }); - child.unref(); - child.on('message', function(msg){ - if (msg.event === 'Error') { - fs.writeSync(process.stderr.fd, - "unable to start daemon: " + msg.value + "\n"); - process.exit(1); - } else if (msg.event === 'IpcListening') { - child.disconnect(); - var sentShutdown = false; - var socket = connectToDaemon(ipcFile, { - event: function(msg){ - if (msg.event === 'Ready') { - process.stdout.write(statusMsg(msg)); - socket.end(); - } else if (msg.event === 'Shutdown') { - console.error("The server crashed without booting. Check stderr.log."); - socket.end(); - process.exit(1); - } else { - printDaemonMsg(msg); - } - } - }); - } else { - throw new Error("unexpected message from daemon"); - } - }); - } -} - -function resolveLogPath(logPath) { - if (logPath === '-') { - return '-'; - } else { - return path.resolve(CWD, logPath); - } -} - -function stopScript(options, ipcFile){ - var socket = getDaemonMessages(ipcFile, { - ready: function(){ - json_socket.send(socket, { - action: 'NaughtShutdown', - timeout: options.timeout - }); - }, - event: function(msg){ - if (msg.event === 'Shutdown') { - socket.end(); - } else if (msg.event === 'AlreadyShuttingDown') { - console.error("Waiting for shutdown already in progress."); - console.error("If it hangs, Ctrl+C this command and try it again with --timeout 1"); - } else { - printDaemonMsg(msg); - } - }, - serverNotRunning: function() { - // The server isn't running. - // Who cares, we're trying to stop it anyway, this is not an error. - } - }); -} - -function workerCountsFromMsg(msg){ - if (!msg.count) return "Unknown"; - return "booting: " + msg.count.booting + - ", online: " + msg.count.online + - ", dying: " + msg.count.dying + - ", new_online: " + msg.count.new_online; -} - -function printDaemonMsg(msg){ - console.error(msg.event + ". " + workerCountsFromMsg(msg)); -} - -function statusMsg(msg){ - if (msg.count.booting > 0) { - return "booting\n" + workerCountsFromMsg(msg) + "\n"; - } else if (msg.waiting_for === 'shutdown') { - return "shutting down\n" + workerCountsFromMsg(msg) + "\n"; - } else if (msg.waiting_for != null) { - return "deploy in progress\n" + workerCountsFromMsg(msg) + "\n"; - } else { - return "workers online: " + msg.count.online + "\n"; - } -} - -function deploy(options, ipcFile){ - var socket = getDaemonMessages(ipcFile, { - ready: function(){ - setAbortKeyboardHook(); - json_socket.send(socket, { - action: 'NaughtDeploy', - newWorkerCount: options['worker-count'], - environment: options['override-env'] ? process.env : {}, - timeout: options.timeout, - cwd: path.resolve(options.cwd) - }); - }, - event: function(msg){ - switch (msg.event) { - case 'ErrorDeployInProgress': - console.error("Deploy already in progress. Press Ctrl+C to abort."); - break; - case 'Shutdown': - console.error("Bootup never succeeded. Check stderr.log and usage of 'online' and 'shutdown' events."); - process.exit(1); - break; - case 'DeployFailed': - console.log("Deploy failed. Check stderr.log and usage of 'online' and 'shutdown' events."); - process.exit(1); - break; - case 'Ready': - console.error("done"); - process.exit(0); - break; - default: - printDaemonMsg(msg); - } - } - }); - function setAbortKeyboardHook(){ - process.once('SIGINT', handleSigInt); - } - function handleSigInt(){ - console.error("aborting deploy"); - json_socket.send(socket, { - action: 'NaughtDeployAbort' - }); - } -} - -function deployAbort(ipcFile){ - var socket = getDaemonMessages(ipcFile, { - ready: function(){ - json_socket.send(socket, { - action: 'NaughtDeployAbort' - }); - }, - event: function(msg){ - switch (msg.event) { - case 'ErrorNoDeployInProgress': - console.error("no deploy in progress"); - process.exit(1); - break; - case 'Ready': - console.error("deploy aborted"); - process.exit(0); - break; - default: - printDaemonMsg(msg); - } - } - }); -} - -function displayStatus(ipcFile){ - var socket = getDaemonMessages(ipcFile, { - ready: function(){ - json_socket.send(socket, { - action: 'NaughtStatus' - }); - }, - event: function(msg){ - if (msg.event === 'Status') { - process.stdout.write(statusMsg(msg)); - socket.end(); - } else { - printDaemonMsg(msg); - } - } - }); -} - function extendedWorkerCount(workerCount){ if (workerCount === 'auto'){ return os.cpus().length; diff --git a/lib/naught.js b/lib/naught.js new file mode 100755 index 0000000..07d91cb --- /dev/null +++ b/lib/naught.js @@ -0,0 +1,298 @@ +var fs = require('fs'); +var os = require('os'); +var net = require('net'); +var assert = require('assert'); +var json_socket = require('./json_socket'); +var spawn = require('child_process').spawn; +var path = require('path'); +var CWD = process.cwd(); +var daemon = require('./daemon'); + +var naught={ + start: startScript, + stop: stopScript, + status: displayStatus, + deploy: deploy, + deployAbort: deployAbort +}; + +function connectToDaemon(socket_path, cbs){ + var socket = net.connect(socket_path, cbs.ready); + json_socket.listen(socket, cbs.event); + return socket; +} + +function exitWithConnRefusedMsg(socket_path){ + fs.writeSync(process.stderr.fd, + "unable to connect to ipc-file `" + socket_path + "`\n\n" + + "1. the ipc file specified is invalid, or\n" + + "2. the daemon process died unexpectedly\n"); + process.exit(1); +} + +function getDaemonMessages(socket_path, cbs){ + var socket = connectToDaemon(socket_path, cbs); + socket.on('error', function(error){ + if (error.code === 'ENOENT') { + fs.writeSync(process.stderr.fd, "server not running\n"); + if(cbs.serverNotRunning) { + // Caller wants to handle the condition of server not running, + // so let them do it. + cbs.serverNotRunning(); + } else { + // Caller isn't prepared to deal with server not running, so die. + process.exit(1); + } + } else if (error.code === 'ECONNREFUSED') { + exitWithConnRefusedMsg(socket_path); + } else { + throw error; + } + }); + return socket; +} + +function startScript(options, script, argv){ + var ipcFile = options['ipc-file']; + var socket = connectToDaemon(ipcFile, { + ready: function(){ + json_socket.send(socket, { + action: 'NaughtStatus' + }); + }, + event: function(msg){ + if (msg.event === 'Status') { + fs.writeSync(process.stdout.fd, statusMsg(msg)); + process.exit(1); + } else { + printDaemonMsg(msg); + } + } + }); + socket.on('error', onSocketError); + + function onSocketError(error) { + socket.end(); + if (error.code === 'ECONNREFUSED') { + if(options['remove-old-ipc']) { + fs.writeSync(process.stderr.fd, + "unable to connect to ipc-file `" + ipcFile + "`\n\n" + + "removing the ipc-file and attempting to continue\n"); + fs.unlinkSync(ipcFile); + startDaemon(); + } else { + exitWithConnRefusedMsg(ipcFile); + } + } else if (error.code === 'ENOENT') { + // no server running + startDaemon(); + } else { + throw error; + } + } + + function startDaemon(){ + var args = [ + options['worker-count'], + path.resolve(CWD, ipcFile), + resolveLogPath(options.log), + resolveLogPath(options.stderr), + resolveLogPath(options.stdout), + options['max-log-size'], + path.resolve(CWD, script), + options['node-args'], + options['pid-file'] + ].concat(argv); + if (options['daemon-mode']) { + startDaemonChild(args); + } else { + startBlockingMaster(args); + } + } + + function startBlockingMaster(args) { + daemon.start(args); + } + + function startDaemonChild(args) { + var modulePath = path.resolve(__dirname, "start_daemon.js"); + var child = spawn(process.execPath, [modulePath].concat(args), { + env: process.env, + stdio: ['ignore', 'ignore', 'ignore', 'ipc'], + detached: true, + cwd: options.cwd + }); + child.unref(); + child.on('message', function(msg){ + if (msg.event === 'Error') { + fs.writeSync(process.stderr.fd, + "unable to start daemon: " + msg.value + "\n"); + process.exit(1); + } else if (msg.event === 'IpcListening') { + child.disconnect(); + var socket = connectToDaemon(ipcFile, { + event: function(msg){ + if (msg.event === 'Ready') { + process.stdout.write(statusMsg(msg)); + socket.end(); + } else if (msg.event === 'Shutdown') { + console.error("The server crashed without booting. Check stderr.log."); + socket.end(); + process.exit(1); + } else { + printDaemonMsg(msg); + } + } + }); + } else { + throw new Error("unexpected message from daemon"); + } + }); + } +} + +function resolveLogPath(logPath) { + if (logPath === '-') { + return '-'; + } else { + return path.resolve(CWD, logPath); + } +} + +function stopScript(options, ipcFile){ + var socket = getDaemonMessages(ipcFile, { + ready: function(){ + json_socket.send(socket, { + action: 'NaughtShutdown', + timeout: options.timeout + }); + }, + event: function(msg){ + if (msg.event === 'Shutdown') { + socket.end(); + } else if (msg.event === 'AlreadyShuttingDown') { + console.error("Waiting for shutdown already in progress."); + console.error("If it hangs, Ctrl+C this command and try it again with --timeout 1"); + } else { + printDaemonMsg(msg); + } + }, + serverNotRunning: function() { + // The server isn't running. + // Who cares, we're trying to stop it anyway, this is not an error. + } + }); +} + +function workerCountsFromMsg(msg){ + if (!msg.count) return "Unknown"; + return "booting: " + msg.count.booting + + ", online: " + msg.count.online + + ", dying: " + msg.count.dying + + ", new_online: " + msg.count.new_online; +} + +function printDaemonMsg(msg){ + console.error(msg.event + ". " + workerCountsFromMsg(msg)); +} + +function statusMsg(msg){ + if (msg.count.booting > 0) { + return "booting\n" + workerCountsFromMsg(msg) + "\n"; + } else if (msg['waiting_for'] === 'shutdown') { + return "shutting down\n" + workerCountsFromMsg(msg) + "\n"; + } else if (msg['waiting_for'] != null) { + return "deploy in progress\n" + workerCountsFromMsg(msg) + "\n"; + } else { + return "workers online: " + msg.count.online + "\n"; + } +} + +function deploy(options, ipcFile){ + var socket = getDaemonMessages(ipcFile, { + ready: function(){ + setAbortKeyboardHook(); + json_socket.send(socket, { + action: 'NaughtDeploy', + newWorkerCount: options['worker-count'], + environment: options['override-env'] ? process.env : {}, + timeout: options.timeout, + cwd: path.resolve(options.cwd) + }); + }, + event: function(msg){ + switch (msg.event) { + case 'ErrorDeployInProgress': + console.error("Deploy already in progress. Press Ctrl+C to abort."); + break; + case 'Shutdown': + console.error("Bootup never succeeded. Check stderr.log and usage of 'online' and 'shutdown' events."); + process.exit(1); + break; + case 'DeployFailed': + console.log("Deploy failed. Check stderr.log and usage of 'online' and 'shutdown' events."); + process.exit(1); + break; + case 'Ready': + console.error("done"); + process.exit(0); + break; + default: + printDaemonMsg(msg); + } + } + }); + function setAbortKeyboardHook(){ + process.once('SIGINT', handleSigInt); + } + function handleSigInt(){ + console.error("aborting deploy"); + json_socket.send(socket, { + action: 'NaughtDeployAbort' + }); + } +} + +function deployAbort(ipcFile){ + var socket = getDaemonMessages(ipcFile, { + ready: function(){ + json_socket.send(socket, { + action: 'NaughtDeployAbort' + }); + }, + event: function(msg){ + switch (msg.event) { + case 'ErrorNoDeployInProgress': + console.error("no deploy in progress"); + process.exit(1); + break; + case 'Ready': + console.error("deploy aborted"); + process.exit(0); + break; + default: + printDaemonMsg(msg); + } + } + }); +} + +function displayStatus(ipcFile){ + var socket = getDaemonMessages(ipcFile, { + ready: function(){ + json_socket.send(socket, { + action: 'NaughtStatus' + }); + }, + event: function(msg){ + if (msg.event === 'Status') { + process.stdout.write(statusMsg(msg)); + socket.end(); + } else { + printDaemonMsg(msg); + } + } + }); +} + +exports=module.exports=naught; diff --git a/package.json b/package.json index 53e5626..078d14e 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,12 @@ "daemon", "daemonize" ], + "main": "lib/main.js", "scripts": { "test": "node test/test.js" }, "bin": { - "naught": "./bin/naught" + "naught": "bin/naught" }, "repository": { "type": "git", From df8e851e9f78980abde5273bf2bbeaa67b5dba4c Mon Sep 17 00:00:00 2001 From: Olivier Penhoat Date: Fri, 29 Jul 2016 18:40:41 +0200 Subject: [PATCH 3/3] allow to use main without shell script --- lib/main.js | 290 ++++++++++++++++++++++++++++++++++++++++++++++-- lib/naught.js | 298 -------------------------------------------------- 2 files changed, 281 insertions(+), 307 deletions(-) delete mode 100755 lib/naught.js diff --git a/lib/main.js b/lib/main.js index b7fc42d..df9ed9b 100755 --- a/lib/main.js +++ b/lib/main.js @@ -3,12 +3,12 @@ var os = require('os'); var net = require('net'); var assert = require('assert'); var json_socket = require('./json_socket'); +var spawn = require('child_process').spawn; var path = require('path'); var DEFAULT_IPC_FILE = 'naught.ipc'; var DEFAULT_PID_FILE = 'naught.pid'; var CWD = process.cwd(); var daemon = require('./daemon'); -var naught = require('./naught'); var packageJson = require('../package.json'); var cmds = { @@ -64,7 +64,7 @@ var cmds = { 'cwd': CWD, 'daemon-mode': 'true', 'remove-old-ipc': 'false', - 'node-args': '' + 'node-args': '', }; var arr = chompArgv(options, argv) , err = arr[0] @@ -76,7 +76,7 @@ var cmds = { if (isNaN(options['worker-count'])) return false; options['max-log-size'] = parseInt(options['max-log-size'], 10); if (isNaN(options['max-log-size'])) return false; - naught.start(options, script, argv); + startScript(options, script, argv); return true; } else { return false; @@ -112,7 +112,7 @@ var cmds = { if (isNaN(options.timeout)) { options.timeout = null; } - naught.stop(options, ipcFile); + stopScript(options, ipcFile); return true; } else { return false; @@ -128,7 +128,7 @@ var cmds = { return false; } var ipcFile = argv[0] || DEFAULT_IPC_FILE; - naught.status(ipcFile); + displayStatus(ipcFile); return true; } }, @@ -198,7 +198,7 @@ var cmds = { options['worker-count'] = parseInt(options['worker-count'], 10); if (isNaN(options['worker-count'])) return false; - naught.deploy(options, ipcFile); + deploy(options, ipcFile); return true; } else { return false; @@ -220,7 +220,7 @@ var cmds = { fn: function(argv){ if (argv.length > 1) return false; var ipcFile = argv[0] || DEFAULT_IPC_FILE; - naught.deployAbort(ipcFile); + deployAbort(ipcFile); return true; } }, @@ -234,7 +234,7 @@ var cmds = { console.log(packageJson.version); return true; } - } + }, }, help: { help: "naught help [cmd]\n\n" + @@ -252,7 +252,7 @@ var cmds = { } }; -var cmd = cmds[process.argv[2]]; +var cmd = cmds[process.argv[2]] if (cmd) { if (!cmd.fn(process.argv.slice(3))) { console.error(cmd.help); @@ -287,6 +287,12 @@ function connectToDaemon(socket_path, cbs){ return socket; } +function assertErrorIsFromInvalidSocket(error){ + if (error.code !== 'ENOENT') { + throw error; + } +} + function exitWithConnRefusedMsg(socket_path){ fs.writeSync(process.stderr.fd, "unable to connect to ipc-file `" + socket_path + "`\n\n" + @@ -295,6 +301,28 @@ function exitWithConnRefusedMsg(socket_path){ process.exit(1); } +function getDaemonMessages(socket_path, cbs){ + var socket = connectToDaemon(socket_path, cbs); + socket.on('error', function(error){ + if (error.code === 'ENOENT') { + fs.writeSync(process.stderr.fd, "server not running\n"); + if(cbs.serverNotRunning) { + // Caller wants to handle the condition of server not running, + // so let them do it. + cbs.serverNotRunning(); + } else { + // Caller isn't prepared to deal with server not running, so die. + process.exit(1); + } + } else if (error.code === 'ECONNREFUSED') { + exitWithConnRefusedMsg(socket_path); + } else { + throw error; + } + }); + return socket; +} + function printUsage(){ for (var name in cmds) { var cmd = cmds[name]; @@ -302,6 +330,250 @@ function printUsage(){ } } +function startScript(options, script, argv){ + var ipcFile = options['ipc-file']; + var socket = connectToDaemon(ipcFile, { + ready: function(){ + json_socket.send(socket, { + action: 'NaughtStatus' + }); + }, + event: function(msg){ + if (msg.event === 'Status') { + fs.writeSync(process.stdout.fd, statusMsg(msg)); + process.exit(1); + } else { + printDaemonMsg(msg); + } + } + }); + socket.on('error', onSocketError); + + function onSocketError(error) { + socket.end(); + if (error.code === 'ECONNREFUSED') { + if(options['remove-old-ipc']) { + fs.writeSync(process.stderr.fd, + "unable to connect to ipc-file `" + ipcFile + "`\n\n" + + "removing the ipc-file and attempting to continue\n"); + fs.unlinkSync(ipcFile); + startDaemon(); + } else { + exitWithConnRefusedMsg(ipcFile); + } + } else if (error.code === 'ENOENT') { + // no server running + startDaemon(); + } else { + throw error; + } + } + + function startDaemon(){ + var args = [ + options['worker-count'], + path.resolve(CWD, ipcFile), + resolveLogPath(options.log), + resolveLogPath(options.stderr), + resolveLogPath(options.stdout), + options['max-log-size'], + path.resolve(CWD, script), + options['node-args'], + options['pid-file'] + ].concat(argv); + if (options['daemon-mode']) { + startDaemonChild(args); + } else { + startBlockingMaster(args); + } + } + + function startBlockingMaster(args) { + daemon.start(args); + } + + function startDaemonChild(args) { + var modulePath = path.resolve(__dirname, "start_daemon.js"); + var child = spawn(process.execPath, [modulePath].concat(args), { + env: process.env, + stdio: ['ignore', 'ignore', 'ignore', 'ipc'], + detached: true, + cwd: options.cwd, + }); + child.unref(); + child.on('message', function(msg){ + if (msg.event === 'Error') { + fs.writeSync(process.stderr.fd, + "unable to start daemon: " + msg.value + "\n"); + process.exit(1); + } else if (msg.event === 'IpcListening') { + child.disconnect(); + var sentShutdown = false; + var socket = connectToDaemon(ipcFile, { + event: function(msg){ + if (msg.event === 'Ready') { + process.stdout.write(statusMsg(msg)); + socket.end(); + } else if (msg.event === 'Shutdown') { + console.error("The server crashed without booting. Check stderr.log."); + socket.end(); + process.exit(1); + } else { + printDaemonMsg(msg); + } + } + }); + } else { + throw new Error("unexpected message from daemon"); + } + }); + } +} + +function resolveLogPath(logPath) { + if (logPath === '-') { + return '-'; + } else { + return path.resolve(CWD, logPath); + } +} + +function stopScript(options, ipcFile){ + var socket = getDaemonMessages(ipcFile, { + ready: function(){ + json_socket.send(socket, { + action: 'NaughtShutdown', + timeout: options.timeout + }); + }, + event: function(msg){ + if (msg.event === 'Shutdown') { + socket.end(); + } else if (msg.event === 'AlreadyShuttingDown') { + console.error("Waiting for shutdown already in progress."); + console.error("If it hangs, Ctrl+C this command and try it again with --timeout 1"); + } else { + printDaemonMsg(msg); + } + }, + serverNotRunning: function() { + // The server isn't running. + // Who cares, we're trying to stop it anyway, this is not an error. + } + }); +} + +function workerCountsFromMsg(msg){ + if (!msg.count) return "Unknown"; + return "booting: " + msg.count.booting + + ", online: " + msg.count.online + + ", dying: " + msg.count.dying + + ", new_online: " + msg.count.new_online; +} + +function printDaemonMsg(msg){ + console.error(msg.event + ". " + workerCountsFromMsg(msg)); +} + +function statusMsg(msg){ + if (msg.count.booting > 0) { + return "booting\n" + workerCountsFromMsg(msg) + "\n"; + } else if (msg.waiting_for === 'shutdown') { + return "shutting down\n" + workerCountsFromMsg(msg) + "\n"; + } else if (msg.waiting_for != null) { + return "deploy in progress\n" + workerCountsFromMsg(msg) + "\n"; + } else { + return "workers online: " + msg.count.online + "\n"; + } +} + +function deploy(options, ipcFile){ + var socket = getDaemonMessages(ipcFile, { + ready: function(){ + setAbortKeyboardHook(); + json_socket.send(socket, { + action: 'NaughtDeploy', + newWorkerCount: options['worker-count'], + environment: options['override-env'] ? process.env : {}, + timeout: options.timeout, + cwd: path.resolve(options.cwd) + }); + }, + event: function(msg){ + switch (msg.event) { + case 'ErrorDeployInProgress': + console.error("Deploy already in progress. Press Ctrl+C to abort."); + break; + case 'Shutdown': + console.error("Bootup never succeeded. Check stderr.log and usage of 'online' and 'shutdown' events."); + process.exit(1); + break; + case 'DeployFailed': + console.log("Deploy failed. Check stderr.log and usage of 'online' and 'shutdown' events."); + process.exit(1); + break; + case 'Ready': + console.error("done"); + process.exit(0); + break; + default: + printDaemonMsg(msg); + } + } + }); + function setAbortKeyboardHook(){ + process.once('SIGINT', handleSigInt); + } + function handleSigInt(){ + console.error("aborting deploy"); + json_socket.send(socket, { + action: 'NaughtDeployAbort' + }); + } +} + +function deployAbort(ipcFile){ + var socket = getDaemonMessages(ipcFile, { + ready: function(){ + json_socket.send(socket, { + action: 'NaughtDeployAbort' + }); + }, + event: function(msg){ + switch (msg.event) { + case 'ErrorNoDeployInProgress': + console.error("no deploy in progress"); + process.exit(1); + break; + case 'Ready': + console.error("deploy aborted"); + process.exit(0); + break; + default: + printDaemonMsg(msg); + } + } + }); +} + +function displayStatus(ipcFile){ + var socket = getDaemonMessages(ipcFile, { + ready: function(){ + json_socket.send(socket, { + action: 'NaughtStatus' + }); + }, + event: function(msg){ + if (msg.event === 'Status') { + process.stdout.write(statusMsg(msg)); + socket.end(); + } else { + printDaemonMsg(msg); + } + } + }); +} + function extendedWorkerCount(workerCount){ if (workerCount === 'auto'){ return os.cpus().length; diff --git a/lib/naught.js b/lib/naught.js deleted file mode 100755 index 07d91cb..0000000 --- a/lib/naught.js +++ /dev/null @@ -1,298 +0,0 @@ -var fs = require('fs'); -var os = require('os'); -var net = require('net'); -var assert = require('assert'); -var json_socket = require('./json_socket'); -var spawn = require('child_process').spawn; -var path = require('path'); -var CWD = process.cwd(); -var daemon = require('./daemon'); - -var naught={ - start: startScript, - stop: stopScript, - status: displayStatus, - deploy: deploy, - deployAbort: deployAbort -}; - -function connectToDaemon(socket_path, cbs){ - var socket = net.connect(socket_path, cbs.ready); - json_socket.listen(socket, cbs.event); - return socket; -} - -function exitWithConnRefusedMsg(socket_path){ - fs.writeSync(process.stderr.fd, - "unable to connect to ipc-file `" + socket_path + "`\n\n" + - "1. the ipc file specified is invalid, or\n" + - "2. the daemon process died unexpectedly\n"); - process.exit(1); -} - -function getDaemonMessages(socket_path, cbs){ - var socket = connectToDaemon(socket_path, cbs); - socket.on('error', function(error){ - if (error.code === 'ENOENT') { - fs.writeSync(process.stderr.fd, "server not running\n"); - if(cbs.serverNotRunning) { - // Caller wants to handle the condition of server not running, - // so let them do it. - cbs.serverNotRunning(); - } else { - // Caller isn't prepared to deal with server not running, so die. - process.exit(1); - } - } else if (error.code === 'ECONNREFUSED') { - exitWithConnRefusedMsg(socket_path); - } else { - throw error; - } - }); - return socket; -} - -function startScript(options, script, argv){ - var ipcFile = options['ipc-file']; - var socket = connectToDaemon(ipcFile, { - ready: function(){ - json_socket.send(socket, { - action: 'NaughtStatus' - }); - }, - event: function(msg){ - if (msg.event === 'Status') { - fs.writeSync(process.stdout.fd, statusMsg(msg)); - process.exit(1); - } else { - printDaemonMsg(msg); - } - } - }); - socket.on('error', onSocketError); - - function onSocketError(error) { - socket.end(); - if (error.code === 'ECONNREFUSED') { - if(options['remove-old-ipc']) { - fs.writeSync(process.stderr.fd, - "unable to connect to ipc-file `" + ipcFile + "`\n\n" + - "removing the ipc-file and attempting to continue\n"); - fs.unlinkSync(ipcFile); - startDaemon(); - } else { - exitWithConnRefusedMsg(ipcFile); - } - } else if (error.code === 'ENOENT') { - // no server running - startDaemon(); - } else { - throw error; - } - } - - function startDaemon(){ - var args = [ - options['worker-count'], - path.resolve(CWD, ipcFile), - resolveLogPath(options.log), - resolveLogPath(options.stderr), - resolveLogPath(options.stdout), - options['max-log-size'], - path.resolve(CWD, script), - options['node-args'], - options['pid-file'] - ].concat(argv); - if (options['daemon-mode']) { - startDaemonChild(args); - } else { - startBlockingMaster(args); - } - } - - function startBlockingMaster(args) { - daemon.start(args); - } - - function startDaemonChild(args) { - var modulePath = path.resolve(__dirname, "start_daemon.js"); - var child = spawn(process.execPath, [modulePath].concat(args), { - env: process.env, - stdio: ['ignore', 'ignore', 'ignore', 'ipc'], - detached: true, - cwd: options.cwd - }); - child.unref(); - child.on('message', function(msg){ - if (msg.event === 'Error') { - fs.writeSync(process.stderr.fd, - "unable to start daemon: " + msg.value + "\n"); - process.exit(1); - } else if (msg.event === 'IpcListening') { - child.disconnect(); - var socket = connectToDaemon(ipcFile, { - event: function(msg){ - if (msg.event === 'Ready') { - process.stdout.write(statusMsg(msg)); - socket.end(); - } else if (msg.event === 'Shutdown') { - console.error("The server crashed without booting. Check stderr.log."); - socket.end(); - process.exit(1); - } else { - printDaemonMsg(msg); - } - } - }); - } else { - throw new Error("unexpected message from daemon"); - } - }); - } -} - -function resolveLogPath(logPath) { - if (logPath === '-') { - return '-'; - } else { - return path.resolve(CWD, logPath); - } -} - -function stopScript(options, ipcFile){ - var socket = getDaemonMessages(ipcFile, { - ready: function(){ - json_socket.send(socket, { - action: 'NaughtShutdown', - timeout: options.timeout - }); - }, - event: function(msg){ - if (msg.event === 'Shutdown') { - socket.end(); - } else if (msg.event === 'AlreadyShuttingDown') { - console.error("Waiting for shutdown already in progress."); - console.error("If it hangs, Ctrl+C this command and try it again with --timeout 1"); - } else { - printDaemonMsg(msg); - } - }, - serverNotRunning: function() { - // The server isn't running. - // Who cares, we're trying to stop it anyway, this is not an error. - } - }); -} - -function workerCountsFromMsg(msg){ - if (!msg.count) return "Unknown"; - return "booting: " + msg.count.booting + - ", online: " + msg.count.online + - ", dying: " + msg.count.dying + - ", new_online: " + msg.count.new_online; -} - -function printDaemonMsg(msg){ - console.error(msg.event + ". " + workerCountsFromMsg(msg)); -} - -function statusMsg(msg){ - if (msg.count.booting > 0) { - return "booting\n" + workerCountsFromMsg(msg) + "\n"; - } else if (msg['waiting_for'] === 'shutdown') { - return "shutting down\n" + workerCountsFromMsg(msg) + "\n"; - } else if (msg['waiting_for'] != null) { - return "deploy in progress\n" + workerCountsFromMsg(msg) + "\n"; - } else { - return "workers online: " + msg.count.online + "\n"; - } -} - -function deploy(options, ipcFile){ - var socket = getDaemonMessages(ipcFile, { - ready: function(){ - setAbortKeyboardHook(); - json_socket.send(socket, { - action: 'NaughtDeploy', - newWorkerCount: options['worker-count'], - environment: options['override-env'] ? process.env : {}, - timeout: options.timeout, - cwd: path.resolve(options.cwd) - }); - }, - event: function(msg){ - switch (msg.event) { - case 'ErrorDeployInProgress': - console.error("Deploy already in progress. Press Ctrl+C to abort."); - break; - case 'Shutdown': - console.error("Bootup never succeeded. Check stderr.log and usage of 'online' and 'shutdown' events."); - process.exit(1); - break; - case 'DeployFailed': - console.log("Deploy failed. Check stderr.log and usage of 'online' and 'shutdown' events."); - process.exit(1); - break; - case 'Ready': - console.error("done"); - process.exit(0); - break; - default: - printDaemonMsg(msg); - } - } - }); - function setAbortKeyboardHook(){ - process.once('SIGINT', handleSigInt); - } - function handleSigInt(){ - console.error("aborting deploy"); - json_socket.send(socket, { - action: 'NaughtDeployAbort' - }); - } -} - -function deployAbort(ipcFile){ - var socket = getDaemonMessages(ipcFile, { - ready: function(){ - json_socket.send(socket, { - action: 'NaughtDeployAbort' - }); - }, - event: function(msg){ - switch (msg.event) { - case 'ErrorNoDeployInProgress': - console.error("no deploy in progress"); - process.exit(1); - break; - case 'Ready': - console.error("deploy aborted"); - process.exit(0); - break; - default: - printDaemonMsg(msg); - } - } - }); -} - -function displayStatus(ipcFile){ - var socket = getDaemonMessages(ipcFile, { - ready: function(){ - json_socket.send(socket, { - action: 'NaughtStatus' - }); - }, - event: function(msg){ - if (msg.event === 'Status') { - process.stdout.write(statusMsg(msg)); - socket.end(); - } else { - printDaemonMsg(msg); - } - } - }); -} - -exports=module.exports=naught;