Class: Lotus::Subscription

Inherits:
Object
  • Object
show all
Defined in:
lib/lotus/subscription.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Subscription

Creates a representation of a subscription.

options:

:callback_url => The url that should be used to handle subscription
                 handshakes.
:topic_url    => The url of the feed one wishes to subscribe to.
:secret       => A secret that will be passed to the callback to better
                 verify that communication is not replayed. Default:
                 A secure random hex.
:hubs         => A list of hubs to negotiate the subscription with.
                 Default: attempts to discover the hubs when it
                 subscribes for the first time.
:hub          => The hub we have a subscription with already.


30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/lotus/subscription.rb', line 30

def initialize(options = {})
  @tokens = []

  secret = options[:secret] || SecureRandom.hex(32)
  @secret = secret.to_s

  @callback_url = options[:callback_url]
  @topic_url    = options[:topic_url]
  @tokens << options[:token] if options[:token]

  @hubs = options[:hubs] || []

  @hub  = options[:hub]
end

Instance Attribute Details

#callback_urlObject (readonly)

The url that should be used to handle subscription handshakes.



9
10
11
# File 'lib/lotus/subscription.rb', line 9

def callback_url
  @callback_url
end

#hubObject (readonly)

The hub this subscription is made with.



15
16
17
# File 'lib/lotus/subscription.rb', line 15

def hub
  @hub
end

#topic_urlObject (readonly)

The url of the feed one wishes to subscribe to.



12
13
14
# File 'lib/lotus/subscription.rb', line 12

def topic_url
  @topic_url
end

Instance Method Details

#challenge_response(challenge_code) ⇒ Object

Gives the content of a challenge response given the challenge body.



110
111
112
113
114
115
# File 'lib/lotus/subscription.rb', line 110

def challenge_response(challenge_code)
  {
    :body => challenge_code,
    :status => 200
  }
end

#change_subscription(mode) ⇒ Object

Change our subscription to this topic at a hub. mode: Either :subscribe or :unsubscribe hub_url: The url of the hub to negotiate with token: A token to verify the response from the hub.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/lotus/subscription.rb', line 73

def change_subscription(mode)
  token ||= SecureRandom.hex(32)
  @tokens << token.to_s

  # TODO: Set up HTTPS foo
  res = Net::HTTP.post_form(URI.parse(self.hub),
                            {
                              'hub.mode' => mode.to_s,
                              'hub.callback' => @callback_url,
                              'hub.verify' => 'async',
                              'hub.verify_token' => token,
                              'hub.lease_seconds' => '',
                              'hub.secret' => @secret,
                              'hub.topic' => @topic_url
                            })
end

#discover_hubs_for_topicObject

Actively searches for hubs by talking to publisher directly



46
47
48
# File 'lib/lotus/subscription.rb', line 46

def discover_hubs_for_topic
  @hubs = Lotus.feed_from_url(self.topic_url).hubs
end

#subscribeObject

Subscribe to the topic through the given hub.



51
52
53
54
55
56
57
58
59
60
# File 'lib/lotus/subscription.rb', line 51

def subscribe
  return unless self.hub.nil?

  # Discover hubs if none exist
  @hubs = discover_hubs_for_topic(self.topic_url) if self.hubs.empty?
  @hub = self.hubs.first
  change_subscription(:subscribe, token)

  # TODO: Check response, if failed, try a different hub
end

#unsubscribeObject

Unsubscribe to the topic.



63
64
65
66
67
# File 'lib/lotus/subscription.rb', line 63

def unsubscribe
  return if self.hub.nil?

  change_subscription(:unsubscribe)
end

#verify_content(body, signature) ⇒ Object

Determines if the given body matches the signature.



102
103
104
105
106
# File 'lib/lotus/subscription.rb', line 102

def verify_content(body, signature)
  hmac = HMAC::SHA1.hexdigest(@secret, body)
  check = "sha1=" + hmac
  check == signature
end

#verify_subscription(token) ⇒ Object

Verify that a subscription response is valid.



91
92
93
94
95
96
97
98
99
# File 'lib/lotus/subscription.rb', line 91

def verify_subscription(token)
  # Is there a token?
  result = @tokens.include?(token)

  # Ensure we cannot reuse the token
  @tokens.delete(token)

  result
end