Created
April 20, 2016 10:43
-
-
Save Kramin42/3d9c3b81e1567f325efbc2787b2359f1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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