- Thu 14 May 2015
- Programming
Recently, Twitter changed the rules for Direct Messaging, so you can message with someone you are not following. That makes it as clean as SMS/texting. I put together a simple app to illustrate how easy it is. You can grab the source with git:
git clone https://bitbucket.org/ericp56/ericp56.bitbucket.org
The following script simply returns the current weather for the US ZIP code provided. You can extend this to provide a wealth of features:
- Leverage your organizations web services in novel ways.
- Follow hashtags and raise alerts in your organization.
- Maintain session state, so you can provide fruitful dialog.
I was able to get this up and running on a basic hosted Linux server; you could do the same for roughly $5/month. There's no reason why it can't be used for your organization. Here's a high level list of the steps to take:
- Set up a Twitter app and generate access tokens.
- Provision a Linux server.
- Install node using package manager
- Create/use a user-level Linux account
- Create a twitter-app folder and npm install the required modules (twitter-js-client, twitter-node-client and user-stream).
- Copy the sample .js and .sh files to the twitter-app folder.
- In the start_weather.sh file, set the variables as defined by your Twitter app.
- Verify firewall rules to allow Twitter traffic and access to web services.
- Run start_weather.sh
Here's the source of twitter_weather_pm.js:
//node libraries
var http = require('http'); //used for Web service calls
var Stream = require('user-stream'); //used to recieve twitter feed
var Twitter = require('twitter-node-client').Twitter; //used to send messages
//Set up the twitter API
var config = {
"consumerKey": process.env.CKEY,
"consumerSecret": process.env.CSEC,
"accessToken": process.env.ATOKEN,
"accessTokenSecret": process.env.ATOKENSEC,
"callBackUrl": process.env.CALLBACKURL
}
var twitter = new Twitter(config);
//Set up twitter stream
var stream = new Stream({
"consumer_key": config.consumerKey,
"consumer_secret": config.consumerSecret,
"access_token_key": config.accessToken,
"access_token_secret": config.accessTokenSecret
});
//Common Callback functions
var error = function (err, response, body) {
console.log('ERROR [%s]', JSON.stringify(err));
};
var success = function (data) {
console.log('Data [%s]', data);
};
//Business Rule Callbacks
function handleIncomingPM(json) {
console.log(json);
if(json && json.direct_message && json.direct_message.text && json.direct_message.sender_id)
getAndReportWeather(json.direct_message.text, json.direct_message.sender_id);
}
function getAndReportStatus(zipCode, twitterId) {
var get_options = {
host: 'api.openweathermap.org',
port: '80',
path: '/data/2.5/weather?zip=ZIPCODE,us'.replace(/ZIPCODE/, zipCode);
method: 'GET',
headers: { }
};
var get_req = http.request(get_options, function(res) {processGetResponse(res, twitterId)});
get_req.end();
}
function processGetResponse(res, twitterId) {
var bodyChunks = [];
res.setEncoding('utf8');
res.on('data', function (chunk) {
bodyChunks.push(chunk);
}).on('end', function() {
processStatusResults(eval(Buffer.concat(bodyChunks)), twitterId);
});
}
function processStatusResults(result, twitterId) {
var status = "No status available";
try {
status = result.weather[0].description;
} catch(e) {
}
twitter.postCustomApiCall('/direct_messages/new.json',{user_id: twitterId, status}, error, success);
}
//OK, create the stream listener and get to work
stream.stream();
stream.on('data', handleIncomingPM);
Here's the source of start_weather.sh:
#!/bin/bash
export CKEY="consumer key from twitter"
export CSEC="consumer secret"
export ATOKEN="access token"
export ATOKENSEC="access token secret"
export CALLBACKURL="callback url for oAuth"
node twitter_weather_pm.js
# once you are happy with observing the app running
# use the following line to let it run in the background
# and log all output to apilog
# node twitter_weather_pm.js > apilog 2>&1 &