A Twitter::Bot instance provides a Safubot::Bot with Twitter-specific processing.
Options are passed straight through to ::TweetStream and ::Twitter, but the :username is ours and important.
# File lib/safubot/twitter.rb, line 249 def initialize(options={}) defaults = { :username => nil, :consumer_key => nil, :consumer_secret => nil, :oauth_token => nil, :oauth_token_secret => nil, :auth_method => :oauth } @opts = defaults.merge(options) DirectMessage.ensure_index('raw.id', :unique => true) @username = @opts[:username] @client = Object::Twitter::Client.new(@opts) end
Stores a DM and creates a matching Request as needed.
# File lib/safubot/twitter.rb, line 174 def handle_message(message) return if message.sender.screen_name == @username handle_request(DirectMessage.from(message).make_request) end
Emit a request event unless the request is already processed.
# File lib/safubot/twitter.rb, line 169 def handle_request(req) emit(:request, req) unless req.processed end
Stores a tweet. If this tweet is directed at us, create a matching Request. Otherwise, emit a :timeline event.
# File lib/safubot/twitter.rb, line 181 def handle_tweet(status) return if status.user.screen_name == @username if status.text.match(/@#{@username}/) handle_request(Tweet.from(status).make_request) else emit(:timeline, Tweet.from(status)) end end
Pulls DMs and mentions using the AJAX API. Used in tandem with the streaming API to ensure we don’t miss too much while we’re offline.
# File lib/safubot/twitter.rb, line 204 def pull begin @client.direct_messages.each do |message| handle_message(message) end @client.mentions.each do |mention| handle_tweet(mention) end rescue ::Twitter::Error::ServiceUnavailable Log.write "Twitter: Couldn't pull tweets due to temporary service unavailability." rescue Exception => e Log.write "Twitter: Unhandled error: #{e}\n#{e.backtrace.join("\n\t")}" end end
Replies to a tweet using the appropriate mentions. @param tweet A Tweet object to respond to. @param text The response text.
# File lib/safubot/twitter.rb, line 198 def reply(tweet, text) @client.update("#{reply_header(tweet)} #{text}", :in_reply_to_status_id => tweet.raw['id']) end
Constructs the appropriate series of mentions for a reply to this tweet.
# File lib/safubot/twitter.rb, line 191 def reply_header(tweet) (["@#{tweet.username}"] + (tweet.header_mentions - ["@#{@username}"])).join end
Starts our TweetStream client running.
# File lib/safubot/twitter.rb, line 221 def run @stream = TweetStream::Client.new(@opts) @stream.on_direct_message do |message| handle_message(message) end @stream.on_error do |err| # HACK (Mispy): For some reason this is a String instead of an Exception. if err.match(/invalid status code: 401/) Log.write("TweetStream authentication failure!") else Log.write "Unhandled TweetStream error: #{err}" Log.write "Reinitialising TweetStream in 5 seconds." sleep 5 run end end @stream.userstream do |status| handle_tweet(status) end Log.write("Twitter client is online at @#{@username} :3") end
Sends a Twitter-sourced Response to the appropriate target.
# File lib/safubot/twitter.rb, line 157 def send(resp) source = resp.request.source if source.is_a?(DirectMessage) @client.direct_message_create(source.raw['sender']['screen_name'], resp.text) elsif source.is_a?(Tweet) reply("#{source.header_mentions.join(' ')} #{resp.text}") else raise NotImplementedError, "Don't know how to send response to a #{req.source.class}!" end end