birdgrinder 0.1.3.1 → 0.1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|