class Safubot::Twitter::Bot

A Twitter::Bot instance provides a Safubot::Bot with Twitter-specific processing.

Attributes

client[R]
opts[R]
username[R]

Public Class Methods

new(options={}) click to toggle source

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

Public Instance Methods

handle_message(message) click to toggle source

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
handle_request(req) click to toggle source

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
handle_tweet(status) click to toggle source

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
pull() click to toggle source

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
reply(tweet, text) click to toggle source

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
reply_header(tweet) click to toggle source

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
run() click to toggle source

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
send(resp) click to toggle source

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