facebooker 1.0.31 → 1.0.41
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/CHANGELOG.rdoc +7 -0
- data/Manifest.txt +5 -0
- data/README.rdoc +9 -0
- data/facebooker.gemspec +8 -9
- data/generators/facebook/templates/public/javascripts/facebooker.js +10 -16
- data/init.rb +4 -1
- data/install.rb +1 -1
- data/lib/facebooker.rb +75 -20
- data/lib/facebooker/adapters/bebo_adapter.rb +9 -9
- data/lib/facebooker/data.rb +14 -14
- data/lib/facebooker/models/page.rb +16 -0
- data/lib/facebooker/models/photo.rb +7 -0
- data/lib/facebooker/models/user.rb +75 -28
- data/lib/facebooker/parser.rb +187 -127
- data/lib/facebooker/rails/backwards_compatible_param_checks.rb +31 -0
- data/lib/facebooker/rails/controller.rb +30 -7
- data/lib/facebooker/rails/extensions/rack_setup.rb +5 -1
- data/lib/facebooker/rails/facebook_request_fix.rb +5 -5
- data/lib/facebooker/rails/facebook_request_fix_2-3.rb +31 -0
- data/lib/facebooker/rails/facebook_url_rewriting.rb +7 -2
- data/lib/facebooker/rails/helpers.rb +29 -5
- data/lib/facebooker/rails/helpers/fb_connect.rb +14 -5
- data/lib/facebooker/rails/publisher.rb +26 -12
- data/lib/facebooker/service.rb +64 -56
- data/lib/facebooker/session.rb +56 -22
- data/lib/facebooker/version.rb +1 -1
- data/lib/rack/facebook.rb +26 -14
- data/lib/tasks/tunnel.rake +1 -1
- data/test/facebooker/adapters_test.rb +78 -0
- data/test/facebooker/data_test.rb +14 -14
- data/test/facebooker/models/page_test.rb +46 -0
- data/test/facebooker/models/photo_test.rb +16 -0
- data/test/facebooker/models/user_test.rb +83 -48
- data/test/facebooker/rails/facebook_request_fix_2-3_test.rb +25 -0
- data/test/facebooker/rails/facebook_url_rewriting_test.rb +39 -0
- data/test/facebooker/rails/publisher_test.rb +5 -1
- data/test/facebooker/rails_integration_test.rb +52 -8
- data/test/facebooker/service_test.rb +58 -0
- data/test/facebooker/session_test.rb +106 -92
- data/test/facebooker_test.rb +2 -2
- data/test/rack/facebook_test.rb +4 -4
- data/test/test_helper.rb +10 -3
- metadata +14 -4
@@ -0,0 +1,31 @@
|
|
1
|
+
module Facebooker::Rails::BackwardsCompatibleParamChecks
|
2
|
+
|
3
|
+
def one_or_true( value )
|
4
|
+
case value
|
5
|
+
when String then
|
6
|
+
value == "1"
|
7
|
+
when Numeric then
|
8
|
+
value.to_f == 1.0
|
9
|
+
when TrueClass then
|
10
|
+
true
|
11
|
+
else
|
12
|
+
false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def zero_or_false( value )
|
17
|
+
case value
|
18
|
+
when String then
|
19
|
+
value == "0"
|
20
|
+
when Numeric then
|
21
|
+
value.to_f == 0.0
|
22
|
+
when FalseClass then
|
23
|
+
true
|
24
|
+
when NilClass then
|
25
|
+
true
|
26
|
+
else
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -3,6 +3,7 @@ require 'facebooker/rails/profile_publisher_extensions'
|
|
3
3
|
module Facebooker
|
4
4
|
module Rails
|
5
5
|
module Controller
|
6
|
+
include Facebooker::Rails::BackwardsCompatibleParamChecks
|
6
7
|
include Facebooker::Rails::ProfilePublisherExtensions
|
7
8
|
def self.included(controller)
|
8
9
|
controller.extend(ClassMethods)
|
@@ -30,6 +31,12 @@ module Facebooker
|
|
30
31
|
secure_with_facebook_params! || secure_with_cookies! || secure_with_token!
|
31
32
|
end
|
32
33
|
|
34
|
+
#this is used to proxy a connection through a rails app so the facebook secret key is not needed
|
35
|
+
#iphone apps use this
|
36
|
+
def create_facebook_session_with_secret
|
37
|
+
secure_with_session_secret!
|
38
|
+
end
|
39
|
+
|
33
40
|
def set_facebook_session
|
34
41
|
# first, see if we already have a session
|
35
42
|
session_set = session_already_secured?
|
@@ -147,6 +154,15 @@ module Facebooker
|
|
147
154
|
@facebook_session
|
148
155
|
end
|
149
156
|
end
|
157
|
+
|
158
|
+
def secure_with_session_secret!
|
159
|
+
if params['auth_token']
|
160
|
+
@facebook_session = new_facebook_session
|
161
|
+
@facebook_session.auth_token = params['auth_token']
|
162
|
+
@facebook_session.secure_with_session_secret!
|
163
|
+
@facebook_session
|
164
|
+
end
|
165
|
+
end
|
150
166
|
|
151
167
|
def secure_with_facebook_params!
|
152
168
|
return unless request_comes_from_facebook?
|
@@ -162,11 +178,15 @@ module Facebooker
|
|
162
178
|
def after_facebook_login_url
|
163
179
|
nil
|
164
180
|
end
|
181
|
+
|
182
|
+
def default_after_facebook_login_url
|
183
|
+
url_for(:only_path => false, :overwrite_params => {})
|
184
|
+
end
|
165
185
|
|
166
186
|
def create_new_facebook_session_and_redirect!
|
167
187
|
session[:facebook_session] = new_facebook_session
|
168
|
-
|
169
|
-
top_redirect_to session[:facebook_session].login_url(
|
188
|
+
next_url = after_facebook_login_url || default_after_facebook_login_url
|
189
|
+
top_redirect_to session[:facebook_session].login_url({:next => next_url}) unless @installation_required
|
170
190
|
false
|
171
191
|
end
|
172
192
|
|
@@ -205,6 +225,10 @@ module Facebooker
|
|
205
225
|
end
|
206
226
|
|
207
227
|
def verify_signature(facebook_sig_params,expected_signature)
|
228
|
+
# Don't verify the signature if rack has already done so.
|
229
|
+
if ::Rails.version >= "2.3"
|
230
|
+
return if ActionController::Dispatcher.middleware.include? Rack::Facebook
|
231
|
+
end
|
208
232
|
raw_string = facebook_sig_params.map{ |*args| args.join('=') }.sort.join
|
209
233
|
actual_sig = Digest::MD5.hexdigest([raw_string, Facebooker::Session.secret_key].join)
|
210
234
|
raise Facebooker::Session::IncorrectSignature if actual_sig != expected_signature
|
@@ -249,14 +273,13 @@ module Facebooker
|
|
249
273
|
end
|
250
274
|
|
251
275
|
def request_is_facebook_ajax?
|
252
|
-
params["fb_sig_is_mockajax"]
|
276
|
+
one_or_true(params["fb_sig_is_mockajax"]) || one_or_true(params["fb_sig_is_ajax"])
|
253
277
|
end
|
278
|
+
|
254
279
|
def xml_http_request?
|
255
280
|
request_is_facebook_ajax? || super
|
256
281
|
end
|
257
282
|
|
258
|
-
|
259
|
-
|
260
283
|
def application_is_installed?
|
261
284
|
facebook_params['added']
|
262
285
|
end
|
@@ -294,8 +317,8 @@ module Facebooker
|
|
294
317
|
end
|
295
318
|
|
296
319
|
def application_is_not_installed_by_facebook_user
|
297
|
-
|
298
|
-
top_redirect_to session[:facebook_session].install_url(
|
320
|
+
next_url = after_facebook_login_url || default_after_facebook_login_url
|
321
|
+
top_redirect_to session[:facebook_session].install_url({:next => next_url})
|
299
322
|
end
|
300
323
|
|
301
324
|
def set_facebook_request_format
|
@@ -1,2 +1,6 @@
|
|
1
|
+
# Somewhere in 2.3 RewindableInput was removed- rack supports it natively
|
1
2
|
require 'rack/facebook'
|
2
|
-
ActionController::Dispatcher.middleware.
|
3
|
+
ActionController::Dispatcher.middleware.insert_before(
|
4
|
+
ActionController::ParamsParser,
|
5
|
+
Rack::Facebook
|
6
|
+
)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module ::ActionController
|
2
2
|
class AbstractRequest
|
3
|
+
include Facebooker::Rails::BackwardsCompatibleParamChecks
|
4
|
+
|
3
5
|
def request_method_with_facebooker
|
4
6
|
if parameters[:_method].blank?
|
5
7
|
if %w{GET HEAD}.include?(parameters[:fb_sig_request_method])
|
@@ -14,15 +16,13 @@ module ::ActionController
|
|
14
16
|
end
|
15
17
|
|
16
18
|
def xml_http_request_with_facebooker?
|
17
|
-
parameters["fb_sig_is_mockajax"]
|
18
|
-
parameters["fb_sig_is_ajax"]
|
19
|
+
one_or_true(parameters["fb_sig_is_mockajax"]) ||
|
20
|
+
one_or_true(parameters["fb_sig_is_ajax"]) ||
|
19
21
|
xml_http_request_without_facebooker?
|
20
22
|
end
|
21
23
|
alias_method_chain :xml_http_request?, :facebooker
|
22
24
|
# we have to re-alias xhr? since it was pointing to the old method
|
23
|
-
|
24
|
-
alias xhr? :xml_http_request?
|
25
|
-
end
|
25
|
+
alias :xhr? :xml_http_request?
|
26
26
|
|
27
27
|
end
|
28
28
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ::ActionController
|
2
|
+
|
3
|
+
class Request
|
4
|
+
|
5
|
+
include Facebooker::Rails::BackwardsCompatibleParamChecks
|
6
|
+
|
7
|
+
def request_method_with_facebooker
|
8
|
+
if parameters[:_method].blank?
|
9
|
+
if %w{GET HEAD}.include?(parameters[:fb_sig_request_method])
|
10
|
+
parameters[:_method] = parameters[:fb_sig_request_method]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
request_method_without_facebooker
|
14
|
+
end
|
15
|
+
|
16
|
+
if new({}).methods.include?("request_method")
|
17
|
+
alias_method_chain :request_method, :facebooker
|
18
|
+
end
|
19
|
+
|
20
|
+
def xml_http_request_with_facebooker?
|
21
|
+
one_or_true(parameters["fb_sig_is_mockajax"]) ||
|
22
|
+
one_or_true(parameters["fb_sig_is_ajax"]) ||
|
23
|
+
xml_http_request_without_facebooker?
|
24
|
+
end
|
25
|
+
alias_method_chain :xml_http_request?, :facebooker
|
26
|
+
|
27
|
+
# we have to re-alias xhr? since it was pointing to the old method
|
28
|
+
alias :xhr? :xml_http_request?
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -23,14 +23,18 @@ module ::ActionController
|
|
23
23
|
end
|
24
24
|
|
25
25
|
class UrlRewriter
|
26
|
+
include Facebooker::Rails::BackwardsCompatibleParamChecks
|
27
|
+
|
26
28
|
RESERVED_OPTIONS << :canvas
|
29
|
+
|
27
30
|
def link_to_new_canvas?
|
28
|
-
@request.parameters["fb_sig_in_new_facebook"]
|
31
|
+
one_or_true @request.parameters["fb_sig_in_new_facebook"]
|
29
32
|
end
|
33
|
+
|
30
34
|
def link_to_canvas?(params, options)
|
31
35
|
option_override = options[:canvas]
|
32
36
|
return false if option_override == false # important to check for false. nil should use default behavior
|
33
|
-
option_override || (can_safely_access_request_parameters? && (@request.parameters["fb_sig_in_canvas"]
|
37
|
+
option_override || (can_safely_access_request_parameters? && (one_or_true(@request.parameters["fb_sig_in_canvas"]) || one_or_true(@request.parameters[:fb_sig_in_canvas]) ))
|
34
38
|
end
|
35
39
|
|
36
40
|
#rails blindly tries to merge things that may be nil into the parameters. Make sure this won't break
|
@@ -51,5 +55,6 @@ module ::ActionController
|
|
51
55
|
end
|
52
56
|
|
53
57
|
alias_method_chain :rewrite_url, :facebooker
|
58
|
+
|
54
59
|
end
|
55
60
|
end
|
@@ -24,6 +24,14 @@ module Facebooker
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
def fb_iframe(src, options = {})
|
28
|
+
content_tag "fb:iframe", '', options.merge({ :src => src })
|
29
|
+
end
|
30
|
+
|
31
|
+
def fb_swf(src, options = {})
|
32
|
+
tag "fb:swf", options.merge(:swfsrc => src)
|
33
|
+
end
|
34
|
+
|
27
35
|
def fb_dialog_title( title )
|
28
36
|
content_tag "fb:dialog-title", title
|
29
37
|
end
|
@@ -331,7 +339,8 @@ module Facebooker
|
|
331
339
|
VALID_FB_SHARED_PHOTO_SIZES = [:thumb, :small, :normal, :square]
|
332
340
|
VALID_FB_PHOTO_SIZES = VALID_FB_SHARED_PHOTO_SIZES
|
333
341
|
VALID_FB_PROFILE_PIC_SIZES = VALID_FB_SHARED_PHOTO_SIZES
|
334
|
-
VALID_PERMISSIONS=[:email, :offline_access, :status_update, :photo_upload, :create_listing, :create_event, :rsvp_event, :sms, :video_upload
|
342
|
+
VALID_PERMISSIONS=[:email, :offline_access, :status_update, :photo_upload, :create_listing, :create_event, :rsvp_event, :sms, :video_upload,
|
343
|
+
:publish_stream, :read_stream]
|
335
344
|
|
336
345
|
# Render an fb:tabs tag containing some number of fb:tab_item tags.
|
337
346
|
# Example:
|
@@ -639,20 +648,22 @@ module Facebooker
|
|
639
648
|
#
|
640
649
|
# You can prompt a user with the following permissions:
|
641
650
|
# * email
|
651
|
+
# * read_stream
|
652
|
+
# * publish_stream
|
642
653
|
# * offline_access
|
643
654
|
# * status_update
|
644
655
|
# * photo_upload
|
645
|
-
# * video_upload
|
646
|
-
# * create_listing
|
647
656
|
# * create_event
|
648
657
|
# * rsvp_event
|
649
658
|
# * sms
|
650
|
-
#
|
659
|
+
# * video_upload
|
660
|
+
# * create_note
|
661
|
+
# * share_item
|
651
662
|
# Example:
|
652
663
|
# <%= fb_prompt_permission('email', "Would you like to receive email from our application?" ) %>
|
653
664
|
#
|
654
665
|
# See http://wiki.developers.facebook.com/index.php/Fb:prompt-permission for
|
655
|
-
# more details
|
666
|
+
# more details. Correct as of 7th June 2009.
|
656
667
|
#
|
657
668
|
def fb_prompt_permission(permission,message,callback=nil)
|
658
669
|
raise(ArgumentError, "Unknown value for permission: #{permission}") unless VALID_PERMISSIONS.include?(permission.to_sym)
|
@@ -661,6 +672,19 @@ module Facebooker
|
|
661
672
|
content_tag("fb:prompt-permission",message,args)
|
662
673
|
end
|
663
674
|
|
675
|
+
# Renders a link to prompt for multiple permissions at once.
|
676
|
+
#
|
677
|
+
# Example:
|
678
|
+
# <%= fb_prompt_permissions(['email','offline_access','status_update'], 'Would you like to grant some permissions?')
|
679
|
+
def fb_prompt_permissions(permissions,message,callback=nil)
|
680
|
+
permissions.each do |p|
|
681
|
+
raise(ArgumentError, "Unknown value for permission: #{p}") unless VALID_PERMISSIONS.include?(p.to_sym)
|
682
|
+
end
|
683
|
+
args={:perms=>permissions*','}
|
684
|
+
args[:next_fbjs]=callback unless callback.nil?
|
685
|
+
content_tag("fb:prompt-permission",message,args)
|
686
|
+
end
|
687
|
+
|
664
688
|
# Renders an <fb:eventlink /> tag that displays the event name and links to the event's page.
|
665
689
|
def fb_eventlink(eid)
|
666
690
|
content_tag "fb:eventlink",nil,:eid=>eid
|
@@ -11,26 +11,35 @@ module Facebooker
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
#
|
15
|
+
# For information on the :app_settings argument see http://wiki.developers.facebook.com/index.php/JS_API_M_FB.Facebook.Init_2
|
16
|
+
# While it would be nice to treat :app_settings as a hash, some of the arguments do different things if they are a string vs a javascript function
|
17
|
+
# and Rails' Hash#to_json always quotes strings so there is no way to indicate when the value should be a javascript function.
|
18
|
+
# For this reason :app_settings needs to be a string that is valid JSON (including the {}'s).
|
19
|
+
#
|
14
20
|
def init_fb_connect(*required_features,&proc)
|
15
21
|
additions = ""
|
16
22
|
if block_given?
|
17
23
|
additions = capture(&proc)
|
18
24
|
end
|
19
25
|
|
20
|
-
|
26
|
+
# Yes, app_settings is set to a string of an empty JSON element. That's intentional.
|
27
|
+
options = {:js => :prototype, :app_settings => '{}'}
|
28
|
+
|
21
29
|
if required_features.last.is_a?(Hash)
|
22
30
|
options.merge!(required_features.pop.symbolize_keys)
|
23
31
|
end
|
24
32
|
|
25
33
|
if request.ssl?
|
26
|
-
init_string = "FB.Facebook.init('#{Facebooker.api_key}','/xd_receiver_ssl.html');"
|
34
|
+
init_string = "FB.Facebook.init('#{Facebooker.api_key}','/xd_receiver_ssl.html', #{options[:app_settings]});"
|
27
35
|
else
|
28
|
-
init_string = "FB.Facebook.init('#{Facebooker.api_key}','/xd_receiver.html');"
|
36
|
+
init_string = "FB.Facebook.init('#{Facebooker.api_key}','/xd_receiver.html', #{options[:app_settings]});"
|
29
37
|
end
|
30
38
|
unless required_features.blank?
|
31
39
|
init_string = <<-FBML
|
32
40
|
#{case options[:js]
|
33
41
|
when :jquery then "$(document).ready("
|
42
|
+
when :dojo then "dojo.addOnLoad("
|
34
43
|
else "Element.observe(window,'load',"
|
35
44
|
end} function() {
|
36
45
|
FB_RequireFeatures(#{required_features.to_json}, function() {
|
@@ -97,9 +106,9 @@ module Facebooker
|
|
97
106
|
link_to_function text, js, *args
|
98
107
|
end
|
99
108
|
|
100
|
-
def fb_user_action(action, user_message =
|
109
|
+
def fb_user_action(action, user_message = nil, prompt = "", callback = nil)
|
101
110
|
update_page do |page|
|
102
|
-
page.call
|
111
|
+
page.call("FB.Connect.showFeedDialog",action.template_id,action.data,action.target_ids,action.body_general,nil,page.literal("FB.RequireConnect.promptConnect"),callback,prompt,user_message.nil? ? nil : {:value=>user_message})
|
103
112
|
end
|
104
113
|
end
|
105
114
|
|
@@ -56,15 +56,15 @@ module Facebooker
|
|
56
56
|
# fbml 'text'
|
57
57
|
# text fbml
|
58
58
|
# end
|
59
|
-
# # This will render the profile in /users/profile.erb
|
59
|
+
# # This will render the profile in /users/profile.fbml.erb
|
60
60
|
# # it will set @user to user_to_update in the template
|
61
61
|
# # The mobile profile will be rendered from the app/views/test_publisher/_mobile.erb
|
62
62
|
# # template
|
63
63
|
# def profile_update(user_to_update,user_with_session_to_use)
|
64
64
|
# send_as :profile
|
65
65
|
# from user_with_session_to_use
|
66
|
-
#
|
67
|
-
# profile render(:
|
66
|
+
# recipients user_to_update
|
67
|
+
# profile render(:file=>"users/profile.fbml.erb",:assigns=>{:user=>user_to_update})
|
68
68
|
# profile_action "A string"
|
69
69
|
# mobile_profile render(:partial=>"mobile",:assigns=>{:user=>user_to_update})
|
70
70
|
# end
|
@@ -74,7 +74,7 @@ module Facebooker
|
|
74
74
|
# def ref_update(user)
|
75
75
|
# send_as :ref
|
76
76
|
# from user
|
77
|
-
# fbml render(:
|
77
|
+
# fbml render(:file=>"users/profile",:assigns=>{:user=>user_to_update})
|
78
78
|
# handle "a_ref_handle"
|
79
79
|
# end
|
80
80
|
#
|
@@ -98,7 +98,11 @@ module Facebooker
|
|
98
98
|
@from = nil
|
99
99
|
@full_story_template = nil
|
100
100
|
@recipients = nil
|
101
|
-
@controller = PublisherController.new
|
101
|
+
@controller = PublisherController.new(self)
|
102
|
+
end
|
103
|
+
|
104
|
+
def default_url_options
|
105
|
+
{:host => Facebooker.canvas_server_base + Facebooker.facebook_path_prefix}
|
102
106
|
end
|
103
107
|
|
104
108
|
# use facebook options everywhere
|
@@ -122,6 +126,8 @@ module Facebooker
|
|
122
126
|
end
|
123
127
|
end
|
124
128
|
|
129
|
+
|
130
|
+
|
125
131
|
class << self
|
126
132
|
|
127
133
|
def register(klass,method)
|
@@ -323,6 +329,10 @@ module Facebooker
|
|
323
329
|
self.href=href
|
324
330
|
end
|
325
331
|
|
332
|
+
def ==(other)
|
333
|
+
self.src == other.src && self.href == other.href
|
334
|
+
end
|
335
|
+
|
326
336
|
def to_json(*args)
|
327
337
|
"{\"src\":#{src.to_json}, \"href\":#{href.to_json}}"
|
328
338
|
end
|
@@ -411,8 +421,11 @@ module Facebooker
|
|
411
421
|
ActionController::Base.append_view_path(controller_root)
|
412
422
|
ActionController::Base.append_view_path(controller_root+"/..")
|
413
423
|
end
|
424
|
+
view_paths = ActionController::Base.view_paths
|
425
|
+
else
|
426
|
+
view_paths = [template_root, controller_root]
|
414
427
|
end
|
415
|
-
returning ActionView::Base.new(
|
428
|
+
returning ActionView::Base.new(view_paths, assigns, self) do |template|
|
416
429
|
template.controller=self
|
417
430
|
template.extend(self.class.master_helper_module)
|
418
431
|
def template.request_comes_from_facebook?
|
@@ -483,11 +496,7 @@ module Facebooker
|
|
483
496
|
|
484
497
|
should_send ? publisher.send_message(method) : publisher._body
|
485
498
|
end
|
486
|
-
|
487
|
-
def default_url_options
|
488
|
-
{:host => Facebooker.canvas_server_base + Facebooker.facebook_path_prefix}
|
489
|
-
end
|
490
|
-
|
499
|
+
|
491
500
|
def controller_path
|
492
501
|
self.to_s.underscore
|
493
502
|
end
|
@@ -521,11 +530,16 @@ module Facebooker
|
|
521
530
|
class PublisherController
|
522
531
|
include Facebooker::Rails::Publisher.master_helper_module
|
523
532
|
include ActionController::UrlWriter
|
533
|
+
|
534
|
+
def initialize(source)
|
535
|
+
self.class.url_option_source = source
|
536
|
+
end
|
524
537
|
|
525
538
|
class << self
|
539
|
+
attr_accessor :url_option_source
|
526
540
|
alias :old_default_url_options :default_url_options
|
527
541
|
def default_url_options(*args)
|
528
|
-
|
542
|
+
url_option_source.default_url_options(*args)
|
529
543
|
end
|
530
544
|
end
|
531
545
|
|
data/lib/facebooker/service.rb
CHANGED
@@ -1,9 +1,3 @@
|
|
1
|
-
begin
|
2
|
-
require 'curb'
|
3
|
-
Facebooker.use_curl = true
|
4
|
-
rescue LoadError
|
5
|
-
require 'net/http'
|
6
|
-
end
|
7
1
|
require 'facebooker/parser'
|
8
2
|
module Facebooker
|
9
3
|
class Service
|
@@ -12,50 +6,86 @@ module Facebooker
|
|
12
6
|
@api_path = api_path
|
13
7
|
@api_key = api_key
|
14
8
|
end
|
9
|
+
|
10
|
+
def self.active_service
|
11
|
+
unless @active_service
|
12
|
+
if Facebooker.use_curl?
|
13
|
+
@active_service = Facebooker::Service::CurlService.new
|
14
|
+
else
|
15
|
+
@active_service = Facebooker::Service::NetHttpService.new
|
16
|
+
end
|
17
|
+
end
|
18
|
+
@active_service
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.active_service=(new_service)
|
22
|
+
@active_service = new_service
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.with_service(service)
|
26
|
+
old_service = active_service
|
27
|
+
self.active_service = service
|
28
|
+
begin
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
self.active_service = old_service
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# Process all calls to Facebook in th block asynchronously
|
37
|
+
# nil will be returned from all calls and no results will be parsed. This is mostly useful
|
38
|
+
# for sending large numbers of notifications or sending a lot of profile updates
|
39
|
+
#
|
40
|
+
# for example:
|
41
|
+
# User.find_in_batches(:batch_size => 200) do |users|
|
42
|
+
# Faceboooker::Service.with_async do
|
43
|
+
# users.each {|u| u.facebook_session.send_notification(...)}
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# Note: You shouldn't make more than about 200 api calls in a with_async block
|
48
|
+
# or you might exhaust all filehandles.
|
49
|
+
#
|
50
|
+
# This functionality require the typhoeus gem
|
51
|
+
#
|
52
|
+
def self.with_async(&proc)
|
53
|
+
block_with_process = Proc.new { proc.call ; process_async}
|
54
|
+
with_service(Facebooker::Service::TyphoeusMultiService.new,&block_with_process)
|
55
|
+
end
|
15
56
|
|
57
|
+
def self.process_async
|
58
|
+
active_service.process
|
59
|
+
end
|
60
|
+
|
61
|
+
|
16
62
|
# TODO: support ssl
|
17
63
|
def post(params)
|
18
64
|
attempt = 0
|
19
|
-
|
65
|
+
if active_service.parse_results?
|
66
|
+
Parser.parse(params[:method], post_form(url,params) )
|
67
|
+
else
|
68
|
+
post_form(url,params)
|
69
|
+
end
|
20
70
|
rescue Errno::ECONNRESET, EOFError
|
21
71
|
if attempt == 0
|
22
72
|
attempt += 1
|
23
73
|
retry
|
24
74
|
end
|
25
75
|
end
|
26
|
-
|
76
|
+
|
27
77
|
def post_form(url,params)
|
28
|
-
|
29
|
-
post_form_with_curl(url,params)
|
30
|
-
else
|
31
|
-
post_form_with_net_http(url,params)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def post_form_with_net_http(url,params)
|
36
|
-
Net::HTTP.post_form(url, params)
|
37
|
-
end
|
38
|
-
|
39
|
-
def post_form_with_curl(url,params,multipart=false)
|
40
|
-
response = Curl::Easy.http_post(url.to_s, *to_curb_params(params)) do |c|
|
41
|
-
c.multipart_form_post = multipart
|
42
|
-
c.timeout = Facebooker.timeout
|
43
|
-
end
|
44
|
-
response.body_str
|
78
|
+
active_service.post_form(url,params)
|
45
79
|
end
|
46
80
|
|
47
81
|
def post_multipart_form(url,params)
|
48
|
-
|
49
|
-
post_form_with_curl(url,params,true)
|
50
|
-
else
|
51
|
-
post_multipart_form_with_net_http(url,params)
|
52
|
-
end
|
82
|
+
active_service.post_multipart_form(url,params)
|
53
83
|
end
|
54
84
|
|
55
|
-
def
|
56
|
-
|
85
|
+
def active_service
|
86
|
+
self.class.active_service
|
57
87
|
end
|
58
|
-
|
88
|
+
|
59
89
|
def post_file(params)
|
60
90
|
service_url = url(params.delete(:base))
|
61
91
|
result = post_multipart_form(service_url, params)
|
@@ -67,28 +97,6 @@ module Facebooker
|
|
67
97
|
base ||= @api_base
|
68
98
|
URI.parse('http://'+ base + @api_path)
|
69
99
|
end
|
70
|
-
|
71
|
-
# Net::HTTP::MultipartPostFile
|
72
|
-
def multipart_post_file?(object)
|
73
|
-
object.respond_to?(:content_type) &&
|
74
|
-
object.respond_to?(:data) &&
|
75
|
-
object.respond_to?(:filename)
|
76
|
-
end
|
77
|
-
|
78
|
-
def to_curb_params(params)
|
79
|
-
parray = []
|
80
|
-
params.each_pair do |k,v|
|
81
|
-
if multipart_post_file?(v)
|
82
|
-
# Curl doesn't like blank field names
|
83
|
-
field = Curl::PostField.file((k.blank? ? 'xxx' : k.to_s), nil, File.basename(v.filename))
|
84
|
-
field.content_type = v.content_type
|
85
|
-
field.content = v.data
|
86
|
-
parray << field
|
87
|
-
else
|
88
|
-
parray << Curl::PostField.content(k.to_s, v.to_s)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
parray
|
92
|
-
end
|
100
|
+
|
93
101
|
end
|
94
102
|
end
|