toot 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|