rack-superfeedr 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.4.1
@@ -2,13 +2,7 @@ require 'base64'
2
2
  require 'net/http'
3
3
  require 'uri'
4
4
 
5
- module Rack
6
-
7
-
8
- ##
9
- # This is a Rack Middleware that can be used in your rack-compatible web framework (Rails, Sinatra...) to perform subscriptions over at superfeedr
10
- # using the PubSubHubbub API.
11
- class Superfeedr
5
+ module SuperfeedrAPI
12
6
 
13
7
  @@superfeedr_endpoint = "https://push.superfeedr.com/"
14
8
  @@port = 80
@@ -18,135 +12,225 @@ module Rack
18
12
  @@login = nil
19
13
  @@password = nil
20
14
 
21
- def self.superfeedr_endpoint= _superfeedr_endpoint
15
+ def superfeedr_endpoint= _superfeedr_endpoint
22
16
  @@superfeedr_endpoint = _superfeedr_endpoint
23
17
  end
24
18
 
25
- def self.port= _port
19
+ def superfeedr_endpoint
20
+ @@superfeedr_endpoint
21
+ end
22
+
23
+ def port= _port
26
24
  @@port = _port
27
25
  end
28
26
 
29
- def self.host= _host
27
+ def port
28
+ @@port
29
+ end
30
+
31
+ def host= _host
30
32
  @@host = _host
31
33
  end
32
34
 
33
- def self.base_path= _base_path
35
+ def host
36
+ @@host
37
+ end
38
+
39
+ def base_path= _base_path
34
40
  @@base_path = _base_path
35
41
  end
36
42
 
37
- def self.scheme= _scheme
43
+ def base_path
44
+ @@base_path
45
+ end
46
+
47
+ def scheme= _scheme
38
48
  @@scheme = _scheme
39
49
  end
40
50
 
41
- def self.login= _login
51
+ def scheme
52
+ @@scheme
53
+ end
54
+
55
+ def login= _login
42
56
  @@login = _login
43
57
  end
44
58
 
45
- def self.password= _password
59
+ def login
60
+ @@login
61
+ end
62
+
63
+ def password= _password
46
64
  @@password = _password
47
65
  end
48
66
 
49
- ##
50
- # Subscribe you to a url. id is optional but strongly recommanded has a unique identifier for this url. It will be used to help you identify which feed
51
- # is concerned by a notification.
52
- # A 3rd options argument can be supplied with
53
- # - retrieve => true if you want to retrieve the previous items in the feed
54
- # - format => 'json' or 'atom' to specify the format of the notifications, defaults to atom
55
- # - secret => a secret string used to compyte HMAC signatures so you can check that the data is coming from Superfeedr
56
- # - sync => true (defaults to false) if you want to perfrom a verification of intent syncrhonously
57
- # - async => true (defaults to false) if you want to perfrom a verification of intent asyncrhonously
58
- # - hub => if you want to use an explicit hub, defaults to Superfeedr's http://push.superfeedr.com
59
- # It yields 3 arguments to a block:
60
- # - body of the response (useful if you used the retrieve option)
61
- # - success flag
62
- # - response (useful to debug failed requests mostly)
63
- def self.subscribe(url, id = nil, opts = {}, &blk)
64
- endpoint = opts[:hub] || @@superfeedr_endpoint
65
- request = prep_request(url, id, endpoint, opts)
66
-
67
- if opts[:retrieve]
68
- request['retrieve'] = true
69
- end
70
-
71
- if opts[:format] == "json"
72
- request['format'] = "json"
73
- end
67
+ def password
68
+ @@password
69
+ end
74
70
 
75
- if opts[:secret]
76
- request['hub.secret'] = opts[:secret]
77
- else
78
- request['hub.secret'] = "WHAT DO WE PICK? A UNIQUE SCRET THE CALLBACK? SO WE CAN USE THAT ON NOTIFS?"
79
- end
80
-
81
- request['hub.mode'] = 'subscribe'
71
+ ##
72
+ # Subscribe you to a url. id is optional but strongly recommanded has a unique identifier for this url. It will be used to help you identify which feed
73
+ # is concerned by a notification.
74
+ # A 3rd options argument can be supplied with
75
+ # - retrieve => true if you want to retrieve the previous items in the feed
76
+ # - format => 'json' or 'atom' to specify the format of the notifications, defaults to atom
77
+ # - secret => a secret string used to compyte HMAC signatures so you can check that the data is coming from Superfeedr
78
+ # - sync => true (defaults to false) if you want to perfrom a verification of intent syncrhonously
79
+ # - async => true (defaults to false) if you want to perfrom a verification of intent asyncrhonously
80
+ # - hub => if you want to use an explicit hub, defaults to Superfeedr's http://push.superfeedr.com
81
+ # It yields 3 arguments to a block:
82
+ # - body of the response (useful if you used the retrieve option)
83
+ # - success flag
84
+ # - response (useful to debug failed requests mostly)
85
+ def subscribe(url, id = nil, opts = {}, &blk)
86
+ endpoint = opts[:hub] || @@superfeedr_endpoint
87
+ request = prep_request(url, id, endpoint, opts)
88
+
89
+ if opts[:retrieve]
90
+ request['retrieve'] = true
91
+ end
92
+
93
+ if opts[:format] == "json"
94
+ request['format'] = "json"
95
+ end
96
+
97
+ if opts[:secret]
98
+ request['hub.secret'] = opts[:secret]
99
+ else
100
+ request['hub.secret'] = "WHAT DO WE PICK? A UNIQUE SCRET THE CALLBACK? SO WE CAN USE THAT ON NOTIFS?"
101
+ end
102
+
103
+ request['hub.mode'] = 'subscribe'
104
+
105
+ response = http_post(endpoint, request)
82
106
 
83
- response = http_post(endpoint, request)
107
+ blk.call(response.body, opts[:async] && Integer(response.code) == 202 || Integer(response.code) == 204 || opts[:retrieve] && Integer(response.code) == 200, response) if blk
108
+ end
84
109
 
85
- blk.call(response.body, opts[:async] && Integer(response.code) == 202 || Integer(response.code) == 204 || opts[:retrieve] && Integer(response.code) == 200, response) if blk
110
+ ##
111
+ # Retrieve the content of a resource at Superfeedr
112
+ # A 2nd options argument can be supplied with
113
+ # - format => 'json' or 'atom' to specify the format of the notifications, defaults to atom
114
+ # - count => Integer (number of items to retrieve)
115
+ # - before => The id of an entry in the feed. The response will only include entries published before this one.
116
+ # - after => The id of an entry in the feed. The response will only include entries published after this one.
117
+ # It yields 3 arguments to a block (if block is supplied. If not, just returns the triplet)
118
+ # - body of the response (useful if you used the retrieve option)
119
+ # - success flag
120
+ # - response (useful to debug failed requests mostly)
121
+ def retrieve_by_topic_url(url, opts = {}, &blk)
122
+ endpoint = opts[:hub] || @@superfeedr_endpoint
123
+ request = prep_request(url, '', endpoint, opts)
124
+
125
+ if opts[:format] == "json"
126
+ request['format'] = "json"
86
127
  end
87
128
 
88
- ##
89
- # Retrieve the content of a resource at Superfeedr
90
- # A 2nd options argument can be supplied with
91
- # - format => 'json' or 'atom' to specify the format of the notifications, defaults to atom
92
- # - count => Integer (number of items to retrieve)
93
- # - before => The id of an entry in the feed. The response will only include entries published before this one.
94
- # - after => The id of an entry in the feed. The response will only include entries published after this one.
95
- # It yields 3 arguments to a block (if block is supplied. If not, just returns the triplet)
96
- # - body of the response (useful if you used the retrieve option)
97
- # - success flag
98
- # - response (useful to debug failed requests mostly)
99
- def self.retrieve_by_topic_url(url, opts = {}, &blk)
100
- endpoint = opts[:hub] || @@superfeedr_endpoint
101
- request = prep_request(url, '', endpoint, opts)
102
-
103
- if opts[:format] == "json"
104
- request['format'] = "json"
105
- end
129
+ if opts[:count]
130
+ request['count'] = opts[:count]
131
+ else
132
+ request['count'] = 10
133
+ end
134
+
135
+ request['hub.mode'] = 'retrieve'
106
136
 
107
- if opts[:count]
108
- request['count'] = opts[:count]
109
- else
110
- request['count'] = 10
111
- end
112
-
113
- request['hub.mode'] = 'retrieve'
137
+ response = http_get(endpoint, request)
114
138
 
115
- response = http_get(endpoint, request)
139
+ if blk
140
+ blk.call(response.body, Integer(response.code) == 200, response) if blk
141
+ else
142
+ [response.body, Integer(response.code) == 200, response]
143
+ end
144
+ end
116
145
 
117
- if blk
118
- blk.call(response.body, Integer(response.code) == 200, response) if blk
119
- else
120
- [response.body, Integer(response.code) == 200, response]
121
- end
146
+ ##
147
+ # Unsubscribes a url. If you used an id for the susbcription, you need to use _the same_.
148
+ # The optional block will be called to let you confirm the subscription (or not). This is not applicable for if you use params[:async] => true
149
+ # It returns true if the unsubscription was successful (or will be confirmed if you used async => true in the options), false otherwise
150
+ # You can also pass an opts third argument that will be merged with the options used in Typhoeus's Request (https://github.com/dbalatero/typhoeus)
151
+
152
+ ##
153
+ # Subscribe you to a url. id needs to match the id you used to subscribe.
154
+ # A 3rd options argument can be supplied with
155
+ # - sync => true (defaults to false) if you want to perfrom a verification of intent syncrhonously
156
+ # - async => true (defaults to false) if you want to perfrom a verification of intent asyncrhonously
157
+ # - hub => if you want to use an explicit hub, defaults to Superfeedr's http://push.superfeedr.com
158
+ # It yields 3 arguments to a block:
159
+ # - body of the response (useful to debug failed notifications)
160
+ # - success flag
161
+ # - response (useful to debug failed requests mostly)
162
+ def unsubscribe(url, id = nil, opts = {}, &blk)
163
+ endpoint = opts[:hub] || @@superfeedr_endpoint
164
+ request = prep_request(url, id, endpoint, opts)
165
+
166
+ request['hub.mode'] = 'unsubscribe'
167
+
168
+ response = http_post(endpoint, request)
169
+
170
+ blk.call(response.body, opts[:async] && Integer(response.code) == 202 || Integer(response.code) == 204, response) if blk
171
+ end
172
+
173
+ protected
174
+
175
+ def prep_request(url, id, endpoint, opts)
176
+ feed_id = "#{id ? id : Base64.urlsafe_encode64(url)}"
177
+
178
+ request = {
179
+ 'hub.topic' => url,
180
+ 'hub.callback' => generate_callback(url, feed_id)
181
+ }
182
+
183
+ if endpoint == @@superfeedr_endpoint && @@login && @@password
184
+ request['authorization'] = Base64.encode64( "#{@@login}:#{@@password}" ).chomp
122
185
  end
123
186
 
124
- ##
125
- # Unsubscribes a url. If you used an id for the susbcription, you need to use _the same_.
126
- # The optional block will be called to let you confirm the subscription (or not). This is not applicable for if you use params[:async] => true
127
- # It returns true if the unsubscription was successful (or will be confirmed if you used async => true in the options), false otherwise
128
- # You can also pass an opts third argument that will be merged with the options used in Typhoeus's Request (https://github.com/dbalatero/typhoeus)
129
-
130
- ##
131
- # Subscribe you to a url. id needs to match the id you used to subscribe.
132
- # A 3rd options argument can be supplied with
133
- # - sync => true (defaults to false) if you want to perfrom a verification of intent syncrhonously
134
- # - async => true (defaults to false) if you want to perfrom a verification of intent asyncrhonously
135
- # - hub => if you want to use an explicit hub, defaults to Superfeedr's http://push.superfeedr.com
136
- # It yields 3 arguments to a block:
137
- # - body of the response (useful to debug failed notifications)
138
- # - success flag
139
- # - response (useful to debug failed requests mostly)
140
- def self.unsubscribe(url, id = nil, opts = {}, &blk)
141
- endpoint = opts[:hub] || @@superfeedr_endpoint
142
- request = prep_request(url, id, endpoint, opts)
143
-
144
- request['hub.mode'] = 'unsubscribe'
145
-
146
- response = http_post(endpoint, request)
147
-
148
- blk.call(response.body, opts[:async] && Integer(response.code) == 202 || Integer(response.code) == 204, response) if blk
187
+ if opts[:async]
188
+ request['hub.verify'] = 'async'
189
+ end
190
+
191
+ if opts[:sync]
192
+ request['hub.verify'] = 'sync'
193
+ end
194
+
195
+ request
196
+ end
197
+
198
+ def http_get(url, opts)
199
+ uri = URI.parse URI.encode(url)
200
+ uri.query = URI.encode_www_form opts || {}
201
+ uri.path=='/' if uri.path.empty?
202
+ http = Net::HTTP.new(uri.host, uri.port)
203
+ http.use_ssl = true
204
+ request = Net::HTTP::Get.new uri.request_uri
205
+ http.request(request)
206
+ end
207
+
208
+ def http_post(url, opts)
209
+ uri = URI.parse URI.encode(url)
210
+ uri.path=='/' if uri.path.empty?
211
+ http = Net::HTTP.new(uri.host, uri.port)
212
+ http.use_ssl = true
213
+ request = Net::HTTP::Post.new uri.request_uri
214
+ request.set_form_data (opts||{})
215
+ http.request(request)
216
+ end
217
+
218
+ def generate_callback(url, feed_id)
219
+ if @@scheme == "https"
220
+ URI::HTTPS.build({:scheme => @@scheme, :host => @@host, :path => "#{@@base_path}#{feed_id}", :port => @@port }).to_s
221
+ else
222
+ URI::HTTP.build({:scheme => @@scheme, :host => @@host, :path => "#{@@base_path}#{feed_id}", :port => @@port }).to_s
149
223
  end
224
+ end
225
+ end
226
+
227
+
228
+ module Rack
229
+
230
+ ##
231
+ # This is a Rack Middleware that can be used in your rack-compatible web framework (Rails, Sinatra...) to perform subscriptions over at superfeedr
232
+ # using the PubSubHubbub API.
233
+ class Superfeedr
150
234
 
151
235
  ##
152
236
  # This allows you to define what happens with the notifications. The block passed in argument is called for each notification, with 4 arguments
@@ -203,13 +287,13 @@ module Rack
203
287
  # Called by Rack!
204
288
  def call(env)
205
289
  req = Rack::Request.new(env)
206
- if env['REQUEST_METHOD'] == 'GET' && feed_id = env['PATH_INFO'].match(/#{@@base_path}(.*)/)
290
+ if env['REQUEST_METHOD'] == 'GET' && feed_id = env['PATH_INFO'].match(/#{Rack::Superfeedr.base_path}(.*)/)
207
291
  if @verification.call(req.params['hub.mode'], feed_id[1], req.params['hub.topic'], req)
208
292
  Rack::Response.new(req.params['hub.challenge'], 200).finish
209
293
  else
210
294
  Rack::Response.new("not valid", 404).finish
211
295
  end
212
- elsif env['REQUEST_METHOD'] == 'POST' && feed_id = env['PATH_INFO'].match(/#{@@base_path}(.*)/)
296
+ elsif env['REQUEST_METHOD'] == 'POST' && feed_id = env['PATH_INFO'].match(/#{Rack::Superfeedr.base_path}(.*)/)
213
297
  @callback.call(feed_id[1], req.body.read, req.env['HTTP_X_PUBSUBHUBBUB_TOPIC'], req)
214
298
  Rack::Response.new("Thanks!", 200).finish
215
299
  else
@@ -217,57 +301,8 @@ module Rack
217
301
  end
218
302
  end
219
303
 
220
- protected
221
-
222
- def self.prep_request(url, id, endpoint, opts)
223
- feed_id = "#{id ? id : Base64.urlsafe_encode64(url)}"
224
-
225
- request = {
226
- 'hub.topic' => url,
227
- 'hub.callback' => generate_callback(url, feed_id)
228
- }
229
-
230
- if endpoint == @@superfeedr_endpoint && @@login && @@password
231
- request['authorization'] = Base64.encode64( "#{@@login}:#{@@password}" ).chomp
232
- end
304
+ extend SuperfeedrAPI
233
305
 
234
- if opts[:async]
235
- request['hub.verify'] = 'async'
236
- end
237
-
238
- if opts[:sync]
239
- request['hub.verify'] = 'sync'
240
- end
241
-
242
- request
243
- end
244
-
245
- def self.http_get(url, opts)
246
- uri = URI.parse URI.encode(url)
247
- uri.query = URI.encode_www_form opts || {}
248
- uri.path=='/' if uri.path.empty?
249
- http = Net::HTTP.new(uri.host, uri.port)
250
- http.use_ssl = true
251
- request = Net::HTTP::Get.new uri.request_uri
252
- http.request(request)
253
- end
254
-
255
- def self.http_post(url, opts)
256
- uri = URI.parse URI.encode(url)
257
- uri.path=='/' if uri.path.empty?
258
- http = Net::HTTP.new(uri.host, uri.port)
259
- http.use_ssl = true
260
- request = Net::HTTP::Post.new uri.request_uri
261
- request.set_form_data (opts||{})
262
- http.request(request)
263
- end
264
-
265
- def self.generate_callback(url, feed_id)
266
- if @@scheme == "https"
267
- URI::HTTPS.build({:scheme => @@scheme, :host => @@host, :path => "#{@@base_path}#{feed_id}", :port => @@port }).to_s
268
- else
269
- URI::HTTP.build({:scheme => @@scheme, :host => @@host, :path => "#{@@base_path}#{feed_id}", :port => @@port }).to_s
270
- end
271
- end
272
306
  end
273
307
  end
308
+
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "rack-superfeedr"
8
- s.version = "0.4.0"
8
+ s.version = "0.4.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["julien51"]
12
- s.date = "2015-04-15"
12
+ s.date = "2015-04-16"
13
13
  s.description = "A gem that provides a rack middleware to interract with Superfeedr's API. "
14
14
  s.email = "julien@superfeedr.com"
15
15
  s.extra_rdoc_files = [
@@ -3,7 +3,7 @@ require 'rack'
3
3
  require_relative 'helper.rb'
4
4
 
5
5
  # To run tests locally, we're using runscope's passageway which proxies requests inside the firewall. (make sure you bind to port 4567)
6
- HOST = '5f83728c358.b.passageway.io'
6
+ HOST = '39fbb9eba21.b.passageway.io'
7
7
  PORT = 80
8
8
  # Also, we need superfeedr credentials.
9
9
  LOGIN = 'demo'
@@ -22,6 +22,11 @@ end
22
22
 
23
23
  # Run an app in a thread
24
24
  Thread.new do
25
+ opts = {
26
+ :Port => 4567,
27
+ # Logger: WEBrick::Log.new("/dev/null"),
28
+ AccessLog: []
29
+ }
25
30
  Rack::Handler::WEBrick.run(Rack::Superfeedr.new(MyRackApp.new) do |superfeedr|
26
31
 
27
32
  superfeedr.on_verification do |mode, feed_id, url, request|
@@ -39,7 +44,7 @@ Thread.new do
39
44
  end
40
45
 
41
46
 
42
- end, :Port => 4567, Logger: WEBrick::Log.new("/dev/null"), AccessLog: [],)
47
+ end, opts)
43
48
  end
44
49
  sleep 3
45
50
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-superfeedr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-04-15 00:00:00.000000000 Z
12
+ date: 2015-04-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -159,7 +159,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
159
159
  version: '0'
160
160
  segments:
161
161
  - 0
162
- hash: 3582772756696706427
162
+ hash: 1123161724621889271
163
163
  required_rubygems_version: !ruby/object:Gem::Requirement
164
164
  none: false
165
165
  requirements: