async-redis 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/async/redis/client.rb +2 -6
- data/lib/async/redis/context/pipeline.rb +13 -10
- data/lib/async/redis/endpoint.rb +268 -0
- data/lib/async/redis/protocol/authenticated.rb +44 -0
- data/lib/async/redis/protocol/selected.rb +44 -0
- data/lib/async/redis/sentinels.rb +34 -27
- data/lib/async/redis/version.rb +2 -2
- data/readme.md +5 -5
- data.tar.gz.sig +0 -0
- metadata +13 -15
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97fe8ed81d0096bd994cbbd3511fc3acb7c0c4629cfafdac47e5c237137083f1
|
4
|
+
data.tar.gz: c8a5b6a33efb6de45dc7cc2154b694fbd9337a14c485f85f1693bfeabbcc0f79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad448e4900402ef3e974a247c27a6a8fa5bf65d47fda67b46260830ecfb76a185c86a03ff0c38cd18ae1d628a7ce332d6952e26704d357f3858458fe593fb49d
|
7
|
+
data.tar.gz: 83535dc337e792808e6e3033864e393cb075a5d709bd5a8c507577d8b792f0600388f98cd28997c891102c36dc79062c6327004359f51c4677b50bab42eced8a
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/async/redis/client.rb
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
require_relative 'context/pipeline'
|
11
11
|
require_relative 'context/transaction'
|
12
12
|
require_relative 'context/subscribe'
|
13
|
-
require_relative '
|
13
|
+
require_relative 'endpoint'
|
14
14
|
|
15
15
|
require 'io/endpoint/host_endpoint'
|
16
16
|
require 'async/pool/controller'
|
@@ -23,14 +23,10 @@ module Async
|
|
23
23
|
# Legacy.
|
24
24
|
ServerError = ::Protocol::Redis::ServerError
|
25
25
|
|
26
|
-
def self.local_endpoint(port: 6379)
|
27
|
-
::IO::Endpoint.tcp('localhost', port)
|
28
|
-
end
|
29
|
-
|
30
26
|
class Client
|
31
27
|
include ::Protocol::Redis::Methods
|
32
28
|
|
33
|
-
def initialize(endpoint =
|
29
|
+
def initialize(endpoint = Endpoint.local, protocol: endpoint.protocol, **options)
|
34
30
|
@endpoint = endpoint
|
35
31
|
@protocol = protocol
|
36
32
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
4
|
# Copyright, 2019, by David Ortiz.
|
5
|
-
# Copyright, 2019-
|
5
|
+
# Copyright, 2019-2024, by Samuel Williams.
|
6
6
|
# Copyright, 2022, by Tim Willard.
|
7
7
|
|
8
8
|
require_relative 'generic'
|
@@ -22,8 +22,8 @@ module Async
|
|
22
22
|
end
|
23
23
|
|
24
24
|
# This method just accumulates the commands and their params.
|
25
|
-
def call(
|
26
|
-
@pipeline.call(
|
25
|
+
def call(...)
|
26
|
+
@pipeline.call(...)
|
27
27
|
|
28
28
|
@pipeline.flush(1)
|
29
29
|
|
@@ -46,6 +46,15 @@ module Async
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
def collect
|
50
|
+
if block_given?
|
51
|
+
flush
|
52
|
+
yield
|
53
|
+
end
|
54
|
+
|
55
|
+
@count.times.map{read_response}
|
56
|
+
end
|
57
|
+
|
49
58
|
def sync
|
50
59
|
@sync ||= Sync.new(self)
|
51
60
|
end
|
@@ -73,15 +82,9 @@ module Async
|
|
73
82
|
end
|
74
83
|
end
|
75
84
|
|
76
|
-
def collect
|
77
|
-
yield
|
78
|
-
|
79
|
-
@count.times.map{read_response}
|
80
|
-
end
|
81
|
-
|
82
85
|
def close
|
83
86
|
flush
|
84
|
-
|
87
|
+
ensure
|
85
88
|
super
|
86
89
|
end
|
87
90
|
end
|
@@ -0,0 +1,268 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'io/endpoint'
|
7
|
+
require 'io/endpoint/host_endpoint'
|
8
|
+
require 'io/endpoint/ssl_endpoint'
|
9
|
+
|
10
|
+
require_relative 'protocol/resp2'
|
11
|
+
require_relative 'protocol/authenticated'
|
12
|
+
require_relative 'protocol/selected'
|
13
|
+
|
14
|
+
module Async
|
15
|
+
module Redis
|
16
|
+
def self.local_endpoint(**options)
|
17
|
+
Endpoint.local(**options)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Represents a way to connect to a remote Redis server.
|
21
|
+
class Endpoint < ::IO::Endpoint::Generic
|
22
|
+
LOCALHOST = URI.parse("redis://localhost").freeze
|
23
|
+
|
24
|
+
def self.local(**options)
|
25
|
+
self.new(LOCALHOST, **options)
|
26
|
+
end
|
27
|
+
|
28
|
+
SCHEMES = {
|
29
|
+
'redis' => URI::Generic,
|
30
|
+
'rediss' => URI::Generic,
|
31
|
+
}
|
32
|
+
|
33
|
+
def self.parse(string, endpoint = nil, **options)
|
34
|
+
url = URI.parse(string).normalize
|
35
|
+
|
36
|
+
return self.new(url, endpoint, **options)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Construct an endpoint with a specified scheme, hostname, optional path, and options.
|
40
|
+
#
|
41
|
+
# @parameter scheme [String] The scheme to use, e.g. "redis" or "rediss".
|
42
|
+
# @parameter hostname [String] The hostname to connect to (or bind to).
|
43
|
+
# @parameter *options [Hash] Additional options, passed to {#initialize}.
|
44
|
+
def self.for(scheme, hostname, credentials: nil, port: nil, database: nil, **options)
|
45
|
+
uri_klass = SCHEMES.fetch(scheme.downcase) do
|
46
|
+
raise ArgumentError, "Unsupported scheme: #{scheme.inspect}"
|
47
|
+
end
|
48
|
+
|
49
|
+
if database
|
50
|
+
path = "/#{database}"
|
51
|
+
end
|
52
|
+
|
53
|
+
self.new(
|
54
|
+
uri_klass.new(scheme, credentials&.join(":"), hostname, port, nil, path, nil, nil, nil).normalize,
|
55
|
+
**options
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Coerce the given object into an endpoint.
|
60
|
+
# @parameter url [String | Endpoint] The URL or endpoint to convert.
|
61
|
+
def self.[](object)
|
62
|
+
if object.is_a?(self)
|
63
|
+
return object
|
64
|
+
else
|
65
|
+
self.parse(object.to_s)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Create a new endpoint.
|
70
|
+
#
|
71
|
+
# @parameter url [URI] The URL to connect to.
|
72
|
+
# @parameter endpoint [Endpoint] The underlying endpoint to use.
|
73
|
+
# @parameter scheme [String] The scheme to use, e.g. "redis" or "rediss".
|
74
|
+
# @parameter hostname [String] The hostname to connect to (or bind to), overrides the URL hostname (used for SNI).
|
75
|
+
# @parameter port [Integer] The port to bind to, overrides the URL port.
|
76
|
+
def initialize(url, endpoint = nil, **options)
|
77
|
+
super(**options)
|
78
|
+
|
79
|
+
raise ArgumentError, "URL must be absolute (include scheme, host): #{url}" unless url.absolute?
|
80
|
+
|
81
|
+
@url = url
|
82
|
+
|
83
|
+
if endpoint
|
84
|
+
@endpoint = self.build_endpoint(endpoint)
|
85
|
+
else
|
86
|
+
@endpoint = nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_url
|
91
|
+
url = @url.dup
|
92
|
+
|
93
|
+
unless default_port?
|
94
|
+
url.port = self.port
|
95
|
+
end
|
96
|
+
|
97
|
+
return url
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_s
|
101
|
+
"\#<#{self.class} #{self.to_url} #{@options}>"
|
102
|
+
end
|
103
|
+
|
104
|
+
def inspect
|
105
|
+
"\#<#{self.class} #{self.to_url} #{@options.inspect}>"
|
106
|
+
end
|
107
|
+
|
108
|
+
attr :url
|
109
|
+
|
110
|
+
def address
|
111
|
+
endpoint.address
|
112
|
+
end
|
113
|
+
|
114
|
+
def secure?
|
115
|
+
['rediss'].include?(self.scheme)
|
116
|
+
end
|
117
|
+
|
118
|
+
def protocol
|
119
|
+
protocol = @options.fetch(:protocol, Protocol::RESP2)
|
120
|
+
|
121
|
+
if credentials = self.credentials
|
122
|
+
protocol = Protocol::Authenticated.new(credentials, protocol)
|
123
|
+
end
|
124
|
+
|
125
|
+
if database = self.database
|
126
|
+
protocol = Protocol::Selected.new(database, protocol)
|
127
|
+
end
|
128
|
+
|
129
|
+
return protocol
|
130
|
+
end
|
131
|
+
|
132
|
+
def default_port
|
133
|
+
6379
|
134
|
+
end
|
135
|
+
|
136
|
+
def default_port?
|
137
|
+
port == default_port
|
138
|
+
end
|
139
|
+
|
140
|
+
def port
|
141
|
+
@options[:port] || @url.port || default_port
|
142
|
+
end
|
143
|
+
|
144
|
+
# The hostname is the server we are connecting to:
|
145
|
+
def hostname
|
146
|
+
@options[:hostname] || @url.hostname
|
147
|
+
end
|
148
|
+
|
149
|
+
def scheme
|
150
|
+
@options[:scheme] || @url.scheme
|
151
|
+
end
|
152
|
+
|
153
|
+
def database
|
154
|
+
@options[:database] || extract_database(@url.path)
|
155
|
+
end
|
156
|
+
|
157
|
+
private def extract_database(path)
|
158
|
+
if path =~ /\/(\d+)$/
|
159
|
+
return $1.to_i
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def credentials
|
164
|
+
@options[:credentials] || extract_userinfo(@url.userinfo)
|
165
|
+
end
|
166
|
+
|
167
|
+
private def extract_userinfo(userinfo)
|
168
|
+
if userinfo
|
169
|
+
credentials = userinfo.split(":").reject(&:empty?)
|
170
|
+
|
171
|
+
if credentials.any?
|
172
|
+
return credentials
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def localhost?
|
178
|
+
@url.hostname =~ /^(.*?\.)?localhost\.?$/
|
179
|
+
end
|
180
|
+
|
181
|
+
# We don't try to validate peer certificates when talking to localhost because they would always be self-signed.
|
182
|
+
def ssl_verify_mode
|
183
|
+
if self.localhost?
|
184
|
+
OpenSSL::SSL::VERIFY_NONE
|
185
|
+
else
|
186
|
+
OpenSSL::SSL::VERIFY_PEER
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def ssl_context
|
191
|
+
@options[:ssl_context] || OpenSSL::SSL::SSLContext.new.tap do |context|
|
192
|
+
context.set_params(
|
193
|
+
verify_mode: self.ssl_verify_mode
|
194
|
+
)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def build_endpoint(endpoint = nil)
|
199
|
+
endpoint ||= tcp_endpoint
|
200
|
+
|
201
|
+
if secure?
|
202
|
+
# Wrap it in SSL:
|
203
|
+
return ::IO::Endpoint::SSLEndpoint.new(endpoint,
|
204
|
+
ssl_context: self.ssl_context,
|
205
|
+
hostname: @url.hostname,
|
206
|
+
timeout: self.timeout,
|
207
|
+
)
|
208
|
+
end
|
209
|
+
|
210
|
+
return endpoint
|
211
|
+
end
|
212
|
+
|
213
|
+
def endpoint
|
214
|
+
@endpoint ||= build_endpoint
|
215
|
+
end
|
216
|
+
|
217
|
+
def endpoint=(endpoint)
|
218
|
+
@endpoint = build_endpoint(endpoint)
|
219
|
+
end
|
220
|
+
|
221
|
+
def bind(*arguments, &block)
|
222
|
+
endpoint.bind(*arguments, &block)
|
223
|
+
end
|
224
|
+
|
225
|
+
def connect(&block)
|
226
|
+
endpoint.connect(&block)
|
227
|
+
end
|
228
|
+
|
229
|
+
def each
|
230
|
+
return to_enum unless block_given?
|
231
|
+
|
232
|
+
self.tcp_endpoint.each do |endpoint|
|
233
|
+
yield self.class.new(@url, endpoint, **@options)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def key
|
238
|
+
[@url, @options]
|
239
|
+
end
|
240
|
+
|
241
|
+
def eql? other
|
242
|
+
self.key.eql? other.key
|
243
|
+
end
|
244
|
+
|
245
|
+
def hash
|
246
|
+
self.key.hash
|
247
|
+
end
|
248
|
+
|
249
|
+
protected
|
250
|
+
|
251
|
+
def tcp_options
|
252
|
+
options = @options.dup
|
253
|
+
|
254
|
+
options.delete(:scheme)
|
255
|
+
options.delete(:port)
|
256
|
+
options.delete(:hostname)
|
257
|
+
options.delete(:ssl_context)
|
258
|
+
options.delete(:protocol)
|
259
|
+
|
260
|
+
return options
|
261
|
+
end
|
262
|
+
|
263
|
+
def tcp_endpoint
|
264
|
+
::IO::Endpoint.tcp(self.hostname, port, **tcp_options)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'protocol/redis'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module Redis
|
10
|
+
module Protocol
|
11
|
+
# Executes AUTH after the user has established a connection.
|
12
|
+
class Authenticated
|
13
|
+
# Authentication has failed for some reason.
|
14
|
+
class AuthenticationError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create a new authenticated protocol.
|
18
|
+
#
|
19
|
+
# @parameter credentials [Array] The credentials to use for authentication.
|
20
|
+
# @parameter protocol [Object] The delegated protocol for connecting.
|
21
|
+
def initialize(credentials, protocol = Async::Redis::Protocol::RESP2)
|
22
|
+
@credentials = credentials
|
23
|
+
@protocol = protocol
|
24
|
+
end
|
25
|
+
|
26
|
+
attr :credentials
|
27
|
+
|
28
|
+
# Create a new client and authenticate it.
|
29
|
+
def client(stream)
|
30
|
+
client = @protocol.client(stream)
|
31
|
+
|
32
|
+
client.write_request(["AUTH", *@credentials])
|
33
|
+
response = client.read_response
|
34
|
+
|
35
|
+
if response != "OK"
|
36
|
+
raise AuthenticationError, "Could not authenticate: #{response}"
|
37
|
+
end
|
38
|
+
|
39
|
+
return client
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2024, by Samuel Williams.
|
5
|
+
|
6
|
+
require 'protocol/redis'
|
7
|
+
|
8
|
+
module Async
|
9
|
+
module Redis
|
10
|
+
module Protocol
|
11
|
+
# Executes AUTH after the user has established a connection.
|
12
|
+
class Selected
|
13
|
+
# Authentication has failed for some reason.
|
14
|
+
class SelectionError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create a new authenticated protocol.
|
18
|
+
#
|
19
|
+
# @parameter index [Integer] The database index to select.
|
20
|
+
# @parameter protocol [Object] The delegated protocol for connecting.
|
21
|
+
def initialize(index, protocol = Async::Redis::Protocol::RESP2)
|
22
|
+
@index = index
|
23
|
+
@protocol = protocol
|
24
|
+
end
|
25
|
+
|
26
|
+
attr :index
|
27
|
+
|
28
|
+
# Create a new client and authenticate it.
|
29
|
+
def client(stream)
|
30
|
+
client = @protocol.client(stream)
|
31
|
+
|
32
|
+
client.write_request(["SELECT", @index])
|
33
|
+
response = client.read_response
|
34
|
+
|
35
|
+
if response != "OK"
|
36
|
+
raise SelectionError, "Could not select database: #{response}"
|
37
|
+
end
|
38
|
+
|
39
|
+
return client
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -11,17 +11,18 @@ module Async
|
|
11
11
|
class SentinelsClient < Client
|
12
12
|
def initialize(master_name, sentinels, role = :master, protocol = Protocol::RESP2, **options)
|
13
13
|
@master_name = master_name
|
14
|
+
|
14
15
|
@sentinel_endpoints = sentinels.map do |sentinel|
|
15
16
|
::IO::Endpoint.tcp(sentinel[:host], sentinel[:port])
|
16
17
|
end
|
18
|
+
|
17
19
|
@role = role
|
18
|
-
|
19
20
|
@protocol = protocol
|
20
21
|
@pool = connect(**options)
|
21
22
|
end
|
22
|
-
|
23
|
+
|
23
24
|
private
|
24
|
-
|
25
|
+
|
25
26
|
# Override the parent method. The only difference is that this one needs
|
26
27
|
# to resolve the master/slave address.
|
27
28
|
def connect(**options)
|
@@ -29,66 +30,72 @@ module Async
|
|
29
30
|
endpoint = resolve_address
|
30
31
|
peer = endpoint.connect
|
31
32
|
stream = ::IO::Stream(peer)
|
32
|
-
|
33
|
+
|
33
34
|
@protocol.client(stream)
|
34
35
|
end
|
35
36
|
end
|
36
|
-
|
37
|
+
|
37
38
|
def resolve_address
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
case @role
|
40
|
+
when :master
|
41
|
+
resolve_master
|
42
|
+
when :slave
|
43
|
+
resolve_slave
|
44
|
+
else
|
45
|
+
raise ArgumentError, "Unknown instance role #{@role}"
|
46
|
+
end => address
|
47
|
+
|
44
48
|
address or raise RuntimeError, "Unable to fetch #{@role} via Sentinel."
|
45
49
|
end
|
46
|
-
|
50
|
+
|
47
51
|
def resolve_master
|
48
52
|
@sentinel_endpoints.each do |sentinel_endpoint|
|
49
|
-
client = Client.new(sentinel_endpoint)
|
50
|
-
|
53
|
+
client = Client.new(sentinel_endpoint, protocol: @protocol)
|
54
|
+
|
51
55
|
begin
|
52
56
|
address = client.call('sentinel', 'get-master-addr-by-name', @master_name)
|
53
57
|
rescue Errno::ECONNREFUSED
|
54
58
|
next
|
55
59
|
end
|
56
|
-
|
60
|
+
|
57
61
|
return ::IO::Endpoint.tcp(address[0], address[1]) if address
|
58
62
|
end
|
59
|
-
|
63
|
+
|
60
64
|
nil
|
61
65
|
end
|
62
|
-
|
66
|
+
|
63
67
|
def resolve_slave
|
64
68
|
@sentinel_endpoints.each do |sentinel_endpoint|
|
65
|
-
client = Client.new(sentinel_endpoint)
|
66
|
-
|
69
|
+
client = Client.new(sentinel_endpoint, protocol: @protocol)
|
70
|
+
|
67
71
|
begin
|
68
72
|
reply = client.call('sentinel', 'slaves', @master_name)
|
69
73
|
rescue Errno::ECONNREFUSED
|
70
74
|
next
|
71
75
|
end
|
72
|
-
|
76
|
+
|
73
77
|
slaves = available_slaves(reply)
|
74
78
|
next if slaves.empty?
|
75
|
-
|
79
|
+
|
76
80
|
slave = select_slave(slaves)
|
77
81
|
return ::IO::Endpoint.tcp(slave['ip'], slave['port'])
|
78
82
|
end
|
79
|
-
|
83
|
+
|
80
84
|
nil
|
81
85
|
end
|
82
|
-
|
83
|
-
def available_slaves(
|
86
|
+
|
87
|
+
def available_slaves(reply)
|
84
88
|
# The reply is an array with the format: [field1, value1, field2,
|
85
89
|
# value2, etc.].
|
86
90
|
# When a slave is marked as down by the sentinel, the "flags" field
|
87
91
|
# (comma-separated array) contains the "s_down" value.
|
88
|
-
|
89
|
-
|
92
|
+
slaves = reply.map{|fields| fields.each_slice(2).to_h}
|
93
|
+
|
94
|
+
slaves.reject do |slave|
|
95
|
+
slave['flags'].split(',').include?('s_down')
|
96
|
+
end
|
90
97
|
end
|
91
|
-
|
98
|
+
|
92
99
|
def select_slave(available_slaves)
|
93
100
|
available_slaves.sample
|
94
101
|
end
|
data/lib/async/redis/version.rb
CHANGED
data/readme.md
CHANGED
@@ -6,9 +6,9 @@ An asynchronous client for Redis including TLS. Support for streaming requests a
|
|
6
6
|
|
7
7
|
## Usage
|
8
8
|
|
9
|
-
Please see the [project documentation](https://github.
|
9
|
+
Please see the [project documentation](https://socketry.github.io/async-redis/) for more details.
|
10
10
|
|
11
|
-
- [Getting Started](https://github.
|
11
|
+
- [Getting Started](https://socketry.github.io/async-redis/guides/getting-started/index) - This guide explains how to use the `async-redis` gem to connect to a Redis server and perform basic operations.
|
12
12
|
|
13
13
|
## Contributing
|
14
14
|
|
@@ -22,8 +22,8 @@ We welcome contributions to this project.
|
|
22
22
|
|
23
23
|
### Developer Certificate of Origin
|
24
24
|
|
25
|
-
|
25
|
+
In order to protect users of this project, we require all contributors to comply with the [Developer Certificate of Origin](https://developercertificate.org/). This ensures that all contributions are properly licensed and attributed.
|
26
26
|
|
27
|
-
###
|
27
|
+
### Community Guidelines
|
28
28
|
|
29
|
-
This project is
|
29
|
+
This project is best served by a collaborative and respectful environment. Treat each other professionally, respect differing viewpoints, and engage constructively. Harassment, discrimination, or harmful behavior is not tolerated. Communicate clearly, listen actively, and support one another. If any issues arise, please inform the project maintainers.
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -48,28 +48,22 @@ cert_chain:
|
|
48
48
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
49
49
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
50
50
|
-----END CERTIFICATE-----
|
51
|
-
date: 2024-
|
51
|
+
date: 2024-08-16 00:00:00.000000000 Z
|
52
52
|
dependencies:
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: async
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
|
-
- - "
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: '1.8'
|
60
|
-
- - "<"
|
57
|
+
- - "~>"
|
61
58
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
59
|
+
version: '2.10'
|
63
60
|
type: :runtime
|
64
61
|
prerelease: false
|
65
62
|
version_requirements: !ruby/object:Gem::Requirement
|
66
63
|
requirements:
|
67
|
-
- - "
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '1.8'
|
70
|
-
- - "<"
|
64
|
+
- - "~>"
|
71
65
|
- !ruby/object:Gem::Version
|
72
|
-
version: '
|
66
|
+
version: '2.10'
|
73
67
|
- !ruby/object:Gem::Dependency
|
74
68
|
name: async-pool
|
75
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -118,14 +112,14 @@ dependencies:
|
|
118
112
|
requirements:
|
119
113
|
- - "~>"
|
120
114
|
- !ruby/object:Gem::Version
|
121
|
-
version: 0.
|
115
|
+
version: '0.9'
|
122
116
|
type: :runtime
|
123
117
|
prerelease: false
|
124
118
|
version_requirements: !ruby/object:Gem::Requirement
|
125
119
|
requirements:
|
126
120
|
- - "~>"
|
127
121
|
- !ruby/object:Gem::Version
|
128
|
-
version: 0.
|
122
|
+
version: '0.9'
|
129
123
|
description:
|
130
124
|
email:
|
131
125
|
executables: []
|
@@ -138,8 +132,11 @@ files:
|
|
138
132
|
- lib/async/redis/context/pipeline.rb
|
139
133
|
- lib/async/redis/context/subscribe.rb
|
140
134
|
- lib/async/redis/context/transaction.rb
|
135
|
+
- lib/async/redis/endpoint.rb
|
141
136
|
- lib/async/redis/key.rb
|
137
|
+
- lib/async/redis/protocol/authenticated.rb
|
142
138
|
- lib/async/redis/protocol/resp2.rb
|
139
|
+
- lib/async/redis/protocol/selected.rb
|
143
140
|
- lib/async/redis/sentinels.rb
|
144
141
|
- lib/async/redis/version.rb
|
145
142
|
- license.md
|
@@ -148,6 +145,7 @@ homepage: https://github.com/socketry/async-redis
|
|
148
145
|
licenses:
|
149
146
|
- MIT
|
150
147
|
metadata:
|
148
|
+
documentation_uri: https://socketry.github.io/async-redis/
|
151
149
|
source_code_uri: https://github.com/socketry/async-redis.git
|
152
150
|
post_install_message:
|
153
151
|
rdoc_options: []
|
@@ -164,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
162
|
- !ruby/object:Gem::Version
|
165
163
|
version: '0'
|
166
164
|
requirements: []
|
167
|
-
rubygems_version: 3.5.
|
165
|
+
rubygems_version: 3.5.11
|
168
166
|
signing_key:
|
169
167
|
specification_version: 4
|
170
168
|
summary: A Redis client library.
|
metadata.gz.sig
CHANGED
Binary file
|