2013-10-09 17:47:55 +02:00
|
|
|
#!/usr/bin/env node
|
|
|
|
|
2014-02-23 18:20:50 +01:00
|
|
|
/*eslint no-sync:0*/
|
|
|
|
|
2014-01-24 04:36:03 +01:00
|
|
|
if (process.getuid && process.getuid() === 0) {
|
2014-11-12 12:14:37 +01:00
|
|
|
global.console.error("Sinopia doesn't need superuser privileges. Don't run it under root.")
|
2013-12-17 17:25:17 +01:00
|
|
|
}
|
|
|
|
|
2014-09-25 03:13:03 +02:00
|
|
|
process.title = 'sinopia'
|
2014-11-12 13:05:07 +01:00
|
|
|
require('es6-shim')
|
2014-09-25 03:13:03 +02:00
|
|
|
|
2013-12-29 01:52:23 +01:00
|
|
|
try {
|
2014-11-12 12:14:37 +01:00
|
|
|
// for debugging memory leaks
|
|
|
|
// totally optional
|
|
|
|
require('heapdump')
|
|
|
|
} catch(err) {}
|
2013-12-29 01:52:23 +01:00
|
|
|
|
2013-10-26 14:18:36 +02:00
|
|
|
var logger = require('./logger')
|
|
|
|
logger.setup() // default setup
|
2013-10-11 07:32:59 +02:00
|
|
|
|
2014-11-12 12:14:37 +01:00
|
|
|
var commander = require('commander')
|
2014-11-10 20:41:38 +01:00
|
|
|
var constants = require('constants')
|
2014-11-12 12:14:37 +01:00
|
|
|
var fs = require('fs')
|
2014-11-10 20:41:38 +01:00
|
|
|
var http = require('http')
|
|
|
|
var https = require('https')
|
2014-11-12 12:14:37 +01:00
|
|
|
var YAML = require('js-yaml')
|
|
|
|
var Path = require('path')
|
2015-03-28 15:20:58 +01:00
|
|
|
var URL = require('url')
|
2014-11-12 12:14:37 +01:00
|
|
|
var server = require('./index')
|
2015-03-28 16:03:36 +01:00
|
|
|
var Utils = require('./utils')
|
2014-11-12 12:14:37 +01:00
|
|
|
var pkg_file = '../package.yaml'
|
|
|
|
var pkg = YAML.safeLoad(fs.readFileSync(__dirname+'/'+ pkg_file, 'utf8'))
|
2013-10-09 17:47:55 +02:00
|
|
|
|
|
|
|
commander
|
2014-11-12 12:14:37 +01:00
|
|
|
.option('-l, --listen <[host:]port>', 'host:port number to listen on (default: localhost:4873)')
|
|
|
|
.option('-c, --config <config.yaml>', 'use this configuration file (default: ./config.yaml)')
|
|
|
|
.version(pkg.version)
|
|
|
|
.parse(process.argv)
|
2013-10-09 17:47:55 +02:00
|
|
|
|
|
|
|
if (commander.args.length == 1 && !commander.config) {
|
2014-11-12 12:14:37 +01:00
|
|
|
// handling "sinopia [config]" case if "-c" is missing in commandline
|
|
|
|
commander.config = commander.args.pop()
|
2013-10-09 17:47:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (commander.args.length != 0) {
|
2014-11-12 12:14:37 +01:00
|
|
|
commander.help()
|
2013-10-09 17:47:55 +02:00
|
|
|
}
|
|
|
|
|
2015-03-28 19:25:53 +01:00
|
|
|
var config, config_path
|
2013-10-09 17:47:55 +02:00
|
|
|
try {
|
2014-11-12 12:14:37 +01:00
|
|
|
if (commander.config) {
|
2014-11-16 14:33:03 +01:00
|
|
|
config_path = Path.resolve(commander.config)
|
2014-11-12 12:14:37 +01:00
|
|
|
} else {
|
2014-11-16 14:33:03 +01:00
|
|
|
config_path = require('./config-path')()
|
2014-11-12 12:14:37 +01:00
|
|
|
}
|
2014-11-16 14:33:03 +01:00
|
|
|
config = YAML.safeLoad(fs.readFileSync(config_path, 'utf8'))
|
2014-11-16 19:44:32 +01:00
|
|
|
logger.logger.warn({ file: config_path }, 'config file - @{file}')
|
2014-11-12 12:14:37 +01:00
|
|
|
} catch (err) {
|
|
|
|
logger.logger.fatal({ file: config_path, err: err }, 'cannot open config file @{file}: @{!err.message}')
|
|
|
|
process.exit(1)
|
2013-10-09 17:47:55 +02:00
|
|
|
}
|
|
|
|
|
2014-11-16 14:33:03 +01:00
|
|
|
afterConfigLoad()
|
2013-10-09 18:22:29 +02:00
|
|
|
|
2015-03-28 15:20:58 +01:00
|
|
|
function get_listen_addresses() {
|
2014-11-12 12:14:37 +01:00
|
|
|
// command line || config file || default
|
2015-03-28 15:20:58 +01:00
|
|
|
var addresses
|
|
|
|
|
|
|
|
if (commander.listen) {
|
|
|
|
addresses = [ commander.listen ]
|
|
|
|
} else if (Array.isArray(config.listen)) {
|
|
|
|
addresses = config.listen
|
|
|
|
} else if (config.listen) {
|
|
|
|
addresses = [ config.listen ]
|
|
|
|
} else {
|
|
|
|
addresses = [ '4873' ]
|
2014-11-12 12:14:37 +01:00
|
|
|
}
|
2015-03-28 15:20:58 +01:00
|
|
|
|
|
|
|
addresses = addresses.map(function(addr) {
|
2015-04-22 01:36:57 +02:00
|
|
|
var parsed_addr = Utils.parse_address(addr)
|
2015-03-28 16:03:36 +01:00
|
|
|
|
2015-04-22 01:36:57 +02:00
|
|
|
if (!parsed_addr) {
|
2015-03-28 15:20:58 +01:00
|
|
|
logger.logger.warn({ addr: addr },
|
|
|
|
'invalid address - @{addr}, we expect a port (e.g. "4873"),'
|
|
|
|
+ ' host:port (e.g. "localhost:4873") or full url'
|
|
|
|
+ ' (e.g. "http://localhost:4873/")')
|
|
|
|
}
|
|
|
|
|
2015-04-22 01:36:57 +02:00
|
|
|
return parsed_addr
|
2015-03-28 16:03:36 +01:00
|
|
|
|
2015-03-28 15:20:58 +01:00
|
|
|
}).filter(Boolean)
|
|
|
|
|
|
|
|
return addresses
|
2013-10-09 17:47:55 +02:00
|
|
|
}
|
2013-10-09 18:22:29 +02:00
|
|
|
|
|
|
|
function afterConfigLoad() {
|
2014-11-12 12:14:37 +01:00
|
|
|
if (!config.self_path) config.self_path = Path.resolve(config_path)
|
2014-11-10 20:41:38 +01:00
|
|
|
if (!config.https) config.https = { enable: false };
|
2013-10-09 18:22:29 +02:00
|
|
|
|
2015-03-28 15:20:58 +01:00
|
|
|
var app = server(config)
|
|
|
|
|
|
|
|
get_listen_addresses().forEach(function(addr) {
|
|
|
|
var webServer
|
|
|
|
|
|
|
|
if (addr.proto === 'https') { // https
|
|
|
|
if (!config.https || !config.https.key || !config.https.cert) {
|
|
|
|
var conf_path = function(file) {
|
|
|
|
if (!file) return config_path
|
|
|
|
return Path.resolve(Path.dirname(config_path), file)
|
|
|
|
}
|
|
|
|
|
|
|
|
logger.logger.fatal([
|
|
|
|
'You need to specify "https.key" and "https.cert" to run https server',
|
|
|
|
'',
|
|
|
|
// commands are borrowed from node.js docs
|
|
|
|
'To quickly create self-signed certificate, use:',
|
|
|
|
' $ openssl genrsa -out ' + conf_path('sinopia-key.pem') + ' 2048',
|
|
|
|
' $ openssl req -new -sha256 -key ' + conf_path('sinopia-key.pem') + ' -out ' + conf_path('sinopia-csr.pem'),
|
|
|
|
' $ openssl x509 -req -in ' + conf_path('sinopia-csr.pem') + ' -signkey ' + conf_path('sinopia-key.pem') + ' -out ' + conf_path('sinopia-cert.pem'),
|
|
|
|
'',
|
|
|
|
'And then add to config file (' + conf_path() + '):',
|
|
|
|
' https:',
|
|
|
|
' key: sinopia-key.pem',
|
|
|
|
' cert: sinopia-cert.pem',
|
|
|
|
].join('\n'))
|
|
|
|
process.exit(2)
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
webServer = https.createServer({
|
2014-11-10 20:41:38 +01:00
|
|
|
secureProtocol: 'SSLv23_method', // disable insecure SSLv2 and SSLv3
|
|
|
|
secureOptions: constants.SSL_OP_NO_SSLv2 | constants.SSL_OP_NO_SSLv3,
|
|
|
|
key: fs.readFileSync(config.https.key),
|
|
|
|
cert: fs.readFileSync(config.https.cert)
|
2015-03-28 15:20:58 +01:00
|
|
|
}, app)
|
|
|
|
} catch (err) { // catch errors related to certificate loading
|
|
|
|
logger.logger.fatal({ err: err }, 'cannot create server: @{err.message}')
|
|
|
|
process.exit(2)
|
|
|
|
}
|
|
|
|
} else { // http
|
|
|
|
webServer = http.createServer(app);
|
2014-11-10 20:41:38 +01:00
|
|
|
}
|
|
|
|
|
2015-03-28 15:20:58 +01:00
|
|
|
webServer
|
2015-04-22 01:36:57 +02:00
|
|
|
.listen(addr.port || addr.path, addr.host)
|
2015-03-28 15:20:58 +01:00
|
|
|
.on('error', function(err) {
|
|
|
|
logger.logger.fatal({ err: err }, 'cannot create server: @{err.message}')
|
|
|
|
process.exit(2)
|
|
|
|
})
|
|
|
|
|
|
|
|
logger.logger.warn({
|
2015-04-22 01:36:57 +02:00
|
|
|
addr: ( addr.path
|
|
|
|
? URL.format({
|
|
|
|
protocol: 'unix',
|
|
|
|
pathname: addr.path,
|
|
|
|
})
|
|
|
|
: URL.format({
|
|
|
|
protocol: addr.proto,
|
|
|
|
hostname: addr.host,
|
|
|
|
port: addr.port,
|
|
|
|
pathname: '/',
|
|
|
|
})
|
|
|
|
),
|
2015-03-28 15:20:58 +01:00
|
|
|
version: 'Sinopia/'+pkg.version,
|
|
|
|
}, 'http address - @{addr}')
|
|
|
|
})
|
2013-10-09 18:22:29 +02:00
|
|
|
|
2014-11-12 12:14:37 +01:00
|
|
|
// undocumented stuff for tests
|
|
|
|
if (typeof(process.send) === 'function') {
|
2015-03-28 16:03:36 +01:00
|
|
|
process.send({ sinopia_started: true })
|
2014-11-12 12:14:37 +01:00
|
|
|
}
|
2013-10-09 17:47:55 +02:00
|
|
|
}
|
|
|
|
|
2013-12-10 11:29:46 +01:00
|
|
|
process.on('uncaughtException', function(err) {
|
2014-11-12 12:14:37 +01:00
|
|
|
logger.logger.fatal( { err: err }
|
|
|
|
, 'uncaught exception, please report this\n@{err.stack}' )
|
|
|
|
process.exit(255)
|
2013-12-10 11:29:46 +01:00
|
|
|
})
|
|
|
|
|