birdgrinder 0.1.0.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -123,7 +123,7 @@ module BirdGrinder
123
123
  @user = options.user.screen_name if options.user? && options.user.screen_name?
124
124
  @user ||= options.sender_screen_name if options.sender_screen_name?
125
125
  @last_message_direct = (message == :incoming_direct_message)
126
- @last_message_id = options.id
126
+ @last_message_id = options.id? ? options.id : -1
127
127
  end
128
128
 
129
129
  def halt_handlers!
@@ -38,9 +38,9 @@ module BirdGrinder
38
38
  # Forwards a given message type (with options) to each handler,
39
39
  # storing the current id if changed.
40
40
  def receive_message(type, options = BirdGrinder::Nash.new)
41
- logger.debug "receiving message: #{type.inspect} - #{options.id}"
41
+ logger.debug "receiving message: #{type.inspect} - #{options.id? ? options.id : 'unknown id'}"
42
42
  dispatch(type.to_sym, options)
43
- update_stored_id_for(type, options.id)
43
+ update_stored_id_for(type, options.id) if options.id?
44
44
  end
45
45
 
46
46
  # Fetches all direct messages and mentions and also schedules
@@ -128,7 +128,7 @@ module BirdGrinder
128
128
  def fetch_latest(name, type)
129
129
  options = {}
130
130
  id = stored_id_for(type)
131
- options[:since_id] = id unless id.blank?
131
+ options[:since_id] = id unless id.blank? || id.to_i == 0
132
132
  @tweeter.send(name, options)
133
133
  end
134
134
 
@@ -0,0 +1,44 @@
1
+ module BirdGrinder
2
+ # A simple BirdGrinder::Base subclass which has a
3
+ # focus on processing tweets from a stream.
4
+ class StreamHandler < Base
5
+
6
+ class << self
7
+
8
+ # Do something on tweet's from a given stream
9
+ # @param [Symbol] the stream name, e.g. :filter / :sample
10
+ def tweet_from_stream(name, &blk)
11
+ on_event(:incoming_stream) do
12
+ instance_eval(&blk) if options.streaming_source == name && options.stream_type == :tweet
13
+ end
14
+ end
15
+
16
+ # Do something on delete's from a given stream
17
+ # @param [Symbol] the stream name, e.g. :filter / :sample
18
+ def delete_from_stream(name, &blk)
19
+ on_event(:incoming_stream) do
20
+ instance_eval(&blk) if options.streaming_source == name && options.stream_type == :delete
21
+ end
22
+ end
23
+
24
+ # Do something on rate limit's from a given stream
25
+ # @param [Symbol] the stream name, e.g. :filter / :sample
26
+ def rate_limit_from_stream(name, &blk)
27
+ on_event(:incoming_stream) do
28
+ instance_eval(&blk) if options.streaming_source == name && options.stream_type == :limit
29
+ end
30
+ end
31
+
32
+ %w(sample filter follow track).each do |type|
33
+ define_method(type.to_sym) do |*args|
34
+ BirdGrinder::Loader.once_running do
35
+ streaming = BirdGrinder::Client.current.tweeter.streaming
36
+ streaming.send(type.to_sym, *args)
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
@@ -18,9 +18,15 @@ module BirdGrinder
18
18
  def process_stream_item(json)
19
19
  return if !json.is_a?(Hash)
20
20
  processed = json.to_nash.normalized
21
- processed.type = lookup_type_for_steam_response(processed)
21
+ stream_type = lookup_type_for_steam_response(processed)
22
+ case stream_type
23
+ when :delete
24
+ processed = processed[:delete].status
25
+ when :limit
26
+ processed = processed.limit
27
+ end
28
+ processed.stream_type = stream_type
22
29
  processed.streaming_source = @stream_name
23
- logger.info "Processing Stream Tweet #{processed.id}: #{processed.text}"
24
30
  @parent.delegate.receive_message(:incoming_stream, processed)
25
31
  end
26
32
 
@@ -61,12 +61,12 @@ module BirdGrinder
61
61
  path = opts.delete(:path)
62
62
  processor = StreamProcessor.new(@parent, name)
63
63
  http_opts = {
64
- :on_response => processor.method(:receive_chunk),
65
- :head => {'Authorization' => @parent.auth_credentials}
64
+ :head => {'Authorization' => @parent.auth_credentials}
66
65
  }
67
66
  http_opts[:query] = opts if opts.present?
68
67
  url = streaming_base_url / api_version.to_s / "statuses" / "#{path || name}.json"
69
68
  http = EventMachine::HttpRequest.new(url).get(http_opts)
69
+ http.stream(&processor.method(:receive_chunk))
70
70
  end
71
71
 
72
72
  end
@@ -159,9 +159,55 @@ module BirdGrinder
159
159
  end
160
160
  end
161
161
  end
162
+
163
+ # Gets a list ids who are following a given user id / screenname
164
+ #
165
+ # @param [String,Integer] id the user id or screen name to get followers for.
166
+ # @param [Hash] opts extra options to pass in the query string.
167
+ # @option opts [Integer] :cursor the cursor offset in the results
168
+ def follower_ids(id, opts = {})
169
+ cursor_list = []
170
+ if opts[:cursor].present?
171
+ logger.info "Getting page w/ cursor #{opts[:cursor]} for #{id}"
172
+ get_followers_page(id, opts) do |res|
173
+ results = BirdGrinder::Nash.new
174
+ results.cursor = opts[:cursor]
175
+ results.user_id = id
176
+ results.ids = res.ids? ? res.ids : []
177
+ results.next_cursor = res.next_cursor || 0
178
+ results.previous_cursor = res.previous_cursor || 0
179
+ results.all = (res.previous_cursor == 0 && res.next_cursor == 0)
180
+ delegate.receive_message(:incoming_follower_ids, results)
181
+ end
182
+ else
183
+ logger.info "Getting all followers for #{id}"
184
+ get_followers(id, opts.merge(:cursor => -1), {
185
+ :user_id => id,
186
+ :all => true,
187
+ :ids => []
188
+ }.to_nash)
189
+ end
190
+ end
162
191
 
163
192
  protected
164
193
 
194
+ def get_followers(id, opts, nash)
195
+ get_followers_page(id, opts) do |res|
196
+ nash.ids += res.ids if res.ids?
197
+ if res.next_cursor == 0
198
+ delegate.receive_message(:incoming_follower_ids, nash)
199
+ else
200
+ get_followers(id, opts.merge(:cursor => res.next_cursor), nash)
201
+ end
202
+ end
203
+ end
204
+
205
+ def get_followers_page(id, opts, &blk)
206
+ get("followers/ids/#{id}.json", opts) do |res|
207
+ blk.call(res)
208
+ end
209
+ end
210
+
165
211
  def request(path = "/")
166
212
  EventMachine::HttpRequest.new(api_base_url / path)
167
213
  end
@@ -191,13 +237,17 @@ module BirdGrinder
191
237
 
192
238
  def add_response_callback(http, blk)
193
239
  http.callback do
194
- res = parse_response(http)
195
- if res.nil?
196
- logger.warn "Got back a blank / errored response."
197
- elsif successful?(res)
198
- blk.call(res) unless blk.blank?
240
+ if http.response_header.status == 200
241
+ res = parse_response(http)
242
+ if res.nil?
243
+ logger.warn "Got back a blank / errored response."
244
+ elsif successful?(res)
245
+ blk.call(res) unless blk.blank?
246
+ else
247
+ logger.error "Error: #{res.error} (on #{res.request})"
248
+ end
199
249
  else
200
- logger.eror "Error: #{res.error} (on #{res.request})"
250
+ logger.info "Request returned a non-200 status code, had #{http.response_header.status} instead."
201
251
  end
202
252
  end
203
253
  end
data/lib/bird_grinder.rb CHANGED
@@ -8,7 +8,7 @@ require 'em-http'
8
8
  module BirdGrinder
9
9
  include Perennial
10
10
 
11
- VERSION = [0, 1, 0, 0]
11
+ VERSION = [0, 1, 1, 0]
12
12
 
13
13
  def self.version(include_minor = false)
14
14
  VERSION[0, (include_minor ? 4 : 3)].join(".")
@@ -22,7 +22,7 @@ module BirdGrinder
22
22
  end
23
23
 
24
24
  has_library :cacheable, :tweeter, :client, :base, :command_handler,
25
- :console, :queue_processor
25
+ :console, :queue_processor, :stream_handler
26
26
 
27
27
  extends_library :loader
28
28
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: birdgrinder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Darcy Laycock
@@ -90,6 +90,7 @@ files:
90
90
  - lib/bird_grinder/exceptions.rb
91
91
  - lib/bird_grinder/loader.rb
92
92
  - lib/bird_grinder/queue_processor.rb
93
+ - lib/bird_grinder/stream_handler.rb
93
94
  - lib/bird_grinder/tweeter/search.rb
94
95
  - lib/bird_grinder/tweeter/stream_processor.rb
95
96
  - lib/bird_grinder/tweeter/streaming.rb