toot 0.1.3 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +179 -8
- data/Rakefile +7 -0
- data/bin/rspec +16 -0
- data/circle.yml +6 -0
- data/lib/tasks/toot.rake +9 -0
- data/lib/toot.rb +51 -2
- data/lib/toot/calls_event_callback.rb +27 -0
- data/lib/toot/calls_handlers.rb +13 -0
- data/lib/toot/config.rb +58 -0
- data/lib/toot/event.rb +46 -0
- data/lib/toot/handler_service.rb +25 -0
- data/lib/toot/publishes_event.rb +19 -0
- data/lib/toot/rails.rb +9 -0
- data/lib/toot/registers_subscriptions.rb +36 -0
- data/lib/toot/source.rb +13 -0
- data/lib/toot/subscription.rb +13 -0
- data/lib/toot/subscriptions_service.rb +31 -0
- data/lib/toot/version.rb +1 -1
- data/toot.gemspec +7 -2
- metadata +74 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 083d9404092e22b97c3cc28414d2a7544f00e4af
|
4
|
+
data.tar.gz: a384f7ab9ebc684a9374b2d6b24f4f1844717322
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc56a2166877aad3957fa83a7a24342bac4191ab05df5b3d73fb409bb6e92740ff0592606cfa66a23741cba03bcc2f8163bddd5c4ec43bb1158a3fd454606201
|
7
|
+
data.tar.gz: 945bc0a83d6b9e0fc831346b835a2157fc21fbff6c0413a1df648853009bfff7cfb46fcb3245eddf9f68814759aae51fd63b16663ced58fd999064b81008ef45
|
data/README.md
CHANGED
@@ -1,8 +1,170 @@
|
|
1
|
-
# Toot
|
1
|
+
# Toot :postal_horn: :dash:
|
2
2
|
|
3
|
-
|
3
|
+
Toot is a library for basic PubSub over HTTP. Toot fires off event
|
4
|
+
payloads, and provides lightweight Rack apps for handling event callbacks and
|
5
|
+
subscription management that you can mount up in any Rack compatible
|
6
|
+
app. All of these actions happen through Sidekiq providing asynchronous,
|
7
|
+
persistent, and fault-tolerant events.
|
4
8
|
|
5
|
-
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
Toot is composed of several standalone components. An app can play the
|
12
|
+
rolls of an event publisher, subscriber, or both. It just depends on how
|
13
|
+
you configure it. Let's take a look at an example using two apps:
|
14
|
+
"publisher" and "subscriber".
|
15
|
+
|
16
|
+
### Overview
|
17
|
+
|
18
|
+
Here is how you could publish an event on the channel "users.updated.v1"
|
19
|
+
from the "publisher" app and then subscribe to that channel on the
|
20
|
+
"subscriber" app.
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
# Publish an event
|
24
|
+
Toot.publish "users.updated.v1", id: 123
|
25
|
+
|
26
|
+
# Subscribe to an event
|
27
|
+
Toot.subscribe :publisher, "users.updated.v1", -> (event) {
|
28
|
+
puts "User with id #{event["id"]} was updated."
|
29
|
+
}
|
30
|
+
```
|
31
|
+
|
32
|
+
The "subscriber" app has a named `source` called "publisher" that is
|
33
|
+
configured in the config block. Let's take a look at what configuration
|
34
|
+
looks like on both apps. First let's take a look at the publisher:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
# Configuration on the publisher
|
38
|
+
Toot.config do |c|
|
39
|
+
c.channel_prefix = "org.example.publisher."
|
40
|
+
end
|
41
|
+
|
42
|
+
# Mount up the subscriptions service (e.g. For Rails in routes.rb)
|
43
|
+
match "/subscriptions", to: Toot::SubscriptionsService, via: :post
|
44
|
+
```
|
45
|
+
|
46
|
+
We set the `channel_prefix` which will prepend all events we publish
|
47
|
+
with this string. This ensures that we don't have name collisions with
|
48
|
+
other publishers we may introduce.
|
49
|
+
|
50
|
+
The `Toot::SubscriptionsService` is a lightweight Rack app that can be
|
51
|
+
mounted up in any Rack compatible application. You can mount it at
|
52
|
+
whatever path you like. We'll need the full URL when we configure our
|
53
|
+
subscriber.
|
54
|
+
|
55
|
+
Let's take a look at the subscriber configuration now:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# Configuration on the subscriber
|
59
|
+
Toot.config do |c|
|
60
|
+
c.callback_url = "https://subscriber.example.org/callbacks"
|
61
|
+
c.source :publisher,
|
62
|
+
subscription_url: "https://publisher.example.org/subscriptions",
|
63
|
+
channel_prefix: "org.example.publisher."
|
64
|
+
end
|
65
|
+
|
66
|
+
# Mount up the handler service (e.g. For Rails in routes.rb)
|
67
|
+
match "/callbacks", to: Toot::HandlerService, via: :post
|
68
|
+
```
|
69
|
+
|
70
|
+
The `source` option defines a new event source called "publisher". We
|
71
|
+
reference this name in any calls to `Toot.subscribe`. We define the
|
72
|
+
`subscription_url` to match the URL that we mounted up the
|
73
|
+
`Toot::SubscriptionsService` Rack app on the publisher, and the
|
74
|
+
`channel_prefix` should match the publisher's.
|
75
|
+
|
76
|
+
The `Toot::HandlerService` is the Rack app that handles the event
|
77
|
+
callback from the publisher. The `callback_url` configuration option
|
78
|
+
should match whatever URL you mount this Rack app to on your
|
79
|
+
application. This is used in the subscibe process to let the publisher
|
80
|
+
know how to notify us about a new event.
|
81
|
+
|
82
|
+
### Event Lifecycle
|
83
|
+
|
84
|
+
If you're having trouble picturing how this is actually working let's
|
85
|
+
trace the journey of a newly published event from the "publisher" to the
|
86
|
+
"subscriber".
|
87
|
+
|
88
|
+
1. Event is published using the `Event.publish` method.
|
89
|
+
2. This enqueues a background job which checks the Database (Redis) for
|
90
|
+
subscribers to this channel and enqueues another job for each
|
91
|
+
subscriber it finds.
|
92
|
+
3. The subscriber's callback URL is called with the event's data payload
|
93
|
+
4. The subscriber enqueues a background job if it has a handler for this
|
94
|
+
event.
|
95
|
+
5. This background job runs the actual event handler code.
|
96
|
+
|
97
|
+
### Subscribing
|
98
|
+
|
99
|
+
Subscribing is handled by a callable class called
|
100
|
+
`Toot::RegistersSusbcriptions`. There is also a rake task available that
|
101
|
+
does the same thing called `toot:register_subscriptions`. If you are
|
102
|
+
using Rails this rake task will be available to you automatically.
|
103
|
+
|
104
|
+
### Configuration
|
105
|
+
|
106
|
+
We've looked at an example, but let's look at the conifguration options
|
107
|
+
in greater detail.
|
108
|
+
|
109
|
+
* `channel_prefix`: This option sets a string that will be prepended to
|
110
|
+
all events published from this app. In all of our examples we've been
|
111
|
+
using the [reverse DNS notation][1], but you can use whatever
|
112
|
+
convention you'd like.
|
113
|
+
* `callback_url`: The event handler URL that this application will
|
114
|
+
register to remote publishers. It should match the full URL to
|
115
|
+
wherever you have mounted the `Toot::HandlerService` for this app.
|
116
|
+
* `http_connection`: An instance of Faraday::Connection which is used
|
117
|
+
for any external HTTP calls. You can use this to add custom middleware
|
118
|
+
for authorization, logging, or debugging.
|
119
|
+
* `redis_connection`: If you'd like to use a custom Redis connection you
|
120
|
+
can configure a callable here that yields a redis connection. By
|
121
|
+
default the Sidekiq Redis connection pool is used.
|
122
|
+
* `source`: This is a method call that defines a named source. It should
|
123
|
+
include a `subscription_url` option and a `channel_prefix` option.
|
124
|
+
* The first argument is the name of this source
|
125
|
+
* The `subscription_url` option is the URL to this source's
|
126
|
+
`Toot::SubscriptionsService` app.
|
127
|
+
* The `channel_prefix` should match this app's configured
|
128
|
+
channel_prefix. This ensures that event channel names will be built
|
129
|
+
correctly on the publisher side and on the subscriber side.
|
130
|
+
* `subscribe`: This is a method call that adds a subscription to a given
|
131
|
+
source's channel. It takes three arguments:
|
132
|
+
* The source name. This must match a previously defined source
|
133
|
+
* The channel suffix. This will be joined with the `channel_prefix`
|
134
|
+
configured on the source to form the full channel name.
|
135
|
+
* A callable event handler. The event object will be passed in as the
|
136
|
+
only argument.
|
137
|
+
|
138
|
+
### The Event Object
|
139
|
+
|
140
|
+
The schema of the publisher's payload is a contract between publisher
|
141
|
+
and subscriber and is outside of the scope of this library. However,
|
142
|
+
Toot does provide some extra information to aid in debugging and general
|
143
|
+
happiness:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
Toot.subscribe :publisher, "awesome.channel", -> (event) {
|
147
|
+
event.id # => "c6c4af6b-a227-4b0e-a7b5-5259d31cf98b"
|
148
|
+
event.timestamp # => 2015-10-23 11:50:09 -0500
|
149
|
+
event.channel # => "org.example.publisher.awesome.channel"
|
150
|
+
event.payload # => { "publisher_data" => 123 }
|
151
|
+
event["publisher_data"] # => 123
|
152
|
+
}
|
153
|
+
```
|
154
|
+
|
155
|
+
### Authentication
|
156
|
+
|
157
|
+
It is important to note that there is no authentication baked into
|
158
|
+
Toot's services. If you aren't running in a trusted environment (almost
|
159
|
+
everybody) you will need to wrap these Rack apps in some kind of
|
160
|
+
authentication middleware. In Rails, you can use the [constraints
|
161
|
+
routing config][2], or more generically, you can just decorate the
|
162
|
+
service with another callable object that does the authentication
|
163
|
+
checks.
|
164
|
+
|
165
|
+
**TODO:** Currently we don't have the ability to add credentials to
|
166
|
+
outgoing requests. This will need to be added before this problem is
|
167
|
+
100% solved.
|
6
168
|
|
7
169
|
## Installation
|
8
170
|
|
@@ -20,17 +182,26 @@ Or install it yourself as:
|
|
20
182
|
|
21
183
|
$ gem install toot
|
22
184
|
|
23
|
-
|
185
|
+
### Requirements
|
24
186
|
|
25
|
-
|
187
|
+
* Sidekiq (and therefore Redis)
|
188
|
+
* Ruby 2.1+ (or at least that's what's tested)
|
26
189
|
|
27
190
|
## Development
|
28
191
|
|
29
|
-
After checking out the repo, run `bin/setup` to install dependencies.
|
192
|
+
After checking out the repo, run `bin/setup` to install dependencies.
|
193
|
+
Then, run `rake rspec` to run the tests. You can also run `bin/console`
|
194
|
+
for an interactive prompt that will allow you to experiment.
|
30
195
|
|
31
|
-
To install this gem onto your local machine, run `bundle exec rake
|
196
|
+
To install this gem onto your local machine, run `bundle exec rake
|
197
|
+
install`. To release a new version, update the version number in
|
198
|
+
`version.rb`, and then run `bundle exec rake release`, which will create
|
199
|
+
a git tag for the version, push git commits and tags, and push the
|
200
|
+
`.gem` file to [rubygems.org](https://rubygems.org).
|
32
201
|
|
33
202
|
## Contributing
|
34
203
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
204
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/watermarkchurch/toot.
|
36
205
|
|
206
|
+
[1]: https://en.wikipedia.org/wiki/Reverse_domain_name_notation
|
207
|
+
[2]: http://guides.rubyonrails.org/routing.html#advanced-constraints
|
data/Rakefile
CHANGED
data/bin/rspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'rspec' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('rspec-core', 'rspec')
|
data/circle.yml
ADDED
data/lib/tasks/toot.rake
ADDED
data/lib/toot.rb
CHANGED
@@ -1,5 +1,54 @@
|
|
1
|
-
require
|
1
|
+
require 'toot/version'
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
require 'sidekiq'
|
5
|
+
|
6
|
+
require 'toot/config'
|
7
|
+
require 'toot/event'
|
8
|
+
require 'toot/source'
|
9
|
+
require 'toot/subscription'
|
10
|
+
|
11
|
+
require 'toot/calls_event_callback'
|
12
|
+
require 'toot/calls_handlers'
|
13
|
+
require 'toot/handler_service'
|
14
|
+
require 'toot/publishes_event'
|
15
|
+
require 'toot/registers_subscriptions'
|
16
|
+
require 'toot/subscriptions_service'
|
2
17
|
|
3
18
|
module Toot
|
4
|
-
|
19
|
+
|
20
|
+
class Error < StandardError; end
|
21
|
+
class ConfigError < Error; end
|
22
|
+
class CallbackFailure < Error; end
|
23
|
+
class RegisterSubscriptionFailure < Error; end
|
24
|
+
|
25
|
+
def self.config
|
26
|
+
if block_given?
|
27
|
+
yield config
|
28
|
+
else
|
29
|
+
@config ||= Config.new
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.reset_config
|
34
|
+
@config = Config.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.publish(channel, payload, prefix: config.channel_prefix)
|
38
|
+
Event.new(
|
39
|
+
channel: [prefix, channel].join,
|
40
|
+
payload: payload
|
41
|
+
).publish
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.subscribe(*args)
|
45
|
+
config.subscribe(*args)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.redis(connection=config.redis_connection, &block)
|
49
|
+
connection.call(&block)
|
50
|
+
end
|
51
|
+
|
5
52
|
end
|
53
|
+
|
54
|
+
require 'toot/rails' if defined?(Rails)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Toot
|
4
|
+
class CallsEventCallback
|
5
|
+
include Sidekiq::Worker
|
6
|
+
|
7
|
+
def perform(callback_url, event_data)
|
8
|
+
uri = URI(callback_url)
|
9
|
+
|
10
|
+
response = Toot.config.http_connection.post do |request|
|
11
|
+
request.url uri
|
12
|
+
request.body = event_data.to_json
|
13
|
+
request.headers["Content-Type"] = "application/json"
|
14
|
+
end
|
15
|
+
|
16
|
+
if response.success?
|
17
|
+
if response.headers["X-Toot-Unsubscribe"]
|
18
|
+
Toot.redis do |r|
|
19
|
+
r.srem event_data["channel"], callback_url
|
20
|
+
end
|
21
|
+
end
|
22
|
+
else
|
23
|
+
raise CallbackFailure, "Response code: #{response.status}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/toot/config.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Toot
|
2
|
+
CONFIG_ATTRS = %i[
|
3
|
+
channel_prefix
|
4
|
+
http_connection
|
5
|
+
redis_connection
|
6
|
+
callback_url
|
7
|
+
]
|
8
|
+
|
9
|
+
class Config < Struct.new(*CONFIG_ATTRS)
|
10
|
+
|
11
|
+
def source(name, subscription_url:, channel_prefix:)
|
12
|
+
Source.new(
|
13
|
+
name: name,
|
14
|
+
subscription_url: subscription_url,
|
15
|
+
channel_prefix: channel_prefix
|
16
|
+
).tap do |source|
|
17
|
+
sources << source
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def subscribe(source_name, channel_suffix, handler)
|
22
|
+
source = find_source_by_name(source_name) or
|
23
|
+
fail(ConfigError, "You cannot subscribe to an undefined source: #{source_name}")
|
24
|
+
Subscription.new(
|
25
|
+
source: source,
|
26
|
+
channel: [source.channel_prefix, channel_suffix].join,
|
27
|
+
handler: handler
|
28
|
+
).tap do |subscription|
|
29
|
+
subscriptions << subscription
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def sources
|
34
|
+
@sources ||= []
|
35
|
+
end
|
36
|
+
|
37
|
+
def subscriptions
|
38
|
+
@subscriptions ||= []
|
39
|
+
end
|
40
|
+
|
41
|
+
def find_source_by_name(name)
|
42
|
+
sources.find { |source| source.name == name }
|
43
|
+
end
|
44
|
+
|
45
|
+
def subscriptions_for_channel(channel)
|
46
|
+
subscriptions.select { |s| s.channel == channel }
|
47
|
+
end
|
48
|
+
|
49
|
+
def http_connection
|
50
|
+
self[:http_connection] ||= Faraday::Connection.new
|
51
|
+
end
|
52
|
+
|
53
|
+
def redis_connection
|
54
|
+
self[:redis_connection] ||= Sidekiq.method(:redis)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
data/lib/toot/event.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Toot
|
4
|
+
class Event
|
5
|
+
|
6
|
+
attr_accessor :id, :timestamp, :payload, :channel
|
7
|
+
|
8
|
+
DEFAULTS = -> {
|
9
|
+
{
|
10
|
+
id: SecureRandom.uuid,
|
11
|
+
timestamp: Time.now,
|
12
|
+
payload: {},
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
def initialize(args={})
|
17
|
+
args = DEFAULTS.().merge(args.symbolize_keys)
|
18
|
+
@id = args[:id]
|
19
|
+
@timestamp = args[:timestamp]
|
20
|
+
@payload = args[:payload]
|
21
|
+
@channel = args[:channel]
|
22
|
+
end
|
23
|
+
|
24
|
+
def publish
|
25
|
+
PublishesEvent.perform_async(to_h)
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_h
|
30
|
+
{
|
31
|
+
id: id,
|
32
|
+
timestamp: timestamp,
|
33
|
+
payload: payload,
|
34
|
+
channel: channel,
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def ==(other)
|
39
|
+
self.id == other.id
|
40
|
+
end
|
41
|
+
|
42
|
+
def [](key)
|
43
|
+
payload[key]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Toot
|
4
|
+
class HandlerService
|
5
|
+
|
6
|
+
def call(env)
|
7
|
+
request = Rack::Request.new(env)
|
8
|
+
response = Rack::Response.new
|
9
|
+
event_data = JSON.parse(request.body.read)
|
10
|
+
|
11
|
+
if Toot.config.subscriptions_for_channel(event_data["channel"]).any?
|
12
|
+
CallsHandlers.perform_async(event_data)
|
13
|
+
else
|
14
|
+
response["X-Toot-Unsubscribe"] = "True"
|
15
|
+
end
|
16
|
+
|
17
|
+
response.finish
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.call(env)
|
21
|
+
new.call(env)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Toot
|
2
|
+
class PublishesEvent
|
3
|
+
include Sidekiq::Worker
|
4
|
+
|
5
|
+
def perform(event_data)
|
6
|
+
event = Event.new(event_data)
|
7
|
+
channel_callback_urls(event.channel)
|
8
|
+
.map { |callback| CallsEventCallback.perform_async(callback, event_data) }
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def channel_callback_urls(channel)
|
14
|
+
Toot.redis do |r|
|
15
|
+
r.smembers channel
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/toot/rails.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Toot
|
2
|
+
class RegistersSubscriptions
|
3
|
+
|
4
|
+
def call
|
5
|
+
subscriptions = Toot.config
|
6
|
+
.subscriptions
|
7
|
+
.each_with_object({}) { |s, hash| hash[[s.source, s.channel]] = s }
|
8
|
+
.values
|
9
|
+
|
10
|
+
subscriptions.each do |subscription|
|
11
|
+
register(subscription)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.call(*args)
|
16
|
+
new.call(*args)
|
17
|
+
end
|
18
|
+
|
19
|
+
private def register(subscription)
|
20
|
+
uri = URI(subscription.source.subscription_url)
|
21
|
+
|
22
|
+
response = Toot.config.http_connection.post uri do |request|
|
23
|
+
request.body = {
|
24
|
+
callback_url: Toot.config.callback_url,
|
25
|
+
channel: subscription.channel,
|
26
|
+
}.to_json
|
27
|
+
request.headers["Content-Type"] = "application/json"
|
28
|
+
end
|
29
|
+
|
30
|
+
unless response.success?
|
31
|
+
raise RegisterSubscriptionFailure, "Response code: #{response.status}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
data/lib/toot/source.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Toot
|
2
|
+
class Source
|
3
|
+
|
4
|
+
attr_accessor :name, :subscription_url, :channel_prefix
|
5
|
+
|
6
|
+
def initialize(name:, subscription_url:, channel_prefix:)
|
7
|
+
@name = name
|
8
|
+
@subscription_url = subscription_url
|
9
|
+
@channel_prefix = channel_prefix
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Toot
|
2
|
+
class SubscriptionsService
|
3
|
+
|
4
|
+
def call(env)
|
5
|
+
request = Rack::Request.new(env)
|
6
|
+
response = Rack::Response.new
|
7
|
+
json = parse_body_json(request)
|
8
|
+
|
9
|
+
if json["channel"] && json["callback_url"]
|
10
|
+
Toot.redis do |r|
|
11
|
+
r.sadd json["channel"], json["callback_url"]
|
12
|
+
end
|
13
|
+
else
|
14
|
+
response.status = 422
|
15
|
+
end
|
16
|
+
|
17
|
+
response.finish
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.call(env)
|
21
|
+
new.call(env)
|
22
|
+
end
|
23
|
+
|
24
|
+
private def parse_body_json(request)
|
25
|
+
JSON.parse(request.body.read)
|
26
|
+
rescue JSON::ParserError
|
27
|
+
{}
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/toot/version.rb
CHANGED
data/toot.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Travis Petticrew"]
|
10
10
|
spec.email = ["travis@petticrew.net"]
|
11
11
|
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.description = %q{
|
12
|
+
spec.summary = %q{Send and receive events from remote services over HTTP.}
|
13
|
+
spec.description = %q{Send and receive events from remote services over HTTP.}
|
14
14
|
spec.homepage = "https://github.com/watermarkchurch/toot"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
@@ -18,7 +18,12 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_dependency "sidekiq", ">=2"
|
22
|
+
spec.add_dependency "rack", ">=1"
|
23
|
+
spec.add_dependency "faraday", "<1"
|
24
|
+
|
21
25
|
spec.add_development_dependency "bundler", "~> 1.10"
|
22
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
27
|
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency "webmock"
|
24
29
|
end
|
metadata
CHANGED
@@ -1,15 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: toot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Travis Petticrew
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: sidekiq
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: faraday
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "<"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "<"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1'
|
13
55
|
- !ruby/object:Gem::Dependency
|
14
56
|
name: bundler
|
15
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,7 +94,21 @@ dependencies:
|
|
52
94
|
- - ">="
|
53
95
|
- !ruby/object:Gem::Version
|
54
96
|
version: '0'
|
55
|
-
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: Send and receive events from remote services over HTTP.
|
56
112
|
email:
|
57
113
|
- travis@petticrew.net
|
58
114
|
executables: []
|
@@ -66,8 +122,22 @@ files:
|
|
66
122
|
- README.md
|
67
123
|
- Rakefile
|
68
124
|
- bin/console
|
125
|
+
- bin/rspec
|
69
126
|
- bin/setup
|
127
|
+
- circle.yml
|
128
|
+
- lib/tasks/toot.rake
|
70
129
|
- lib/toot.rb
|
130
|
+
- lib/toot/calls_event_callback.rb
|
131
|
+
- lib/toot/calls_handlers.rb
|
132
|
+
- lib/toot/config.rb
|
133
|
+
- lib/toot/event.rb
|
134
|
+
- lib/toot/handler_service.rb
|
135
|
+
- lib/toot/publishes_event.rb
|
136
|
+
- lib/toot/rails.rb
|
137
|
+
- lib/toot/registers_subscriptions.rb
|
138
|
+
- lib/toot/source.rb
|
139
|
+
- lib/toot/subscription.rb
|
140
|
+
- lib/toot/subscriptions_service.rb
|
71
141
|
- lib/toot/version.rb
|
72
142
|
- toot.gemspec
|
73
143
|
homepage: https://github.com/watermarkchurch/toot
|
@@ -92,5 +162,5 @@ rubyforge_project:
|
|
92
162
|
rubygems_version: 2.4.2
|
93
163
|
signing_key:
|
94
164
|
specification_version: 4
|
95
|
-
summary:
|
165
|
+
summary: Send and receive events from remote services over HTTP.
|
96
166
|
test_files: []
|