Class: Rack::Superfeedr

Inherits:
Object
  • Object
show all
Defined in:
lib/rack-superfeedr.rb

Overview

This is a Rack Middleware that can be used in your rack-compatible web framework (Rails, Sinatra…) to perform subscriptions over at superfeedr using the PubSubHubbub API.

Constant Summary

@@superfeedr_endpoint =
"https://push.superfeedr.com/"
@@port =
80
@@host =
'my-app.com'
@@base_path =
'/superfeedr/feed/'
@@scheme =
'http'
@@login =
nil
@@password =
nil

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, &block) ⇒ Superfeedr

Initializes the Rack Middleware Make sure you define the following class attribues before that: Rack::Superfeedr.superfeedr_endpoint => push.superfeedr.com, defaults (do not change!) Rack::Superfeedr.host => Host for your application, used to build callback urls Rack::Superfeedr.port => Port for your application, used to build callback urls, defaults to Rack::Superfeedr.base_path => Base path for callback urls. Defauls to '/superfeedr/feed/' Rack::Superfeedr.scheme => Scheme to build callback urls, defaults to 'http' Rack::Superfeedr.login => Superfeedr login Rack::Superfeedr.password => Superfeedr password



148
149
150
151
152
153
# File 'lib/rack-superfeedr.rb', line 148

def initialize(app, &block)
  @app = app
  reset
  block.call(self)
  self
end

Class Method Details

.base_path=(_base_path) ⇒ Object



33
34
35
# File 'lib/rack-superfeedr.rb', line 33

def self.base_path= _base_path
  @@base_path = _base_path
end

.host=(_host) ⇒ Object



29
30
31
# File 'lib/rack-superfeedr.rb', line 29

def self.host= _host
  @@host = _host
end

.login=(_login) ⇒ Object



41
42
43
# File 'lib/rack-superfeedr.rb', line 41

def self.login= 
  @@login = 
end

.password=(_password) ⇒ Object



45
46
47
# File 'lib/rack-superfeedr.rb', line 45

def self.password= _password
  @@password = _password
end

.port=(_port) ⇒ Object



25
26
27
# File 'lib/rack-superfeedr.rb', line 25

def self.port= _port
  @@port = _port
end

.scheme=(_scheme) ⇒ Object



37
38
39
# File 'lib/rack-superfeedr.rb', line 37

def self.scheme= _scheme
  @@scheme = _scheme
end

.subscribe(url, id = nil, opts = {}, &blk) ⇒ Object

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 is concerned by a notification. A 3rd options argument can be supplied with

  • retrive => true if you want to retrieve the previous items in the feed

  • format => 'json' or 'atom' to specify the format of the notifications, defaults to atom

  • secret => a secret string used to compyte HMAC signatures so you can check that the data is coming from Superfeedr

  • sync => true (defaults to false) if you want to perfrom a verification of intent syncrhonously

  • async => true (defaults to false) if you want to perfrom a verification of intent asyncrhonously

  • hub => if you want to use an explicit hub, defaults to Superfeedr's push.superfeedr.com

It yields 3 arguments to a block:

  • body of the response (useful if you used the retrieve option)

  • success flag

  • response (useful to debug failed requests mostly)



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rack-superfeedr.rb', line 63

def self.subscribe(url, id = nil, opts = {}, &blk)
  endpoint = opts[:hub] || @@superfeedr_endpoint
  request = prep_request(url, id, endpoint, opts)

  if opts[:retrieve]
    request['retrieve'] = true
  end
  
  if opts[:format] == "json"
    request['format'] = "json"
  end

  if opts[:secret]
    request['hub.secret'] = opts[:secret]
  else
    request['hub.secret'] = "WHAT DO WE PICK? A UNIQUE SCRET THE CALLBACK? SO WE CAN USE THAT ON NOTIFS?" 
  end
  
  request['hub.mode'] = 'subscribe'

  response = http_post(endpoint, request)

  blk.call(response.body, opts[:async] && Integer(response.code) == 202 || Integer(response.code) == 204 || opts[:retrieve] && Integer(response.code) == 200, response) if blk
end

.superfeedr_endpoint=(_superfeedr_endpoint) ⇒ Object



21
22
23
# File 'lib/rack-superfeedr.rb', line 21

def self.superfeedr_endpoint= _superfeedr_endpoint
  @@superfeedr_endpoint = _superfeedr_endpoint
end

.unsubscribe(url, id = nil, opts = {}, &blk) ⇒ Object

Subscribe you to a url. id needs to match the id you used to subscribe. A 3rd options argument can be supplied with

  • sync => true (defaults to false) if you want to perfrom a verification of intent syncrhonously

  • async => true (defaults to false) if you want to perfrom a verification of intent asyncrhonously

  • hub => if you want to use an explicit hub, defaults to Superfeedr's push.superfeedr.com

It yields 3 arguments to a block:

  • body of the response (useful to debug failed notifications)

  • success flag

  • response (useful to debug failed requests mostly)



104
105
106
107
108
109
110
111
112
113
# File 'lib/rack-superfeedr.rb', line 104

def self.unsubscribe(url, id = nil, opts = {}, &blk)
  endpoint = opts[:hub] || @@superfeedr_endpoint
  request = prep_request(url, id, endpoint, opts)

  request['hub.mode'] = 'unsubscribe'

  response = http_post(endpoint, request)

  blk.call(response.body, opts[:async] && Integer(response.code) == 202 || Integer(response.code) == 204, response) if blk
end

Instance Method Details

#call(env) ⇒ Object

Called by Rack!



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/rack-superfeedr.rb', line 168

def call(env)
  req = Rack::Request.new(env)
  if env['REQUEST_METHOD'] == 'GET' && feed_id = env['PATH_INFO'].match(/#{@@base_path}(.*)/)
    puts "----"
    puts req.params['hub.mode'], feed_id[1], req.params['hub.topic']
    puts "----"
    if @verification.call(req.params['hub.mode'], feed_id[1], req.params['hub.topic'], req)
      Rack::Response.new(req.params['hub.challenge'], 200).finish
    else
      Rack::Response.new("not valid", 404).finish
    end
  elsif env['REQUEST_METHOD'] == 'POST' && feed_id = env['PATH_INFO'].match(/#{@@base_path}(.*)/)
    @callback.call(feed_id[1], req.body.read, req.env['HTTP_X_PUBSUBHUBBUB_TOPIC'], req)
    Rack::Response.new("Thanks!", 200).finish
  else
    @app.call(env)
  end
end

#on_notification(&block) ⇒ Object

This allows you to define what happens with the notifications. The block passed in argument is called for each notification, with 4 arguments

  • feed_id (used in subscriptions)

  • body (Atom or JSON) based on subscription

  • url (optional‚Ķ if the hub supports that, Superfeedr does)

  • Rack::Request object. Useful for debugging and checking signatures



121
122
123
# File 'lib/rack-superfeedr.rb', line 121

def on_notification(&block)
  @callback = block
end

#on_verification(&block) ⇒ Object

This allows you to define what happens with verification of intents It's a block called with

  • mode: subscribe|unsubscribe

  • Feed id (if available/supplied upon subscription)

  • Feed url

  • request (the Rack::Request object, should probably not be used, except for debugging)

If the block returns true, subscription will be confirmed If it returns false, it will be denied



134
135
136
# File 'lib/rack-superfeedr.rb', line 134

def on_verification(&block)
  @verification = block
end

#resetObject

Resets.



157
158
159
160
161
162
163
164
# File 'lib/rack-superfeedr.rb', line 157

def reset 
  @callback = Proc.new { |feed_id, body, url, request|
    # Nothing to do by default!
  }
  @verification = Proc.new { |mode, feed_id, url, request|
    true # Accept all by default!
  }
end