Class: Safubot::Twitter::Bot

Inherits:
Object
  • Object
show all
Includes:
Evented
Defined in:
lib/safubot/twitter.rb

Overview

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

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Methods included from Evented

#bind, #emit, #on, #once, #unbind

Constructor Details

- (Bot) initialize(options = {})

Options are passed straight through to ::TweetStream and ::Twitter, but the :username is ours and important.



265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/safubot/twitter.rb', line 265

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

Instance Attribute Details

- (Object) client (readonly)

Returns the value of attribute client



159
160
161
# File 'lib/safubot/twitter.rb', line 159

def client
  @client
end

- (Object) opts (readonly)

Returns the value of attribute opts



159
160
161
# File 'lib/safubot/twitter.rb', line 159

def opts
  @opts
end

- (Object) username (readonly)

Returns the value of attribute username



159
160
161
# File 'lib/safubot/twitter.rb', line 159

def username
  @username
end

Instance Method Details

- (Object) handle_message(message)

Stores a DM and creates a matching Request as needed.



179
180
181
182
# File 'lib/safubot/twitter.rb', line 179

def handle_message(message)
		return if message.sender.screen_name == @username
		DirectMessage.from(message).make_request
end

- (Object) handle_request(req)

Emit a request event unless the request is already processed.



174
175
176
# File 'lib/safubot/twitter.rb', line 174

def handle_request(req)
		emit(:request, req) unless req.nil? || req.processed
end

- (Object) handle_tweet(status)

Stores a tweet. If this tweet is directed at us, create a matching Request. Otherwise, emit a :timeline event.



186
187
188
189
190
191
192
193
# File 'lib/safubot/twitter.rb', line 186

def handle_tweet(status)
		return if status.user.screen_name == @username
		if status.text.match(/@#{@username}/i)
 Tweet.from(status).make_request
		else
 emit(:timeline, Tweet.from(status))
		end
end

- (Object) pull

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.



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/safubot/twitter.rb', line 209

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.error "Twitter: Couldn't pull tweets due to temporary service unavailability."
		rescue Exception => e
 Log.error "Twitter: Unhandled error: #{e}\n#{e.backtrace.join("\n\t")}"
		end
end

- (Object) reply(tweet, text)

Replies to a tweet using the appropriate mentions.

Parameters:

  • tweet

    A Tweet object to respond to.

  • text

    The response text.



203
204
205
# File 'lib/safubot/twitter.rb', line 203

def reply(tweet, text)
		@client.update("#{reply_header(tweet)} #{text}", :in_reply_to_status_id => tweet.raw['id'])
end

- (Object) reply_header(tweet)

Constructs the appropriate series of mentions for a reply to this tweet.



196
197
198
# File 'lib/safubot/twitter.rb', line 196

def reply_header(tweet)
		(["@#{tweet.username}"] + (tweet.header_mentions - ["@#{@username}"])).join
end

- (Object) run

Starts our TweetStream client running.



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/safubot/twitter.rb', line 226

def run
		Fiber.new do
 @stream = TweetStream::Client.new(@opts)

 @stream.on_direct_message do |message|
dm = handle_message(message)
handle_request(dm.request)
 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.error "TweetStream authentication failure!"
else
  Log.error "Unhandled TweetStream error: #{$!} #{$@}"
end
 end

 begin
@stream.userstream do |status|
  tweet = handle_tweet(status)
  handle_request(tweet.request) if tweet.is_a? Tweet
end
 rescue Exception => e
if e.is_a? Interrupt
  exit
else
  Log.error "TweetStream event loop exited: #{$!} #{$@}"
  Log.error "Reinitialising TweetStream in 5 seconds."
  EM::Timer.new(5) { run }
end
 end

 Log.info("Twitter client is online at @#{@username} :3")
		end.resume
end

- (Object) send(resp)

Sends a Twitter-sourced Response to the appropriate target.



162
163
164
165
166
167
168
169
170
171
# File 'lib/safubot/twitter.rb', line 162

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