hootenanny 0.0.1 → 0.1.0
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/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +5 -7
- data/Gemfile.lock +46 -28
- data/app/controllers/hootenanny/notifications_controller.rb +31 -0
- data/app/controllers/hootenanny/parameters.rb +16 -0
- data/app/controllers/hootenanny/subscriptions_controller.rb +24 -3
- data/app/models/hootenanny/publish_notification.rb +90 -0
- data/app/models/hootenanny/subscription.rb +72 -23
- data/config/routes.rb +2 -1
- data/db/migrate/20130607182642_add_started_at_and_lease_duration_to_subscriptions.rb +15 -0
- data/db/migrate/20130608225621_add_hmac_secret_to_subscription.rb +5 -0
- data/db/migrate/20130611235218_add_publish_notifications.rb +9 -0
- data/db/migrate/20130612153138_add_timestamps_to_publish_notification.rb +5 -0
- data/db/migrate/20130705200729_add_processed_flag_to_publish_notifications.rb +6 -0
- data/db/migrate/20130711061329_switch_publish_notification_process_state_from_boolean_to_string.rb +11 -0
- data/db/migrate/20130711061558_add_index_to_notifications_state.rb +5 -0
- data/hootenanny.gemspec +6 -2
- data/lib/hootenanny/configuration.rb +43 -0
- data/lib/hootenanny/correspondent.rb +44 -0
- data/lib/hootenanny/errors.rb +42 -1
- data/lib/hootenanny/feed.rb +75 -0
- data/lib/hootenanny/feed/atom_feed.rb +18 -0
- data/lib/hootenanny/feed/atom_feed_item.rb +8 -0
- data/lib/hootenanny/feed/digest_feed.rb +14 -0
- data/lib/hootenanny/feed/digest_feed_item.rb +11 -0
- data/lib/hootenanny/feed/feed_item.rb +30 -0
- data/lib/hootenanny/feed/file.rb +66 -0
- data/lib/hootenanny/feed/json_feed.rb +48 -0
- data/lib/hootenanny/feed/json_feed_item.rb +8 -0
- data/lib/hootenanny/feed/null_feed.rb +27 -0
- data/lib/hootenanny/feed/rss_feed.rb +52 -0
- data/lib/hootenanny/feed/rss_feed_item.rb +8 -0
- data/lib/hootenanny/feed_store.rb +30 -0
- data/lib/hootenanny/feed_store/file_feed_store.rb +55 -0
- data/lib/hootenanny/feed_store/web_feed_store.rb +42 -0
- data/lib/hootenanny/hub.rb +116 -22
- data/lib/hootenanny/publish_notification_expiration_policy.rb +17 -0
- data/lib/hootenanny/request.rb +40 -0
- data/lib/hootenanny/request/publish_notification.rb +94 -0
- data/lib/hootenanny/request/subscription.rb +153 -0
- data/lib/hootenanny/subscription_delivery.rb +47 -0
- data/lib/hootenanny/topic.rb +38 -0
- data/lib/hootenanny/topic_synchronizer.rb +71 -0
- data/lib/hootenanny/uri.rb +53 -0
- data/lib/hootenanny/verification.rb +108 -0
- data/lib/hootenanny/version.rb +1 -1
- data/spec/dummy/config/database.yml +12 -6
- data/spec/dummy/db/migrate/20130607183149_add_started_at_and_lease_duration_to_subscriptions.hootenanny.rb +16 -0
- data/spec/dummy/db/migrate/20130608231253_add_hmac_secret_to_subscription.hootenanny.rb +6 -0
- data/spec/dummy/db/migrate/20130611235546_add_publish_notifications.hootenanny.rb +10 -0
- data/spec/dummy/db/migrate/20130612153353_add_timestamps_to_publish_notification.hootenanny.rb +6 -0
- data/spec/dummy/db/migrate/20130705200832_add_processed_flag_to_publish_notifications.hootenanny.rb +7 -0
- data/spec/dummy/db/migrate/20130711061518_switch_publish_notification_process_state_from_boolean_to_string.hootenanny.rb +12 -0
- data/spec/dummy/db/migrate/20130711061629_add_index_to_notifications_state.hootenanny.rb +6 -0
- data/spec/factories/publish_notification.rb +13 -0
- data/spec/factories/requests/publish_notification.rb +11 -0
- data/spec/factories/requests/subscription.rb +46 -0
- data/spec/factories/subscription.rb +14 -2
- data/spec/factories/verification.rb +15 -0
- data/spec/features/publishers/can_notify_the_hub_of_content_updates_spec.rb +58 -0
- data/spec/features/subscribers/are_protected_from_unwarranted_subscriptions_spec.rb +59 -0
- data/spec/features/subscribers/can_receive_distributions_of_topic_content_spec.rb +175 -0
- data/spec/features/subscribers/can_subscribe_to_a_topic_spec.rb +76 -7
- data/spec/fixtures/feeds/atom/97d79220f68b4bf27.atom +0 -0
- data/spec/fixtures/feeds/atom/sample_feed.atom +51 -0
- data/spec/fixtures/feeds/digest/97d79220f68b4bf27.digest +1 -0
- data/spec/fixtures/feeds/digest/complete_broadcasted_items/5b187098da59f077f/97d79220f68b4bf27.digest +6 -0
- data/spec/fixtures/feeds/digest/incomplete_broadcasted_items/5b187098da59f077f/97d79220f68b4bf27.digest +5 -0
- data/spec/fixtures/feeds/digest/sample_feed.digest +6 -0
- data/spec/fixtures/feeds/json/97d79220f68b4bf27.json +1 -0
- data/spec/fixtures/feeds/json/feed_with_one_item.json +21 -0
- data/spec/fixtures/feeds/json/sample_feed.json +30 -0
- data/spec/fixtures/feeds/rss/5b187098da59f077f/97d79220f68b4bf27.rss +21 -0
- data/spec/fixtures/feeds/rss/97d79220f68b4bf27.rss +0 -0
- data/spec/fixtures/feeds/rss/feed_with_one_item.rss +15 -0
- data/spec/fixtures/feeds/rss/minimal_feed.rss +12 -0
- data/spec/fixtures/feeds/rss/sample_feed.rss +22 -0
- data/spec/fixtures/feeds/rss/sample_feed_2.rss +22 -0
- data/spec/lib/hootenanny/configuration_spec.rb +7 -0
- data/spec/lib/hootenanny/correspondent_spec.rb +94 -0
- data/spec/lib/hootenanny/errors_spec.rb +21 -0
- data/spec/lib/hootenanny/feed/atom_feed_item_spec.rb +9 -0
- data/spec/lib/hootenanny/feed/atom_feed_spec.rb +40 -0
- data/spec/lib/hootenanny/feed/digest_feed_item_spec.rb +9 -0
- data/spec/lib/hootenanny/feed/digest_feed_spec.rb +40 -0
- data/spec/lib/hootenanny/feed/feed_item_spec.rb +49 -0
- data/spec/lib/hootenanny/feed/file_spec.rb +66 -0
- data/spec/lib/hootenanny/feed/json_feed_item_spec.rb +9 -0
- data/spec/lib/hootenanny/feed/json_feed_spec.rb +128 -0
- data/spec/lib/hootenanny/feed/null_feed_spec.rb +9 -0
- data/spec/lib/hootenanny/feed/rss_feed_item_spec.rb +9 -0
- data/spec/lib/hootenanny/feed/rss_feed_spec.rb +143 -0
- data/spec/lib/hootenanny/feed_spec.rb +159 -0
- data/spec/lib/hootenanny/feed_store/file_feed_store_spec.rb +58 -0
- data/spec/lib/hootenanny/feed_store/web_feed_store_spec.rb +47 -0
- data/spec/lib/hootenanny/feed_store_spec.rb +27 -0
- data/spec/lib/hootenanny/hub_spec.rb +73 -0
- data/spec/lib/hootenanny/publish_notification_expiration_policy_spec.rb +35 -0
- data/spec/lib/hootenanny/request/publish_notification_spec.rb +43 -0
- data/spec/lib/hootenanny/request/subscription_spec.rb +89 -0
- data/spec/lib/hootenanny/request_spec.rb +21 -0
- data/spec/lib/hootenanny/subscription_delivery_spec.rb +54 -0
- data/spec/lib/hootenanny/topic_spec.rb +15 -0
- data/spec/lib/hootenanny/topic_synchronizer_spec.rb +98 -0
- data/spec/lib/hootenanny/uri_spec.rb +32 -0
- data/spec/lib/hootenanny/verification_spec.rb +92 -0
- data/spec/models/hootenanny/publish_notification_spec.rb +55 -0
- data/spec/models/hootenanny/subscription_spec.rb +58 -19
- data/spec/support/verification.rb +63 -0
- metadata +231 -14
- data/spec/controllers/hootenanny/hub_spec.rb +0 -15
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -17,10 +17,8 @@ gem "jquery-rails"
|
|
17
17
|
# gem 'debugger'
|
18
18
|
gem 'strong_parameters'
|
19
19
|
|
20
|
-
|
21
|
-
gem '
|
22
|
-
gem '
|
23
|
-
gem '
|
24
|
-
|
25
|
-
gem 'factory_girl_rails'
|
26
|
-
gem 'awesome_print'
|
20
|
+
group :development do
|
21
|
+
gem 'pry'
|
22
|
+
# gem 'pry-plus'
|
23
|
+
gem 'awesome_print'
|
24
|
+
end
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
hootenanny (0.0
|
4
|
+
hootenanny (0.1.0)
|
5
|
+
chronological (~> 1.0.0beta10)
|
6
|
+
faraday (~> 0.8.7)
|
5
7
|
rails (~> 3.2)
|
6
8
|
strong_parameters (~> 0.2.1)
|
7
9
|
|
@@ -35,10 +37,14 @@ GEM
|
|
35
37
|
activesupport (3.2.13)
|
36
38
|
i18n (= 0.6.1)
|
37
39
|
multi_json (~> 1.0)
|
40
|
+
addressable (2.3.4)
|
38
41
|
arel (3.0.2)
|
39
42
|
awesome_print (1.1.0)
|
40
43
|
builder (3.0.4)
|
41
|
-
|
44
|
+
chronological (1.0.0beta10)
|
45
|
+
coderay (1.0.9)
|
46
|
+
crack (0.3.2)
|
47
|
+
database_cleaner (0.9.1)
|
42
48
|
diff-lcs (1.2.4)
|
43
49
|
erubis (2.7.0)
|
44
50
|
factory_girl (4.2.0)
|
@@ -46,11 +52,13 @@ GEM
|
|
46
52
|
factory_girl_rails (4.2.1)
|
47
53
|
factory_girl (~> 4.2.0)
|
48
54
|
railties (>= 3.0.0)
|
49
|
-
|
55
|
+
faraday (0.8.7)
|
56
|
+
multipart-post (~> 1.1)
|
57
|
+
fuubar (1.1.1)
|
50
58
|
rspec (~> 2.0)
|
51
59
|
rspec-instafail (~> 0.2.0)
|
52
|
-
ruby-progressbar (~> 1.0
|
53
|
-
hike (1.2.
|
60
|
+
ruby-progressbar (~> 1.0)
|
61
|
+
hike (1.2.3)
|
54
62
|
i18n (0.6.1)
|
55
63
|
journey (1.0.4)
|
56
64
|
jquery-rails (2.2.1)
|
@@ -60,10 +68,16 @@ GEM
|
|
60
68
|
mail (2.5.4)
|
61
69
|
mime-types (~> 1.16)
|
62
70
|
treetop (~> 1.4.8)
|
71
|
+
method_source (0.8.1)
|
63
72
|
mime-types (1.23)
|
64
|
-
multi_json (1.7.
|
73
|
+
multi_json (1.7.6)
|
74
|
+
multipart-post (1.2.0)
|
65
75
|
pg (0.15.1)
|
66
76
|
polyglot (0.3.3)
|
77
|
+
pry (0.9.12.2)
|
78
|
+
coderay (~> 1.0.5)
|
79
|
+
method_source (~> 0.8)
|
80
|
+
slop (~> 3.4)
|
67
81
|
rack (1.4.5)
|
68
82
|
rack-cache (1.2)
|
69
83
|
rack (>= 0.4)
|
@@ -89,57 +103,61 @@ GEM
|
|
89
103
|
rake (10.0.4)
|
90
104
|
rdoc (3.12.2)
|
91
105
|
json (~> 1.4)
|
92
|
-
rspec (2.
|
93
|
-
rspec-core (
|
94
|
-
rspec-expectations (
|
95
|
-
rspec-mocks (
|
96
|
-
rspec-core (2.
|
97
|
-
rspec-expectations (2.
|
106
|
+
rspec (2.14.0.rc1)
|
107
|
+
rspec-core (= 2.14.0.rc1)
|
108
|
+
rspec-expectations (= 2.14.0.rc1)
|
109
|
+
rspec-mocks (= 2.14.0.rc1)
|
110
|
+
rspec-core (2.14.0.rc1)
|
111
|
+
rspec-expectations (2.14.0.rc1)
|
98
112
|
diff-lcs (>= 1.1.3, < 2.0)
|
99
113
|
rspec-instafail (0.2.4)
|
100
|
-
rspec-mocks (2.
|
101
|
-
rspec-rails (2.
|
114
|
+
rspec-mocks (2.14.0.rc1)
|
115
|
+
rspec-rails (2.14.0.rc1)
|
102
116
|
actionpack (>= 3.0)
|
103
117
|
activesupport (>= 3.0)
|
104
118
|
railties (>= 3.0)
|
105
|
-
rspec-core (
|
106
|
-
rspec-expectations (
|
107
|
-
rspec-mocks (
|
119
|
+
rspec-core (= 2.14.0.rc1)
|
120
|
+
rspec-expectations (= 2.14.0.rc1)
|
121
|
+
rspec-mocks (= 2.14.0.rc1)
|
108
122
|
rspectacular (0.13.0)
|
109
123
|
fuubar (~> 1.0)
|
110
124
|
rspec (~> 2.12)
|
111
|
-
ruby-progressbar (1.
|
112
|
-
|
113
|
-
activesupport (>= 3.0.0)
|
125
|
+
ruby-progressbar (1.1.1)
|
126
|
+
slop (3.4.5)
|
114
127
|
sprockets (2.2.2)
|
115
128
|
hike (~> 1.2)
|
116
129
|
multi_json (~> 1.0)
|
117
130
|
rack (~> 1.0)
|
118
131
|
tilt (~> 1.1, != 1.3.0)
|
119
|
-
sqlite3 (1.3.7)
|
120
132
|
strong_parameters (0.2.1)
|
121
133
|
actionpack (~> 3.0)
|
122
134
|
activemodel (~> 3.0)
|
123
135
|
railties (~> 3.0)
|
124
136
|
thor (0.18.1)
|
125
137
|
tilt (1.4.1)
|
126
|
-
|
138
|
+
timecop (0.6.1)
|
139
|
+
treetop (1.4.14)
|
127
140
|
polyglot
|
128
141
|
polyglot (>= 0.3.1)
|
129
142
|
tzinfo (0.3.37)
|
143
|
+
webmock (1.11.0)
|
144
|
+
addressable (>= 2.2.7)
|
145
|
+
crack (>= 0.3.2)
|
130
146
|
|
131
147
|
PLATFORMS
|
132
148
|
ruby
|
133
149
|
|
134
150
|
DEPENDENCIES
|
135
151
|
awesome_print
|
136
|
-
database_cleaner
|
137
|
-
factory_girl_rails
|
152
|
+
database_cleaner (~> 0.9.1)
|
153
|
+
factory_girl_rails (~> 4.2)
|
138
154
|
hootenanny!
|
139
155
|
jquery-rails
|
140
156
|
pg
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
157
|
+
pry
|
158
|
+
rspec (~> 2.14.0.rc1)
|
159
|
+
rspec-rails (~> 2.14.0.rc1)
|
160
|
+
rspectacular (~> 0.13)
|
145
161
|
strong_parameters
|
162
|
+
timecop (~> 0.6.1)
|
163
|
+
webmock (~> 1.11)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'hootenanny/hub'
|
2
|
+
require 'controllers/hootenanny/parameters'
|
3
|
+
|
4
|
+
module Hootenanny
|
5
|
+
class PublishNotificationsController < ActionController::Base
|
6
|
+
include Hootenanny::Parameters
|
7
|
+
|
8
|
+
def create
|
9
|
+
if Hootenanny::Hub.notify_of_publication(publish_notification_request)
|
10
|
+
render :nothing => true, :status => :no_content
|
11
|
+
end
|
12
|
+
rescue Hootenanny::Error => error
|
13
|
+
render json: error,
|
14
|
+
status: :bad_request
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def publish_notification_request
|
20
|
+
@request ||= Hootenanny::Hub.request publish_notification_request_params
|
21
|
+
end
|
22
|
+
|
23
|
+
def publish_notification_request_params
|
24
|
+
params[:type] ||= :publish_notification
|
25
|
+
|
26
|
+
params.permit(:url)
|
27
|
+
|
28
|
+
params
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Hootenanny
|
2
|
+
module Parameters
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception|
|
7
|
+
render json: {
|
8
|
+
error: {
|
9
|
+
message: "Required parameter missing: #{parameter_missing_exception.param}"
|
10
|
+
}
|
11
|
+
},
|
12
|
+
status: :bad_request
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,14 +1,35 @@
|
|
1
1
|
require 'hootenanny/hub'
|
2
|
+
require 'controllers/hootenanny/parameters'
|
2
3
|
|
3
4
|
module Hootenanny
|
4
5
|
class SubscriptionsController < ActionController::Base
|
6
|
+
include Hootenanny::Parameters
|
7
|
+
|
5
8
|
def create
|
6
|
-
if Hootenanny::Hub.subscribe(
|
9
|
+
if Hootenanny::Hub.subscribe(subscription_request)
|
7
10
|
render :nothing => true, :status => :no_content
|
8
11
|
end
|
9
|
-
rescue Hootenanny::
|
10
|
-
render json:
|
12
|
+
rescue Hootenanny::Error => error
|
13
|
+
render json: error,
|
11
14
|
status: :bad_request
|
12
15
|
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def subscription_request
|
20
|
+
@request ||= Hootenanny::Hub.request subscription_request_params
|
21
|
+
end
|
22
|
+
|
23
|
+
def subscription_request_params
|
24
|
+
params[:type] ||= :subscription
|
25
|
+
|
26
|
+
params.require(:callback)
|
27
|
+
params.require(:topic)
|
28
|
+
params.permit(:lease_seconds,
|
29
|
+
:verify_token,
|
30
|
+
:secret)
|
31
|
+
|
32
|
+
params
|
33
|
+
end
|
13
34
|
end
|
14
35
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'hootenanny/uri'
|
2
|
+
|
3
|
+
module Hootenanny
|
4
|
+
class PublishNotification < ActiveRecord::Base
|
5
|
+
self.table_name = 'hootenanny_publish_notifications'
|
6
|
+
|
7
|
+
###
|
8
|
+
# Private: Retrieves a set of notifications for a given set of topics. If
|
9
|
+
# given one topic, only one notification should be returned since there can
|
10
|
+
# only be one notification for a given topic in the queue at any time.
|
11
|
+
#
|
12
|
+
# topic - A String or an Array representing the Topic to look for.
|
13
|
+
#
|
14
|
+
# Examples:
|
15
|
+
#
|
16
|
+
# Hootenanny::PublishNotification.for('http://mytopic')
|
17
|
+
# #=> <ActiveRecord::Relation>
|
18
|
+
#
|
19
|
+
# Hootenanny::PublishNotification.for %w{http://mytopic
|
20
|
+
# http://anothertopic}
|
21
|
+
# #=> <ActiveRecord::Relation>
|
22
|
+
#
|
23
|
+
# Returns an ActiveRecord::Relation
|
24
|
+
#
|
25
|
+
def self.for(topic)
|
26
|
+
where(:topic => topic)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.unprocessed
|
30
|
+
where(:state => 'unprocessed')
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.processed
|
34
|
+
where(:state => 'processed')
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.expired
|
38
|
+
where(:state => 'expired')
|
39
|
+
end
|
40
|
+
|
41
|
+
###
|
42
|
+
# Private: Creates a notification for a given topic. If the notification for
|
43
|
+
# the topic exists, it touches it to reflect the new update time and returns
|
44
|
+
# it. It does _not_ create a new notification.
|
45
|
+
#
|
46
|
+
# topic - A String representing a URI of a topic which has been proposed to
|
47
|
+
# have been updated.
|
48
|
+
#
|
49
|
+
# Examples:
|
50
|
+
#
|
51
|
+
# Hootenanny::PublishNotification.notify('http://example.com')
|
52
|
+
# # => <Hootenanny::PublishNotification topic: 'http://example.com'>
|
53
|
+
#
|
54
|
+
# Returns a Hootenanny::PublishNotification
|
55
|
+
# Raises a Hootenanny::URI::InvalidSchemeError if the topic URI are using
|
56
|
+
# something other than HTTP or HTTPS
|
57
|
+
# Raises a Hootenanny::URI::InvalidError if the URI can't be parsed properly
|
58
|
+
#
|
59
|
+
def self.notify(topic)
|
60
|
+
topic = Hootenanny::URI.parse(topic).to_s
|
61
|
+
|
62
|
+
find_or_initialize(topic).touch
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.each_unprocessed
|
66
|
+
unprocessed.find_each do |notification|
|
67
|
+
yield notification
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def process
|
72
|
+
self.update_attributes(:state => 'processed')
|
73
|
+
end
|
74
|
+
|
75
|
+
def expire
|
76
|
+
self.update_attributes(:state => 'expired')
|
77
|
+
end
|
78
|
+
|
79
|
+
def processed?
|
80
|
+
self.state == 'processed'
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def self.find_or_initialize(topic)
|
86
|
+
where(topic: topic).first ||
|
87
|
+
PublishNotification.create!(topic: topic)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -1,13 +1,26 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'active_record'
|
2
|
+
require 'chronological'
|
3
|
+
require 'hootenanny/uri'
|
3
4
|
|
4
5
|
module Hootenanny
|
5
6
|
class Subscription < ActiveRecord::Base
|
7
|
+
extend Chronological
|
8
|
+
|
6
9
|
self.table_name = 'hootenanny_subscriptions'
|
7
10
|
|
11
|
+
###
|
12
|
+
# Chronological generates time range logic based on :started_at and
|
13
|
+
# :duration_in_seconds
|
14
|
+
#
|
15
|
+
timeframe type: :duration_from_start,
|
16
|
+
duration: :lease_duration
|
17
|
+
|
8
18
|
###
|
9
19
|
# Private: Finds all subscriptions which are subscribed to a given topic
|
10
20
|
#
|
21
|
+
# It takes into account only _active_ subscriptions. If the subscription has
|
22
|
+
# expired, it will not be returned.
|
23
|
+
#
|
11
24
|
# topic - A String represeenting a topic which has been subscribed to
|
12
25
|
#
|
13
26
|
# Example:
|
@@ -19,28 +32,39 @@ class Subscription < ActiveRecord::Base
|
|
19
32
|
# subscriptions which are subscribed to the topic.
|
20
33
|
#
|
21
34
|
def self.to(topic)
|
22
|
-
where(:topic => topic)
|
35
|
+
active.where(:topic => topic.to_s)
|
23
36
|
end
|
24
37
|
|
25
38
|
###
|
26
|
-
# Private:
|
39
|
+
# Private: Subscribes a given subscriber to a given topic URL by creating
|
27
40
|
# a Subscription.
|
28
41
|
#
|
42
|
+
# This operation is idempotent. It will not modify a subscription if one
|
43
|
+
# already exists for the subscriber/topic passed in.
|
44
|
+
#
|
29
45
|
# options - A Hash of options
|
30
46
|
#
|
31
|
-
# :subscriber
|
32
|
-
#
|
33
|
-
# :to
|
34
|
-
#
|
35
|
-
#
|
47
|
+
# :subscriber - A String representing the URI which should be
|
48
|
+
# notified when changes occur on the topic
|
49
|
+
# :to - A String representing the topic URI which is
|
50
|
+
# publishing the items that the subscriber is
|
51
|
+
# interested in.
|
52
|
+
# :digest_secret - A String token of no more than 200 bytes which
|
53
|
+
# will be used during content distribution so that
|
54
|
+
# the subscriber can verify that the request is
|
55
|
+
# from the hub and not a undesired 3rd party
|
56
|
+
# (optional).
|
57
|
+
# :lease_duration - A Number representing the length of time (in
|
58
|
+
# seconds) after the subscription is created until
|
59
|
+
# it should be considered invalid
|
36
60
|
#
|
37
61
|
# Example:
|
38
62
|
#
|
39
63
|
# # If a subscription does not yet exist for the subscriber/topic, it
|
40
64
|
# # creates # a new Subscription
|
41
65
|
#
|
42
|
-
# Subscription.
|
43
|
-
#
|
66
|
+
# Subscription.subscribe(subscriber: 'http://example.com/my_callback',
|
67
|
+
# to: 'http://example.org/my_topic')
|
44
68
|
#
|
45
69
|
# # => <Subscription subscriber: 'http://example.com/my_callback',
|
46
70
|
# topic: 'http://example.org/my_topic'>
|
@@ -48,24 +72,49 @@ class Subscription < ActiveRecord::Base
|
|
48
72
|
#
|
49
73
|
#
|
50
74
|
# # If a subscription already exists for the subscriber/topic, it retrieves
|
51
|
-
# # and returns the current Subscription
|
75
|
+
# # and returns the current Subscription with all other attributes updated
|
76
|
+
# # as if the subscription were new.
|
52
77
|
#
|
53
|
-
# Subscription.
|
54
|
-
#
|
78
|
+
# Subscription.subscribe(subscriber: 'http://example.com/my_callback',
|
79
|
+
# to: 'http://example.org/my_topic',
|
80
|
+
# digest_secret: 'new_secret')
|
55
81
|
#
|
56
|
-
# # => <Subscription subscriber:
|
57
|
-
# topic:
|
82
|
+
# # => <Subscription subscriber: 'http://example.com/my_callback',
|
83
|
+
# topic: 'http://example.org/my_topic',
|
84
|
+
# digest_secret: 'new_secret'>
|
58
85
|
#
|
59
86
|
# Returns a Subscription
|
87
|
+
# Raises a Hootenanny::URI::InvalidSchemeError if the URIs are using something
|
88
|
+
# other than HTTP or HTTPS
|
89
|
+
# Raises a Hootenanny::URI::InvalidError if the URI can't be parsed properly
|
60
90
|
#
|
61
|
-
def self.
|
62
|
-
subscriber
|
63
|
-
topic
|
91
|
+
def self.subscribe(options = {})
|
92
|
+
subscriber = Hootenanny::URI.parse(options.fetch(:subscriber)).to_s
|
93
|
+
topic = Hootenanny::URI.parse(options.fetch(:to)).to_s
|
94
|
+
|
95
|
+
attrs = {}
|
96
|
+
attrs[:started_at] = Time.now.utc
|
97
|
+
attrs[:digest_secret] = options.fetch(:digest_secret, nil)
|
98
|
+
attrs[:lease_duration] = options.fetch(:lease_duration)
|
99
|
+
|
100
|
+
subscription = find_or_initialize(subscriber, topic)
|
101
|
+
|
102
|
+
subscription.update_attributes(attrs)
|
103
|
+
|
104
|
+
subscription
|
105
|
+
end
|
106
|
+
|
107
|
+
def subscriber
|
108
|
+
Hootenanny::URI.parse(read_attribute(:subscriber))
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
64
112
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
113
|
+
def self.find_or_initialize(subscriber, topic)
|
114
|
+
where(subscriber: subscriber,
|
115
|
+
topic: topic).first ||
|
116
|
+
Subscription.new(subscriber: subscriber,
|
117
|
+
topic: topic)
|
69
118
|
end
|
70
119
|
end
|
71
120
|
end
|