redis-client 0.2.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/Gemfile +1 -2
  4. data/Gemfile.lock +2 -3
  5. data/README.md +71 -8
  6. data/Rakefile +43 -23
  7. data/lib/redis_client/command_builder.rb +91 -0
  8. data/lib/redis_client/config.rb +19 -50
  9. data/lib/redis_client/connection_mixin.rb +40 -0
  10. data/lib/redis_client/decorator.rb +84 -0
  11. data/lib/redis_client/pooled.rb +38 -30
  12. data/lib/redis_client/ruby_connection/buffered_io.rb +153 -0
  13. data/lib/redis_client/{resp3.rb → ruby_connection/resp3.rb} +0 -26
  14. data/lib/redis_client/{connection.rb → ruby_connection.rb} +26 -31
  15. data/lib/redis_client/version.rb +1 -1
  16. data/lib/redis_client.rb +183 -36
  17. data/redis-client.gemspec +2 -4
  18. metadata +12 -59
  19. data/.rubocop.yml +0 -190
  20. data/ext/redis_client/hiredis/export.clang +0 -2
  21. data/ext/redis_client/hiredis/export.gcc +0 -7
  22. data/ext/redis_client/hiredis/extconf.rb +0 -61
  23. data/ext/redis_client/hiredis/hiredis_connection.c +0 -708
  24. data/ext/redis_client/hiredis/vendor/.gitignore +0 -9
  25. data/ext/redis_client/hiredis/vendor/.travis.yml +0 -131
  26. data/ext/redis_client/hiredis/vendor/CHANGELOG.md +0 -364
  27. data/ext/redis_client/hiredis/vendor/CMakeLists.txt +0 -165
  28. data/ext/redis_client/hiredis/vendor/COPYING +0 -29
  29. data/ext/redis_client/hiredis/vendor/Makefile +0 -308
  30. data/ext/redis_client/hiredis/vendor/README.md +0 -664
  31. data/ext/redis_client/hiredis/vendor/adapters/ae.h +0 -130
  32. data/ext/redis_client/hiredis/vendor/adapters/glib.h +0 -156
  33. data/ext/redis_client/hiredis/vendor/adapters/ivykis.h +0 -84
  34. data/ext/redis_client/hiredis/vendor/adapters/libev.h +0 -179
  35. data/ext/redis_client/hiredis/vendor/adapters/libevent.h +0 -175
  36. data/ext/redis_client/hiredis/vendor/adapters/libuv.h +0 -117
  37. data/ext/redis_client/hiredis/vendor/adapters/macosx.h +0 -115
  38. data/ext/redis_client/hiredis/vendor/adapters/qt.h +0 -135
  39. data/ext/redis_client/hiredis/vendor/alloc.c +0 -86
  40. data/ext/redis_client/hiredis/vendor/alloc.h +0 -91
  41. data/ext/redis_client/hiredis/vendor/appveyor.yml +0 -24
  42. data/ext/redis_client/hiredis/vendor/async.c +0 -887
  43. data/ext/redis_client/hiredis/vendor/async.h +0 -147
  44. data/ext/redis_client/hiredis/vendor/async_private.h +0 -75
  45. data/ext/redis_client/hiredis/vendor/dict.c +0 -352
  46. data/ext/redis_client/hiredis/vendor/dict.h +0 -126
  47. data/ext/redis_client/hiredis/vendor/fmacros.h +0 -12
  48. data/ext/redis_client/hiredis/vendor/hiredis-config.cmake.in +0 -13
  49. data/ext/redis_client/hiredis/vendor/hiredis.c +0 -1174
  50. data/ext/redis_client/hiredis/vendor/hiredis.h +0 -336
  51. data/ext/redis_client/hiredis/vendor/hiredis.pc.in +0 -12
  52. data/ext/redis_client/hiredis/vendor/hiredis_ssl-config.cmake.in +0 -13
  53. data/ext/redis_client/hiredis/vendor/hiredis_ssl.h +0 -157
  54. data/ext/redis_client/hiredis/vendor/hiredis_ssl.pc.in +0 -12
  55. data/ext/redis_client/hiredis/vendor/net.c +0 -612
  56. data/ext/redis_client/hiredis/vendor/net.h +0 -56
  57. data/ext/redis_client/hiredis/vendor/read.c +0 -739
  58. data/ext/redis_client/hiredis/vendor/read.h +0 -129
  59. data/ext/redis_client/hiredis/vendor/sds.c +0 -1289
  60. data/ext/redis_client/hiredis/vendor/sds.h +0 -278
  61. data/ext/redis_client/hiredis/vendor/sdsalloc.h +0 -44
  62. data/ext/redis_client/hiredis/vendor/sockcompat.c +0 -248
  63. data/ext/redis_client/hiredis/vendor/sockcompat.h +0 -92
  64. data/ext/redis_client/hiredis/vendor/ssl.c +0 -544
  65. data/ext/redis_client/hiredis/vendor/test.c +0 -1401
  66. data/ext/redis_client/hiredis/vendor/test.sh +0 -78
  67. data/ext/redis_client/hiredis/vendor/win32.h +0 -56
  68. data/lib/redis_client/buffered_io.rb +0 -151
  69. data/lib/redis_client/hiredis_connection.rb +0 -80
@@ -49,40 +49,48 @@ class RedisClient
49
49
  pool.size
50
50
  end
51
51
 
52
- %w(pipelined).each do |method|
53
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
54
- def #{method}(&block)
55
- with { |r| r.#{method}(&block) }
56
- end
57
- RUBY
58
- end
59
-
60
- %w(multi).each do |method|
61
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
62
- def #{method}(**kwargs, &block)
63
- with { |r| r.#{method}(**kwargs, &block) }
64
- end
65
- RUBY
66
- end
52
+ methods = %w(pipelined multi pubsub call call_once blocking_call)
53
+ iterable_methods = %w(scan sscan hscan zscan)
54
+ begin
55
+ methods.each do |method|
56
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
57
+ def #{method}(...)
58
+ with { |r| r.#{method}(...) }
59
+ end
60
+ RUBY
61
+ end
67
62
 
68
- %w(call call_once blocking_call pubsub).each do |method|
69
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
70
- def #{method}(*args)
71
- with { |r| r.#{method}(*args) }
72
- end
73
- RUBY
74
- end
63
+ iterable_methods.each do |method|
64
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
65
+ def #{method}(...)
66
+ unless block_given?
67
+ return to_enum(__callee__, ...)
68
+ end
75
69
 
76
- %w(scan sscan hscan zscan).each do |method|
77
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
78
- def #{method}(*args, &block)
79
- unless block_given?
80
- return to_enum(__callee__, *args)
70
+ with { |r| r.#{method}(...) }
71
+ end
72
+ RUBY
73
+ end
74
+ rescue SyntaxError
75
+ methods.each do |method|
76
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
77
+ def #{method}(*args, &block)
78
+ with { |r| r.#{method}(*args, &block) }
81
79
  end
80
+ RUBY
81
+ end
82
82
 
83
- with { |r| r.#{method}(*args, &block) }
84
- end
85
- RUBY
83
+ iterable_methods.each do |method|
84
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
85
+ def #{method}(*args, &block)
86
+ unless block_given?
87
+ return to_enum(__callee__, *args)
88
+ end
89
+
90
+ with { |r| r.#{method}(*args, &block) }
91
+ end
92
+ RUBY
93
+ end
86
94
  end
87
95
 
88
96
  private
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "io/wait" unless IO.method_defined?(:wait_readable) && IO.method_defined?(:wait_writable)
4
+
5
+ class RedisClient
6
+ class RubyConnection
7
+ class BufferedIO
8
+ EOL = "\r\n".b.freeze
9
+ EOL_SIZE = EOL.bytesize
10
+
11
+ attr_accessor :read_timeout, :write_timeout
12
+
13
+ def initialize(io, read_timeout:, write_timeout:, chunk_size: 4096)
14
+ @io = io
15
+ @buffer = "".b
16
+ @offset = 0
17
+ @chunk_size = chunk_size
18
+ @read_timeout = read_timeout
19
+ @write_timeout = write_timeout
20
+ @blocking_reads = false
21
+ end
22
+
23
+ def close
24
+ @io.to_io.close
25
+ end
26
+
27
+ def closed?
28
+ @io.to_io.closed?
29
+ end
30
+
31
+ def eof?
32
+ @offset >= @buffer.bytesize && @io.eof?
33
+ end
34
+
35
+ def with_timeout(new_timeout)
36
+ new_timeout = false if new_timeout == 0
37
+
38
+ previous_read_timeout = @read_timeout
39
+ previous_blocking_reads = @blocking_reads
40
+
41
+ if new_timeout
42
+ @read_timeout = new_timeout
43
+ else
44
+ @blocking_reads = true
45
+ end
46
+
47
+ begin
48
+ yield
49
+ ensure
50
+ @read_timeout = previous_read_timeout
51
+ @blocking_reads = previous_blocking_reads
52
+ end
53
+ end
54
+
55
+ def skip(offset)
56
+ ensure_remaining(offset)
57
+ @offset += offset
58
+ nil
59
+ end
60
+
61
+ def write(string)
62
+ total = remaining = string.bytesize
63
+ loop do
64
+ case bytes_written = @io.write_nonblock(string, exception: false)
65
+ when Integer
66
+ remaining -= bytes_written
67
+ if remaining > 0
68
+ string = string.byteslice(bytes_written..-1)
69
+ else
70
+ return total
71
+ end
72
+ when :wait_readable
73
+ @io.to_io.wait_readable(@read_timeout) or raise ReadTimeoutError
74
+ when :wait_writable
75
+ @io.to_io.wait_writable(@write_timeout) or raise WriteTimeoutError
76
+ when nil
77
+ raise Errno::ECONNRESET
78
+ else
79
+ raise "Unexpected `write_nonblock` return: #{bytes.inspect}"
80
+ end
81
+ end
82
+ end
83
+
84
+ def getbyte
85
+ ensure_remaining(1)
86
+ byte = @buffer.getbyte(@offset)
87
+ @offset += 1
88
+ byte
89
+ end
90
+
91
+ def gets_chomp
92
+ fill_buffer(false) if @offset >= @buffer.bytesize
93
+ until eol_index = @buffer.index(EOL, @offset)
94
+ fill_buffer(false)
95
+ end
96
+
97
+ line = @buffer.byteslice(@offset, eol_index - @offset)
98
+ @offset = eol_index + EOL_SIZE
99
+ line
100
+ end
101
+
102
+ def read_chomp(bytes)
103
+ ensure_remaining(bytes + EOL_SIZE)
104
+ str = @buffer.byteslice(@offset, bytes)
105
+ @offset += bytes + EOL_SIZE
106
+ str
107
+ end
108
+
109
+ private
110
+
111
+ def ensure_remaining(bytes)
112
+ needed = bytes - (@buffer.bytesize - @offset)
113
+ if needed > 0
114
+ fill_buffer(true, needed)
115
+ end
116
+ end
117
+
118
+ def fill_buffer(strict, size = @chunk_size)
119
+ remaining = size
120
+ empty_buffer = @offset >= @buffer.bytesize
121
+
122
+ loop do
123
+ bytes = if empty_buffer
124
+ @io.read_nonblock([remaining, @chunk_size].max, @buffer, exception: false)
125
+ else
126
+ @io.read_nonblock([remaining, @chunk_size].max, exception: false)
127
+ end
128
+ case bytes
129
+ when String
130
+ if empty_buffer
131
+ @offset = 0
132
+ empty_buffer = false
133
+ else
134
+ @buffer << bytes
135
+ end
136
+ remaining -= bytes.bytesize
137
+ return if !strict || remaining <= 0
138
+ when :wait_readable
139
+ unless @io.to_io.wait_readable(@read_timeout)
140
+ raise ReadTimeoutError unless @blocking_reads
141
+ end
142
+ when :wait_writable
143
+ @io.to_io.wait_writable(@write_timeout) or raise WriteTimeoutError
144
+ when nil
145
+ raise Errno::ECONNRESET
146
+ else
147
+ raise "Unexpected `read_nonblock` return: #{bytes.inspect}"
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -58,32 +58,6 @@ class RedisClient
58
58
  String.new(encoding: Encoding::BINARY, capacity: 128)
59
59
  end
60
60
 
61
- def coerce_command!(command)
62
- command = command.flat_map do |element|
63
- case element
64
- when Hash
65
- element.flatten
66
- when Set
67
- element.to_a
68
- else
69
- element
70
- end
71
- end
72
-
73
- command.map! do |element|
74
- case element
75
- when String
76
- element
77
- when Integer, Float, Symbol
78
- element.to_s
79
- else
80
- raise TypeError, "Unsupported command argument type: #{element.class}"
81
- end
82
- end
83
-
84
- command
85
- end
86
-
87
61
  def dump_any(object, buffer)
88
62
  method = DUMP_TYPES.fetch(object.class) do
89
63
  raise TypeError, "Unsupported command argument type: #{object.class}"
@@ -2,47 +2,42 @@
2
2
 
3
3
  require "socket"
4
4
  require "openssl"
5
- require "redis_client/buffered_io"
5
+ require "redis_client/connection_mixin"
6
+ require "redis_client/ruby_connection/buffered_io"
7
+ require "redis_client/ruby_connection/resp3"
6
8
 
7
9
  class RedisClient
8
- class Connection
9
- module Common
10
- def call(command, timeout)
11
- write(command)
12
- result = read(timeout)
13
- if result.is_a?(CommandError)
14
- raise result
15
- else
16
- result
17
- end
18
- end
10
+ class RubyConnection
11
+ include ConnectionMixin
19
12
 
20
- def call_pipelined(commands, timeouts)
21
- exception = nil
13
+ class << self
14
+ def ssl_context(ssl_params)
15
+ params = ssl_params.dup || {}
22
16
 
23
- size = commands.size
24
- results = Array.new(commands.size)
25
- write_multi(commands)
17
+ cert = params[:cert]
18
+ if cert.is_a?(String)
19
+ cert = File.read(cert) if File.exist?(cert)
20
+ params[:cert] = OpenSSL::X509::Certificate.new(cert)
21
+ end
26
22
 
27
- size.times do |index|
28
- timeout = timeouts && timeouts[index]
29
- result = read(timeout)
30
- if result.is_a?(CommandError)
31
- exception ||= result
32
- end
33
- results[index] = result
23
+ key = params[:key]
24
+ if key.is_a?(String)
25
+ key = File.read(key) if File.exist?(key)
26
+ params[:key] = OpenSSL::PKey.read(key)
34
27
  end
35
28
 
36
- if exception
37
- raise exception
38
- else
39
- results
29
+ context = OpenSSL::SSL::SSLContext.new
30
+ context.set_params(params)
31
+ if context.verify_mode != OpenSSL::SSL::VERIFY_NONE
32
+ if context.respond_to?(:verify_hostname) # Missing on JRuby
33
+ context.verify_hostname
34
+ end
40
35
  end
36
+
37
+ context
41
38
  end
42
39
  end
43
40
 
44
- include Common
45
-
46
41
  SUPPORTS_RESOLV_TIMEOUT = Socket.method(:tcp).parameters.any? { |p| p.last == :resolv_timeout }
47
42
 
48
43
  def initialize(config, connect_timeout:, read_timeout:, write_timeout:)
@@ -60,7 +55,7 @@ class RedisClient
60
55
  end
61
56
 
62
57
  if config.ssl
63
- socket = OpenSSL::SSL::SSLSocket.new(socket, config.openssl_context)
58
+ socket = OpenSSL::SSL::SSLSocket.new(socket, config.ssl_context)
64
59
  socket.hostname = config.host
65
60
  loop do
66
61
  case status = socket.connect_nonblock(exception: false)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class RedisClient
4
- VERSION = "0.2.1"
4
+ VERSION = "0.5.0"
5
5
  end