namira 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cd40f31fd9c696c000f54eeb83a09db3c4213222
4
- data.tar.gz: a707df33c8946cb12d735e7ba9ec5204c54ae3fc
2
+ SHA256:
3
+ metadata.gz: 61aed0e8cd917b38eb9eb293a3ed95331aa79066c08e1230fd517335bfe4a9c4
4
+ data.tar.gz: 129c02c6bb5a4fdaad7d1f91fd6f7ea1f6811ce30d6d20cb3f5b995954742e0a
5
5
  SHA512:
6
- metadata.gz: 8149d922e3f943da4717c04df6aca73d51b27a8a45e69108e37b2d47bb35624e31638df989ca102b7288bb9c2524938509a7e1263406dd957357b1edf62b54c4
7
- data.tar.gz: faca22f4f42291a472e2c19486b2953648e9dd29116a9f49b282d96eee27906b87994b89f7e240dcead130e357d88d67399145cc769179a9dd0bc65edfb134c2
6
+ metadata.gz: 847929dfe0d91112e5d54f6b8f0a3889ea9b2f0245e556d22d6c6b5681aa3ba97cf2c503c055e4fd118c0036c9c45cc3d8e1b3ab16edbea0775066f4603471ca
7
+ data.tar.gz: d4db9832c632cc6b299484ca7116236d9792dfec85ca569a5b747670bfd76fa26c9fe92754225df4efab01325f6bb3cc75bdc253f781f89fcc18a4d911819b2c
@@ -1,8 +1,7 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.2
2
+ TargetRubyVersion: 2.3
3
3
  Exclude:
4
4
  - Rakefile
5
- - spec/**/*
6
5
 
7
6
  Metrics/AbcSize:
8
7
  Max: 30
@@ -19,6 +18,11 @@ Metrics/ParameterLists:
19
18
  Metrics/CyclomaticComplexity:
20
19
  Max: 10
21
20
 
21
+ Metrics/BlockLength:
22
+ Enabled: true
23
+ Exclude:
24
+ - spec/**/*
25
+
22
26
  DotPosition:
23
27
  EnforcedStyle: leading
24
28
 
@@ -0,0 +1 @@
1
+ 2.5.3
@@ -1,3 +1,7 @@
1
+ # 1.3 (2019-02-06)
2
+
3
+ * Support for async requests. Supports ActiveJob and plain Sidekiq.
4
+
1
5
  # 1.2 (2019-01-18)
2
6
 
3
7
  * Auto add Bugsnag error information
@@ -1,3 +1,4 @@
1
+ require 'namira/async'
1
2
  require 'namira/config'
2
3
  require 'namira/env'
3
4
  require 'namira/error_helpers'
@@ -0,0 +1,5 @@
1
+ require_relative 'async/active_job/request_job' if defined?(::ActiveJob)
2
+ require_relative 'async/sidekiq/request_worker' if defined?(::Sidekiq)
3
+
4
+ require_relative 'async/performer'
5
+ require_relative 'async/serializer'
@@ -0,0 +1,13 @@
1
+ require_relative '../performer'
2
+
3
+ module Namira
4
+ module Async
5
+ module ActiveJob
6
+ class RequestJob < ::ActiveJob::Base
7
+ def perform(payload)
8
+ Namira::Async::Performer.perform(payload)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'serializer'
2
+ require_relative '../config'
3
+ require_relative '../errors'
4
+
5
+ module Namira
6
+ module Async
7
+ class Performer
8
+ class << self
9
+ def schedule(request, async_adapter, queue_name)
10
+ async_adapter = adapter(async_adapter)
11
+ queue_name ||= Namira.config.async_queue_name
12
+ payload = Namira::Async::Serializer.serialize_request(request)
13
+
14
+ case async_adapter
15
+ when :active_job
16
+ Namira::Async::ActiveJob::RequestJob.set(queue: queue_name).perform_later(payload)
17
+ when :sidekiq
18
+ Namira::Async::Sidekiq::RequestWorker.set(queue: queue_name).perform_async(payload)
19
+ when :thread
20
+ Thread.new { perform(payload) }
21
+ else
22
+ raise Namira::Errors::AsyncError, "Unknown Async Adapter #{async_adapter}"
23
+ end
24
+ end
25
+
26
+ def perform(payload)
27
+ request = Namira::Async::Serializer.unserialize_request(payload)
28
+ request.send_request
29
+ Namira::Async::Serializer.serialize_response(request.response)
30
+ end
31
+
32
+ private
33
+
34
+ def adapter(async_adapter)
35
+ async_adapter ||= Namira.config.async_adapter
36
+ if async_adapter == :active_job && !defined?(ActiveJob)
37
+ adapter(:sidekiq)
38
+ elsif async_adapter == :sidekiq && !defined?(Sidekiq)
39
+ adapter(:thread)
40
+ else
41
+ async_adapter
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,61 @@
1
+ require_relative '../errors'
2
+
3
+ module Namira
4
+ module Async
5
+ class Serializer
6
+ class << self
7
+ def serialize_request(request)
8
+ JSON.dump(
9
+ u: request.uri,
10
+ m: request.http_method,
11
+ h: request.headers.to_h,
12
+ b: request.body,
13
+ c: request.config.to_h
14
+ )
15
+ end
16
+
17
+ def unserialize_request(payload)
18
+ data = JSON.parse(payload)
19
+ Namira::Request.new(
20
+ uri: data.fetch('u'),
21
+ http_method: data.fetch('m').to_sym,
22
+ headers: data.fetch('h'),
23
+ body: data.fetch('b'),
24
+ config: data.fetch('c')
25
+ )
26
+ rescue KeyError => error
27
+ raise Namira::Errors::AsyncError, error.message
28
+ end
29
+
30
+ def serialize_response(response)
31
+ backing = response.instance_variable_get('@backing')
32
+ JSON.dump(
33
+ b: backing.to_a,
34
+ m: response.method,
35
+ r: response.redirect_count,
36
+ u: response.url.to_s,
37
+ v: backing.instance_variable_get('@version')
38
+ )
39
+ end
40
+
41
+ def unserialize_response(payload)
42
+ data = JSON.parse(payload)
43
+ backing = HTTP::Response.new(
44
+ status: data.fetch('b')[0],
45
+ headers: data.fetch('b')[1],
46
+ body: data.fetch('b')[2],
47
+ version: data.fetch('v')
48
+ )
49
+ Namira::Response.new(
50
+ data.fetch('m').to_sym,
51
+ Addressable::URI.parse(data.fetch('u')),
52
+ data.fetch('r').to_i,
53
+ backing
54
+ )
55
+ rescue KeyError => error
56
+ raise Namira::Errors::AsyncError, error.message
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,15 @@
1
+ require_relative '../performer'
2
+
3
+ module Namira
4
+ module Async
5
+ module ActiveJob
6
+ class RequestWorker
7
+ include Sidekiq::Worker
8
+
9
+ def perform(payload)
10
+ Namira::Async::Performer.perform(payload)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -30,11 +30,20 @@ module Namira
30
30
  #
31
31
  # @!attribute [r] headers
32
32
  # Default headers to send with each request
33
- # @return [OpenStruct]
33
+ # @return [Hash]
34
34
  #
35
35
  # @!attribute [rw] log_requests
36
36
  # Log requests using puts or Rails.logger.debug if it's defined
37
37
  # @return (Bool) Defaults: true
38
+ #
39
+ # @!attribute [rw] async_queue_name
40
+ # The queue name that async requests should be added too.
41
+ # @return [Symbol] Defaults: :default
42
+ #
43
+ # @!attribute [rw] async_adapter
44
+ # The preferred async adapter to use.
45
+ # Possible Values: :active_job, :sidekiq
46
+ # @return [Symbol] Defaults: :active_job
38
47
  class Config < OpenStruct
39
48
  ##
40
49
  # The
@@ -45,11 +54,13 @@ module Namira
45
54
 
46
55
  DEFAULT_SETTINGS = {
47
56
  max_redirect: 3,
48
- timeout: 5.0,
49
- backend: nil,
50
- user_agent: "Namira/#{Namira::VERSION}",
51
- headers: OpenStruct.new,
52
- log_requests: true
57
+ timeout: 5.0,
58
+ backend: nil,
59
+ user_agent: "Namira/#{Namira::VERSION}",
60
+ headers: {},
61
+ log_requests: true,
62
+ async_queue_name: :default,
63
+ async_adapter: :active_job
53
64
  }.freeze
54
65
 
55
66
  private_constant :DEFAULT_SETTINGS
@@ -62,8 +73,12 @@ module Namira
62
73
  ##
63
74
  # The shared configuration
64
75
  def self.configure
76
+ yield(config) if block_given?
77
+ config
78
+ end
79
+
80
+ def self.config
65
81
  @config ||= Config.new
66
- yield(@config) if block_given?
67
82
  @config
68
83
  end
69
84
  end
@@ -17,13 +17,12 @@ if defined?(::Bugsnag)
17
17
  notification.exceptions.each do |exception|
18
18
  next unless exception.is_a?(Namira::Errors::HTTPError)
19
19
 
20
- notification.add_tab("Namira #{exception.response.status.to_i}", {
20
+ notification.add_tab("Namira #{exception.response.status.to_i}",
21
21
  headers: exception.response.headers.to_h,
22
22
  body: exception.response.body.to_s[0...200],
23
23
  method: exception.response.method.to_s,
24
24
  url: exception.response.url.to_s,
25
- redirected: (exception.response.redirect_count > 0).to_s
26
- })
25
+ redirected: (exception.response.redirect_count > 0).to_s)
27
26
  end
28
27
 
29
28
  @bugsnag.call(notification)
@@ -1,4 +1,5 @@
1
1
  require_relative 'errors/base_error'
2
+ require_relative 'errors/async_error'
2
3
  require_relative 'errors/http_error'
3
4
  require_relative 'errors/invalid_uri_error'
4
5
  require_relative 'errors/redirect_error'
@@ -0,0 +1,8 @@
1
+ module Namira
2
+ module Errors
3
+ ##
4
+ # An async API error
5
+ class AsyncError < BaseError
6
+ end
7
+ end
8
+ end
@@ -87,7 +87,7 @@ module Namira
87
87
  '415' => 'Unsupported Media Type',
88
88
  '416' => 'Range Not Satisfiable',
89
89
  '417' => 'Expectation Failed',
90
- '418' => "Im A Teapot",
90
+ '418' => 'Im A Teapot',
91
91
  '421' => 'Misdirected Request',
92
92
  '422' => 'Unprocessable Entity',
93
93
  '423' => 'Locked',
@@ -19,7 +19,7 @@ module Namira
19
19
  private
20
20
 
21
21
  def merge_config(config)
22
- Namira.configure.to_h.merge(config)
22
+ Namira.config.to_h.merge(config)
23
23
  end
24
24
  end
25
25
  end
@@ -12,7 +12,7 @@ module Namira
12
12
  #
13
13
  # @param env [Namira::Env] The request environment
14
14
  def call(env)
15
- headers = Hash(Namira.configure.headers.to_h).dup
15
+ headers = Hash(Namira.config.headers.to_h).dup
16
16
  headers.merge!(additional_headers(env))
17
17
  headers.merge!(env.headers.to_h)
18
18
  env.headers = convert_headers(headers)
@@ -23,15 +23,16 @@ module Namira
23
23
  private
24
24
 
25
25
  def logging?(env)
26
- if env.config.keys.include?(SKIP_LOGGING_KEY)
26
+ if env.config.key?(SKIP_LOGGING_KEY)
27
27
  env.config[SKIP_LOGGING_KEY] == false
28
28
  else
29
- Namira.configure.log_requests == true
29
+ Namira.config.log_requests == true
30
30
  end
31
31
  end
32
32
 
33
33
  def log_request(env)
34
34
  return unless logging?(env)
35
+
35
36
  message = "#{env.method.to_s.upcase} - #{env.uri}"
36
37
  if defined?(::Rails)
37
38
  Rails.logger.debug(message)
@@ -15,9 +15,9 @@ module Namira
15
15
  timeout = env.config[:timeout] || 30.0
16
16
  http = HTTP.timeout(
17
17
  :per_operation,
18
- write: timeout,
18
+ write: timeout,
19
19
  connect: timeout,
20
- read: timeout
20
+ read: timeout
21
21
  )
22
22
  http = http.headers(env.headers)
23
23
  env.response = http.send(env.method, env.uri, body: env.body)
@@ -59,6 +59,7 @@ module Namira
59
59
 
60
60
  def redirect?(error, env)
61
61
  return false unless env.config[:follow_redirect].nil? ? true : env.config[:follow_redirect]
62
+
62
63
  REDIRECT_STATUS.include?(error.status)
63
64
  end
64
65
  end
@@ -1,4 +1,5 @@
1
1
  require 'http'
2
+ require_relative 'async'
2
3
 
3
4
  module Namira
4
5
  ##
@@ -6,7 +7,7 @@ module Namira
6
7
  #
7
8
  # response = Namira::Request.new(uri: 'https://httpbin.org/headers').response
8
9
  class Request
9
- attr_reader :uri, :http_method
10
+ attr_reader :uri, :http_method, :headers, :body, :config
10
11
 
11
12
  ##
12
13
  # Create a new request
@@ -21,7 +22,7 @@ module Namira
21
22
  @http_method = http_method
22
23
  @headers = Hash(headers)
23
24
  @body = body
24
- @config = Namira.configure.to_h.merge(Hash(config))
25
+ @config = Namira.config.to_h.merge(Hash(config))
25
26
  @stack = Namira::Stack.default
26
27
  end
27
28
 
@@ -33,6 +34,10 @@ module Namira
33
34
  @response = _send_request
34
35
  end
35
36
 
37
+ def send_async(queue_name: nil, adapter: nil)
38
+ Namira::Async::Performer.schedule(self, adapter, queue_name)
39
+ end
40
+
36
41
  ##
37
42
  # The {Namira::Response} for the request.
38
43
  #
@@ -1,3 +1,5 @@
1
+ require_relative 'async/serializer'
2
+
1
3
  module Namira
2
4
  ##
3
5
  # HTTP response
@@ -8,6 +10,10 @@ module Namira
8
10
 
9
11
  attr_reader :redirect_count
10
12
 
13
+ def self.serialized(raw_response)
14
+ Namira::Async::Serializer.unserialize_response(raw_response)
15
+ end
16
+
11
17
  ##
12
18
  # Create a new {Namira::Response}
13
19
  def initialize(method, url, redirect_count, backing)
@@ -30,6 +30,7 @@ module Namira
30
30
  # @param env [Namira::Env] The request environment
31
31
  def call(env)
32
32
  raise ArgumentError, 'Invalid environment' unless env.is_a?(Namira::Env)
33
+
33
34
  to_app.call(env)
34
35
  end
35
36
 
@@ -1,5 +1,5 @@
1
1
  module Namira
2
2
  ##
3
3
  # The current version of Namira
4
- VERSION = '1.2.0'.freeze
4
+ VERSION = '1.3.0'.freeze
5
5
  end
@@ -18,15 +18,16 @@ 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.required_ruby_version = '>= 2.2'
21
+ spec.required_ruby_version = '>= 2.3'
22
22
 
23
23
  spec.add_dependency 'http', '>= 2.0.0', '< 4.0'
24
24
 
25
- spec.add_development_dependency 'bundler', '~> 1.15'
26
- spec.add_development_dependency 'pry', '~> 0.11.3'
27
- spec.add_development_dependency 'rake', '~> 10.0'
28
- spec.add_development_dependency 'rspec', '~> 3.2'
29
- spec.add_development_dependency 'simplecov', '~> 0.15'
30
- spec.add_development_dependency 'webmock', '~> 3.3.0'
31
- spec.add_development_dependency 'yard', '~> 0.9'
25
+ spec.add_development_dependency 'bundler', '~> 1.15'
26
+ spec.add_development_dependency 'pry', '~> 0.11.3'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec', '~> 3.2'
29
+ spec.add_development_dependency 'simplecov', '~> 0.15'
30
+ spec.add_development_dependency 'sinatra', '~> 2.0.5'
31
+ spec.add_development_dependency 'webmock', '~> 3.3.0'
32
+ spec.add_development_dependency 'yard', '~> 0.9'
32
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: namira
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Skylar Schipper
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-01-18 00:00:00.000000000 Z
11
+ date: 2019-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http
@@ -100,6 +100,20 @@ dependencies:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0.15'
103
+ - !ruby/object:Gem::Dependency
104
+ name: sinatra
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: 2.0.5
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: 2.0.5
103
117
  - !ruby/object:Gem::Dependency
104
118
  name: webmock
105
119
  requirement: !ruby/object:Gem::Requirement
@@ -139,6 +153,7 @@ files:
139
153
  - ".gitignore"
140
154
  - ".rspec"
141
155
  - ".rubocop.yml"
156
+ - ".ruby-version"
142
157
  - ".travis.yml"
143
158
  - CHANGELOG.md
144
159
  - Gemfile
@@ -148,10 +163,16 @@ files:
148
163
  - bin/console
149
164
  - bin/setup
150
165
  - lib/namira.rb
166
+ - lib/namira/async.rb
167
+ - lib/namira/async/active_job/request_job.rb
168
+ - lib/namira/async/performer.rb
169
+ - lib/namira/async/serializer.rb
170
+ - lib/namira/async/sidekiq/request_worker.rb
151
171
  - lib/namira/config.rb
152
172
  - lib/namira/env.rb
153
173
  - lib/namira/error_helpers.rb
154
174
  - lib/namira/errors.rb
175
+ - lib/namira/errors/async_error.rb
155
176
  - lib/namira/errors/base_error.rb
156
177
  - lib/namira/errors/http_error.rb
157
178
  - lib/namira/errors/invalid_uri_error.rb
@@ -184,7 +205,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
184
205
  requirements:
185
206
  - - ">="
186
207
  - !ruby/object:Gem::Version
187
- version: '2.2'
208
+ version: '2.3'
188
209
  required_rubygems_version: !ruby/object:Gem::Requirement
189
210
  requirements:
190
211
  - - ">="
@@ -192,7 +213,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
192
213
  version: '0'
193
214
  requirements: []
194
215
  rubyforge_project:
195
- rubygems_version: 2.5.2.3
216
+ rubygems_version: 2.7.6
196
217
  signing_key:
197
218
  specification_version: 4
198
219
  summary: A simple wrapper around HTTP