simple-feed 2.0.2 → 3.1.2
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 +5 -5
- data/.envrc +3 -0
- data/.github/workflows/rubocop.yml +33 -0
- data/.github/workflows/ruby.yml +34 -0
- data/.gitignore +2 -1
- data/.relaxed-rubocop-2.4.yml +174 -0
- data/.rspec +1 -1
- data/.rubocop.yml +43 -1150
- data/.rubocop_todo.yml +203 -0
- data/.travis.yml +7 -10
- data/CHANGELOG.md +120 -0
- data/Gemfile +4 -0
- data/Guardfile +3 -3
- data/README.adoc +601 -0
- data/Rakefile +5 -6
- data/bin/console +1 -0
- data/codecov.yml +28 -0
- data/examples/shared/provider_example.rb +51 -26
- data/lib/simple-feed.rb +2 -0
- data/lib/simple_feed.rb +2 -0
- data/lib/simplefeed/activity/base.rb +2 -0
- data/lib/simplefeed/activity/multi_user.rb +8 -6
- data/lib/simplefeed/activity/single_user.rb +7 -6
- data/lib/simplefeed/dsl/activities.rb +4 -3
- data/lib/simplefeed/dsl/formatter.rb +79 -40
- data/lib/simplefeed/dsl.rb +3 -1
- data/lib/simplefeed/event.rb +52 -13
- data/lib/simplefeed/feed.rb +36 -28
- data/lib/simplefeed/providers/base/provider.rb +7 -4
- data/lib/simplefeed/providers/hash.rb +2 -0
- data/lib/simplefeed/providers/key.rb +60 -36
- data/lib/simplefeed/providers/proxy.rb +28 -14
- data/lib/simplefeed/providers/redis/driver.rb +25 -27
- data/lib/simplefeed/providers/redis/provider.rb +41 -39
- data/lib/simplefeed/providers/redis/stats.rb +12 -13
- data/lib/simplefeed/providers/redis.rb +2 -0
- data/lib/simplefeed/providers.rb +24 -10
- data/lib/simplefeed/response.rb +7 -7
- data/lib/simplefeed/version.rb +3 -1
- data/lib/simplefeed.rb +27 -21
- data/man/running-example-redis-debug.png +0 -0
- data/man/running-example.png +0 -0
- data/man/sf-color-dump.png +0 -0
- data/simple-feed.gemspec +23 -16
- metadata +115 -44
- data/README.md +0 -415
- data/examples/hash_provider_example.rb +0 -24
- data/lib/simplefeed/key/template.rb +0 -52
- data/lib/simplefeed/key/type.rb +0 -26
- data/lib/simplefeed/providers/hash/paginator.rb +0 -31
- data/lib/simplefeed/providers/hash/provider.rb +0 -198
@@ -1,4 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'simplefeed/providers/key'
|
4
|
+
require 'date'
|
5
|
+
require 'time'
|
2
6
|
|
3
7
|
module SimpleFeed
|
4
8
|
module Providers
|
@@ -27,7 +31,7 @@ module SimpleFeed
|
|
27
31
|
at = at.to_time if at.respond_to?(:to_time)
|
28
32
|
at = at.to_f if at.respond_to?(:to_f)
|
29
33
|
|
30
|
-
if
|
34
|
+
if respond_to?(:reset_last_read)
|
31
35
|
reset_last_read(user_ids: user_ids, at: at)
|
32
36
|
else
|
33
37
|
raise ArgumentError, "Class #{self.class} does not implement #reset_last_read method"
|
@@ -54,7 +58,7 @@ module SimpleFeed
|
|
54
58
|
def with_response_batched(user_ids, external_response = nil)
|
55
59
|
with_response(external_response) do |response|
|
56
60
|
batch(user_ids) do |key|
|
57
|
-
response.for(key.
|
61
|
+
response.for(key.consumer) { yield(key, response) }
|
58
62
|
end
|
59
63
|
end
|
60
64
|
end
|
@@ -70,7 +74,7 @@ module SimpleFeed
|
|
70
74
|
def with_response(response = nil)
|
71
75
|
response ||= SimpleFeed::Response.new
|
72
76
|
yield(response)
|
73
|
-
if
|
77
|
+
if respond_to?(:transform_response)
|
74
78
|
response.transform do |user_id, result|
|
75
79
|
# calling into a subclass
|
76
80
|
transform_response(user_id, result)
|
@@ -78,7 +82,6 @@ module SimpleFeed
|
|
78
82
|
end
|
79
83
|
response
|
80
84
|
end
|
81
|
-
|
82
85
|
end
|
83
86
|
end
|
84
87
|
end
|
@@ -1,9 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'base62-rb'
|
2
4
|
require 'hashie/mash'
|
3
|
-
require 'simplefeed/key/template'
|
4
|
-
require 'simplefeed/key/type'
|
5
|
-
|
6
|
-
require 'forwardable'
|
7
5
|
|
8
6
|
module SimpleFeed
|
9
7
|
module Providers
|
@@ -13,60 +11,86 @@ module SimpleFeed
|
|
13
11
|
# ↓ ↓
|
14
12
|
# "ff|u.f23098.m"
|
15
13
|
# ↑ ↑
|
16
|
-
# namespace
|
14
|
+
# namespace consumer(base62)
|
17
15
|
#
|
18
16
|
class Key
|
19
|
-
|
17
|
+
class << self
|
18
|
+
def rot13(value)
|
19
|
+
value.tr('abcdefghijklmnopqrstuvwxyz',
|
20
|
+
'nopqrstuvwxyzabcdefghijklm')
|
21
|
+
end
|
22
|
+
end
|
20
23
|
|
21
|
-
|
22
|
-
|
24
|
+
SERIALIZED_DATA_TEMPLATE = '{{namespace}}u.{{data_id}}.d'
|
25
|
+
SERIALIZED_META_TEMPLATE = '{{namespace}}u.{{meta_id}}.m'
|
23
26
|
|
24
|
-
|
25
|
-
self.user_id = user_id
|
26
|
-
self.key_template = key_template
|
27
|
+
attr_reader :consumer, :namespace, :data_key_transformer, :meta_key_transformer
|
27
28
|
|
28
|
-
|
29
|
+
def initialize(consumer,
|
30
|
+
namespace: nil,
|
31
|
+
data_key_transformer: nil,
|
32
|
+
meta_key_transformer: nil)
|
33
|
+
@consumer = consumer
|
34
|
+
@namespace = namespace
|
35
|
+
@data_key_transformer = data_key_transformer
|
36
|
+
@meta_key_transformer = meta_key_transformer
|
29
37
|
end
|
30
38
|
|
31
|
-
def
|
32
|
-
|
33
|
-
key_name = type.name
|
34
|
-
unless self.respond_to?(key_name)
|
35
|
-
self.class.send(:define_method, key_name) do
|
36
|
-
instance_variable_get("@#{key_name}") ||
|
37
|
-
instance_variable_set("@#{key_name}", type.render(render_options))
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
39
|
+
def data
|
40
|
+
@data ||= render(SERIALIZED_DATA_TEMPLATE)
|
42
41
|
end
|
43
42
|
|
44
|
-
def
|
45
|
-
@
|
43
|
+
def meta
|
44
|
+
@meta ||= render(SERIALIZED_META_TEMPLATE)
|
46
45
|
end
|
47
46
|
|
48
47
|
def keys
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
def render_options
|
53
|
-
key_template.render_options.merge!({
|
54
|
-
'user_id' => user_id,
|
55
|
-
'base62_user_id' => base62_user_id
|
56
|
-
})
|
48
|
+
[data, meta]
|
57
49
|
end
|
58
50
|
|
59
51
|
def to_s
|
60
|
-
super +
|
52
|
+
super + key_params.to_s
|
61
53
|
end
|
62
54
|
|
63
55
|
def inspect
|
64
|
-
|
56
|
+
super + key_params.inspect
|
65
57
|
end
|
66
58
|
|
67
59
|
private
|
68
60
|
|
61
|
+
def render(template)
|
62
|
+
template.dup.tap do |output|
|
63
|
+
key_params.each_pair do |key, value|
|
64
|
+
output.gsub!(/{{#{key}}}/, value.to_s)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def obscure_value(id)
|
70
|
+
id = id.to_i if id.is_a?(String) && id =~ /^\d+$/
|
71
|
+
|
72
|
+
if id.is_a?(Numeric)
|
73
|
+
::Base62.encode(id)
|
74
|
+
else
|
75
|
+
self.class.rot13(id.to_s)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def key_params
|
80
|
+
@key_params ||= Hashie::Mash.new(
|
81
|
+
namespace: namespace ? "#{namespace}|" : '',
|
82
|
+
data_id: obscure_value(data_id),
|
83
|
+
meta_id: obscure_value(meta_id)
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def meta_id
|
88
|
+
meta_key_transformer&.call(consumer) || consumer
|
89
|
+
end
|
90
|
+
|
91
|
+
def data_id
|
92
|
+
data_key_transformer&.call(consumer) || consumer
|
93
|
+
end
|
69
94
|
end
|
70
95
|
end
|
71
96
|
end
|
72
|
-
|
@@ -1,36 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module SimpleFeed
|
2
4
|
module Providers
|
5
|
+
RUBY_MAJOR_VERSION = RUBY_VERSION.split('.')[0..1].join.to_i
|
6
|
+
|
3
7
|
class Proxy
|
4
8
|
attr_accessor :provider
|
5
9
|
|
6
10
|
def self.from(definition)
|
7
11
|
if definition.is_a?(::Hash)
|
8
12
|
::SimpleFeed.symbolize!(definition)
|
9
|
-
|
13
|
+
new(definition[:klass], *definition[:args], **definition[:opts])
|
10
14
|
else
|
11
|
-
|
15
|
+
new(definition)
|
12
16
|
end
|
13
|
-
|
14
17
|
end
|
15
18
|
|
16
19
|
def initialize(provider_or_klass, *args, **options)
|
17
|
-
if provider_or_klass.is_a?(::String)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
20
|
+
self.provider = if provider_or_klass.is_a?(::String) || provider_or_klass.is_a?(::Symbol)
|
21
|
+
::Object.const_get(provider_or_klass).new(*args, **options)
|
22
|
+
else
|
23
|
+
provider_or_klass
|
24
|
+
end
|
22
25
|
|
23
26
|
SimpleFeed::Providers::REQUIRED_METHODS.each do |m|
|
24
27
|
raise ArgumentError, "Invalid provider #{provider.class}\nMethod '#{m}' is required." unless provider.respond_to?(m)
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
if RUBY_MAJOR_VERSION >= 27
|
32
|
+
# Forward all other method calls to Provider
|
33
|
+
def method_missing(name, *args, **opts, &block)
|
34
|
+
if provider&.respond_to?(name)
|
35
|
+
provider.send(name, *args, **opts, &block)
|
36
|
+
else
|
37
|
+
super(name, *args, **opts, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
else
|
41
|
+
# Forward all other method calls to Provider
|
42
|
+
def method_missing(name, *args, &block)
|
43
|
+
if provider&.respond_to?(name)
|
44
|
+
provider.send(name, *args, &block)
|
45
|
+
else
|
46
|
+
super(name, *args, &block)
|
47
|
+
end
|
34
48
|
end
|
35
49
|
end
|
36
50
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'redis'
|
2
4
|
require 'redis/connection/hiredis'
|
3
5
|
require 'connection_pool'
|
@@ -12,10 +14,10 @@ module SimpleFeed
|
|
12
14
|
@debug = ENV['REDIS_DEBUG']
|
13
15
|
|
14
16
|
def self.debug?
|
15
|
-
|
17
|
+
debug
|
16
18
|
end
|
17
19
|
|
18
|
-
def self.with_debug
|
20
|
+
def self.with_debug
|
19
21
|
previous_value = SimpleFeed::Providers::Redis.debug
|
20
22
|
SimpleFeed::Providers::Redis.debug = true
|
21
23
|
result = yield if block_given?
|
@@ -48,10 +50,11 @@ module SimpleFeed
|
|
48
50
|
colors = [:blue, nil, :blue, :blue, :yellow, :cyan, nil, :blue]
|
49
51
|
components = [
|
50
52
|
Time.now.strftime('%H:%M:%S.%L'), ' rtt=',
|
51
|
-
(sprintf '%.5f', delta*1000), ' ms ',
|
53
|
+
(sprintf '%.5f', delta * 1000), ' ms ',
|
52
54
|
(sprintf '%15s ', m.to_s.upcase),
|
53
55
|
(sprintf '%-40s', args.inspect.gsub(/[",\[\]]/, '')), ' ⇒ ',
|
54
|
-
(result.is_a?(::Redis::Future) ? '' : result.to_s)
|
56
|
+
(result.is_a?(::Redis::Future) ? '' : result.to_s)
|
57
|
+
]
|
55
58
|
components.each_with_index do |component, index|
|
56
59
|
color = self.class.disable_color ? nil : colors[index]
|
57
60
|
component = component.send(color) if color
|
@@ -71,18 +74,16 @@ module SimpleFeed
|
|
71
74
|
|
72
75
|
attr_accessor :pool
|
73
76
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
SimpleFeed::Redis::Driver.new(
|
79
|
-
SimpleFeed::Redis::Driver.new(redis:
|
80
|
-
SimpleFeed::Redis::Driver.new(redis:
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
def initialize(**opts)
|
85
|
-
if opts[:pool] && opts[:pool].respond_to?(:with)
|
77
|
+
#
|
78
|
+
# Various ways of defining a new Redis driver:
|
79
|
+
#
|
80
|
+
# SimpleFeed::Redis::Driver.new(pool: ConnectionPool.new(size: 2) { Redis.new })
|
81
|
+
# SimpleFeed::Redis::Driver.new(redis: -> { Redis.new }, pool_size: 2)
|
82
|
+
# SimpleFeed::Redis::Driver.new(redis: Redis.new)
|
83
|
+
# SimpleFeed::Redis::Driver.new(redis: { host: 'localhost', port: 6379, db: 1, timeout: 0.2 }, pool_size: 1)
|
84
|
+
#
|
85
|
+
def initialize(opts)
|
86
|
+
if opts[:pool]&.respond_to?(:with)
|
86
87
|
self.pool = opts[:pool]
|
87
88
|
|
88
89
|
elsif opts[:redis]
|
@@ -104,7 +105,7 @@ SimpleFeed::Redis::Driver.new(redis: { host: 'localhost', port: 6379, db: 1, tim
|
|
104
105
|
end
|
105
106
|
end
|
106
107
|
|
107
|
-
raise ArgumentError, "Unable to construct Redis connection from arguments: #{opts.inspect}" unless
|
108
|
+
raise ArgumentError, "Unable to construct Redis connection from arguments: #{opts.inspect}" unless pool&.respond_to?(:with)
|
108
109
|
end
|
109
110
|
|
110
111
|
%i(set get incr decr setex expire del setnx exists zadd zrange).each do |method|
|
@@ -117,7 +118,7 @@ SimpleFeed::Redis::Driver.new(redis: { host: 'localhost', port: 6379, db: 1, tim
|
|
117
118
|
alias_method :rm, :del
|
118
119
|
alias_method :exists?, :exists
|
119
120
|
|
120
|
-
def exec(redis_method, *args, **
|
121
|
+
def exec(redis_method, *args, **_opts, &block)
|
121
122
|
send_proc = redis_method if redis_method.respond_to?(:call)
|
122
123
|
send_proc ||= ->(redis) { redis.send(redis_method, *args, &block) }
|
123
124
|
|
@@ -125,7 +126,7 @@ SimpleFeed::Redis::Driver.new(redis: { host: 'localhost', port: 6379, db: 1, tim
|
|
125
126
|
end
|
126
127
|
|
127
128
|
class MockRedis
|
128
|
-
def method_missing(name, *args, &block)
|
129
|
+
def method_missing(name, *args, **_opts, &block)
|
129
130
|
puts "calling redis.#{name}(#{args.to_s.gsub(/[\[\]]/, '')}) { #{block ? block.call : nil} }"
|
130
131
|
end
|
131
132
|
end
|
@@ -133,17 +134,15 @@ SimpleFeed::Redis::Driver.new(redis: { host: 'localhost', port: 6379, db: 1, tim
|
|
133
134
|
def with_redis
|
134
135
|
with_retries do
|
135
136
|
pool.with do |redis|
|
136
|
-
yield(
|
137
|
+
yield(debug? ? LoggingRedis.new(redis) : redis)
|
137
138
|
end
|
138
139
|
end
|
139
140
|
end
|
140
141
|
|
141
|
-
def with_pipelined
|
142
|
+
def with_pipelined(&block)
|
142
143
|
with_retries do
|
143
144
|
with_redis do |redis|
|
144
|
-
redis.pipelined
|
145
|
-
yield(redis)
|
146
|
-
end
|
145
|
+
redis.pipelined(&block)
|
147
146
|
end
|
148
147
|
end
|
149
148
|
end
|
@@ -170,13 +169,12 @@ SimpleFeed::Redis::Driver.new(redis: { host: 'localhost', port: 6379, db: 1, tim
|
|
170
169
|
on_error e
|
171
170
|
end
|
172
171
|
rescue ::Redis::CommandError => e
|
173
|
-
|
172
|
+
e.message =~ /loading/i || e.message =~ /connection/i ? on_error(e) : raise(e)
|
174
173
|
end
|
175
174
|
|
176
175
|
def on_error(e)
|
177
|
-
raise Error
|
176
|
+
raise Error, e
|
178
177
|
end
|
179
|
-
|
180
178
|
end
|
181
179
|
end
|
182
180
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'redis'
|
2
4
|
require 'base62-rb'
|
3
5
|
require 'forwardable'
|
@@ -21,7 +23,6 @@ module SimpleFeed
|
|
21
23
|
# u.afkj234.meta: { total: 2, unread: 2, last_read: 2016-11-20 22:00:34 -08:00 GMT }
|
22
24
|
# ```
|
23
25
|
class Provider < ::SimpleFeed::Providers::Base::Provider
|
24
|
-
|
25
26
|
# SimpleFeed::Providers.define_provider_methods(self) do |provider, method, **opts, &block|
|
26
27
|
# users = Users.new(provider: provider, user_ids: opts.delete(:user_ids))
|
27
28
|
# opts.empty? ?
|
@@ -48,10 +49,11 @@ module SimpleFeed
|
|
48
49
|
|
49
50
|
def delete_if(user_ids:)
|
50
51
|
raise ArgumentError, '#delete_if must be called with a block that receives (user_id, event) as arguments.' unless block_given?
|
52
|
+
|
51
53
|
with_response_batched(user_ids) do |key|
|
52
|
-
fetch(user_ids: [key.
|
54
|
+
fetch(user_ids: [key.consumer])[key.consumer].map do |event|
|
53
55
|
with_redis do |redis|
|
54
|
-
if yield(event, key.
|
56
|
+
if yield(event, key.consumer)
|
55
57
|
redis.zrem(key.data, event.value) ? event : nil
|
56
58
|
end
|
57
59
|
end
|
@@ -88,7 +90,7 @@ module SimpleFeed
|
|
88
90
|
|
89
91
|
response = with_response_pipelined(user_ids) do |redis, key|
|
90
92
|
if since == :unread
|
91
|
-
redis.zrevrangebyscore(key.data, '+inf', (last_read_response.delete(key.
|
93
|
+
redis.zrevrangebyscore(key.data, '+inf', (last_read_response.delete(key.consumer) || 0).to_f, withscores: true)
|
92
94
|
elsif since
|
93
95
|
redis.zrevrangebyscore(key.data, '+inf', since.to_f, withscores: true)
|
94
96
|
else
|
@@ -118,7 +120,7 @@ module SimpleFeed
|
|
118
120
|
get_users_last_read(redis, key)
|
119
121
|
end
|
120
122
|
with_response_pipelined(response.user_ids, response) do |redis, key, _response|
|
121
|
-
last_read = _response.delete(key.
|
123
|
+
last_read = _response.delete(key.consumer).to_f
|
122
124
|
redis.zcount(key.data, last_read, '+inf')
|
123
125
|
end
|
124
126
|
end
|
@@ -129,7 +131,7 @@ module SimpleFeed
|
|
129
131
|
end
|
130
132
|
end
|
131
133
|
|
132
|
-
FEED_METHODS = %i(total_memory_bytes total_users last_disk_save_time)
|
134
|
+
FEED_METHODS = %i(total_memory_bytes total_users last_disk_save_time).freeze
|
133
135
|
|
134
136
|
def total_memory_bytes
|
135
137
|
with_stats(:used_memory_since_boot)
|
@@ -147,39 +149,39 @@ module SimpleFeed
|
|
147
149
|
|
148
150
|
def transform_response(user_id = nil, result)
|
149
151
|
case result
|
150
|
-
|
151
|
-
|
152
|
+
when ::Redis::Future
|
153
|
+
transform_response(user_id, result.value)
|
152
154
|
|
153
|
-
|
155
|
+
when ::Hash
|
154
156
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
157
|
+
if result.values.any? { |v| transformable_type?(v) }
|
158
|
+
result.each { |k, v| result[k] = transform_response(user_id, v) }
|
159
|
+
else
|
160
|
+
result
|
161
|
+
end
|
160
162
|
|
161
|
-
|
163
|
+
when ::Array
|
162
164
|
|
163
|
-
|
164
|
-
|
165
|
-
|
165
|
+
if result.any? { |v| transformable_type?(v) }
|
166
|
+
result = result.map { |v| transform_response(user_id, v) }
|
167
|
+
end
|
166
168
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
169
|
+
if result.size == 2 && result[1].is_a?(Float)
|
170
|
+
SimpleFeed::Event.new(value: result[0], at: Time.at(result[1]))
|
171
|
+
else
|
172
|
+
result
|
173
|
+
end
|
172
174
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
else
|
179
|
-
result
|
180
|
-
end
|
175
|
+
when ::String
|
176
|
+
if result =~ /^\d+\.\d+$/
|
177
|
+
result.to_f
|
178
|
+
elsif result =~ /^\d+$/
|
179
|
+
result.to_i
|
181
180
|
else
|
182
181
|
result
|
182
|
+
end
|
183
|
+
else
|
184
|
+
result
|
183
185
|
end
|
184
186
|
end
|
185
187
|
|
@@ -194,9 +196,9 @@ module SimpleFeed
|
|
194
196
|
|
195
197
|
private
|
196
198
|
|
197
|
-
|
199
|
+
# ——————————————————————————————————————————————————————————————————————————————————————
|
198
200
|
# helpers
|
199
|
-
|
201
|
+
# ——————————————————————————————————————————————————————————————————————————————————————
|
200
202
|
|
201
203
|
def reset_users_last_read(redis, key, time = nil)
|
202
204
|
time = time.nil? ? Time.now.to_f : time.to_f
|
@@ -214,14 +216,14 @@ module SimpleFeed
|
|
214
216
|
redis.zrevrange(key.data, (page - 1) * per_page, page * per_page - 1, withscores: true)
|
215
217
|
end
|
216
218
|
|
217
|
-
|
219
|
+
# ——————————————————————————————————————————————————————————————————————————————————————
|
218
220
|
# Operations with response
|
219
|
-
|
221
|
+
# ——————————————————————————————————————————————————————————————————————————————————————
|
220
222
|
|
221
223
|
def with_response_pipelined(user_ids, response = nil)
|
222
224
|
with_response(response) do |response|
|
223
225
|
batch_pipelined(user_ids) do |redis, key|
|
224
|
-
response.for(key.
|
226
|
+
response.for(key.consumer) { yield(redis, key, response) }
|
225
227
|
end
|
226
228
|
end
|
227
229
|
end
|
@@ -229,14 +231,14 @@ module SimpleFeed
|
|
229
231
|
def with_response_multi(user_ids, response = nil)
|
230
232
|
with_response(response) do |response|
|
231
233
|
batch_multi(user_ids) do |redis, key|
|
232
|
-
response.for(key.
|
234
|
+
response.for(key.consumer) { yield(redis, key, response) }
|
233
235
|
end
|
234
236
|
end
|
235
237
|
end
|
236
238
|
|
237
|
-
|
239
|
+
# ——————————————————————————————————————————————————————————————————————————————————————
|
238
240
|
# Batch operations
|
239
|
-
|
241
|
+
# ——————————————————————————————————————————————————————————————————————————————————————
|
240
242
|
def batch_pipelined(user_ids)
|
241
243
|
to_array(user_ids).each_slice(batch_size) do |batch|
|
242
244
|
with_pipelined do |redis|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'redis'
|
2
4
|
require 'hashie/mash'
|
3
5
|
require 'yaml'
|
@@ -6,7 +8,6 @@ module SimpleFeed
|
|
6
8
|
module Providers
|
7
9
|
module Redis
|
8
10
|
class Stats
|
9
|
-
|
10
11
|
attr_accessor :redis
|
11
12
|
|
12
13
|
def initialize(redis)
|
@@ -56,27 +57,25 @@ module SimpleFeed
|
|
56
57
|
end
|
57
58
|
|
58
59
|
def load_boot_stats!
|
59
|
-
@boot_info ||= destringify(YAML.load(File.open(File.expand_path('
|
60
|
+
@boot_info ||= destringify(YAML.load(File.open(File.expand_path('boot_info.yml', __dir__))))
|
60
61
|
end
|
61
|
-
|
62
62
|
end
|
63
63
|
|
64
64
|
load_boot_stats!
|
65
65
|
|
66
66
|
boot_info.keys.each do |key|
|
67
|
-
|
67
|
+
next if key.to_s =~ /^db[0-9]+/
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
define_method(key.to_sym) do
|
70
|
+
info[key]
|
71
|
+
end
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
73
|
+
define_method("#{key}_at_boot".to_sym) do
|
74
|
+
boot_info[key]
|
75
|
+
end
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
end
|
77
|
+
define_method("#{key}_since_boot".to_sym) do
|
78
|
+
info[key] - boot_info[key]
|
80
79
|
end
|
81
80
|
end
|
82
81
|
end
|
data/lib/simplefeed/providers.rb
CHANGED
@@ -1,33 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'providers/key'
|
2
4
|
require_relative 'providers/proxy'
|
3
5
|
|
4
6
|
module SimpleFeed
|
5
7
|
module Providers
|
6
8
|
@registry = {}
|
7
|
-
|
9
|
+
|
8
10
|
def self.registry
|
9
11
|
@registry
|
10
12
|
end
|
11
|
-
|
13
|
+
|
12
14
|
def self.register(provider_name, provider_class)
|
13
|
-
|
15
|
+
registry[provider_name] = provider_class
|
14
16
|
end
|
15
|
-
|
17
|
+
|
16
18
|
# These methods must be implemented by each Provider, and operation on a given
|
17
19
|
# set of users passed via the user_ids: parameter.
|
18
|
-
ACTIVITY_METHODS = %i
|
20
|
+
ACTIVITY_METHODS = %i[
|
21
|
+
store
|
22
|
+
delete
|
23
|
+
delete_if
|
24
|
+
wipe
|
25
|
+
reset_last_read
|
26
|
+
last_read paginate
|
27
|
+
fetch
|
28
|
+
total_count
|
29
|
+
unread_count
|
30
|
+
].freeze
|
19
31
|
|
20
|
-
# These methods must be implemented in order to gather statistics about each provider's
|
32
|
+
# These optional methods must be implemented in order to gather statistics about each provider's
|
21
33
|
# memory consumption and state.
|
22
|
-
FEED_METHODS = %i
|
34
|
+
FEED_METHODS = %i[
|
35
|
+
total_memory_bytes
|
36
|
+
total_users
|
37
|
+
].freeze
|
23
38
|
|
24
|
-
REQUIRED_METHODS = ACTIVITY_METHODS + FEED_METHODS
|
39
|
+
REQUIRED_METHODS = (ACTIVITY_METHODS + FEED_METHODS).freeze
|
25
40
|
|
26
41
|
def self.define_provider_methods(klass, prefix = nil, &block)
|
27
42
|
# Methods on the class instance
|
28
43
|
klass.class_eval do
|
29
44
|
SimpleFeed::Providers::REQUIRED_METHODS.each do |m|
|
30
|
-
method_name = prefix ? "#{prefix}_#{m
|
45
|
+
method_name = prefix ? "#{prefix}_#{m}".to_sym : m
|
31
46
|
define_method(method_name) do |*args, **opts, &b|
|
32
47
|
block.call(self, m, *args, **opts, &b)
|
33
48
|
end
|
@@ -37,5 +52,4 @@ module SimpleFeed
|
|
37
52
|
end
|
38
53
|
end
|
39
54
|
|
40
|
-
require_relative 'providers/hash'
|
41
55
|
require_relative 'providers/redis'
|