Skip to content
This repository has been archived by the owner on Jul 10, 2019. It is now read-only.

Commit

Permalink
Merge pull request #1 from shrikrishnaholla/dev
Browse files Browse the repository at this point in the history
v0.1.0 Logging bot
  • Loading branch information
shrikrishnaholla committed Dec 25, 2013
2 parents b36760e + 3deec14 commit 90e2314
Show file tree
Hide file tree
Showing 15 changed files with 520 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ results

npm-debug.log
node_modules
irclogs
debuglogs
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ Optimus is a P.R.I.M.E. (Pseudo Robotic Irc Messaging Entity). He is being devel

The attempt here is to write an IRC bot, but at the same time try to give it a personality, that of the character [Optimus Prime](http://en.wikipedia.org/wiki/Optimus_Prime) in [Transformers](http://en.wikipedia.org/wiki/Transformers) series

###Installation
1. Clone the repository and change to the project directory
2. Run ```npm install```
3. Run ```gem install haste``` to install the haste client
4. Download and install the latest version of [ElasticSearch](http://www.elasticsearch.org/download/)
5. Run ```node index.js```. The bot will have connected to the set channels and started logging


###Contributing
The philosophy, tech stack, coding guidelines are available in [wiki](https://github.com/pesos/optimus/wiki)

Expand Down
53 changes: 53 additions & 0 deletions config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* Configuration for various components of the project */

module.exports = {
botOpts : {
userName: 'OptimusPrime',
realName: 'Optimus Prime',
nick: 'optimusbot',
password: 'linus',
port: 6667,
debug: false,
showErrors: false,
autoRejoin: true,
autoConnect: true,
ircserver : 'irc.freenode.net',
channels: ['#pes-os', '#optimus-test'],
secure: false,
selfSigned: false,
certExpired: false,
floodProtection: false,
floodProtectionDelay: 1000,
sasl: true,
stripColors: true,
channelPrefixes: "&#",
messageSplit: 512
},
irclogformat : {
channelName : false,
datetime : true,
from : true,
separator : ':\t'
},
irclogarchive : {
interval : 'monthly', // or 'annually' or 'weekly' or 'daily' or 'hourly'
prefix : 'irclog',
channelname : true,
datetime : true,
separator : '-', // Separator to the filename
extension : '.log',
location : './model/irclogs/'
},
debuglogarchive : {
interval : 'monthly', // or 'annually' or 'weekly' or 'daily' or 'hourly'
prefix : 'debuglog',
datetime : true,
separator : '-', // Separator to the filename
extension : '.log',
location : './debuglogger/debuglogs/'
},
ircreplyformat : {
mentionuser : true,
separator : ': '
}
};
25 changes: 25 additions & 0 deletions controller/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
var model = require('../model');
var parser = require('./parser');
var eventManager = require('../util').eventManager;

exports.init = function() {

/* Process new message */
eventManager.on('newmessage', function(from, to, message) {
processmessage(from, to, message, function(reply) {
eventManager.emit('reply', from, to, reply);
});
});
};

function processmessage (from, channel, message, Callback) {
var parsedmsg = parser(message);
switch(parsedmsg) {
case 'logrequest':
model.readlog(channel, message.split(' ')[1], Callback);
break;
default:
model.writelog(from, channel, message, Callback);
break;
};
};
20 changes: 20 additions & 0 deletions controller/parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* Parser module for Optimus Bot */

var commandpresets = [
{
regex : /!logs?[ ][0-9]+$/i,
op : 'logrequest'
}
];

module.exports = function(message) {
return isCommand(message);
};

function isCommand (body) {
return commandpresets.map(function(value, index, array) {
if(body.match(value.regex) !== null) {
return value.op;
}
})[0]; // Because map returns a list of all matches
}
67 changes: 67 additions & 0 deletions debuglogger/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* This is the debugging module. It keeps the log of server messages and errors
* This acts as an adapter so that, whatever library being used,
* the internal api being used in the project remains the same
* Refer https://github.com/pesos/optimus/wiki/Coding-philosophy
*/

var logger = require('caterpillar').createLogger({level:7});
var filter = require('caterpillar-filter').createFilter();
var human = require('caterpillar-human').createHuman();
var fs = require('fs');
var schedule = require('../util').schedule;
var makeFilename = require('../util').makeFilename;
var config = require('../config').debuglogarchive;
var writeStream;

// Pipe to filter to human to stdout
logger.pipe(filter).pipe(human).pipe(process.stdout);
if (!fs.existsSync(config.location)) {
fs.mkdirSync(config.location);
}

writeStream = fs.createWriteStream(makeFilename(config));
logger.pipe(writeStream);

/* For most cases, the default level can be used.
However, if needed, other levels of debug messages can be used as well */
exports.info = function(message) {
logger.log('info', message);
};

exports.alert = function(message) {
logger.log('alert', message);
};

exports.emergency = function(message) {
logger.log('emergency', message);
};

exports.critical = function(message) {
logger.log('critical', message);
};

exports.error = function(message) {
logger.log('error', message);
};

exports.warning = function(message) {
logger.log('warning', message);
};

exports.notice = function(message) {
logger.log('notice', message);
};

exports.debug = function(message) {
logger.log('debug', message);
};

/* Schedule creation of new logfile regularly to avoid pile up */
schedule(config.interval, function() {
logger.unpipe(writeStream);
writeStream.end(function() {
writeStream = fs.createWriteStream(makeFilename(config)); //debug-yyyy-mm.log
logger.pipe(writeStream);
});
});
8 changes: 8 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var irc = require('irc'),
view = require('./view'),
controller = require('./controller'),
botOpts = require('./config').botOpts;

var bot = new irc.Client(botOpts.ircserver, botOpts.nick, botOpts);
view.init(bot);
controller.init();
66 changes: 66 additions & 0 deletions model/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
var debuglogger = require('../debuglogger');
var schedule = require('../util').schedule;
var makeFilename = require('../util').makeFilename;
var archiveconfig= require('../config').irclogarchive;
var logformat = require('../config').irclogformat;
var botOpts = require('../config').botOpts;
// var elasticsearch = require('elasticsearch');
var fs = require('fs');
var exec = require('child_process').exec;

// var client = new elasticsearch.Client({
// host: 'localhost:9200',
// log: 'trace'
// });

if (!fs.existsSync(archiveconfig.location)) {
fs.mkdirSync(archiveconfig.location);
}

var filenames = {};
botOpts.channels.map(function(channelname, index, array) {
filenames[channelname] = makeFilename(archiveconfig, channelname);
});

// Schedule creation of a new log file
schedule(archiveconfig.interval, function() {
debuglogger.notice('Creating new log files\n');
botOpts.channels.map(function(channelname, index, array) {
filenames[channelname] = makeFilename(archiveconfig, channelname);
});
});

exports.writelog = function(from, channelname, message, Callback) {
formattedmessage = '';
if (logformat.channelName) {
formattedmessage += channelname + logformat.separator;
};
if (logformat.datetime) {
formattedmessage += '[' + (new Date()).toISOString() + ']' + logformat.separator;
};
if (logformat.from) {
formattedmessage += from + logformat.separator;
};
formattedmessage += message + '\n';

fs.writeFile(filenames[channelname], formattedmessage, {flag:'a+'}, function(err) {
if (err) {
debuglogger.error('Writing into the irc log failed!\n');
};
Callback();
});
};

exports.readlog = function(channelname, number, Callback) {
if (typeof number === 'string') {
number = parseInt(number);
};
number++;
exec('tail -n ' + number.toString() + ' ' + filenames[channelname] + ' | haste' ,
function (error, stdout, stderr) {
Callback(stdout);
if (error !== null) {
debuglogger.error('exec error: ' + error + '\n');
}
});
};
37 changes: 37 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "optimusbot",
"version": "0.1.0",
"description": "Optimus is a P.R.I.M.E. (Pseudo Robotic Irc Messaging Entity). He is being developed to monitor the logs and provide assistance in IRC channels",
"main": "index.js",
"dependencies": {
"caterpillar": "~2.0.7",
"caterpillar-filter": "~2.0.3",
"caterpillar-human": "~2.1.1",
"elasticsearch": "~1.0.3",
"irc": "~0.3.6",
"node-schedule": "~0.1.13"
},
"devDependencies": {},
"scripts": {
"test": ""
},
"repository": {
"type": "git",
"url": "git://github.com/pesos/optimus.git"
},
"keywords": [
"IRC",
"irc",
"bot",
"ircbot",
"mvc",
"optimus",
"pesos"
],
"author": "PES OpenSource community <[email protected]>",
"license": "MIT",
"bugs": {
"url": "https://github.com/pesos/optimus/issues"
},
"homepage": "https://github.com/pesos/optimus"
}
12 changes: 12 additions & 0 deletions util/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* Consists of utility modules used by the project */

/* Task Scheduler. To schedule running of operations */

exports.schedule = require('./scheduler').scheduleTask;

/* Construct filenames for logfiles */
exports.makeFilename = require('./mkfilename');

/* Event emitter. Used to emit and handle events */
var events = require('events');
exports.eventManager = new events.EventEmitter();
49 changes: 49 additions & 0 deletions util/mkfilename.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* Utility module used to construct filenames for logfiles */

module.exports = function(config, channelname) {
var identifier;

if (config.datetime) {
var datestring = (new Date()).toISOString();
switch(config.interval) {
case 'hourly' :
identifier = datestring.split(':')[0];
break;
case 'daily' :
case 'weekly' :
identifier = datestring.split('T')[0];
break;
case 'monthly' :
identifier = datestring.split('T')[0].slice(0,7);
break;
case 'annually' :
identifier = datestring.split('T')[0].slice(0,4);
break;
default:
identifier = makeid(5);
break;
}
} else {
identifier = makeid(5);
}

if (config.channelname === true) {
identifier = channelname + config.separator + identifier;
};

identifier.replace(/-/g, config.separator);

var filename = config.location + config.prefix + config.separator + identifier + config.extension;
return filename;
};

function makeid(length)
{
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

for( var i=0; i < length; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));

return text;
}
28 changes: 28 additions & 0 deletions util/scheduler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* Scheduler - Can be used to schedule tasks to be executed at particuar time */

var schedule = require('node-schedule');

exports.scheduleTask = function(type, operation) {
var rule = new schedule.RecurrenceRule();
if (type === 'annually') {
rule.month = 0;
rule.date = 1;
rule.hour = 0;
rule.minute = 0;
} else if (type === 'monthly') {
rule.date = 1;
rule.hour = 0;
rule.minute = 0;
} else if (type === 'weekly') {
rule.dayOfWeek = 0;
rule.hour = 0;
rule.minute = 0;
} else if (type === 'daily') {
rule.hour = 0;
rule.minute = 0;
} else if (type === 'hourly') {
rule.minute = 0;
}
var job = schedule.scheduleJob(rule, operation);
return job;
};
Loading

0 comments on commit 90e2314

Please sign in to comment.