redis 4.2.5 → 4.3.1

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: 862e8133262fead707e4ca317b29d0e35425e3a7861ea1a52033bc91ba61bf6d
4
- data.tar.gz: 5b2b32250d783fe58b0af54cc386f2568241644a0badc0b7247bb29b1ac94a93
3
+ metadata.gz: 416a2f007042c19453c13361aa4440a507e47fb32c28adc68e7c574c6651f5b4
4
+ data.tar.gz: 1a845f2af649d64f8b274962c9d5d10e6eb5d046474b6e44288676432fe8a98b
5
5
  SHA512:
6
- metadata.gz: 2aab289f4f22b2f3a804ca7b0da4cf95e352a8d246611490d8d803edebbbc7e7c299355cd0b90e6f3ac8bc0d11e9bf3792a328c95847d32e1d984729afe66ed2
7
- data.tar.gz: d9ec8ba4d314d099e909cdddf6dfb4c3c14b853b46f45c4909ac3ba10fb1880bd9a7b0465257fa91f9a4ea6c9f82723c16c177810ac15c89fab3790d7af31ad0
6
+ metadata.gz: 3766992242ae284ca474bc8564c6760de88e635a8c3bc3c80da08062d698cc891bf00455b5d98768709ecc766f8ad305fe03cc5806f03fda3ebb93049e0a1cce
7
+ data.tar.gz: f440c984ec58ff091a6a696952239cb04cf145752b485543e5da7215a327b40be4391b3fe6ca67753f84ec43913b9d90ec0b6f812e1696890a7c17cbf3aa3630
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Unreleased
2
2
 
3
+ # 4.3.1
4
+
5
+ * Fix password authentication against redis server 5 and older.
6
+
7
+ # 4.3.0
8
+
9
+ * Add the TYPE argument to scan and scan_each. See #985.
10
+ * Support AUTH command for ACL. See #967.
11
+
3
12
  # 4.2.5
4
13
 
5
14
  * Optimize the ruby connector write buffering. See #964.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # redis-rb [![Build Status][travis-image]][travis-link] [![Inline docs][inchpages-image]][inchpages-link] ![](https://github.com/redis/redis-rb/workflows/Test/badge.svg?branch=master)
1
+ # redis-rb [![Build Status][gh-actions-image]][gh-actions-link] [![Inline docs][inchpages-image]][inchpages-link]
2
2
 
3
3
  A Ruby client that tries to match [Redis][redis-home]' API one-to-one, while still
4
4
  providing an idiomatic interface.
@@ -54,6 +54,12 @@ To connect to a password protected Redis instance, use:
54
54
  redis = Redis.new(password: "mysecret")
55
55
  ```
56
56
 
57
+ To connect a Redis instance using [ACL](https://redis.io/topics/acl), use:
58
+
59
+ ```ruby
60
+ redis = Redis.new(username: 'myname', password: 'mysecret')
61
+ ```
62
+
57
63
  The Redis class exports methods that are named identical to the commands
58
64
  they execute. The arguments these methods accept are often identical to
59
65
  the arguments specified on the [Redis website][redis-commands]. For
@@ -440,7 +446,7 @@ redis = Redis.new(:driver => :synchrony)
440
446
  ## Testing
441
447
 
442
448
  This library is tested against recent Ruby and Redis versions.
443
- Check [Travis][travis-link] for the exact versions supported.
449
+ Check [Github Actions][gh-actions-link] for the exact versions supported.
444
450
 
445
451
  ## See Also
446
452
 
@@ -459,12 +465,11 @@ client and evangelized Redis in Rubyland. Thank you, Ezra.
459
465
  requests.
460
466
 
461
467
 
462
- [inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
463
- [inchpages-link]: https://inch-ci.org/github/redis/redis-rb
464
- [redis-commands]: https://redis.io/commands
465
- [redis-home]: https://redis.io
466
- [redis-url]: http://www.iana.org/assignments/uri-schemes/prov/redis
467
- [travis-home]: https://travis-ci.org/
468
- [travis-image]: https://secure.travis-ci.org/redis/redis-rb.svg?branch=master
469
- [travis-link]: https://travis-ci.org/redis/redis-rb
470
- [rubydoc]: http://www.rubydoc.info/gems/redis
468
+ [inchpages-image]: https://inch-ci.org/github/redis/redis-rb.svg
469
+ [inchpages-link]: https://inch-ci.org/github/redis/redis-rb
470
+ [redis-commands]: https://redis.io/commands
471
+ [redis-home]: https://redis.io
472
+ [redis-url]: http://www.iana.org/assignments/uri-schemes/prov/redis
473
+ [gh-actions-image]: https://github.com/redis/redis-rb/workflows/Test/badge.svg
474
+ [gh-actions-link]: https://github.com/redis/redis-rb/actions
475
+ [rubydoc]: http://www.rubydoc.info/gems/redis
data/lib/redis.rb CHANGED
@@ -39,6 +39,7 @@ class Redis
39
39
  # @option options [String] :path path to server socket (overrides host and port)
40
40
  # @option options [Float] :timeout (5.0) timeout in seconds
41
41
  # @option options [Float] :connect_timeout (same as timeout) timeout for initial connect in seconds
42
+ # @option options [String] :username Username to authenticate against server
42
43
  # @option options [String] :password Password to authenticate against server
43
44
  # @option options [Integer] :db (0) Database to select after initial connect
44
45
  # @option options [Symbol] :driver Driver to use, currently supported: `:ruby`, `:hiredis`, `:synchrony`
@@ -143,12 +144,13 @@ class Redis
143
144
 
144
145
  # Authenticate to the server.
145
146
  #
146
- # @param [String] password must match the password specified in the
147
- # `requirepass` directive in the configuration file
147
+ # @param [Array<String>] args includes both username and password
148
+ # or only password
148
149
  # @return [String] `OK`
149
- def auth(password)
150
+ # @see https://redis.io/commands/auth AUTH command
151
+ def auth(*args)
150
152
  synchronize do |client|
151
- client.call([:auth, password])
153
+ client.call([:auth, *args])
152
154
  end
153
155
  end
154
156
 
@@ -1170,23 +1172,29 @@ class Redis
1170
1172
  end
1171
1173
  end
1172
1174
 
1173
- # Remove and get the first element in a list.
1175
+ # Remove and get the first elements in a list.
1174
1176
  #
1175
1177
  # @param [String] key
1176
- # @return [String]
1177
- def lpop(key)
1178
+ # @param [Integer] count number of elements to remove
1179
+ # @return [String, Array<String>] the values of the first elements
1180
+ def lpop(key, count = nil)
1178
1181
  synchronize do |client|
1179
- client.call([:lpop, key])
1182
+ command = [:lpop, key]
1183
+ command << count if count
1184
+ client.call(command)
1180
1185
  end
1181
1186
  end
1182
1187
 
1183
- # Remove and get the last element in a list.
1188
+ # Remove and get the last elements in a list.
1184
1189
  #
1185
1190
  # @param [String] key
1186
- # @return [String]
1187
- def rpop(key)
1191
+ # @param [Integer] count number of elements to remove
1192
+ # @return [String, Array<String>] the values of the last elements
1193
+ def rpop(key, count = nil)
1188
1194
  synchronize do |client|
1189
- client.call([:rpop, key])
1195
+ command = [:rpop, key]
1196
+ command << count if count
1197
+ client.call(command)
1190
1198
  end
1191
1199
  end
1192
1200
 
@@ -2636,12 +2644,13 @@ class Redis
2636
2644
  _eval(:evalsha, args)
2637
2645
  end
2638
2646
 
2639
- def _scan(command, cursor, args, match: nil, count: nil, &block)
2647
+ def _scan(command, cursor, args, match: nil, count: nil, type: nil, &block)
2640
2648
  # SSCAN/ZSCAN/HSCAN already prepend the key to +args+.
2641
2649
 
2642
2650
  args << cursor
2643
2651
  args << "MATCH" << match if match
2644
2652
  args << "COUNT" << count if count
2653
+ args << "TYPE" << type if type
2645
2654
 
2646
2655
  synchronize do |client|
2647
2656
  client.call([command] + args, &block)
@@ -2656,11 +2665,15 @@ class Redis
2656
2665
  # @example Retrieve a batch of keys matching a pattern
2657
2666
  # redis.scan(4, :match => "key:1?")
2658
2667
  # # => ["92", ["key:13", "key:18"]]
2668
+ # @example Retrieve a batch of keys of a certain type
2669
+ # redis.scan(92, :type => "zset")
2670
+ # # => ["173", ["sortedset:14", "sortedset:78"]]
2659
2671
  #
2660
2672
  # @param [String, Integer] cursor the cursor of the iteration
2661
2673
  # @param [Hash] options
2662
2674
  # - `:match => String`: only return keys matching the pattern
2663
2675
  # - `:count => Integer`: return count keys at most per iteration
2676
+ # - `:type => String`: return keys only of the given type
2664
2677
  #
2665
2678
  # @return [String, Array<String>] the next cursor and all found keys
2666
2679
  def scan(cursor, **options)
@@ -2676,10 +2689,15 @@ class Redis
2676
2689
  # redis.scan_each(:match => "key:1?") {|key| puts key}
2677
2690
  # # => key:13
2678
2691
  # # => key:18
2692
+ # @example Execute block for each key of a type
2693
+ # redis.scan_each(:type => "hash") {|key| puts redis.type(key)}
2694
+ # # => "hash"
2695
+ # # => "hash"
2679
2696
  #
2680
2697
  # @param [Hash] options
2681
2698
  # - `:match => String`: only return keys matching the pattern
2682
2699
  # - `:count => Integer`: return count keys at most per iteration
2700
+ # - `:type => String`: return keys only of the given type
2683
2701
  #
2684
2702
  # @return [Enumerator] an enumerator for all found keys
2685
2703
  def scan_each(**options, &block)
data/lib/redis/client.rb CHANGED
@@ -17,6 +17,7 @@ class Redis
17
17
  write_timeout: nil,
18
18
  connect_timeout: nil,
19
19
  timeout: 5.0,
20
+ username: nil,
20
21
  password: nil,
21
22
  db: 0,
22
23
  driver: nil,
@@ -61,6 +62,10 @@ class Redis
61
62
  @options[:read_timeout]
62
63
  end
63
64
 
65
+ def username
66
+ @options[:username]
67
+ end
68
+
64
69
  def password
65
70
  @options[:password]
66
71
  end
@@ -110,7 +115,17 @@ class Redis
110
115
  # Don't try to reconnect when the connection is fresh
111
116
  with_reconnect(false) do
112
117
  establish_connection
113
- call [:auth, password] if password
118
+ if password
119
+ if username
120
+ begin
121
+ call [:auth, username, password]
122
+ rescue CommandError # Likely on Redis < 6
123
+ call [:auth, password]
124
+ end
125
+ else
126
+ call [:auth, password]
127
+ end
128
+ end
114
129
  call [:select, db] if db != 0
115
130
  call [:client, :setname, @options[:id]] if @options[:id]
116
131
  @connector.check(self)
@@ -131,7 +146,7 @@ class Redis
131
146
  reply = process([command]) { read }
132
147
  raise reply if reply.is_a?(CommandError)
133
148
 
134
- if block_given?
149
+ if block_given? && reply != 'QUEUED'
135
150
  yield reply
136
151
  else
137
152
  reply
@@ -434,7 +449,8 @@ class Redis
434
449
  defaults[:scheme] = uri.scheme
435
450
  defaults[:host] = uri.host if uri.host
436
451
  defaults[:port] = uri.port if uri.port
437
- defaults[:password] = CGI.unescape(uri.password) if uri.password
452
+ defaults[:username] = CGI.unescape(uri.user) if uri.user && !uri.user.empty?
453
+ defaults[:password] = CGI.unescape(uri.password) if uri.password && !uri.password.empty?
438
454
  defaults[:db] = uri.path[1..-1].to_i if uri.path
439
455
  defaults[:role] = :master
440
456
  else
@@ -510,7 +526,7 @@ class Redis
510
526
  require_relative "connection/#{driver}"
511
527
  rescue LoadError, NameError
512
528
  begin
513
- require "connection/#{driver}"
529
+ require "redis/connection/#{driver}"
514
530
  rescue LoadError, NameError => error
515
531
  raise "Cannot load driver #{driver.inspect}: #{error.message}"
516
532
  end
@@ -579,6 +595,7 @@ class Redis
579
595
  client = Client.new(@options.merge({
580
596
  host: sentinel[:host] || sentinel["host"],
581
597
  port: sentinel[:port] || sentinel["port"],
598
+ username: sentinel[:username] || sentinel["username"],
582
599
  password: sentinel[:password] || sentinel["password"],
583
600
  reconnect_attempts: 0
584
601
  }))
data/lib/redis/cluster.rb CHANGED
@@ -128,7 +128,7 @@ class Redis
128
128
  def send_command(command, &block)
129
129
  cmd = command.first.to_s.downcase
130
130
  case cmd
131
- when 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
131
+ when 'acl', 'auth', 'bgrewriteaof', 'bgsave', 'quit', 'save'
132
132
  @node.call_all(command, &block).first
133
133
  when 'flushall', 'flushdb'
134
134
  @node.call_master(command, &block).first
@@ -18,6 +18,7 @@ class Redis
18
18
  @node_opts = build_node_options(node_addrs)
19
19
  @replica = options.delete(:replica) == true
20
20
  add_common_node_option_if_needed(options, @node_opts, :scheme)
21
+ add_common_node_option_if_needed(options, @node_opts, :username)
21
22
  add_common_node_option_if_needed(options, @node_opts, :password)
22
23
  @options = options
23
24
  end
@@ -63,7 +64,9 @@ class Redis
63
64
  raise InvalidClientOptionError, "Invalid uri scheme #{addr}" unless VALID_SCHEMES.include?(uri.scheme)
64
65
 
65
66
  db = uri.path.split('/')[1]&.to_i
66
- { scheme: uri.scheme, password: uri.password, host: uri.host, port: uri.port, db: db }.reject { |_, v| v.nil? }
67
+
68
+ { scheme: uri.scheme, username: uri.user, password: uri.password, host: uri.host, port: uri.port, db: db }
69
+ .reject { |_, v| v.nil? || v == '' }
67
70
  rescue URI::InvalidURIError => err
68
71
  raise InvalidClientOptionError, err.message
69
72
  end
@@ -79,7 +82,7 @@ class Redis
79
82
 
80
83
  # Redis cluster node returns only host and port information.
81
84
  # So we should complement additional information such as:
82
- # scheme, password and so on.
85
+ # scheme, username, password and so on.
83
86
  def add_common_node_option_if_needed(options, node_opts, key)
84
87
  return options if options[key].nil? && node_opts.first[key].nil?
85
88
 
@@ -413,14 +413,14 @@ class Redis
413
413
  node_for(key).rpushx(key, value)
414
414
  end
415
415
 
416
- # Remove and get the first element in a list.
417
- def lpop(key)
418
- node_for(key).lpop(key)
416
+ # Remove and get the first elements in a list.
417
+ def lpop(key, count = nil)
418
+ node_for(key).lpop(key, count)
419
419
  end
420
420
 
421
- # Remove and get the last element in a list.
422
- def rpop(key)
423
- node_for(key).rpop(key)
421
+ # Remove and get the last elements in a list.
422
+ def rpop(key, count = nil)
423
+ node_for(key).rpop(key, count)
424
424
  end
425
425
 
426
426
  # Remove the last element in a list, append it to another list and return
data/lib/redis/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Redis
4
- VERSION = '4.2.5'
4
+ VERSION = '4.3.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.2.5
4
+ version: 4.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ezra Zygmuntowicz
@@ -16,7 +16,7 @@ authors:
16
16
  autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
- date: 2020-11-20 00:00:00.000000000 Z
19
+ date: 2021-06-11 00:00:00.000000000 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: em-synchrony
@@ -102,9 +102,9 @@ licenses:
102
102
  metadata:
103
103
  bug_tracker_uri: https://github.com/redis/redis-rb/issues
104
104
  changelog_uri: https://github.com/redis/redis-rb/blob/master/CHANGELOG.md
105
- documentation_uri: https://www.rubydoc.info/gems/redis/4.2.5
105
+ documentation_uri: https://www.rubydoc.info/gems/redis/4.3.1
106
106
  homepage_uri: https://github.com/redis/redis-rb
107
- source_code_uri: https://github.com/redis/redis-rb/tree/v4.2.5
107
+ source_code_uri: https://github.com/redis/redis-rb/tree/v4.3.1
108
108
  post_install_message:
109
109
  rdoc_options: []
110
110
  require_paths: