birdgrinder 0.1.3.1 → 0.1.4.0
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.
- data/bin/birdgrinder +21 -0
- data/lib/bird_grinder.rb +1 -1
- data/lib/bird_grinder/stream_handler.rb +9 -3
- data/lib/bird_grinder/tweeter.rb +23 -21
- data/lib/bird_grinder/tweeter/abstract_authorization.rb +19 -0
- data/lib/bird_grinder/tweeter/basic_authorization.rb +23 -0
- data/lib/bird_grinder/tweeter/oauth_authorization.rb +54 -0
- data/lib/bird_grinder/tweeter/streaming.rb +6 -5
- data/lib/bird_grinder/tweeter/streaming_request.rb +11 -5
- metadata +25 -2
data/bin/birdgrinder
CHANGED
@@ -26,5 +26,26 @@ BirdGrinder::Application.processing(ARGV) do |a|
|
|
26
26
|
template 'hello_world_handler.erb', 'handlers/hello_world_handler.rb'
|
27
27
|
template 'rakefile.erb', 'Rakefile'
|
28
28
|
end
|
29
|
+
|
30
|
+
a.add("authorize", "Gets oauth access token information making it possible to use oauth authentication") do |options|
|
31
|
+
puts "First, you need to create a twitter application and get a consumer key and secret."
|
32
|
+
puts "To do this, visit http://twitter.com/apps/new"
|
33
|
+
system("open", "http://twitter.com/apps/new") if yes?("Are you running OSX and wish to open this url now?")
|
34
|
+
consumer_key, consumer_secret = "", ""
|
35
|
+
consumer_key = ask("What is your applications consumer key?", "") while consumer_key.blank?
|
36
|
+
consumer_secret = ask("What is your applications consumer secret?", "") while consumer_secret.blank?
|
37
|
+
BirdGrinder::Settings.oauth.consumer_key = consumer_key
|
38
|
+
BirdGrinder::Settings.oauth.consumer_secret = consumer_secret
|
39
|
+
oauth = BirdGrinder::Tweeter::OAuthAuthentication
|
40
|
+
rtoken = oauth.request_token
|
41
|
+
token, secret = rtoken.token, rtoken.secret
|
42
|
+
puts "To get a pin for your account, please visit: #{rtoken.authorize_url}"
|
43
|
+
system("open", rtoken.authorize_url) if yes?("Are you running OSX and wish to open this url now?")
|
44
|
+
value = ""
|
45
|
+
value = ask("What is the PIN twitter gave you?", "") while value.blank?
|
46
|
+
puts "Updating settings..."
|
47
|
+
oauth.retrieve_access_token!(token, secret, value)
|
48
|
+
puts "Done! - Your access token should now be stored"
|
49
|
+
end
|
29
50
|
|
30
51
|
end
|
data/lib/bird_grinder.rb
CHANGED
@@ -9,7 +9,7 @@ module BirdGrinder
|
|
9
9
|
# @param [Symbol] the stream name, e.g. :filter / :sample
|
10
10
|
def tweet_from_stream(name, &blk)
|
11
11
|
on_event(:incoming_stream) do
|
12
|
-
instance_eval(&blk) if
|
12
|
+
instance_eval(&blk) if correct_stream?(name, :tweet)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -17,7 +17,7 @@ module BirdGrinder
|
|
17
17
|
# @param [Symbol] the stream name, e.g. :filter / :sample
|
18
18
|
def delete_from_stream(name, &blk)
|
19
19
|
on_event(:incoming_stream) do
|
20
|
-
instance_eval(&blk) if
|
20
|
+
instance_eval(&blk) if correct_stream?(name, :delete)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
@@ -25,7 +25,7 @@ module BirdGrinder
|
|
25
25
|
# @param [Symbol] the stream name, e.g. :filter / :sample
|
26
26
|
def rate_limit_from_stream(name, &blk)
|
27
27
|
on_event(:incoming_stream) do
|
28
|
-
instance_eval(&blk) if
|
28
|
+
instance_eval(&blk) if correct_stream?(name, :limit)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -40,5 +40,11 @@ module BirdGrinder
|
|
40
40
|
|
41
41
|
end
|
42
42
|
|
43
|
+
protected
|
44
|
+
|
45
|
+
def correct_stream?(name, type)
|
46
|
+
options.streaming_source == name && options.stream_type == type
|
47
|
+
end
|
48
|
+
|
43
49
|
end
|
44
50
|
end
|
data/lib/bird_grinder/tweeter.rb
CHANGED
@@ -20,13 +20,14 @@ module BirdGrinder
|
|
20
20
|
|
21
21
|
require 'bird_grinder/tweeter/streaming'
|
22
22
|
require 'bird_grinder/tweeter/search'
|
23
|
+
require 'bird_grinder/tweeter/abstract_authorization'
|
24
|
+
require 'bird_grinder/tweeter/basic_authorization'
|
25
|
+
require 'bird_grinder/tweeter/oauth_authorization'
|
23
26
|
|
24
27
|
VALID_FETCHES = [:direct_messages, :mentions]
|
25
28
|
|
26
29
|
cattr_accessor :api_base_url
|
27
30
|
self.api_base_url = "http://twitter.com/"
|
28
|
-
|
29
|
-
attr_reader :auth_credentials
|
30
31
|
|
31
32
|
# Initializes the tweeter with a given delegate. It will use
|
32
33
|
# username and password from your settings file for authorization
|
@@ -35,7 +36,6 @@ module BirdGrinder
|
|
35
36
|
# @param [Delegate] delegate the delegate class
|
36
37
|
def initialize(delegate)
|
37
38
|
check_auth!
|
38
|
-
@auth_credentials = [BirdGrinder::Settings.username, BirdGrinder::Settings.password]
|
39
39
|
delegate_to delegate
|
40
40
|
end
|
41
41
|
|
@@ -58,7 +58,7 @@ module BirdGrinder
|
|
58
58
|
user = user.to_s.strip
|
59
59
|
logger.info "Following '#{user}'"
|
60
60
|
post("friendships/create.json", opts.merge(:screen_name => user)) do
|
61
|
-
delegate.receive_message(:outgoing_follow,
|
61
|
+
delegate.receive_message(:outgoing_follow, N(:user => user))
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -70,7 +70,7 @@ module BirdGrinder
|
|
70
70
|
user = user.to_s.strip
|
71
71
|
logger.info "Unfollowing '#{user}'"
|
72
72
|
post("friendships/destroy.json", opts.merge(:screen_name => user)) do
|
73
|
-
delegate.receive_message(:outgoing_unfollow,
|
73
|
+
delegate.receive_message(:outgoing_unfollow, N(:user => user))
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
@@ -95,8 +95,8 @@ module BirdGrinder
|
|
95
95
|
text = text.to_s.strip
|
96
96
|
user = user.to_s.strip
|
97
97
|
logger.debug "DM'ing #{user}: #{text}"
|
98
|
-
post("direct_messages/new.json", opts.merge(:user => user, :text => text)) do
|
99
|
-
delegate.receive_message(:outgoing_direct_message,
|
98
|
+
post("direct_messages/new.json", opts.merge(:user => user, :text => text)) do |json|
|
99
|
+
delegate.receive_message(:outgoing_direct_message, status_to_args(json, :direct_message))
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
@@ -182,13 +182,18 @@ module BirdGrinder
|
|
182
182
|
end
|
183
183
|
else
|
184
184
|
logger.info "Getting all followers for #{id}"
|
185
|
-
get_followers(id, opts.merge(:cursor => -1), {
|
185
|
+
get_followers(id, opts.merge(:cursor => -1), N({
|
186
186
|
:user_id => id,
|
187
187
|
:all => true,
|
188
188
|
:ids => []
|
189
|
-
}
|
189
|
+
}))
|
190
190
|
end
|
191
191
|
end
|
192
|
+
|
193
|
+
# @todo Use correct authorization method
|
194
|
+
def authorization_method
|
195
|
+
@authorization_method ||= (OAuthAuthorization.enabled? ? OAuthAuthorization : BasicAuthorization).new
|
196
|
+
end
|
192
197
|
|
193
198
|
protected
|
194
199
|
|
@@ -214,10 +219,9 @@ module BirdGrinder
|
|
214
219
|
end
|
215
220
|
|
216
221
|
def get(path, params = {}, &blk)
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
})
|
222
|
+
req = request(path)
|
223
|
+
http = req.get(:query => params)
|
224
|
+
authorization_method.add_header_to(http)
|
221
225
|
add_response_callback(http, blk)
|
222
226
|
http
|
223
227
|
end
|
@@ -225,13 +229,12 @@ module BirdGrinder
|
|
225
229
|
def post(path, params = {}, &blk)
|
226
230
|
real_params = {}
|
227
231
|
params.each_pair { |k,v| real_params[CGI.escape(k.to_s)] = CGI.escape(v) }
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
'Content-Type' => 'application/x-www-form-urlencoded'
|
232
|
-
},
|
232
|
+
req = request(path)
|
233
|
+
http = req.post({
|
234
|
+
:head => {'Content-Type' => 'application/x-www-form-urlencoded'},
|
233
235
|
:body => real_params
|
234
236
|
})
|
237
|
+
authorization_method.add_header_to(http)
|
235
238
|
add_response_callback(http, blk)
|
236
239
|
http
|
237
240
|
end
|
@@ -276,9 +279,8 @@ module BirdGrinder
|
|
276
279
|
end
|
277
280
|
|
278
281
|
def check_auth!
|
279
|
-
if BirdGrinder::Settings
|
280
|
-
|
281
|
-
end
|
282
|
+
return if BirdGrinder::Settings.username? && BirdGrinder::Settings.password?
|
283
|
+
raise BirdGrinder::MissingAuthDetails, "Missing twitter username or password."
|
282
284
|
end
|
283
285
|
|
284
286
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module BirdGrinder
|
2
|
+
class Tweeter
|
3
|
+
class AbstractAuthorization
|
4
|
+
|
5
|
+
is :loggable
|
6
|
+
|
7
|
+
def add_header_to(http)
|
8
|
+
headers = (http.options[:head] ||= {})
|
9
|
+
headers['Authorization'] = self.header_for(http)
|
10
|
+
end
|
11
|
+
|
12
|
+
def header_for(http)
|
13
|
+
raise NotImplementedError
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module BirdGrinder
|
2
|
+
class Tweeter
|
3
|
+
class BasicAuthorization < AbstractAuthorization
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@basic_auth_credentials = [BirdGrinder::Settings.username, BirdGrinder::Settings.password]
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :basic_auth_credentials
|
10
|
+
|
11
|
+
# Authenticats a given request using Basic authorization.
|
12
|
+
def header_for(http)
|
13
|
+
@basic_auth_credentials
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def generate_header!
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'oauth'
|
2
|
+
require 'em-http-oauth-request'
|
3
|
+
|
4
|
+
module BirdGrinder
|
5
|
+
class Tweeter
|
6
|
+
class OAuthAuthorization< AbstractAuthorization
|
7
|
+
|
8
|
+
# Authenticates a given request.
|
9
|
+
def header_for(request)
|
10
|
+
OAuth::Client::Helper.new(request, {
|
11
|
+
:token => self.class.oauth_access_token,
|
12
|
+
:consumer => self.class.oauth_consumer
|
13
|
+
}).header
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.enabled?
|
17
|
+
oauth = BirdGrinder::Settings.oauth
|
18
|
+
oauth.present? && [:consumer_key, :consumer_secret, :access_token_token, :access_token_secret].all? { |k| oauth[k].present? }
|
19
|
+
end
|
20
|
+
|
21
|
+
# From the twitter gem, with modification
|
22
|
+
def self.retrieve_access_token!(raw_request_token, request_secret, pin)
|
23
|
+
request_token = OAuth::RequestToken.new(self.oauth_consumer, raw_request_token, request_secret)
|
24
|
+
access_token = request_token.get_access_token(:oauth_verifier => pin)
|
25
|
+
original_settings = BirdGrinder::Settings.oauth.to_hash
|
26
|
+
original_settings.merge! :access_token_token => access_token.token,
|
27
|
+
:access_token_secret => access_token.secret
|
28
|
+
BirdGrinder::Settings.update! :oauth => original_settings.stringify_keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.request_token
|
32
|
+
@request_token ||= self.oauth_consumer.get_request_token
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def self.oauth_consumer
|
38
|
+
@oauth_consumer ||= begin
|
39
|
+
settings = BirdGrinder::Settings.oauth
|
40
|
+
site = Tweeter.api_base_url.gsub(/\/$/, '')
|
41
|
+
OAuth::Consumer.new(settings.consumer_key, settings.consumer_secret, :site => site)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.oauth_access_token
|
46
|
+
@oauth_access_token ||= begin
|
47
|
+
settings = BirdGrinder::Settings.oauth
|
48
|
+
OAuth::AccessToken.new(self.oauth_consumer, settings.access_token_token, settings.access_token_secret)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -40,19 +40,20 @@ module BirdGrinder
|
|
40
40
|
# Start processing the filter stream with a given follow
|
41
41
|
# argument.
|
42
42
|
#
|
43
|
-
# @param [Array] args what to follow, joined with ","
|
43
|
+
# @param [Array] args what to follow, joined with "," followed by opts
|
44
44
|
def follow(*args)
|
45
45
|
opts = args.extract_options!
|
46
|
-
opts[:follow] = args.join(",")
|
46
|
+
opts[:follow] = args.flatten.join(",")
|
47
47
|
opts[:path] = :filter
|
48
48
|
stream(:follow, opts)
|
49
49
|
end
|
50
50
|
|
51
51
|
# Starts tracking a specific query.
|
52
52
|
#
|
53
|
-
# @param [
|
54
|
-
def track(
|
55
|
-
opts
|
53
|
+
# @param [Array] args what to track, joined with "," followed by opts
|
54
|
+
def track(*args)
|
55
|
+
opts = args.extract_options!
|
56
|
+
opts[:track] = args.flatten.join(",")
|
56
57
|
opts[:path] = :filter
|
57
58
|
stream(:track, opts)
|
58
59
|
end
|
@@ -45,7 +45,8 @@ module BirdGrinder
|
|
45
45
|
logger.debug "Preparing to start stream"
|
46
46
|
@stream_processor = nil
|
47
47
|
type = request_method
|
48
|
-
http = EventMachine::HttpRequest.new(full_url).send(type, http_options(type))
|
48
|
+
http = EventMachine::HttpRequest.new(full_url).send(type, http_options(type, request))
|
49
|
+
authorization_method.add_header_to(http)
|
49
50
|
# Handle failures correctly so we can back off
|
50
51
|
@current_request = http
|
51
52
|
http.errback { fail!(:network)}
|
@@ -100,21 +101,22 @@ module BirdGrinder
|
|
100
101
|
# what method is used to send the request. It's important that
|
101
102
|
# this is used for credentials as well as making sure there is
|
102
103
|
# no timeout on the connection
|
103
|
-
def default_request_options
|
104
|
-
{:
|
104
|
+
def default_request_options(r)
|
105
|
+
{:timeout => 0, :head => {}}
|
105
106
|
end
|
106
107
|
|
107
108
|
# Returns normalized http options for the current request, built
|
108
109
|
# on top of default_request_options and a few other details.
|
109
110
|
#
|
110
111
|
# @param [Symbol] type the type of request - :post or :get
|
111
|
-
|
112
|
+
# @param [EventMachine::HttpRequest] the request itself
|
113
|
+
def http_options(type, request)
|
112
114
|
base = self.default_request_options
|
113
115
|
if @options.present?
|
114
116
|
if type == :get
|
115
117
|
base[:query] = @options
|
116
118
|
else
|
117
|
-
base[:head]
|
119
|
+
base[:head]['Content-Type'] = "application/x-www-form-urlencoded"
|
118
120
|
base[:body] = body = {}
|
119
121
|
@options.each_pair { |k,v| body[CGI.escape(k.to_s)] = CGI.escape(v) }
|
120
122
|
end
|
@@ -136,6 +138,10 @@ module BirdGrinder
|
|
136
138
|
@full_url ||= (Streaming.streaming_base_url / Streaming.api_version.to_s / "statuses" / "#{@path}.json")
|
137
139
|
end
|
138
140
|
|
141
|
+
def authorization_method
|
142
|
+
@authorization_method ||= BasicAuthorization.new
|
143
|
+
end
|
144
|
+
|
139
145
|
end
|
140
146
|
end
|
141
147
|
end
|
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.
|
4
|
+
version: 0.1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Darcy Laycock
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-29 00:00:00 +08:00
|
13
13
|
default_executable: birdgrinder
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -52,6 +52,26 @@ dependencies:
|
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: 0.1.8
|
54
54
|
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: moneta
|
57
|
+
type: :runtime
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.6.0
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: em-http-oauth-request
|
67
|
+
type: :runtime
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 0.1.0
|
74
|
+
version:
|
55
75
|
description:
|
56
76
|
email: sutto@sutto.net
|
57
77
|
executables:
|
@@ -71,6 +91,9 @@ files:
|
|
71
91
|
- lib/bird_grinder/loader.rb
|
72
92
|
- lib/bird_grinder/queue_processor.rb
|
73
93
|
- lib/bird_grinder/stream_handler.rb
|
94
|
+
- lib/bird_grinder/tweeter/abstract_authorization.rb
|
95
|
+
- lib/bird_grinder/tweeter/basic_authorization.rb
|
96
|
+
- lib/bird_grinder/tweeter/oauth_authorization.rb
|
74
97
|
- lib/bird_grinder/tweeter/search.rb
|
75
98
|
- lib/bird_grinder/tweeter/stream_processor.rb
|
76
99
|
- lib/bird_grinder/tweeter/streaming.rb
|