2011-08-16 18:41:29 +02:00
|
|
|
var fs = require('fs');
|
2011-09-04 16:39:03 +02:00
|
|
|
var timers = require('./timer');
|
2012-07-17 15:10:58 +02:00
|
|
|
var jsbot = require('./jsbot/jsbot');
|
2011-09-04 16:39:03 +02:00
|
|
|
require('./snippets');
|
2011-08-23 01:04:40 +02:00
|
|
|
|
2012-02-11 17:02:16 +01:00
|
|
|
var DBot = function(timers) {
|
2012-02-13 20:56:04 +01:00
|
|
|
// Load external files
|
2012-12-23 03:25:58 +01:00
|
|
|
var requiredConfigKeys = [ 'name', 'servers', 'admins', 'moduleNames', 'language', 'debugMode' ];
|
2012-12-12 19:25:07 +01:00
|
|
|
try {
|
|
|
|
this.config = JSON.parse(fs.readFileSync('config.json', 'utf-8'));
|
|
|
|
} catch(err) {
|
|
|
|
console.log('Config file is screwed up. Attempting to load defaults.');
|
|
|
|
try {
|
|
|
|
this.config = JSON.parse(fs.readFileSync('config.json.sample', 'utf-8'));
|
|
|
|
} catch(err) {
|
|
|
|
console.log('Error loading sample config. Bugger off. Stopping.');
|
|
|
|
process.exit();
|
|
|
|
}
|
|
|
|
}
|
2012-12-12 19:33:29 +01:00
|
|
|
requiredConfigKeys.each(function(key) {
|
|
|
|
if(!this.config.hasOwnProperty(key)) {
|
|
|
|
console.log('Error: Please set a value for ' + key + ' in ' +
|
|
|
|
'config.json. Stopping.');
|
|
|
|
process.exit();
|
|
|
|
}
|
|
|
|
}.bind(this));
|
2012-12-12 19:25:07 +01:00
|
|
|
|
2012-03-10 19:38:56 +01:00
|
|
|
var rawDB;
|
2012-03-07 00:54:52 +01:00
|
|
|
try {
|
2012-03-10 19:38:56 +01:00
|
|
|
var rawDB = fs.readFileSync('db.json', 'utf-8');
|
2012-12-11 21:06:29 +01:00
|
|
|
} catch(err) {
|
2012-03-15 19:08:40 +01:00
|
|
|
this.db = {}; // If no db file, make empty one
|
2012-03-10 19:38:56 +01:00
|
|
|
}
|
2012-12-11 21:06:29 +01:00
|
|
|
|
|
|
|
try {
|
|
|
|
if(!this.db) { // If it wasn't empty
|
|
|
|
this.db = JSON.parse(rawDB);
|
|
|
|
}
|
|
|
|
} catch(err) {
|
2012-12-12 19:25:07 +01:00
|
|
|
console.log('Syntax error in db.json. Stopping: ' + err);
|
|
|
|
process.exit();
|
2012-03-10 19:38:56 +01:00
|
|
|
}
|
|
|
|
|
2012-04-20 15:14:28 +02:00
|
|
|
// Load Strings file
|
2012-12-11 21:06:29 +01:00
|
|
|
try {
|
|
|
|
this.strings = JSON.parse(fs.readFileSync('strings.json', 'utf-8'));
|
|
|
|
} catch(err) {
|
2012-12-12 19:25:07 +01:00
|
|
|
console.log('Probably a syntax error in strings.json: ' + err);
|
2012-12-11 21:06:29 +01:00
|
|
|
this.strings = {};
|
|
|
|
}
|
2011-08-24 02:57:52 +02:00
|
|
|
|
2012-04-20 15:14:28 +02:00
|
|
|
// Initialise run-time resources
|
2012-12-11 21:06:29 +01:00
|
|
|
this.usage = {};
|
2012-04-20 15:14:28 +02:00
|
|
|
this.sessionData = {};
|
|
|
|
this.timers = timers.create();
|
|
|
|
|
2012-02-13 20:56:04 +01:00
|
|
|
// Populate bot properties with config data
|
2012-04-20 15:14:28 +02:00
|
|
|
// Create JSBot and connect to each server
|
2012-12-17 18:18:31 +01:00
|
|
|
this.instance = jsbot.createJSBot(this.config.name);
|
|
|
|
for(var name in this.config.servers) {
|
|
|
|
if(this.config.servers.hasOwnProperty(name)) {
|
|
|
|
var server = this.config.servers[name];
|
|
|
|
this.instance.addConnection(name, server.server, server.port,
|
|
|
|
this.config.admin, function(event) {
|
|
|
|
var server = this.config.servers[event.server];
|
2012-05-25 22:36:13 +02:00
|
|
|
for(var i=0;i<server.channels.length;i++) {
|
|
|
|
this.instance.join(event, server.channels[i]);
|
|
|
|
}
|
2012-04-20 15:14:28 +02:00
|
|
|
}.bind(this), server.nickserv, server.password);
|
2011-11-09 22:54:16 +01:00
|
|
|
}
|
2012-04-20 15:14:28 +02:00
|
|
|
}
|
2011-08-24 02:57:52 +02:00
|
|
|
|
2012-02-13 20:56:04 +01:00
|
|
|
// Load the modules and connect to the server
|
2011-08-24 02:57:52 +02:00
|
|
|
this.reloadModules();
|
2012-04-20 15:14:28 +02:00
|
|
|
this.instance.connectAll();
|
2011-08-24 02:57:52 +02:00
|
|
|
};
|
|
|
|
|
2012-02-13 20:56:04 +01:00
|
|
|
// Say something in a channel
|
2012-05-23 20:38:10 +02:00
|
|
|
DBot.prototype.say = function(server, channel, message) {
|
|
|
|
this.instance.say(server, channel, message);
|
2011-08-24 02:57:52 +02:00
|
|
|
};
|
|
|
|
|
2012-05-19 17:33:31 +02:00
|
|
|
// Format given stored string in config language
|
|
|
|
DBot.prototype.t = function(string, formatData) {
|
2012-12-11 21:06:29 +01:00
|
|
|
var formattedString;
|
|
|
|
if(this.strings.hasOwnProperty(string)) {
|
2012-12-17 18:18:31 +01:00
|
|
|
var lang = this.config.language;
|
2012-12-11 21:06:29 +01:00
|
|
|
if(!this.strings[string].hasOwnProperty(lang)) {
|
|
|
|
lang = "english";
|
|
|
|
}
|
2012-05-19 17:33:31 +02:00
|
|
|
|
2012-12-11 21:06:29 +01:00
|
|
|
formattedString = this.strings[string][lang].format(formatData);
|
|
|
|
} else {
|
|
|
|
formattedString = 'String not found. Something has gone screwy. Maybe.';
|
|
|
|
}
|
|
|
|
|
|
|
|
return formattedString;
|
2012-05-19 17:33:31 +02:00
|
|
|
};
|
|
|
|
|
2012-05-23 20:38:10 +02:00
|
|
|
/*DBot.prototype.act = function(channel, data) {
|
2012-03-09 22:44:05 +01:00
|
|
|
this.instance.send('PRIVMSG', channel, ':\001ACTION ' + data + '\001');
|
2012-05-23 20:38:10 +02:00
|
|
|
}*/
|
2012-02-27 17:43:47 +01:00
|
|
|
|
2012-02-13 20:56:04 +01:00
|
|
|
// Save the database file
|
2011-08-24 02:57:52 +02:00
|
|
|
DBot.prototype.save = function() {
|
2011-10-12 16:12:06 +02:00
|
|
|
fs.writeFile('db.json', JSON.stringify(this.db, null, ' '));
|
2011-08-24 02:57:52 +02:00
|
|
|
};
|
|
|
|
|
2012-02-13 20:56:04 +01:00
|
|
|
// Hot-reload module files.
|
2011-08-24 02:57:52 +02:00
|
|
|
DBot.prototype.reloadModules = function() {
|
2012-02-13 20:56:04 +01:00
|
|
|
if(this.modules) { // Run 'onDestroy' code for each module if it exists.
|
2011-09-14 18:31:26 +02:00
|
|
|
this.modules.each(function(module) {
|
|
|
|
if(module.onDestroy) {
|
|
|
|
module.onDestroy();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2011-09-14 18:30:39 +02:00
|
|
|
|
2011-08-24 02:57:52 +02:00
|
|
|
this.rawModules = [];
|
|
|
|
this.modules = [];
|
2011-08-28 16:00:22 +02:00
|
|
|
this.commands = {};
|
2012-04-15 21:42:23 +02:00
|
|
|
this.commandMap = {}; // Map of which commands belong to which modules
|
2012-12-11 21:06:29 +01:00
|
|
|
this.usage = {};
|
2011-09-04 16:39:03 +02:00
|
|
|
this.timers.clearTimers();
|
2011-10-12 15:52:58 +02:00
|
|
|
|
2012-12-11 21:47:50 +01:00
|
|
|
try {
|
|
|
|
this.strings = JSON.parse(fs.readFileSync('strings.json', 'utf-8'));
|
|
|
|
} catch(err) {
|
|
|
|
this.strings = {};
|
|
|
|
}
|
|
|
|
|
2012-12-17 18:18:31 +01:00
|
|
|
var moduleNames = this.config.moduleNames;
|
|
|
|
|
2012-03-15 19:08:40 +01:00
|
|
|
// Enforce having command. it can still be reloaded, but dbot _will not_
|
|
|
|
// function without it, so not having it should be impossible
|
2012-12-17 18:18:31 +01:00
|
|
|
if(!moduleNames.include("command")) {
|
|
|
|
moduleNames.push("command");
|
2012-03-10 18:35:50 +01:00
|
|
|
}
|
|
|
|
|
2012-02-13 20:56:04 +01:00
|
|
|
// Reload Javascript snippets
|
2011-08-25 18:54:59 +02:00
|
|
|
var path = require.resolve('./snippets');
|
2012-02-08 19:42:38 +01:00
|
|
|
delete require.cache[path];
|
2011-08-25 18:54:59 +02:00
|
|
|
require('./snippets');
|
|
|
|
|
2012-04-15 21:42:23 +02:00
|
|
|
this.instance.removeListeners();
|
|
|
|
|
2012-12-17 18:18:31 +01:00
|
|
|
moduleNames.each(function(name) {
|
2012-12-11 21:06:29 +01:00
|
|
|
var moduleDir = './modules/' + name + '/';
|
|
|
|
var cacheKey = require.resolve(moduleDir + name);
|
2012-02-08 19:42:38 +01:00
|
|
|
delete require.cache[cacheKey];
|
2012-04-15 21:46:42 +02:00
|
|
|
|
2011-08-24 19:23:00 +02:00
|
|
|
try {
|
2012-12-18 12:07:39 +01:00
|
|
|
// Load the module config data
|
|
|
|
try {
|
|
|
|
var config = JSON.parse(fs.readFileSync(moduleDir + 'config.json', 'utf-8'))
|
|
|
|
this.config[name] = config;
|
|
|
|
for(var i=0;i<config.dbKeys.length;i++) {
|
|
|
|
if(!this.db.hasOwnProperty(config.dbKeys[i])) {
|
|
|
|
this.db[config.dbKeys[i]] = {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch(err) {
|
|
|
|
// Invalid or no config data
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:06:29 +01:00
|
|
|
// Load the module itself
|
|
|
|
var rawModule = require(moduleDir + name);
|
2012-04-15 21:42:23 +02:00
|
|
|
var module = rawModule.fetch(this);
|
|
|
|
this.rawModules.push(rawModule);
|
2011-08-28 16:00:22 +02:00
|
|
|
|
2012-04-15 21:42:23 +02:00
|
|
|
if(module.listener) {
|
2012-12-23 17:54:30 +01:00
|
|
|
var listenOn = module.on;
|
|
|
|
if(!(listenOn instanceof Array)) {
|
|
|
|
listenOn = [listenOn];
|
|
|
|
}
|
|
|
|
|
|
|
|
listenOn.each(function(on) {
|
|
|
|
this.instance.addListener(on, module.name, module.listener);
|
|
|
|
}.bind(this));
|
2012-04-15 21:42:23 +02:00
|
|
|
}
|
2011-08-28 16:00:22 +02:00
|
|
|
|
2012-04-15 21:42:23 +02:00
|
|
|
if(module.onLoad) {
|
2012-06-05 01:17:51 +02:00
|
|
|
module.onLoad();
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:06:29 +01:00
|
|
|
// Load module commands
|
2012-06-05 01:17:51 +02:00
|
|
|
if(module.commands) {
|
|
|
|
var newCommands = module.commands;
|
2012-04-15 21:42:23 +02:00
|
|
|
for(key in newCommands) {
|
|
|
|
if(newCommands.hasOwnProperty(key) && Object.prototype.isFunction(newCommands[key])) {
|
|
|
|
this.commands[key] = newCommands[key];
|
2012-04-15 22:43:02 +02:00
|
|
|
this.commandMap[key] = name;
|
2012-04-15 21:42:23 +02:00
|
|
|
}
|
2011-08-28 16:00:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-11 21:06:29 +01:00
|
|
|
// Load the module usage data
|
2012-12-11 21:23:31 +01:00
|
|
|
try {
|
|
|
|
var usage = JSON.parse(fs.readFileSync(moduleDir + 'usage.json', 'utf-8'));
|
|
|
|
for(key in usage) {
|
|
|
|
if(usage.hasOwnProperty(key)) {
|
|
|
|
if(this.usage.hasOwnProperty(key)) {
|
|
|
|
console.log('Usage key clash for ' + key + ' in ' + name);
|
|
|
|
} else {
|
|
|
|
this.usage[key] = usage[key];
|
|
|
|
}
|
2012-12-11 21:06:29 +01:00
|
|
|
}
|
|
|
|
}
|
2012-12-11 21:23:31 +01:00
|
|
|
} catch(err) {
|
|
|
|
// Invalid or no usage info
|
2012-12-11 21:06:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Load the module string data
|
2012-12-11 21:23:31 +01:00
|
|
|
try {
|
|
|
|
var strings = JSON.parse(fs.readFileSync(moduleDir + 'strings.json', 'utf-8'));
|
|
|
|
for(key in strings) {
|
|
|
|
if(strings.hasOwnProperty(key)) {
|
|
|
|
if(this.strings.hasOwnProperty(key)) {
|
|
|
|
console.log('Strings key clash for ' + key + ' in ' + name);
|
|
|
|
} else {
|
|
|
|
this.strings[key] = strings[key];
|
|
|
|
}
|
2012-12-11 21:06:29 +01:00
|
|
|
}
|
|
|
|
}
|
2012-12-11 21:23:31 +01:00
|
|
|
} catch(err) {
|
|
|
|
// Invalid or no string info
|
2012-12-11 21:06:29 +01:00
|
|
|
}
|
|
|
|
|
2012-04-15 21:42:23 +02:00
|
|
|
this.modules.push(module);
|
|
|
|
} catch(err) {
|
2012-05-23 19:02:02 +02:00
|
|
|
console.log(this.t('module_load_error', {'moduleName': name}));
|
2012-12-24 04:13:41 +01:00
|
|
|
if(this.config.debugMode) {
|
|
|
|
console.log('MODULE ERROR (' + name + '): ' + err.stack );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
console.log('MODULE ERROR (' + name + '): ' + err );
|
|
|
|
}
|
2012-04-15 21:42:23 +02:00
|
|
|
}
|
2011-08-24 02:57:52 +02:00
|
|
|
}.bind(this));
|
2012-12-17 20:37:33 +01:00
|
|
|
this.save();
|
2011-08-24 02:57:52 +02:00
|
|
|
};
|
|
|
|
|
2011-11-10 20:36:01 +01:00
|
|
|
DBot.prototype.cleanNick = function(key) {
|
|
|
|
key = key.toLowerCase();
|
|
|
|
while(key.endsWith("_")) {
|
|
|
|
if(this.db.quoteArrs.hasOwnProperty(key)) {
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
key = key.substring(0, key.length-1);
|
|
|
|
}
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2012-02-11 17:26:29 +01:00
|
|
|
new DBot(timers);
|