activehook 0.1.0 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Procfile +2 -0
- data/README.md +134 -13
- data/activehook.gemspec +5 -3
- data/bin/activehook-app +7 -0
- data/bin/activehook-server +7 -0
- data/lib/activehook/app/base.rb +17 -0
- data/lib/activehook/app/config.rb +17 -0
- data/lib/activehook/app/config.ru +6 -0
- data/lib/activehook/app/launcher.rb +51 -0
- data/lib/activehook/app/middleware.rb +70 -0
- data/lib/activehook/client/base.rb +8 -0
- data/lib/activehook/client/config.rb +16 -0
- data/lib/activehook/client/recieve.rb +55 -0
- data/lib/activehook/config.rb +19 -20
- data/lib/activehook/errors.rb +2 -0
- data/lib/activehook/hook.rb +36 -18
- data/lib/activehook/log.rb +1 -1
- data/lib/activehook/redis.rb +0 -2
- data/lib/activehook/server/base.rb +19 -0
- data/lib/activehook/server/config.rb +32 -0
- data/lib/activehook/server/launcher.rb +47 -0
- data/lib/activehook/server/manager.rb +64 -0
- data/lib/activehook/{workers → server}/queue.rb +22 -9
- data/lib/activehook/{workers → server}/retry.rb +11 -6
- data/lib/activehook/server/send.rb +70 -0
- data/lib/activehook/server/worker.rb +78 -0
- data/lib/activehook/validate.rb +29 -0
- data/lib/activehook/version.rb +2 -1
- data/lib/activehook.rb +7 -8
- metadata +52 -11
- data/bin/activehook +0 -7
- data/lib/activehook/cli.rb +0 -32
- data/lib/activehook/post.rb +0 -71
- data/lib/activehook/server.rb +0 -19
- data/lib/activehook/workers/base.rb +0 -13
- data/lib/activehook/workers/manager.rb +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3a59808084220469fb34637c67bf5e9f262e631
|
4
|
+
data.tar.gz: 791adea3103be50f0b47ae4a1bcc85456271279b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40f0470b5c5239cc3f7ea56cb20c458239d72ada5180327ac45356ab32357ee0770d66a8c23691619ba4d2eeca3dff0df0e133154384803ed90189b0f450a2a9
|
7
|
+
data.tar.gz: e9cd328d156e39b4d9478fb3aa8740d5999404629ac0adae3a8c0c67b8e55071168a98ba8c7c843b6e46a34b8c9d47ac95b5d0e1dae3b920f831e605342c1524
|
data/Procfile
ADDED
data/README.md
CHANGED
@@ -3,7 +3,11 @@
|
|
3
3
|
|
4
4
|
Fast and simple webhook microservice for Ruby. **Please consider it under development at the moment.**
|
5
5
|
|
6
|
-
ActiveHook provides a scalable solution to your applications webhook sending needs. Its Redis-backed, with support for forking and threading - letting it send an enormous amount of webhooks in short order. Basically a much more focused version of a job processor such as Sidekiq, DelayedJob, Resque, etc.
|
6
|
+
ActiveHook provides a scalable solution to your applications webhook sending needs. Its Redis-backed, with support for forking and threading - letting it send an enormous amount of webhooks in short order. Basically a much more focused version of a job processor such as Sidekiq, DelayedJob, Resque, etc. It includes the following:
|
7
|
+
|
8
|
+
- A server for the purpose of sending webhooks.
|
9
|
+
- A mixin module for the purpose of recieving and validating webhooks.
|
10
|
+
- A piece of Rack middleware for the purpose of performing validation.
|
7
11
|
|
8
12
|
## Installation
|
9
13
|
|
@@ -23,38 +27,155 @@ Or install it yourself as:
|
|
23
27
|
|
24
28
|
## Getting Started
|
25
29
|
|
26
|
-
Before starting, ensure you have a functioning Redis server available.
|
30
|
+
Before starting, ensure you have a functioning Redis server available.
|
31
|
+
|
32
|
+
ActiveHook can be run in a few different ways.
|
33
|
+
|
34
|
+
#### Server Mode
|
27
35
|
|
28
|
-
|
36
|
+
In order to send webhooks, we operate ActiveHook in server mode. This will be run as a seperate service beyond your web application (Rails, Sinatra, etc). To start the server simply type the following in your console.
|
29
37
|
|
30
|
-
|
38
|
+
$ bundle exec activehook-server -c config/activehook.rb
|
39
|
+
|
40
|
+
By providing a path to a configuration file, we can setup ActiveHook with plain old ruby. Below is a list of currently available server options:
|
31
41
|
|
32
42
|
```ruby
|
43
|
+
# ActiveHook server configuration
|
33
44
|
ActiveHook.configure do |config|
|
34
45
|
#Your redis server url
|
35
46
|
config.redis_url = ENV['REDIS_URL']
|
36
47
|
#The number of redis connections to provide
|
37
|
-
config.redis_pool =
|
48
|
+
config.redis_pool = 10
|
38
49
|
#The number of forked workers to create for the server
|
39
50
|
config.workers = 2
|
40
51
|
#The number of queue threads to provide for each worker
|
41
|
-
config.queue_threads =
|
52
|
+
config.queue_threads = 2
|
42
53
|
#The number of retry threads to provide for each worker
|
43
|
-
config.retry_threads =
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
54
|
+
config.retry_threads = 1
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
#### App Mode
|
59
|
+
|
60
|
+
In order to create webhooks, we operate ActiveHook in app mode. Like above, we need to provide information on Redis. We will also need to provide a path in our web application that can be used for validation. With Rails, we should place this configuration with our initializers.
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
#IMPORTANT!
|
64
|
+
require 'activehook/app/base'
|
65
|
+
|
66
|
+
# ActiveHook app configuration
|
67
|
+
ActiveHook.configure do |config|
|
68
|
+
#Your redis server url
|
69
|
+
config.redis_url = ENV['REDIS_URL']
|
70
|
+
#The number of redis connections to provide
|
71
|
+
config.redis_pool = 5
|
72
|
+
#The route to our webhook validator
|
73
|
+
config.validation_path = '/hooks/validate'
|
48
74
|
end
|
49
75
|
```
|
50
76
|
|
51
|
-
|
77
|
+
With our app setup, we can create webhooks for processing. From within our application, all we have to do is:
|
52
78
|
|
53
79
|
```ruby
|
54
80
|
ActiveHook::Hook.new(uri: 'http://example.com/webhook', payload: { msg: 'My first webhook!' })
|
55
81
|
```
|
56
82
|
|
57
|
-
That's it! We provide a valid string URI, as well hash payload. ActiveHooks
|
83
|
+
That's it! We provide a valid string URI, as well hash payload. ActiveHooks server will then attempt to send the webhook. If the webhook fails to be delivered, it will be sent to the retry queue. Delivery will be reattempted at the specified intervals, and eventually dropped if all attempts fail.
|
84
|
+
|
85
|
+
The default setting for failed webhooks is 3 more attempts at an interval of 3600 seconds (1 hour). You can change these values by including them in your hook initialization.
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
ActiveHook::Hook.new(uri: 'http://example.com/webhook', payload: { msg: 'My first webhook!' }, retry_max: 3, retry_time: 3600)
|
89
|
+
```
|
90
|
+
|
91
|
+
We will go over app webhook validation after the following section...
|
92
|
+
|
93
|
+
#### Client Mode
|
94
|
+
|
95
|
+
ActiveHook provides a class as well as mixin module for the purposes of recieving webhooks and performing validation on them. The class should be used for personal projects and testing, while the mixin module can be integrated with other application gems.
|
96
|
+
|
97
|
+
Using the class is easy. We should first add use the following config:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
#IMPORTANT!
|
101
|
+
require 'activehook/client/base'
|
102
|
+
|
103
|
+
# ActiveHook client configuration
|
104
|
+
ActiveHook.configure do |config|
|
105
|
+
#Your validation uri
|
106
|
+
config.validation_uri = 'http://localhost:3000/hooks/validate'
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
If we were using Rails we could then do the following:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
class WebhooksController < ApplicationController
|
114
|
+
|
115
|
+
def create
|
116
|
+
@webhook = ActiveHook::Recieve.new(webhook_params)
|
117
|
+
if @webhook.hook_valid?
|
118
|
+
#We can now do stuff with the Hash @webhook.payload
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
def webhook_params
|
125
|
+
params.require(:hook_id, :hook_key, :payload)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
```
|
129
|
+
|
130
|
+
Using the mixin module for our own classes would go like this:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
require 'activehook/client/base'
|
134
|
+
|
135
|
+
module MyApp
|
136
|
+
class Webhook
|
137
|
+
include ActiveHook::Client::Recieve
|
138
|
+
|
139
|
+
#IMPORTANT! We will go over running the validation server next.
|
140
|
+
VALIDATION_URI = 'http://myapp.com/hooks/validate'
|
141
|
+
end
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
This would allow us to perform the same validation actions as in our Rails example, except we could use:
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
@webhook = MyApp::Webhook.new(webhook_params)
|
149
|
+
if @webhook.hook_valid?
|
150
|
+
#We can now do stuff with the Hash @webhook.payload
|
151
|
+
end
|
152
|
+
```
|
153
|
+
|
154
|
+
#### App Mode Validation
|
155
|
+
|
156
|
+
Sending webhooks is one thing - ensuring they are from who we want is another.
|
157
|
+
|
158
|
+
ActiveHook includes a piece of Rack middleware for the purpose of validation. When a client attempts to validate a webhook, they are sending a message back to your server. The message includes the hooks ID as well as key. These are are then cross-referenced. If they match, we provide the AOK.
|
159
|
+
|
160
|
+
In Rails, we would add the middleware like this:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
# In config/application.rb
|
164
|
+
config.middleware.use ActiveHook::App::Middleware
|
165
|
+
```
|
166
|
+
|
167
|
+
Or with Rackup files:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
# In config.ru
|
171
|
+
use ActiveHook::App::Middleware
|
172
|
+
```
|
173
|
+
|
174
|
+
ActiveHook also provides a straight lightweight validation microservice. This simply runs the middleware with Puma on its own.
|
175
|
+
|
176
|
+
$ bundle exec activehook-app -p config/puma.rb -c config/activehook.rb
|
177
|
+
|
178
|
+
We must provide a path to our Puma config file as well as our ActiveHook app config file. Please read more about Puma if you need help with this.
|
58
179
|
|
59
180
|
## Development
|
60
181
|
|
data/activehook.gemspec
CHANGED
@@ -14,11 +14,13 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
-
spec.executables = %w( activehook )
|
17
|
+
spec.executables = %w( activehook-server activehook-app )
|
18
18
|
spec.require_paths = %w( lib )
|
19
19
|
|
20
|
-
spec.add_runtime_dependency
|
21
|
-
spec.add_runtime_dependency
|
20
|
+
spec.add_runtime_dependency "redis", "~> 3.3"
|
21
|
+
spec.add_runtime_dependency "connection_pool", "~> 2.2"
|
22
|
+
spec.add_runtime_dependency "puma", "~> 3.4"
|
23
|
+
spec.add_runtime_dependency "rack"
|
22
24
|
spec.add_development_dependency "bundler", "~> 1.12"
|
23
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
26
|
spec.add_development_dependency "minitest", "~> 5.0"
|
data/bin/activehook-app
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
ActiveHook.mode = :app
|
2
|
+
|
3
|
+
require 'puma'
|
4
|
+
require 'rack'
|
5
|
+
require 'redis'
|
6
|
+
require 'json'
|
7
|
+
require 'connection_pool'
|
8
|
+
require 'activehook/config'
|
9
|
+
require 'activehook/log'
|
10
|
+
require 'activehook/redis'
|
11
|
+
require 'activehook/errors'
|
12
|
+
require 'activehook/hook'
|
13
|
+
require 'activehook/validate'
|
14
|
+
require 'activehook/version'
|
15
|
+
require 'activehook/app/config'
|
16
|
+
require 'activehook/app/launcher'
|
17
|
+
require 'activehook/app/middleware'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveHook
|
2
|
+
module App
|
3
|
+
class Config < ActiveHook::BaseConfig
|
4
|
+
OTHER_DEFAULTS = {
|
5
|
+
validation_path: '/hooks/validate',
|
6
|
+
creation_path: '/hooks'
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
attr_accessor :validation_path, :creation_path
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super
|
13
|
+
OTHER_DEFAULTS.each { |key, value| send("#{key}=", value) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ActiveHook
|
2
|
+
module App
|
3
|
+
# Handles the start of the ActiveHook web via command line
|
4
|
+
#
|
5
|
+
class Launcher
|
6
|
+
def initialize(argv)
|
7
|
+
@argv = argv
|
8
|
+
@puma_config = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def start
|
12
|
+
start_message
|
13
|
+
setup_options
|
14
|
+
boot_puma
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def start_message
|
20
|
+
ActiveHook.log.info('ActiveHook App starting!')
|
21
|
+
ActiveHook.log.info("* Version #{VERSION}, codename: #{CODENAME}")
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parses the arguments passed through the command line.
|
25
|
+
#
|
26
|
+
def setup_options
|
27
|
+
parser = OptionParser.new do |o|
|
28
|
+
o.banner = 'Usage: bundle exec bin/activehook [options]'
|
29
|
+
|
30
|
+
o.on('-c', '--config PATH', 'Load PATH for config file') do |arg|
|
31
|
+
load(arg)
|
32
|
+
ActiveHook.log.info("* App config: #{arg}")
|
33
|
+
end
|
34
|
+
|
35
|
+
o.on('-p', '--puma config PATH', 'Load PATH for puma config file') do |arg|
|
36
|
+
@puma_config = arg
|
37
|
+
ActiveHook.log.info("* Puma config: #{arg}")
|
38
|
+
end
|
39
|
+
|
40
|
+
o.on('-h', '--help', 'Prints this help') { puts o && exit }
|
41
|
+
end
|
42
|
+
parser.parse!(@argv)
|
43
|
+
end
|
44
|
+
|
45
|
+
def boot_puma
|
46
|
+
ActiveHook.log.info('* Booting Puma...')
|
47
|
+
exec("bundle exec puma -C #{@puma_config} --dir lib/activehook/app/")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ActiveHook
|
2
|
+
module App
|
3
|
+
class Middleware
|
4
|
+
class << self
|
5
|
+
attr_accessor :valid, :invalid, :not_created, :created
|
6
|
+
end
|
7
|
+
|
8
|
+
@invalid = ->(_env) { [400, { "Content-Type" => "application/json" }, [{ valid: false }.to_json]] }
|
9
|
+
@valid = ->(_env) { [200, { "Content-Type" => "application/json" }, [{ valid: true }.to_json]] }
|
10
|
+
@not_created = ->(_env) { [400, { "Content-Type" => "application/json" }, [{ status: false }.to_json]] }
|
11
|
+
@created = ->(_env) { [200, { "Content-Type" => "application/json" }, [{ status: true }.to_json]] }
|
12
|
+
|
13
|
+
def initialize(app)
|
14
|
+
@app = app
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
@env = env
|
19
|
+
@req = Rack::Request.new(env)
|
20
|
+
|
21
|
+
if validation_request? then valid?
|
22
|
+
elsif creation_request? then create?
|
23
|
+
else @app.call(@env)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def validation_request?
|
28
|
+
@req.path == ActiveHook.config.validation_path && @req.get?
|
29
|
+
end
|
30
|
+
|
31
|
+
def creation_request?
|
32
|
+
@req.path == ActiveHook.config.creation_path && @req.post?
|
33
|
+
end
|
34
|
+
|
35
|
+
def valid?
|
36
|
+
if Validation.new(@req.params).start
|
37
|
+
self.class.valid.call(@env)
|
38
|
+
else
|
39
|
+
self.class.invalid.call(@env)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def create?
|
44
|
+
if Creation.new(@req.params).start
|
45
|
+
self.class.created.call(@env)
|
46
|
+
else
|
47
|
+
self.class.not_created.call(@env)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
Validation = Struct.new(:params) do
|
53
|
+
def start
|
54
|
+
hook = { id: params['id'].to_i, key: params['key'] }
|
55
|
+
ActiveHook::Validate.new(hook).perform
|
56
|
+
rescue
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Creation = Struct.new(:params) do
|
62
|
+
def start
|
63
|
+
hook = { uri: params['uri'], payload: JSON.parse(params['payload']) }
|
64
|
+
ActiveHook::Hook.new(hook).perform
|
65
|
+
rescue
|
66
|
+
false
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ActiveHook
|
2
|
+
module Client
|
3
|
+
class Config < ActiveHook::BaseConfig
|
4
|
+
OTHER_DEFAULTS = {
|
5
|
+
validation_uri: 'http://localhost:3000/hooks/validate'
|
6
|
+
}.freeze
|
7
|
+
|
8
|
+
attr_accessor :validation_uri
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super
|
12
|
+
OTHER_DEFAULTS.each { |key, value| send("#{key}=", value) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ActiveHook
|
2
|
+
module Client
|
3
|
+
module Recieve
|
4
|
+
|
5
|
+
REQUEST_HEADERS = {
|
6
|
+
"Content-Type" => "application/json",
|
7
|
+
"Accept" => "application/json",
|
8
|
+
"User-Agent" => "ActiveHook/#{ActiveHook::VERSION}"
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
attr_accessor :hook_id, :hook_key
|
12
|
+
attr_reader :payload
|
13
|
+
|
14
|
+
def hook_valid?
|
15
|
+
@hook_valid ||= validate_hook
|
16
|
+
end
|
17
|
+
|
18
|
+
def payload=(payload)
|
19
|
+
@payload = JSON.parse(payload)
|
20
|
+
rescue
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def validated_payload
|
25
|
+
raise StandardError, 'Webhook is invalid.' unless hook_valid?
|
26
|
+
@payload
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def hook_uri
|
32
|
+
@hook_uri ||= URI.parse(self.class::VALIDATION_URI)
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_hook
|
36
|
+
http = Net::HTTP.new(hook_uri.host, hook_uri.port)
|
37
|
+
response = http.post(hook_uri.path, hook_json, REQUEST_HEADERS)
|
38
|
+
response.code.to_i == 200 ? true : false
|
39
|
+
rescue
|
40
|
+
false
|
41
|
+
end
|
42
|
+
|
43
|
+
def hook_json
|
44
|
+
{ id: @hook_id,
|
45
|
+
key: @hook_key }.to_json
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Recieve
|
51
|
+
include ActiveHook::Client::Recieve
|
52
|
+
|
53
|
+
VALIDATION_URI = (ActiveHook.config.validation_uri).freeze
|
54
|
+
end
|
55
|
+
end
|
data/lib/activehook/config.rb
CHANGED
@@ -6,7 +6,17 @@ module ActiveHook
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def config
|
9
|
-
@config ||=
|
9
|
+
@config ||= build_config
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_config
|
13
|
+
klass =
|
14
|
+
case ActiveHook.mode
|
15
|
+
when :server then ActiveHook::Server::Config
|
16
|
+
when :client then ActiveHook::Client::Config
|
17
|
+
else ActiveHook::App::Config
|
18
|
+
end
|
19
|
+
klass.new
|
10
20
|
end
|
11
21
|
|
12
22
|
def reset
|
@@ -15,33 +25,22 @@ module ActiveHook
|
|
15
25
|
end
|
16
26
|
end
|
17
27
|
|
18
|
-
class
|
19
|
-
|
28
|
+
class BaseConfig
|
29
|
+
BASE_DEFAULTS = {
|
20
30
|
redis_url: ENV['REDIS_URL'],
|
21
|
-
redis_pool: 5
|
22
|
-
workers: 2,
|
23
|
-
queue_threads: 4,
|
24
|
-
retry_threads: 2,
|
25
|
-
retry_max: 3,
|
26
|
-
retry_time: 3600,
|
31
|
+
redis_pool: 5
|
27
32
|
}.freeze
|
28
33
|
|
29
|
-
attr_accessor :redis_url, :redis_pool
|
30
|
-
:workers, :queue_threads, :retry_threads
|
34
|
+
attr_accessor :redis_url, :redis_pool
|
31
35
|
|
32
36
|
def initialize
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
def retry_max_time
|
37
|
-
@retry_max_time ||= retry_max * retry_time
|
37
|
+
BASE_DEFAULTS.each { |key, value| send("#{key}=", value) }
|
38
38
|
end
|
39
39
|
|
40
|
-
def
|
40
|
+
def redis
|
41
41
|
{
|
42
|
-
|
43
|
-
|
44
|
-
retry_threads: retry_threads
|
42
|
+
size: redis_pool,
|
43
|
+
url: redis_url
|
45
44
|
}
|
46
45
|
end
|
47
46
|
end
|
data/lib/activehook/errors.rb
CHANGED
data/lib/activehook/hook.rb
CHANGED
@@ -2,7 +2,7 @@ require 'securerandom'
|
|
2
2
|
|
3
3
|
module ActiveHook
|
4
4
|
class Hook
|
5
|
-
attr_accessor :uri, :payload, :id, :
|
5
|
+
attr_accessor :uri, :payload, :id, :key, :retry_max, :retry_time, :created_at
|
6
6
|
|
7
7
|
def initialize(options = {})
|
8
8
|
options = defaults.merge(options)
|
@@ -10,47 +10,65 @@ module ActiveHook
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def perform
|
13
|
-
|
13
|
+
validate!
|
14
14
|
ActiveHook.redis.with do |conn|
|
15
|
-
conn.
|
16
|
-
|
17
|
-
|
18
|
-
end
|
15
|
+
@id = conn.incr('ah:total_queued')
|
16
|
+
conn.lpush('ah:queue', to_json)
|
17
|
+
conn.zadd('ah:validation', @id, @key)
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
|
-
def
|
23
|
-
|
21
|
+
def retry?
|
22
|
+
fail_at > Time.now.to_i
|
24
23
|
end
|
25
24
|
|
26
|
-
def
|
27
|
-
|
25
|
+
def retry_at
|
26
|
+
Time.now.to_i + @retry_time.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
def fail_at
|
30
|
+
@created_at.to_i + retry_max_time
|
31
|
+
end
|
32
|
+
|
33
|
+
def retry_max_time
|
34
|
+
@retry_time.to_i * @retry_max.to_i
|
28
35
|
end
|
29
36
|
|
30
37
|
def to_json
|
31
38
|
{ id: @id,
|
39
|
+
key: @key,
|
32
40
|
created_at: @created_at,
|
33
|
-
|
34
|
-
|
41
|
+
retry_time: @retry_time,
|
42
|
+
retry_max: @retry_max,
|
35
43
|
uri: @uri,
|
36
44
|
payload: @payload }.to_json
|
37
45
|
end
|
38
46
|
|
47
|
+
def secure_payload
|
48
|
+
{ hook_id: @id,
|
49
|
+
hook_key: @key,
|
50
|
+
payload: @payload }.to_json
|
51
|
+
end
|
52
|
+
|
53
|
+
def valid?
|
54
|
+
HookValidator.new(id: @id, key: @key).server_valid?
|
55
|
+
end
|
56
|
+
|
39
57
|
private
|
40
58
|
|
41
59
|
def defaults
|
42
|
-
{
|
60
|
+
{ key: SecureRandom.uuid,
|
43
61
|
created_at: Time.now.to_i,
|
44
|
-
|
45
|
-
|
62
|
+
retry_time: 3600,
|
63
|
+
retry_max: 3 }
|
46
64
|
end
|
47
65
|
|
48
|
-
def
|
66
|
+
def validate!
|
49
67
|
raise Errors::Hook, 'Payload must be a Hash.' unless @payload.is_a?(Hash)
|
50
68
|
raise Errors::Hook, 'URI is not a valid format.' unless @uri =~ /\A#{URI::regexp}\z/
|
51
69
|
raise Errors::Hook, 'Created at must be an Integer.' unless @created_at.is_a?(Integer)
|
52
|
-
raise Errors::Hook, 'Retry
|
53
|
-
raise Errors::Hook, '
|
70
|
+
raise Errors::Hook, 'Retry time must be an Integer.' unless @retry_time.is_a?(Integer)
|
71
|
+
raise Errors::Hook, 'Retry max must be an Integer.' unless @retry_max.is_a?(Integer)
|
54
72
|
end
|
55
73
|
end
|
56
74
|
end
|
data/lib/activehook/log.rb
CHANGED