Skip to content

Instantly share code, notes, and snippets.

@Kramin42
Created April 20, 2016 10:43
Show Gist options
  • Save Kramin42/3d9c3b81e1567f325efbc2787b2359f1 to your computer and use it in GitHub Desktop.
Save Kramin42/3d9c3b81e1567f325efbc2787b2359f1 to your computer and use it in GitHub Desktop.
#!/bin/env node
var express = require('express');
var fs = require('fs');
var irc = require('irc');
var Dota2Api = require('dota2-api');
//DOTA_API_KEY = 'D3FE4C4AAE0631B3D9C0E3D4E6560D4F';
var da = Dota2Api.create('D3FE4C4AAE0631B3D9C0E3D4E6560D4F');
var heroes = [];
da.getHeroes({language: 'en'}, function(err, result){
if(!err) {
//console.log(result);
heroes = JSON.parse(result)['result']['heroes'];
}
});
//mongoDB stuff
var ip_addr = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1';
var port = process.env.OPENSHIFT_NODEJS_PORT || '8080';
// default to a 'localhost' configuration:
var connection_string = '127.0.0.1:27017/kbot';
// if OPENSHIFT env variables are present, use the available connection info:
if(process.env.OPENSHIFT_MONGODB_DB_PASSWORD){
connection_string = process.env.OPENSHIFT_MONGODB_DB_USERNAME + ":" +
process.env.OPENSHIFT_MONGODB_DB_PASSWORD + "@" +
process.env.OPENSHIFT_MONGODB_DB_HOST + ':' +
process.env.OPENSHIFT_MONGODB_DB_PORT + '/' +
process.env.OPENSHIFT_APP_NAME;
}
console.log("connection_string: "+connection_string);
var mongojs = require('mongojs');
var db = mongojs(connection_string, ['recipes','messages']);
var recipes = db.collection('recipes');
var messages = db.collection('messages');
var botnick = 'dotabot';
var announce_timer;
function timeSince(date) {
var seconds = Math.floor(((new Date().getTime()/1000) - date/1000)),
interval = Math.floor(seconds / 31536000);
if (interval > 1) return interval + "Y";
interval = Math.floor(seconds / 2592000);
if (interval > 1) return interval + "M";
interval = Math.floor(seconds / 86400);
if (interval >= 1) return interval + "D";
interval = Math.floor(seconds / 3600);
if (interval >= 1) return interval + "h";
interval = Math.floor(seconds / 60);
if (interval > 1) return interval + "m ";
return Math.floor(seconds) + "s";
}
function leftPad(number, targetLength) {
var output = number + '';
while (output.length < targetLength) {
output = '0' + output;
}
return output;
}
function announce_check(){
delay = 30;
console.log('Checking recent games on timer...');
db.messages.find({'dota_account_id': {$exists: true}}, {'dota_account_id': 1, 'nick': 1}).toArray(function(err, accounts){
if (!err) {
//console.log(accounts);
var idtoname = {};
var nametoid = {};
accounts.forEach(function(account){
idtoname[account['dota_account_id']] = account['nick'];
nametoid[account['nick']] = account['dota_account_id'];
});
console.log(idtoname);
query = {
'matches_requested': 100
};
da.getMatchHistory(query, function(err, result){
if(!err){
console.log(result)
result = JSON.parse(result);
if (!result['result']){
return;
}
result = result['result'];
console.log('checking '+result['matches'].length+' most recent matches.');
var matches = result['matches'].filter(function(match){
var ps = match['players'].filter(function(p){
return p in nametoid;
});
return ps.length > 0;
});
console.log(matches);
matches.forEach(function(match){
da.getMatchDetails({'match_id': match['match_id']}, function(err, result){
if(!err){
var result = JSON.parse(result)
result = result['result'];
console.log(result);
//var player = result['players'].filter(function(p){return p['account_id']==query['account_id'];})[0];
//console.log(player);
//var date = new Date(result['start_time']*1000);
var dur = result['duration'];
var players = match['players'].filter(function(p){
return p in nametoid;
});
players.forEach(function(player){
var hero = heroes.filter(function(h){return h['id']==player['hero_id'];})[0];
bot.say('##kramell', name+' '+(player['player_slot']<128 == result['radiant_win'] ? 'won' : 'lost')+' as '+hero['localized_name']+' after '+Math.floor(dur/3600)+':'+leftPad(Math.floor((dur/60)%60), 2)+':'+leftPad(dur%60, 2)+' with '+player['kills']+'/'+player['deaths']+'/'+player['assists']+" ("+timeSince((result['start_time']+dur)*1000)+" ago)");
});
}
});
});
//console.log(result);
}
});
} else {
console.log(err);
}
});
if (announce_timer) {
clearTimeout(announce_timer);
}
// announce_timer = setTimeout(
// function() {
// announce_check();
// },
// delay * 1000
// );
}
function do_command(command, arg, nick, chan) {
if (command === "tell") {
db.messages.update({"nick":arg[0].toLowerCase()},{$addToSet: {"messages": {"from": nick, "time": new Date().getTime(),"text": arg.slice(1).join(' ')}}, $set: {"notified": false}}, function (err, updated) {
if (updated["n"]>0) {
bot.say(chan, nick+": OK, I'll let "+arg[0]+" know.");
} else {
bot.say(chan, "Sorry "+nick+", I don't know who "+arg[0]+" is.");
}
});
}
if (command === "messages") {
db.messages.findOne({"nick": nick.toLowerCase()}, function(err, data) {
if (data) {
if (!data["messages"] || data["messages"].length==0) {
bot.say(chan, "No messages for "+nick+".");
} else {
count = data["messages"].length;
text = data["messages"][0]["text"];
time = data["messages"][0]["time"];
from = data["messages"][0]["from"];
bot.say(chan, "(1/"+count+") "+from+" said ("+timeSince(time)+" ago): "+text);
db.messages.update({"nick": nick.toLowerCase()}, {$pull: {"messages":{"time":time}}, $set: {"notified": true}});
}
}
});
}
if (command === "seen") {
}
if (command === "lg") {
query = {
'matches_requested': 1
};
name = nick;
if (arg[0] && arg[0]!='.')
name = arg[0];
db.messages.findOne({"nick": name.toLowerCase()}, function(err, data) {
if (data && data['dota_account_id']) {
query['account_id'] = data['dota_account_id'];
} else if (arg[0] && arg[0].match(/\d+/)) {
query['account_id'] = arg[0];
} else {
bot.say(chan, name+' is not registered, use !register <name> <account ID>');
return;
}
console.log(query);
da.getMatchHistory(query, function(err, result){
if(!err){
console.log(err)
result = JSON.parse(result);
if (!result['result']){
bot.say(chan, 'No matches found or the DotA 2 WebAPI is down.');
return;
}
result = result['result'];
console.log(result);
da.getMatchDetails({'match_id': result['matches'][0]['match_id']}, function(err, result){
if(!err){
var result = JSON.parse(result)
result = result['result'];
console.log(result);
var player = result['players'].filter(function(p){return p['account_id']==query['account_id'];})[0];
console.log(player);
var hero = heroes.filter(function(h){return h['id']==player['hero_id'];})[0];
//var date = new Date(result['start_time']*1000);
var dur = result['duration'];
bot.say(chan, name+' '+(player['player_slot']<128 == result['radiant_win'] ? 'won' : 'lost')+' as '+hero['localized_name']+' after '+Math.floor(dur/3600)+':'+leftPad(Math.floor((dur/60)%60), 2)+':'+leftPad(dur%60, 2)+' with '+player['kills']+'/'+player['deaths']+'/'+player['assists']+" ("+timeSince((result['start_time']+dur)*1000)+" ago)");
}
});
}
});
});
}
if (command === 'register') {
name = nick;
if (arg[0] && arg[0]!='.') {
name = arg[0];
}
if (arg[1] && arg[1].match(/\d+/)) {
db.messages.update({"nick": name.toLowerCase()}, {$set: {"dota_account_id": arg[1]}}, function(err,result) {
if (err) { console.log(err); res.send(err); return;}
if (result) {
bot.say(chan, 'Account ID of '+name+' set to '+arg[1]);
} else {
bot.say(chan, 'Sorry, I don\'t know who '+name+' is.');
}
});
} else {
bot.say(chan, 'Please enter a valid account ID. (!register <name> <account ID>)');
}
}
if (command === 'test'){
announce_check();
}
}
function handle_message(from, to, message) {
if (!announce_timer){announce_check();}
nick = from;
chan = to[0]==='#' ? to : nick;
if( message.indexOf('Hi '+botnick) > -1) {
bot.say(to, 'Hi '+from);
}
if ('!'.indexOf(message[0])>-1){
//remove prefix and handle " "
arg = message.slice(1, message.length).trim().split('\"');
arg = arg.map(function(val,index) {return index%2==0 ? val : val.replace(/ /g, 'SPCSPCSPC');});
arg = arg.join('').split(' ');
arg = arg.map(function(val,index) {return val.replace(/SPCSPCSPC/g, ' ');});
//arg = [].concat.apply([], arg);
console.log(arg);
//admin = chan==control_channel || adminlist.indexOf(nick)>-1;
do_command(arg[0], arg.slice(1), nick, chan);
}
db.messages.findOne({"nick": nick.toLowerCase()}, function(err, data) {
if (!data) {
db.messages.insert({"nick": nick.toLowerCase(), "seen": new Date().getTime()});
} else {
db.messages.update({"nick": nick.toLowerCase()}, {$set: {"seen": new Date().getTime(), "lastsaid":message}});
if (data["messages"] && data["messages"].length>0 && !data["notified"] && message.search("!messages")!=0) {
n = data["messages"].length;
bot.say(chan, nick+": You have "+n+(n>1 ? " messages" : " message")+". Use !messages to read "+(n>1 ? "them." : "it."));
db.messages.update({"nick": nick.toLowerCase()}, {$set: {"notified": true}});
}
}
});
}
var bot = new irc.Client('chat.freenode.net', botnick, {
channels: ['##kramell'], // , #dota2
port: 6667,
debug: true,
autoRejoin: true,
autoConnect: true
});
bot.addListener('message', handle_message);
/**
* Define the sample application.
*/
var SampleApp = function() {
// Scope.
var self = this;
/* ================================================================ */
/* Helper functions. */
/* ================================================================ */
/**
* Set up server IP address and port # using env variables/defaults.
*/
self.setupVariables = function() {
// Set the environment variables we need.
self.ipaddress = process.env.OPENSHIFT_NODEJS_IP;
self.port = process.env.OPENSHIFT_NODEJS_PORT || 8080;
if (typeof self.ipaddress === "undefined") {
// Log errors on OpenShift but continue w/ 127.0.0.1 - this
// allows us to run/test the app locally.
console.warn('No OPENSHIFT_NODEJS_IP var, using 127.0.0.1');
self.ipaddress = "127.0.0.1";
};
};
/**
* Populate the cache.
*/
self.populateCache = function() {
if (typeof self.zcache === "undefined") {
self.zcache = { 'index.html': '' };
}
// Local cache for static content.
self.zcache['index.html'] = fs.readFileSync('./index.html');
};
/**
* Retrieve entry (content) from cache.
* @param {string} key Key identifying content to retrieve from cache.
*/
self.cache_get = function(key) { return self.zcache[key]; };
/**
* terminator === the termination handler
* Terminate server on receipt of the specified signal.
* @param {string} sig Signal to terminate on.
*/
self.terminator = function(sig){
if (typeof sig === "string") {
console.log('%s: Received %s - terminating sample app ...',
Date(Date.now()), sig);
process.exit(1);
}
console.log('%s: Node server stopped.', Date(Date.now()) );
};
/**
* Setup termination handlers (for exit and a list of signals).
*/
self.setupTerminationHandlers = function(){
// Process on exit and signals.
process.on('exit', function() { self.terminator(); });
// Removed 'SIGPIPE' from the list - bugz 852598.
['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT',
'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGTERM'
].forEach(function(element, index, array) {
process.on(element, function() { self.terminator(element); });
});
};
/* ================================================================ */
/* App server functions (main app logic here). */
/* ================================================================ */
/**
* Create the routing table entries + handlers for the application.
*/
self.createRoutes = function() {
self.routes = { };
self.routes['/asciimo'] = function(req, res) {
var link = "http://i.imgur.com/kmbjB.png";
res.send("<html><body><img src='" + link + "'></body></html>");
};
self.routes['/'] = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.send(self.cache_get('index.html') );
};
};
/**
* Initialize the server (express) and create the routes and register
* the handlers.
*/
self.initializeServer = function() {
self.createRoutes();
self.app = express.createServer();
// Add handlers for the app (from the routes).
for (var r in self.routes) {
self.app.get(r, self.routes[r]);
}
};
/**
* Initializes the sample application.
*/
self.initialize = function() {
self.setupVariables();
self.populateCache();
self.setupTerminationHandlers();
// Create the express server and routes.
self.initializeServer();
};
/**
* Start the server (starts up the sample application).
*/
self.start = function() {
// Start the app on the specific interface (and port).
self.app.listen(self.port, self.ipaddress, function() {
console.log('%s: Node server started on %s:%d ...',
Date(Date.now() ), self.ipaddress, self.port);
});
};
}; /* Sample Application. */
/**
* main(): Main code.
*/
var zapp = new SampleApp();
zapp.initialize();
zapp.start();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment