userlist 0.7.2 → 0.8.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
2
  SHA256:
3
- metadata.gz: ee5f47b48e2bcc0babdbb7bcc85e84e5b197dacefb777eb19764d6f23e78e682
4
- data.tar.gz: 53caac6db3e462e9fe280541a7249da39e821a6a8bed7c70373131bebe9a6e19
3
+ metadata.gz: ee98b5cd1e17b91ed12fce427d0c87ec4593da547349015ca4ed9272dba73100
4
+ data.tar.gz: 3ec9d567b7c8c1894841483cd136c76db4e1a667eac7101541fcd3d232b20a8f
5
5
  SHA512:
6
- metadata.gz: 687b4ff1d89c5c98814fc89fe7cb8097577bd0cea63138f40e194eb47d6d6a2807b624c9dd15f2b64868f0473f1baaf268b6f7cb3945b713c20d00150b71739c
7
- data.tar.gz: 0b72bc8a28a6cba596c5afaff369e62b26cc8a84347f0059f68859c02df270562663c9e7faa8ddbb89a7053cf6d811d7dfcafa75f2f9233c27a36aebd72e4b4a
6
+ metadata.gz: 68340e08984d801834f1f853102119df452da6455bdca3b1eedf0d743d829c750fc81e234ef661f964402e44173b9951a891f15cb9ed0665929d525fbd0b03df
7
+ data.tar.gz: 1d6e7976d2e5486506306b2623135b4addf4cb7c6b6f3c3d81e30fde6d4fb733eb9d289027812ae6390d82b0b7cf4a5742104b0496d88372b0e720a8ed89402d
@@ -5,14 +5,12 @@ jobs:
5
5
  strategy:
6
6
  matrix:
7
7
  ruby:
8
- - 2.4
9
- - 2.5
10
- - 2.6
11
- - 2.7
12
8
  - 3.0
9
+ - 3.1
10
+ - 3.2
13
11
  runs-on: ubuntu-latest
14
12
  steps:
15
- - uses: actions/checkout@v2
13
+ - uses: actions/checkout@v3
16
14
  - uses: ruby/setup-ruby@v1
17
15
  with:
18
16
  ruby-version: ${{ matrix.ruby }}
data/.rubocop.yml CHANGED
@@ -51,6 +51,9 @@ Style/ClassAndModuleChildren:
51
51
  Layout/MultilineMethodCallIndentation:
52
52
  EnforcedStyle: indented
53
53
 
54
+ Layout/SpaceAroundOperators:
55
+ EnforcedStyleForExponentOperator: space
56
+
54
57
  Style/SymbolArray:
55
58
  Enabled: false
56
59
 
data/Gemfile CHANGED
@@ -6,6 +6,8 @@ gemspec
6
6
 
7
7
  gem 'guard-rspec', '~> 4.7'
8
8
  gem 'guard-rubocop', '~> 1.3'
9
- gem 'rubocop', '~> 0.68'
9
+ gem 'rubocop', '~> 1.45'
10
10
 
11
11
  gem 'sidekiq'
12
+ gem 'activejob'
13
+ gem 'uri'
data/README.md CHANGED
@@ -44,15 +44,15 @@ end
44
44
 
45
45
  The possible configuration values are listed in the table below.
46
46
 
47
- | Name | Default value | Description |
48
- | ----------------------- | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
49
- | `push_key` | `nil` | The push key for your account. See [Push API settings](https://app.userlist.com/settings/push). |
50
- | `push_id` | `nil` | The push id for your account. See [Push API settings](https://app.userlist.com/settings/push). |
51
- | `push_endpoint` | `https://push.userlist.com/` | The HTTP endpoint that the library will send data to. |
52
- | `push_strategy` | `:threaded` | The strategy to use to send data to the HTTP endpoint. Possible values are `:threaded`, `:sidekiq`, `:direct`, and `:null`. |
53
- | `push_strategy_options` | `{}` | Any additional options for the push strategy. |
54
- | `log_level` | `:warn` | The log level for Userlist related log messages. Possible values are `:debug`, `:error`, `:fatal`, `:info`, and `:warn` |
55
- | `token_lifetime` | `3600` | The lifetime of generated in-app messages tokens in seconds |
47
+ | Name | Default value | Description |
48
+ | ----------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
49
+ | `push_key` | `nil` | The push key for your account. See [Push API settings](https://app.userlist.com/settings/push). |
50
+ | `push_id` | `nil` | The push id for your account. See [Push API settings](https://app.userlist.com/settings/push). |
51
+ | `push_endpoint` | `https://push.userlist.com/` | The HTTP endpoint that the library will send data to. |
52
+ | `push_strategy` | `:threaded` | The strategy to use to send data to the HTTP endpoint. Possible values are `:threaded`, `:sidekiq`, `:active_job`, `:direct`, and `:null`. |
53
+ | `push_strategy_options` | `{}` | Any additional options for the push strategy. |
54
+ | `log_level` | `:warn` | The log level for Userlist related log messages. Possible values are `:debug`, `:error`, `:fatal`, `:info`, and `:warn` |
55
+ | `token_lifetime` | `3600` | The lifetime of generated in-app messages tokens in seconds |
56
56
 
57
57
  ### Disabling in development and test environments
58
58
 
@@ -53,7 +53,7 @@ module Userlist
53
53
 
54
54
  def config_from_environment
55
55
  default_config.keys.each_with_object({}) do |key, config|
56
- value = ENV["USERLIST_#{key.to_s.upcase}"]
56
+ value = ENV.fetch("USERLIST_#{key.to_s.upcase}", nil)
57
57
  config[key] = value if value
58
58
  end
59
59
  end
@@ -27,8 +27,8 @@ module Userlist
27
27
  request(Net::HTTP::Put, endpoint, payload)
28
28
  end
29
29
 
30
- def delete(endpoint)
31
- request(Net::HTTP::Delete, endpoint)
30
+ def delete(endpoint, payload = nil)
31
+ request(Net::HTTP::Delete, endpoint, payload)
32
32
  end
33
33
 
34
34
  private
@@ -58,7 +58,11 @@ module Userlist
58
58
  logger.debug "Sending #{request.method} to #{URI.join(endpoint, request.path)} with body #{request.body}"
59
59
 
60
60
  http.start unless http.started?
61
- http.request(request)
61
+ response = http.request(request)
62
+
63
+ logger.debug "Recieved #{response.code} #{response.message} with body #{response.body}"
64
+
65
+ response
62
66
  end
63
67
 
64
68
  def endpoint
@@ -33,9 +33,9 @@ module Userlist
33
33
  relationships[name.to_sym] = { type: type }
34
34
 
35
35
  generated_methods.class_eval <<-RUBY, __FILE__, __LINE__ + 1
36
- def #{name}
37
- #{type}.from_payload(payload[:#{name}], config)
38
- end
36
+ def #{name} # def company
37
+ #{type}.from_payload(payload[:#{name}], config) # Company.from_payload(payload[:company], config)
38
+ end # end
39
39
  RUBY
40
40
  end
41
41
 
@@ -43,11 +43,11 @@ module Userlist
43
43
  relationships[name.to_sym] = options
44
44
 
45
45
  generated_methods.class_eval <<-RUBY, __FILE__, __LINE__ + 1
46
- def #{name}
47
- relationship = self.class.relationships[:#{name}]
48
-
49
- ResourceCollection.new(payload[:#{name}], relationship, self, config)
50
- end
46
+ def #{name} # def companies
47
+ relationship = self.class.relationships[:#{name}] # relationship = self.class.relationships[:companies]
48
+ #
49
+ ResourceCollection.new(payload[:#{name}], relationship, self, config) # ResourceCollection.new(payload[:companies], relationship, self, config)
50
+ end #
51
51
  RUBY
52
52
  end
53
53
 
@@ -0,0 +1,16 @@
1
+ require 'active_job'
2
+
3
+ module Userlist
4
+ class Push
5
+ module Strategies
6
+ class ActiveJob
7
+ class Worker < ::ActiveJob::Base
8
+ def perform(method, *args)
9
+ client = Userlist::Push::Client.new
10
+ client.public_send(method, *args)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,47 @@
1
+ require 'active_job'
2
+
3
+ require 'userlist/push/strategies/active_job/worker'
4
+
5
+ module Userlist
6
+ class Push
7
+ module Strategies
8
+ class ActiveJob
9
+ def initialize(config = {})
10
+ @config = Userlist.config.merge(config)
11
+ end
12
+
13
+ def call(*args)
14
+ options = default_options.merge(self.options)
15
+
16
+ worker_name = options.delete(:class)
17
+ worker_class = Object.const_get(worker_name)
18
+ worker_class
19
+ .set(options)
20
+ .perform_later(*normalize(args))
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :config
26
+
27
+ def options
28
+ @options ||= begin
29
+ options = config.push_strategy_options || {}
30
+ options.each_with_object({}) { |(k, v), h| h[k.to_sym] = v }
31
+ end
32
+ end
33
+
34
+ def default_options
35
+ {
36
+ class: 'Userlist::Push::Strategies::ActiveJob::Worker',
37
+ queue: 'default'
38
+ }
39
+ end
40
+
41
+ def normalize(args)
42
+ JSON.parse(JSON.generate(args))
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -7,7 +7,7 @@ module Userlist
7
7
  end
8
8
 
9
9
  def call(*args)
10
- client.public_send(*args)
10
+ retryable.attempt { client.public_send(*args) }
11
11
  end
12
12
 
13
13
  private
@@ -17,6 +17,14 @@ module Userlist
17
17
  def client
18
18
  @client ||= Userlist::Push::Client.new(config)
19
19
  end
20
+
21
+ def retryable
22
+ @retryable ||= Userlist::Retryable.new do |response|
23
+ status = response.code.to_i
24
+
25
+ status >= 500 || status == 429
26
+ end
27
+ end
20
28
  end
21
29
  end
22
30
  end
@@ -22,7 +22,7 @@ module Userlist
22
22
  method, *args = *queue.pop
23
23
  break if method == :stop
24
24
 
25
- client.public_send(method, *args)
25
+ retryable.attempt { client.public_send(method, *args) }
26
26
  rescue StandardError => e
27
27
  logger.error "Failed to deliver payload: [#{e.class.name}] #{e.message}"
28
28
  end
@@ -44,6 +44,14 @@ module Userlist
44
44
  def client
45
45
  @client ||= Userlist::Push::Client.new(config)
46
46
  end
47
+
48
+ def retryable
49
+ @retryable ||= Userlist::Retryable.new do |response|
50
+ status = response.code.to_i
51
+
52
+ status >= 500 || status == 429
53
+ end
54
+ end
47
55
  end
48
56
  end
49
57
  end
@@ -12,13 +12,16 @@ module Userlist
12
12
  return strategy unless strategy.is_a?(Symbol) || strategy.is_a?(String)
13
13
 
14
14
  require_strategy(strategy)
15
- const_get(strategy.to_s.capitalize, false)
15
+
16
+ class_name = classify_strategy(strategy)
17
+ const_get(class_name, false)
16
18
  end
17
19
 
18
20
  def self.strategy_defined?(strategy)
19
21
  return true unless strategy.is_a?(Symbol) || strategy.is_a?(String)
20
22
 
21
- const_defined?(strategy.to_s.capitalize, false)
23
+ class_name = classify_strategy(strategy)
24
+ const_defined?(class_name, false)
22
25
  end
23
26
 
24
27
  def self.require_strategy(strategy)
@@ -26,6 +29,11 @@ module Userlist
26
29
 
27
30
  require("userlist/push/strategies/#{strategy}") unless strategy_defined?(strategy)
28
31
  end
32
+
33
+ def self.classify_strategy(strategy)
34
+ strategy.to_s.split('_').map(&:capitalize).join
35
+ end
36
+ private_class_method :classify_strategy
29
37
  end
30
38
  end
31
39
  end
@@ -0,0 +1,49 @@
1
+ module Userlist
2
+ class Retryable
3
+ include Userlist::Logging
4
+
5
+ RETRIES = 10
6
+ DELAY = 100
7
+ MULTIPLIER = 2
8
+ MAX_DELAY = 10_000
9
+
10
+ def initialize(retries: RETRIES, delay: DELAY, max_delay: MAX_DELAY, multiplier: MULTIPLIER, &retry_check)
11
+ @retries = retries
12
+ @delay = delay
13
+ @max_delay = max_delay
14
+ @multiplier = multiplier
15
+ @retry_check = retry_check
16
+ end
17
+
18
+ def retry?(value)
19
+ @retry_check.call(value)
20
+ end
21
+
22
+ def attempt
23
+ (0..@retries).each do |attempt|
24
+ if attempt.positive?
25
+ milliseconds = delay(attempt)
26
+ logger.debug "Retrying in #{milliseconds}ms, #{@retries - attempt} retries left"
27
+ sleep(milliseconds / 1000.0)
28
+ end
29
+
30
+ result = yield
31
+
32
+ return result unless retry?(result)
33
+ end
34
+
35
+ logger.debug 'Retries exhausted, giving up'
36
+
37
+ nil
38
+ end
39
+
40
+ private
41
+
42
+ def delay(attempt)
43
+ [
44
+ @delay * (@multiplier ** attempt),
45
+ @max_delay
46
+ ].min
47
+ end
48
+ end
49
+ end
@@ -1,3 +1,3 @@
1
1
  module Userlist
2
- VERSION = '0.7.2'.freeze
2
+ VERSION = '0.8.0'.freeze
3
3
  end
data/lib/userlist.rb CHANGED
@@ -3,6 +3,7 @@ require 'logger'
3
3
  require 'userlist/version'
4
4
  require 'userlist/config'
5
5
  require 'userlist/logging'
6
+ require 'userlist/retryable'
6
7
  require 'userlist/push'
7
8
  require 'userlist/token'
8
9
 
data/userlist.gemspec CHANGED
@@ -23,7 +23,9 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency 'bundler', '>= 1.15'
25
25
  spec.add_development_dependency 'jwt', '~> 2.2'
26
- spec.add_development_dependency 'rake', '~> 12.3', '>= 12.3.3'
26
+ spec.add_development_dependency 'rake', '~> 13.0'
27
27
  spec.add_development_dependency 'rspec', '~> 3.0'
28
- spec.add_development_dependency 'webmock', '~> 1.22'
28
+ spec.add_development_dependency 'webmock', '~> 3.18'
29
+
30
+ spec.metadata = { 'rubygems_mfa_required' => 'true' }
29
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: userlist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benedikt Deicke
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-20 00:00:00.000000000 Z
11
+ date: 2023-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,20 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '12.3'
48
- - - ">="
49
- - !ruby/object:Gem::Version
50
- version: 12.3.3
47
+ version: '13.0'
51
48
  type: :development
52
49
  prerelease: false
53
50
  version_requirements: !ruby/object:Gem::Requirement
54
51
  requirements:
55
52
  - - "~>"
56
53
  - !ruby/object:Gem::Version
57
- version: '12.3'
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: 12.3.3
54
+ version: '13.0'
61
55
  - !ruby/object:Gem::Dependency
62
56
  name: rspec
63
57
  requirement: !ruby/object:Gem::Requirement
@@ -78,14 +72,14 @@ dependencies:
78
72
  requirements:
79
73
  - - "~>"
80
74
  - !ruby/object:Gem::Version
81
- version: '1.22'
75
+ version: '3.18'
82
76
  type: :development
83
77
  prerelease: false
84
78
  version_requirements: !ruby/object:Gem::Requirement
85
79
  requirements:
86
80
  - - "~>"
87
81
  - !ruby/object:Gem::Version
88
- version: '1.22'
82
+ version: '3.18'
89
83
  description:
90
84
  email:
91
85
  - benedikt@userlist.com
@@ -120,6 +114,8 @@ files:
120
114
  - lib/userlist/push/resource_collection.rb
121
115
  - lib/userlist/push/serializer.rb
122
116
  - lib/userlist/push/strategies.rb
117
+ - lib/userlist/push/strategies/active_job.rb
118
+ - lib/userlist/push/strategies/active_job/worker.rb
123
119
  - lib/userlist/push/strategies/direct.rb
124
120
  - lib/userlist/push/strategies/null.rb
125
121
  - lib/userlist/push/strategies/sidekiq.rb
@@ -127,13 +123,15 @@ files:
127
123
  - lib/userlist/push/strategies/threaded.rb
128
124
  - lib/userlist/push/strategies/threaded/worker.rb
129
125
  - lib/userlist/push/user.rb
126
+ - lib/userlist/retryable.rb
130
127
  - lib/userlist/token.rb
131
128
  - lib/userlist/version.rb
132
129
  - userlist.gemspec
133
130
  homepage: http://github.com/userlistio/userlist-ruby
134
131
  licenses:
135
132
  - MIT
136
- metadata: {}
133
+ metadata:
134
+ rubygems_mfa_required: 'true'
137
135
  post_install_message:
138
136
  rdoc_options: []
139
137
  require_paths:
@@ -149,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
147
  - !ruby/object:Gem::Version
150
148
  version: '0'
151
149
  requirements: []
152
- rubygems_version: 3.3.7
150
+ rubygems_version: 3.4.6
153
151
  signing_key:
154
152
  specification_version: 4
155
153
  summary: Ruby wrapper for the Userlist API