Switch config to YAML

This commit is contained in:
calzoneman 2014-01-22 17:11:26 -06:00
parent 0a2dd6cbbe
commit 4a2366eb06
11 changed files with 251 additions and 134 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
*.swp
cfg.json
config.yaml
chandump
chanlogs
*.log

66
config.template.yaml Normal file
View File

@ -0,0 +1,66 @@
# MySQL server details
# server: domain or IP of MySQL server
# database: a MySQL database that the user specified has read/write access to
# user: username to authenticate as
# password: password for user
mysql:
server: 'localhost'
database: 'cytube3'
user: 'cytube3'
password: 'pickles'
# HTTP server details
http:
host: ''
port: 8080
domain: 'http://localhost'
# HTTPS server details
https:
enabled: false
port: 8443
domain: 'https://localhost'
keyfile: 'localhost.key'
passphrase: ''
certfile: 'localhost.cert'
# Socket.IO server details
io:
port: 1337
# limit the number of concurrent socket connections per IP address
ip-connection-limit: 10
# Mailer details (used for sending password reset links)
# see https://github.com/andris9/Nodemailer
mail:
enabled: false
transport: 'SMTP'
config:
service: 'Gmail'
auth:
user: 'some.user@gmail.com'
password: 'supersecretpassword'
from-address: 'some.user@gmail.com'
# GData API v2 developer key (for non-anonymous youtube requests)
youtube-v2-key: ''
# Minutes between saving channel state to disk
channel-save-interval: 5
# Minimum number of seconds between guest logins from the same IP
guest-login-delay: 60
# Block known Tor IP addresses
enable-tor-blocker: true
# Configure statistics tracking
stats:
# Interval (in milliseconds) between data points - default 1h
interval: 3600000
# Maximum age of a datapoint (ms) before it is deleted - default 24h
max-age: 86400000
# Configure periodic clearing of old alias data
aliases:
# Interval (in milliseconds) between subsequent runs of clearing
purge-interval: 3600000
# Maximum age of an alias (in milliseconds) - default 1 month
max-age: 2592000000

View File

@ -13,10 +13,9 @@ var Server = require("./lib/server");
var Config = require("./lib/config");
var Logger = require("./lib/logger");
Config.load("cfg.json", function (cfg) {
cfg["debug"] = true;
var sv = Server.init(cfg);
if(!cfg["debug"]) {
Config.load("config.yaml");
var sv = Server.init();
if (!Config.get("debug")) {
process.on("uncaughtException", function (err) {
Logger.errlog.log("[SEVERE] Uncaught Exception: " + err);
Logger.errlog.log(err.stack);
@ -25,5 +24,4 @@ Config.load("cfg.json", function (cfg) {
process.on("SIGINT", function () {
sv.shutdown();
});
}
});
}

View File

@ -18,13 +18,14 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
*/
var Logger = require("./logger");
var Config = require("./config");
var init = null;
/* Stats */
function initStats(Server) {
var STAT_INTERVAL = Server.cfg["stat-interval"];
var STAT_EXPIRE = Server.cfg["stat-max-age"];
var STAT_INTERVAL = Config.get("stats.interval");
var STAT_EXPIRE = Config.get("stats.max-age");
setInterval(function () {
var db = Server.db;
@ -44,8 +45,8 @@ function initStats(Server) {
/* Alias cleanup */
function initAliasCleanup(Server) {
var CLEAN_INTERVAL = Server.cfg["alias-purge-interval"];
var CLEAN_EXPIRE = Server.cfg["alias-max-age"];
var CLEAN_INTERVAL = Config.get("aliases.purge-interval");
var CLEAN_EXPIRE = Config.get("aliases.max-age");
setInterval(function () {
Server.db.cleanOldAliases(CLEAN_EXPIRE, function (err) {
@ -68,7 +69,7 @@ function initIpThrottleCleanup(Server) {
}
function initChannelDumper(Server) {
var CHANNEL_SAVE_INTERVAL = Server.cfg["channel-save-interval"] * 60000;
var CHANNEL_SAVE_INTERVAL = Config.get("channel-save-interval") * 60000;
setInterval(function () {
for (var i = 0; i < Server.channels.length; i++) {
var chan = Server.channels[i];

View File

@ -10,99 +10,145 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
*/
var fs = require("fs");
var path = require("path");
var Logger = require("./logger");
var nodemailer = require("nodemailer");
var YAML = require("yamljs");
var defaults = {
"mysql-server" : "localhost",
"mysql-db" : "cytube",
"mysql-user" : "cytube",
"mysql-pw" : "supersecretpass",
"express-host" : "0.0.0.0",
"io-host" : "0.0.0.0",
"enable-ssl" : false,
"ssl-keyfile" : "",
"ssl-passphrase" : "",
"ssl-certfile" : "",
"ssl-port" : 443,
"asset-cache-ttl" : 0,
"web-port" : 8080,
"io-port" : 1337,
"ip-connection-limit" : 10,
"guest-login-delay" : 60,
"channel-save-interval" : 5,
"enable-mail" : false,
"mail-transport" : "SMTP",
"mail-config" : {
"service" : "Gmail",
"auth" : {
"user" : "some.user@gmail.com",
"pass" : "supersecretpassword"
}
mysql: {
server: "localhost",
database: "cytube3",
user: "cytube3",
password: ""
},
"mail-from" : "some.user@gmail.com",
"domain" : "http://localhost",
"ytv3apikey" : "",
"enable-ytv3" : false,
"ytv2devkey" : "",
"stat-interval" : 3600000,
"stat-max-age" : 86400000,
"alias-purge-interval" : 3600000,
"alias-max-age" : 2592000000,
"tor-blocker" : false
http: {
host: "",
port: 8080,
domain: "http://localhost"
},
https: {
enabled: false,
port: 8443,
domain: "https://localhost:8443",
keyfile: "localhost.key",
passphrase: "",
certfile: "localhost.cert"
},
io: {
port: 1337,
"ip-connection-limit": 10
},
mail: {
enabled: false,
transport: "SMTP",
/* the key "config" is omitted because the format depends on the
service the owner is configuring for nodemailer */
"from-address": "some.user@gmail.com"
},
"youtube-v2-key": "",
"channel-save-interval": 5,
"guest-login-delay": 60,
"enable-tor-blocker": true,
stats: {
interval: 3600000,
"max-age": 86400000
},
aliases: {
"purge-interval": 3600000,
"max-age": 2592000000
}
};
/**
* Merges a config object with the defaults, warning about missing keys
*/
function merge(obj, def, path) {
for (var key in def) {
if (key in obj) {
if (typeof obj[key] === "object") {
merge(obj[key], def[key], path + "." + key);
}
} else {
Logger.syslog.log("[WARNING] Missing config key " + (path + "." + key) +
"; using default: " + JSON.stringify(def[key]));
obj[key] = def[key];
}
}
}
function save(cfg, file) {
if(!cfg.loaded)
return;
var x = {};
for(var k in cfg) {
if(k !== "nodemailer" && k !== "loaded")
x[k] = cfg[k];
}
fs.writeFileSync(file, JSON.stringify(x, null, 4));
}
exports.load = function (file, callback) {
var cfg = {};
for(var k in defaults)
cfg[k] = defaults[k];
fs.readFile(file, function (err, data) {
if(err) {
if(err.code == "ENOENT") {
Logger.syslog.log("Config file not found, generating default");
Logger.syslog.log("Edit cfg.json to configure");
data = "{}";
}
else {
Logger.errlog.log("Config load failed");
Logger.errlog.log(err);
return;
}
}
var cfg = defaults;
/**
* Initializes the configuration from the given YAML file
*/
exports.load = function (file) {
try {
data = JSON.parse(data + "");
} catch(e) {
Logger.errlog.log("Config JSON is invalid: ");
Logger.errlog.log(e);
cfg = YAML.load(path.join(__dirname, "..", file));
} catch (e) {
if (e.code === "ENOENT") {
Logger.syslog.log(file + " does not exist, assuming default configuration");
cfg = defaults;
return;
} else {
Logger.errlog.log("Error loading config file " + file + ": ");
if (e.stack) {
Logger.errlog.log(e.stack);
}
cfg = defaults;
return;
}
}
if (cfg == null) {
Logger.syslog.log(file + " is an Invalid configuration file, " +
"assuming default configuration");
cfg = defaults;
return;
}
for(var k in data)
cfg[k] = data[k];
if(cfg["enable-mail"]) {
cfg["nodemailer"] = nodemailer.createTransport(
cfg["mail-transport"],
cfg["mail-config"]
);
var mailconfig = {};
if (cfg.mail && cfg.mail.config) {
mailconfig = cfg.mail.config;
delete cfg.mail.config;
}
cfg["loaded"] = true;
merge(cfg, defaults, "config");
save(cfg, file);
callback(cfg);
});
}
cfg.mail.config = mailconfig;
cfg.mail.nodemailer = nodemailer.createTransport(
cfg.mail.transport,
cfg.mail.config
);
if (process.env.DEBUG === "1" || process.env.DEBUG === "true") {
cfg.debug = true;
} else {
cfg.debug = false;
}
Logger.syslog.log("Loaded configuration from " + file);
};
/**
* Retrieves a configuration value with the given key
*
* Accepts a dot-separated key for nested values, e.g. "http.port"
* Throws an error if a nonexistant key is requested
*/
exports.get = function (key) {
var obj = cfg;
var keylist = key.split(".");
var current = keylist.shift();
var path = current;
while (keylist.length > 0) {
if (!(current in obj)) {
throw new Error("Nonexistant config key '" + path + "." + current + "'");
}
obj = obj[current];
current = keylist.shift();
path += "." + current;
}
return obj[current];
};

View File

@ -2,16 +2,17 @@ var mysql = require("mysql");
var bcrypt = require("bcrypt");
var $util = require("./utilities");
var Logger = require("./logger");
var Config = require("./config");
var pool = null;
var global_ipbans = {};
module.exports.init = function (cfg) {
module.exports.init = function () {
pool = mysql.createPool({
host: cfg["mysql-server"],
user: cfg["mysql-user"],
password: cfg["mysql-pw"],
database: cfg["mysql-db"],
host: Config.get("mysql.server"),
user: Config.get("mysql.user"),
password: Config.get("mysql.password"),
database: Config.get("mysql.database"),
multipleStatements: true
});

View File

@ -16,6 +16,7 @@ var Logger = require("./logger.js");
var Media = require("./media.js").Media;
var CustomEmbedFilter = require("./customembed").filter;
var Server = require("./server");
var Config = require("./config");
var urlRetrieve = function (transport, options, callback) {
// Catch any errors that crop up along the way of the request
@ -48,10 +49,12 @@ var Getters = {
/* youtube.com */
yt: function (id, callback) {
var sv = Server.getServer();
/*
if (sv.cfg["enable-ytv3"] && sv.cfg["ytv3apikey"]) {
Getters["ytv3"](id, callback);
return;
}
*/
var m = id.match(/([\w-]+)/);
if (m) {
@ -70,9 +73,9 @@ var Getters = {
timeout: 1000
};
if(sv.cfg["ytv2devkey"]) {
if(Config.get("youtube-v2-key")) {
options.headers = {
"X-Gdata-Key": "key=" + sv.cfg["ytv2devkey"]
"X-Gdata-Key": "key=" + Config.get("youtube-v2-key")
};
}
@ -147,6 +150,7 @@ var Getters = {
},
/* youtube.com API v3 (requires API key) */
// DEPRECATED
ytv3: function (id, callback) {
var sv = Server.getServer();
var m = id.match(/([\w-]+)/);
@ -226,9 +230,9 @@ var Getters = {
timeout: 1000
};
if(sv.cfg["ytv2devkey"]) {
if(Config.get("youtube-v2-key")) {
options.headers = {
"X-Gdata-Key": "key=" + sv.cfg["ytv2devkey"]
"X-Gdata-Key": "key=" + Config.get("youtube-v2-key")
};
}
@ -291,9 +295,9 @@ var Getters = {
timeout: 1000
};
if(sv.cfg["ytv2devkey"]) {
if(Config.get("youtube-v2-key")) {
options.headers = {
"X-Gdata-Key": "key=" + sv.cfg["ytv2devkey"]
"X-Gdata-Key": "key=" + Config.get("youtube-v2-key")
};
}

View File

@ -4,6 +4,7 @@ var Logger = require("../logger");
var db = require("../database");
var User = require("../user");
var Server = require("../server");
var Config = require("../config");
var $util = require("../utilities");
var CONNECT_RATE = {
@ -89,7 +90,7 @@ function handleConnection(sock) {
}
ipCount[ip]++;
if (ipCount[ip] > srv.cfg["ip-connection-limit"]) {
if (ipCount[ip] > Config.get("io.ip-connection-limit")) {
sock.emit("kick", {
reason: "Too many connections from your IP address"
});
@ -117,11 +118,11 @@ function handleConnection(sock) {
module.exports = {
init: function (srv) {
var ioport = srv.cfg["io-port"];
var webport = srv.cfg["web-port"];
var ioport = Config.get("io.port");
var webport = Config.get("http.port");
var app;
if (ioport !== webport) {
app = require("express")().listen(ioport, srv.cfg["express-host"]);
app = require("express")().listen(ioport, Config.get("http.host"));
srv.ioWeb = app;
} else {
app = srv.express;
@ -132,7 +133,7 @@ module.exports = {
srv.io.set("authorization", handleAuth);
srv.io.on("connection", handleConnection);
if (srv.cfg["enable-ssl"]) {
if (Config.get("https.enabled")) {
srv.ioSecure = sio.listen(srv.https);
srv.ioSecure.set("log level", 1);
srv.ioSecure.set("authorization", handleAuth);

View File

@ -9,11 +9,12 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
const VERSION = "2.4.5";
const VERSION = "3.0.0-alpha";
var singleton = null;
var Config = require("./config");
module.exports = {
init: function (cfg) {
init: function () {
Logger.syslog.log("Starting CyTube v" + VERSION);
var chanlogpath = path.join(__dirname, "../chanlogs");
fs.exists(chanlogpath, function (exists) {
@ -24,7 +25,7 @@ module.exports = {
fs.exists(chandumppath, function (exists) {
exists || fs.mkdir(chandumppath);
});
singleton = new Server(cfg);
singleton = new Server();
return singleton;
},
@ -38,17 +39,14 @@ var fs = require("fs");
var http = require("http");
var https = require("https");
var express = require("express");
var Config = require("./config");
var Logger = require("./logger");
var Channel = require("./channel-new");
var User = require("./user");
var $util = require("./utilities");
var ActionLog = require("./actionlog");
var Server = function (cfg) {
var Server = function () {
var self = this;
self.cfg = cfg;
self.channels = [],
self.express = null;
self.http = null;
@ -66,7 +64,7 @@ var Server = function (cfg) {
// database init ------------------------------------------------------
var Database = require("./database");
self.db = Database;
self.db.init(self.cfg);
self.db.init();
// webserver init -----------------------------------------------------
self.httplog = new Logger.Logger(path.join(__dirname,
@ -155,23 +153,23 @@ var Server = function (cfg) {
*/
// http/https/sio server init -----------------------------------------
if (self.cfg["enable-ssl"]) {
if (Config.get("https.enabled")) {
var key = fs.readFileSync(path.resolve(__dirname, "..",
self.cfg["ssl-keyfile"]));
Config.get("https.keyfile")));
var cert = fs.readFileSync(path.resolve(__dirname, "..",
self.cfg["ssl-certfile"]));
Config.get("https.certfile")));
var opts = {
key: key,
cert: cert,
passphrase: self.cfg["ssl-passphrase"]
passphrase: Config.get("https.passphrase")
};
self.https = https.createServer(opts, self.express)
.listen(self.cfg["ssl-port"]);
.listen(Config.get("https.port"));
}
self.http = self.express.listen(self.cfg["web-port"],
self.cfg["express-host"]);
self.http = self.express.listen(Config.get("http.port"),
Config.get("http.host") || undefined);
/*
self.ioWeb = express().listen(self.cfg["io-port"], self.cfg["io-host"]);
self.io = require("socket.io").listen(self.ioWeb);
@ -186,7 +184,7 @@ var Server = function (cfg) {
require("./bgtask")(self);
// tor blocker init ---------------------------------------------------
if (self.cfg["tor-blocker"]) {
if (Config.get("enable-tor-blocker")) {
self.torblocker = require("./torblocker")();
}
};

View File

@ -4,6 +4,7 @@ var util = require("./utilities");
var MakeEmitter = require("./emitter");
var db = require("./database");
var InfoGetter = require("./get-info");
var Config = require("./config");
function User(socket) {
var self = this;
@ -387,15 +388,14 @@ User.prototype.whenLoggedIn = function (fn) {
var lastguestlogin = {};
User.prototype.guestLogin = function (name) {
var self = this;
var srv = Server.getServer();
if (self.ip in lastguestlogin) {
var diff = (Date.now() - lastguestlogin[self.ip]) / 1000;
if (diff < srv.cfg["guest-login-delay"]) {
if (diff < Config.get("guest-login-delay")) {
self.socket.emit("login", {
success: false,
error: "Guest logins are restricted to one per IP address per " +
srv.cfg["guest-login-delay"] + " seconds."
Config.get("guest-login-delay") + " seconds."
});
return;
}

View File

@ -13,6 +13,7 @@
"jade": "~1.1.5",
"socket.io": "~0.9.16",
"nodemailer": "~0.6.0",
"cookie": "~0.1.0"
"cookie": "~0.1.0",
"yamljs": "~0.1.4"
}
}