Skip to content

Instantly share code, notes, and snippets.

@jnx
Created September 20, 2011 15:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jnx/1229355 to your computer and use it in GitHub Desktop.
Save jnx/1229355 to your computer and use it in GitHub Desktop.
Node.js Campfire bot
// main app.js
var client = require('ranger').createClient('ROOM',
'SECRET');
var timestamp = require('./timestamp').timestamp;
var getWeatherWrapper = require('./weather').getWeatherWrapper;
var showMap = require('./map').showMap;
var getTweets = require('./tweets').getTweets;
client.room(ROOMID, function(room) {
console.log('Joining ' + room.name + ': ' + timestamp());
room.join(function() {
room.listen(function(msg) {
if (msg.type === 'TextMessage') {
if (msg.body.match(/^!s(hutdown)?/)) {
console.log('Leaving ' + room.name + ': ' + timestamp());
room.leave(function() { process.exit(0); });
}
// this works
if (wanted = msg.body.match(/^!w(?:eather)?\s+(.*)/)) {
getWeatherWrapper(wanted[1], function(e, weather) {
if (e || !weather) {
return console.log(e.message || 'Got no weather!');
}
for (var i = 0; i < 3; i++ ) {
(function() {
var j = i;
process.nextTick(function() {room.speak(weather[j]);})
})();
}
});
}
// works well - but it's only one item
if (wanted = msg.body.match(/^!m(?:ap)?\s+(.*)/)) {
showMap(wanted[1], function(e, url) {
if (e || !url) {
return console.log(e.message || 'Got no url from showMap!');
}
room.speak(url);
});
}
// not working - makes me want to pull out my hair...
if (wanted = msg.body.match(/^!t(?:weets)?\s+(.*)/)) {
// I tried this, but I'm not even using it at the moment - mostly I blew
// the stack when getting this wrong
var handle_tweets = function(ids, iteration, callback) {
if (iteration >= 3) {
return callback(null, ids.shift());
}
handle_tweets(ids, iteration+1, callback);
}
getTweets(wanted[1], function(e, tweet_ids) {
if (e || !tweet_ids) {
console.log(e.message || 'Got no tweet ids');
}
// This uses the same process.nextTick as the weather above, but it doesn't
// work for whatever reason.
console.log('tweet_ids ' + tweet_ids);
for (var i = 0; i < 3; i++) {
(function() {
var j = i;
var status = 'http://twitter.com/' + wanted[1] +
'/status/' + tweet_ids[j];
process.nextTick(function() {room.tweet(status);})
})();
}
});
}
}
});
});
});
// weather.js - this one works to give three items in order
var http = require('http');
var url = require('url');
// Use this later to cache woeids of places we want weather for
var query_to_woeid = {};
function getWOEID(wanted, callback) {
var path = '/v1/public/yql?q='
var query = 'select woeid from geo.places where text="' +
wanted + '" limit 1' + '&format=json';
query = encodeURI(query);
var options = {
host: 'query.yahooapis.com',
port: 80,
path: path + query,
method: 'GET'
};
var req = http.request(options, function(res) {
var json = '';
res.on('data', function(chunk) { json += chunk; });
res.on('end', function() {
results = JSON.parse(json);
woeid = results['query']['results']['place']['woeid'];
return callback(null, woeid);
})
res.on('error', function(e) {
return callback(e);
});
});
req.on('error', function(e) {
return callback(e);
});
req.end();
}
function getWeather(woeid, callback) {
// Uncomment for debugging
//console.log('Start of getWeather: ' + woeid);
var path = '/forecastjson?w=' + woeid;
var options = {
host: 'weather.yahooapis.com',
port: 80,
path: path,
method: 'GET'
};
var req = http.request(options, function(res) {
var json = '';
res.on('data', function(chunk) { json += chunk; });
res.on('end', function() {
results = JSON.parse(json);
cur = 'Current - ' + results['condition']['text'] + ': ' +
results['condition']['temperature'];
today = 'Today - ' + results['forecast'][0]['condition'] +
': high - ' + results['forecast'][0]['high_temperature'] +
', low - ' + results['forecast'][0]['low_temperature'];
tomorrow = 'Tomorrow - ' + results['forecast'][1]['condition'] +
': high - ' + results['forecast'][1]['high_temperature'] +
', low - ' + results['forecast'][1]['low_temperature'];
return callback(null, [ cur, today, tomorrow ]);
});
res.on('error', function(e) {
return callback(e);
});
});
req.on('error', function(e) {
return callback(e);
});
req.end();
}
function getWeatherWrapper(wanted, callback) {
var seen = query_to_woeid[wanted];
if (seen) {
console.log('Already seen ' + wanted + '. Using the cache...');
getWeather(seen, function(e, weather) {
if (e) {
return console.log(e.message);
}
callback(null, weather);
});
}
else {
getWOEID(wanted, function(e, woeid) {
if (e) {
return console.log(e.message);
}
query_to_woeid[wanted] = woeid;
getWeather(woeid, function(e, weather) {
if (e) {
return console.log(e.message);
}
callback(null, weather);
});
});
}
}
exports.getWeatherWrapper = getWeatherWrapper;
// twitter.js - still doesn't work never three, often just one - though
// I can see in the logs that I'm getting three valid Twitter status ids
exports.getTweets = function(wanted, callback) {
var http = require('http');
var url = require('url');
var path = '/1/statuses/user_timeline.json?screen_name='
var query = wanted + '&count=3';
query = encodeURI(query);
var options = {
host: 'api.twitter.com',
port: 80,
path: path + query,
method: 'GET'
};
var req = http.request(options, function(res) {
var json = '';
res.on('data', function(chunk) { json += chunk; });
res.on('end', function() {
tweets = JSON.parse(json);
console.log('tweets ' + tweets);
ids = [];
for (var i = 0; i < 3; i++) {
if (tweets[i] && tweets[i]['id_str']) {
ids.push(tweets[i]['id_str']);
}
}
console.log('ids ' + ids);
return callback(null, ids);
});
res.on('error', function(e) {
return callback(e);
});
});
req.on('error', function(e) {
return callback(e);
});
req.end();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment