async-redis 0.8.0 → 0.9.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: 46c7b31b58959e0fe6165b3c2b506d9948d095477a5c9efd656dbcb590bfbfe1
4
- data.tar.gz: 5d1b6ba10c70e35796b3ee7d02d2be2678dbb99c5fec21be5c2a37eb38aeea41
3
+ metadata.gz: 97fe8ed81d0096bd994cbbd3511fc3acb7c0c4629cfafdac47e5c237137083f1
4
+ data.tar.gz: c8a5b6a33efb6de45dc7cc2154b694fbd9337a14c485f85f1693bfeabbcc0f79
5
5
  SHA512:
6
- metadata.gz: 7c117ee7b68fc57780806754c976686bfff540e22e2077b518892fcd863fe9b86b98dbbf69a37dd7b647f7bf6ad7a4fed1e82071db72c8549fb09bf39e79814a
7
- data.tar.gz: 95870e075f3528b95a3503fc3d597a8e9fefe9e038d2f9f62448a8cb1b6df9fb2ae67dc24e5dbadd4798b3619f09089f6dbe2f1058d53895f2b2636df952152f
6
+ metadata.gz: ad448e4900402ef3e974a247c27a6a8fa5bf65d47fda67b46260830ecfb76a185c86a03ff0c38cd18ae1d628a7ce332d6952e26704d357f3858458fe593fb49d
7
+ data.tar.gz: 83535dc337e792808e6e3033864e393cb075a5d709bd5a8c507577d8b792f0600388f98cd28997c891102c36dc79062c6327004359f51c4677b50bab42eced8a
checksums.yaml.gz.sig CHANGED
Binary file
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2018-2023, by Samuel Williams.
4
+ # Copyright, 2018-2024, by Samuel Williams.
5
5
  # Copyright, 2018, by Huba Nagy.
6
6
  # Copyright, 2019, by Mikael Henriksson.
7
7
  # Copyright, 2019, by David Ortiz.
@@ -10,28 +10,23 @@
10
10
  require_relative 'context/pipeline'
11
11
  require_relative 'context/transaction'
12
12
  require_relative 'context/subscribe'
13
+ require_relative 'endpoint'
13
14
 
14
- require_relative 'protocol/resp2'
15
-
16
- require 'async/io'
17
- require 'async/io/stream'
15
+ require 'io/endpoint/host_endpoint'
18
16
  require 'async/pool/controller'
19
-
20
17
  require 'protocol/redis/methods'
21
18
 
19
+ require 'io/stream'
20
+
22
21
  module Async
23
22
  module Redis
24
23
  # Legacy.
25
24
  ServerError = ::Protocol::Redis::ServerError
26
25
 
27
- def self.local_endpoint(port: 6379)
28
- Async::IO::Endpoint.tcp('localhost', port)
29
- end
30
-
31
26
  class Client
32
27
  include ::Protocol::Redis::Methods
33
28
 
34
- def initialize(endpoint = Redis.local_endpoint, protocol: Protocol::RESP2, **options)
29
+ def initialize(endpoint = Endpoint.local, protocol: endpoint.protocol, **options)
35
30
  @endpoint = endpoint
36
31
  @protocol = protocol
37
32
 
@@ -121,7 +116,7 @@ module Async
121
116
  # We will manage flushing ourselves:
122
117
  peer.sync = true
123
118
 
124
- stream = IO::Stream.new(peer)
119
+ stream = ::IO::Stream(peer)
125
120
 
126
121
  @protocol.client(stream)
127
122
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2019, by David Ortiz.
5
- # Copyright, 2019-2023, by Samuel Williams.
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(command, *arguments)
26
- @pipeline.call(command, *arguments)
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
- ensure
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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2018-2023, by Samuel Williams.
4
+ # Copyright, 2018-2024, by Samuel Williams.
5
5
 
6
6
  require 'protocol/redis'
7
7
 
@@ -15,7 +15,7 @@ module Async
15
15
  end
16
16
 
17
17
  def viable?
18
- @stream.connected?
18
+ @stream.readable?
19
19
  end
20
20
 
21
21
  def reusable?
@@ -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
@@ -2,91 +2,100 @@
2
2
 
3
3
  # Released under the MIT License.
4
4
  # Copyright, 2020, by David Ortiz.
5
- # Copyright, 2023, by Samuel Williams.
5
+ # Copyright, 2023-2024, by Samuel Williams.
6
+
7
+ require 'io/stream'
6
8
 
7
9
  module Async
8
10
  module Redis
9
11
  class SentinelsClient < Client
10
12
  def initialize(master_name, sentinels, role = :master, protocol = Protocol::RESP2, **options)
11
13
  @master_name = master_name
14
+
12
15
  @sentinel_endpoints = sentinels.map do |sentinel|
13
- Async::IO::Endpoint.tcp(sentinel[:host], sentinel[:port])
16
+ ::IO::Endpoint.tcp(sentinel[:host], sentinel[:port])
14
17
  end
18
+
15
19
  @role = role
16
-
17
20
  @protocol = protocol
18
21
  @pool = connect(**options)
19
22
  end
20
-
23
+
21
24
  private
22
-
25
+
23
26
  # Override the parent method. The only difference is that this one needs
24
27
  # to resolve the master/slave address.
25
28
  def connect(**options)
26
29
  Async::Pool::Controller.wrap(**options) do
27
30
  endpoint = resolve_address
28
31
  peer = endpoint.connect
29
- stream = IO::Stream.new(peer)
30
-
32
+ stream = ::IO::Stream(peer)
33
+
31
34
  @protocol.client(stream)
32
35
  end
33
36
  end
34
-
37
+
35
38
  def resolve_address
36
- address = case @role
37
- when :master then resolve_master
38
- when :slave then resolve_slave
39
- else raise ArgumentError, "Unknown instance role #{@role}"
40
- end
41
-
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
+
42
48
  address or raise RuntimeError, "Unable to fetch #{@role} via Sentinel."
43
49
  end
44
-
50
+
45
51
  def resolve_master
46
52
  @sentinel_endpoints.each do |sentinel_endpoint|
47
- client = Client.new(sentinel_endpoint)
48
-
53
+ client = Client.new(sentinel_endpoint, protocol: @protocol)
54
+
49
55
  begin
50
56
  address = client.call('sentinel', 'get-master-addr-by-name', @master_name)
51
57
  rescue Errno::ECONNREFUSED
52
58
  next
53
59
  end
54
-
55
- return Async::IO::Endpoint.tcp(address[0], address[1]) if address
60
+
61
+ return ::IO::Endpoint.tcp(address[0], address[1]) if address
56
62
  end
57
-
63
+
58
64
  nil
59
65
  end
60
-
66
+
61
67
  def resolve_slave
62
68
  @sentinel_endpoints.each do |sentinel_endpoint|
63
- client = Client.new(sentinel_endpoint)
64
-
69
+ client = Client.new(sentinel_endpoint, protocol: @protocol)
70
+
65
71
  begin
66
72
  reply = client.call('sentinel', 'slaves', @master_name)
67
73
  rescue Errno::ECONNREFUSED
68
74
  next
69
75
  end
70
-
76
+
71
77
  slaves = available_slaves(reply)
72
78
  next if slaves.empty?
73
-
79
+
74
80
  slave = select_slave(slaves)
75
- return Async::IO::Endpoint.tcp(slave['ip'], slave['port'])
81
+ return ::IO::Endpoint.tcp(slave['ip'], slave['port'])
76
82
  end
77
-
83
+
78
84
  nil
79
85
  end
80
-
81
- def available_slaves(slaves_cmd_reply)
86
+
87
+ def available_slaves(reply)
82
88
  # The reply is an array with the format: [field1, value1, field2,
83
89
  # value2, etc.].
84
90
  # When a slave is marked as down by the sentinel, the "flags" field
85
91
  # (comma-separated array) contains the "s_down" value.
86
- slaves_cmd_reply.map { |s| s.each_slice(2).to_h }
87
- .reject { |s| s.fetch('flags').split(',').include?('s_down') }
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
88
97
  end
89
-
98
+
90
99
  def select_slave(available_slaves)
91
100
  available_slaves.sample
92
101
  end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2018-2023, by Samuel Williams.
4
+ # Copyright, 2018-2024, by Samuel Williams.
5
5
 
6
6
  module Async
7
7
  module Redis
8
- VERSION = "0.8.0"
8
+ VERSION = "0.9.0"
9
9
  end
10
10
  end
data/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2018-2023, by Samuel Williams.
3
+ Copyright, 2018-2024, by Samuel Williams.
4
4
  Copyright, 2018, by Huba Nagy.
5
5
  Copyright, 2019-2020, by David Ortiz.
6
6
  Copyright, 2019, by Pierre Montelle.
data/readme.md CHANGED
@@ -1,111 +1,14 @@
1
1
  # Async::Redis
2
2
 
3
- An asynchronous client for Redis including TLS. Support for streaming requests and responses. Built on top of [async](https://github.com/socketry/async) and [async-io](https://github.com/socketry/async-io).
3
+ An asynchronous client for Redis including TLS. Support for streaming requests and responses. Built on top of [async](https://github.com/socketry/async).
4
4
 
5
5
  [![Development Status](https://github.com/socketry/async-redis/workflows/Test/badge.svg)](https://github.com/socketry/async-redis/actions?workflow=Test)
6
6
 
7
- ## Installation
8
-
9
- ``` shell
10
- $ bundle add async-redis
11
- ```
12
-
13
7
  ## Usage
14
8
 
15
- ### Basic Local Connection
16
-
17
- ``` ruby
18
- require 'async/redis'
19
-
20
- endpoint = Async::Redis.local_endpoint
21
- client = Async::Redis::Client.new(endpoint)
22
-
23
- Async do
24
- pp client.info
25
- ensure
26
- client.close
27
- end
28
- ```
29
-
30
- ### Connecting to Redis SSL Endpoint
31
-
32
- This example demonstrates parsing an environment variable with a `redis://` or SSL `rediss://` scheme, and demonstrates how you can specify SSL parameters on the SSLContext object.
33
-
34
- ``` ruby
35
- require 'async/redis'
36
-
37
- def make_redis_endpoint(uri)
38
- tcp_endpoint = Async::IO::Endpoint.tcp(uri.hostname, uri.port)
39
- case uri.scheme
40
- when 'redis'
41
- tcp_endpoint
42
- when 'rediss'
43
- ssl_context = OpenSSL::SSL::SSLContext.new
44
- ssl_context.set_params(
45
- ca_file: "/path/to/ca.crt",
46
- cert: OpenSSL::X509::Certificate.new(File.read("client.crt")),
47
- key: OpenSSL::PKey::RSA.new(File.read("client.key")),
48
- )
49
- Async::IO::SSLEndpoint.new(tcp_endpoint, ssl_context: ssl_context)
50
- else
51
- raise ArgumentError
52
- end
53
- end
54
-
55
- endpoint = make_redis_endpoint(URI(ENV['REDIS_URL']))
56
- client = Async::Redis::Client.new(endpoint)
57
-
58
- # ...
59
- ```
9
+ Please see the [project documentation](https://socketry.github.io/async-redis/) for more details.
60
10
 
61
- ### Variables
62
-
63
- ``` ruby
64
- require 'async'
65
- require 'async/redis'
66
-
67
- endpoint = Async::Redis.local_endpoint
68
- client = Async::Redis::Client.new(endpoint)
69
-
70
- Async do
71
- client.set('X', 10)
72
- pp client.get('X')
73
- ensure
74
- client.close
75
- end
76
- ```
77
-
78
- ### Subscriptions
79
-
80
- ``` ruby
81
- require 'async'
82
- require 'async/redis'
83
-
84
- endpoint = Async::Redis.local_endpoint
85
- client = Async::Redis::Client.new(endpoint)
86
-
87
- Async do |task|
88
- condition = Async::Condition.new
89
-
90
- publisher = task.async do
91
- condition.wait
92
-
93
- client.publish 'status.frontend', 'good'
94
- end
95
-
96
- subscriber = task.async do
97
- client.subscribe 'status.frontend' do |context|
98
- condition.signal # We are waiting for messages.
99
-
100
- type, name, message = context.listen
101
-
102
- pp type, name, message
103
- end
104
- end
105
- ensure
106
- client.close
107
- end
108
- ```
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.
109
12
 
110
13
  ## Contributing
111
14
 
@@ -116,3 +19,11 @@ We welcome contributions to this project.
116
19
  3. Commit your changes (`git commit -am 'Add some feature'`).
117
20
  4. Push to the branch (`git push origin my-new-feature`).
118
21
  5. Create new Pull Request.
22
+
23
+ ### Developer Certificate of Origin
24
+
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
+
27
+ ### Community Guidelines
28
+
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.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -48,70 +48,78 @@ cert_chain:
48
48
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
49
49
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
50
50
  -----END CERTIFICATE-----
51
- date: 2023-06-13 00:00:00.000000000 Z
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: '3.0'
59
+ version: '2.10'
63
60
  type: :runtime
64
61
  prerelease: false
65
62
  version_requirements: !ruby/object:Gem::Requirement
66
63
  requirements:
67
- - - ">="
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '2.10'
67
+ - !ruby/object:Gem::Dependency
68
+ name: async-pool
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
68
72
  - !ruby/object:Gem::Version
69
- version: '1.8'
70
- - - "<"
73
+ version: '0.2'
74
+ type: :runtime
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
71
79
  - !ruby/object:Gem::Version
72
- version: '3.0'
80
+ version: '0.2'
73
81
  - !ruby/object:Gem::Dependency
74
- name: async-io
82
+ name: io-endpoint
75
83
  requirement: !ruby/object:Gem::Requirement
76
84
  requirements:
77
85
  - - "~>"
78
86
  - !ruby/object:Gem::Version
79
- version: '1.10'
87
+ version: '0.10'
80
88
  type: :runtime
81
89
  prerelease: false
82
90
  version_requirements: !ruby/object:Gem::Requirement
83
91
  requirements:
84
92
  - - "~>"
85
93
  - !ruby/object:Gem::Version
86
- version: '1.10'
94
+ version: '0.10'
87
95
  - !ruby/object:Gem::Dependency
88
- name: async-pool
96
+ name: io-stream
89
97
  requirement: !ruby/object:Gem::Requirement
90
98
  requirements:
91
99
  - - "~>"
92
100
  - !ruby/object:Gem::Version
93
- version: '0.2'
101
+ version: '0.4'
94
102
  type: :runtime
95
103
  prerelease: false
96
104
  version_requirements: !ruby/object:Gem::Requirement
97
105
  requirements:
98
106
  - - "~>"
99
107
  - !ruby/object:Gem::Version
100
- version: '0.2'
108
+ version: '0.4'
101
109
  - !ruby/object:Gem::Dependency
102
110
  name: protocol-redis
103
111
  requirement: !ruby/object:Gem::Requirement
104
112
  requirements:
105
113
  - - "~>"
106
114
  - !ruby/object:Gem::Version
107
- version: 0.8.0
115
+ version: '0.9'
108
116
  type: :runtime
109
117
  prerelease: false
110
118
  version_requirements: !ruby/object:Gem::Requirement
111
119
  requirements:
112
120
  - - "~>"
113
121
  - !ruby/object:Gem::Version
114
- version: 0.8.0
122
+ version: '0.9'
115
123
  description:
116
124
  email:
117
125
  executables: []
@@ -124,8 +132,11 @@ files:
124
132
  - lib/async/redis/context/pipeline.rb
125
133
  - lib/async/redis/context/subscribe.rb
126
134
  - lib/async/redis/context/transaction.rb
135
+ - lib/async/redis/endpoint.rb
127
136
  - lib/async/redis/key.rb
137
+ - lib/async/redis/protocol/authenticated.rb
128
138
  - lib/async/redis/protocol/resp2.rb
139
+ - lib/async/redis/protocol/selected.rb
129
140
  - lib/async/redis/sentinels.rb
130
141
  - lib/async/redis/version.rb
131
142
  - license.md
@@ -133,7 +144,9 @@ files:
133
144
  homepage: https://github.com/socketry/async-redis
134
145
  licenses:
135
146
  - MIT
136
- metadata: {}
147
+ metadata:
148
+ documentation_uri: https://socketry.github.io/async-redis/
149
+ source_code_uri: https://github.com/socketry/async-redis.git
137
150
  post_install_message:
138
151
  rdoc_options: []
139
152
  require_paths:
@@ -142,14 +155,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
142
155
  requirements:
143
156
  - - ">="
144
157
  - !ruby/object:Gem::Version
145
- version: '0'
158
+ version: '3.1'
146
159
  required_rubygems_version: !ruby/object:Gem::Requirement
147
160
  requirements:
148
161
  - - ">="
149
162
  - !ruby/object:Gem::Version
150
163
  version: '0'
151
164
  requirements: []
152
- rubygems_version: 3.2.33
165
+ rubygems_version: 3.5.11
153
166
  signing_key:
154
167
  specification_version: 4
155
168
  summary: A Redis client library.
metadata.gz.sig CHANGED
Binary file