hiredis 0.4.1-java

Sign up to get free protection for your applications and to get access to all the features.
data/COPYING ADDED
@@ -0,0 +1,10 @@
1
+ Copyright (c) 2010, Pieter Noordhuis
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+ * Neither the name of Redis nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9
+
10
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,46 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rake/testtask"
5
+ require "rake/extensiontask"
6
+
7
+ unless defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
8
+
9
+ Rake::ExtensionTask.new('hiredis_ext') do |task|
10
+ # Pass --with-foo-config args to extconf.rb
11
+ task.config_options = ARGV[1..-1] || []
12
+ task.lib_dir = File.join(*['lib', 'hiredis', 'ext'])
13
+ end
14
+
15
+ namespace :hiredis do
16
+ task :clean do
17
+ # Fetch hiredis if not present
18
+ if !File.directory?("vendor/hiredis/.git")
19
+ system("git submodule update --init")
20
+ end
21
+ system("cd vendor/hiredis && make clean")
22
+ end
23
+ end
24
+
25
+ # "rake clean" should also clean bundled hiredis
26
+ Rake::Task[:clean].enhance(['hiredis:clean'])
27
+
28
+ # Build from scratch
29
+ task :rebuild => [:clean, :compile]
30
+
31
+ else
32
+
33
+ task :rebuild do
34
+ # no-op
35
+ end
36
+
37
+ end
38
+
39
+ task :default => [:rebuild, :test]
40
+
41
+ desc "Run tests"
42
+ Rake::TestTask.new(:test) do |t|
43
+ t.libs << "test"
44
+ t.pattern = 'test/**/*_test.rb'
45
+ t.verbose = true
46
+ end
@@ -0,0 +1,2 @@
1
+ require "hiredis/version"
2
+ require "hiredis/connection"
@@ -0,0 +1,10 @@
1
+ module Hiredis
2
+ begin
3
+ require "hiredis/ext/connection"
4
+ Connection = Ext::Connection
5
+ rescue LoadError
6
+ warn "WARNING: could not load hiredis extension, using (slower) pure Ruby implementation."
7
+ require "hiredis/ruby/connection"
8
+ Connection = Ruby::Connection
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ require "hiredis/ext/hiredis_ext"
2
+ require "hiredis/version"
3
+ require "socket"
4
+
5
+ module Hiredis
6
+ module Ext
7
+ class Connection
8
+ alias :_disconnect :disconnect
9
+
10
+ def disconnect
11
+ _disconnect
12
+ ensure
13
+ @sock = nil
14
+ end
15
+
16
+ alias :_read :read
17
+
18
+ def read
19
+ _read
20
+ rescue ::EOFError
21
+ raise Errno::ECONNRESET
22
+ end
23
+
24
+ def sock
25
+ @sock ||= Socket.for_fd(fileno)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,2 @@
1
+ require "hiredis/ext/hiredis_ext"
2
+ require "hiredis/version"
@@ -0,0 +1,10 @@
1
+ module Hiredis
2
+ begin
3
+ require "hiredis/ext/reader"
4
+ Reader = Ext::Reader
5
+ rescue LoadError
6
+ warn "WARNING: could not load hiredis extension, using (slower) pure Ruby implementation."
7
+ require "hiredis/ruby/reader"
8
+ Reader = Ruby::Reader
9
+ end
10
+ end
@@ -0,0 +1,298 @@
1
+ require "socket"
2
+ require "hiredis/ruby/reader"
3
+ require "hiredis/version"
4
+
5
+ module Hiredis
6
+ module Ruby
7
+ class Connection
8
+
9
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx"
10
+
11
+ def self.errno_to_class
12
+ Errno::Mapping
13
+ end
14
+
15
+ else
16
+
17
+ def self.errno_to_class
18
+ @mapping ||= Hash[Errno.constants.map do |name|
19
+ klass = Errno.const_get(name)
20
+ [klass.const_get("Errno"), klass]
21
+ end]
22
+ end
23
+
24
+ end
25
+
26
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
27
+
28
+ require "timeout"
29
+
30
+ def _connect(host, port, timeout)
31
+ sock = nil
32
+
33
+ begin
34
+ Timeout.timeout(timeout) do
35
+ sock = TCPSocket.new(host, port)
36
+ end
37
+ rescue SocketError => se
38
+ raise se.message
39
+ rescue Timeout::Error
40
+ raise Errno::ETIMEDOUT
41
+ end
42
+
43
+ sock
44
+ end
45
+
46
+ def _connect_unix(path, timeout)
47
+ sock = nil
48
+
49
+ begin
50
+ Timeout.timeout(timeout) do
51
+ sock = UNIXSocket.new(path)
52
+ end
53
+ rescue SocketError => se
54
+ raise se.message
55
+ rescue Timeout::Error
56
+ raise Errno::ETIMEDOUT
57
+ end
58
+
59
+ sock
60
+ end
61
+
62
+ def _write(sock, data, timeout)
63
+ begin
64
+ Timeout.timeout(timeout) do
65
+ sock.write(data)
66
+ end
67
+ rescue Timeout::Error
68
+ raise Errno::EAGAIN
69
+ end
70
+ end
71
+
72
+ else
73
+
74
+ def _connect(host, port, timeout)
75
+ error = nil
76
+ sock = nil
77
+
78
+ # Resolve address
79
+ begin
80
+ addrinfo = Socket.getaddrinfo(host, port, Socket::AF_UNSPEC, Socket::SOCK_STREAM)
81
+ rescue SocketError => se
82
+ raise se.message
83
+ end
84
+
85
+ addrinfo.each do |_, port, name, addr, af|
86
+ begin
87
+ sockaddr = Socket.pack_sockaddr_in(port, addr)
88
+ sock = _connect_sockaddr(af, sockaddr, timeout)
89
+ rescue => aux
90
+ case aux
91
+ when Errno::EAFNOSUPPORT, Errno::ECONNREFUSED
92
+ error = aux
93
+ next
94
+ else
95
+ # Re-raise
96
+ raise
97
+ end
98
+ else
99
+ # No errors, awesome!
100
+ break
101
+ end
102
+ end
103
+
104
+ unless sock
105
+ # Re-raise last error since the last try obviously failed
106
+ raise error if error
107
+
108
+ # This code path should not happen: getaddrinfo should always return
109
+ # at least one record, which should either succeed or fail and leave
110
+ # and error to raise.
111
+ raise
112
+ end
113
+
114
+ sock
115
+ end
116
+
117
+ def _connect_unix(path, timeout)
118
+ sockaddr = Socket.pack_sockaddr_un(path)
119
+ _connect_sockaddr(Socket::AF_UNIX, sockaddr, timeout)
120
+ end
121
+
122
+ def _write(sock, data, timeout)
123
+ data.force_encoding("binary") if data.respond_to?(:force_encoding)
124
+
125
+ begin
126
+ nwritten = @sock.write_nonblock(data)
127
+
128
+ while nwritten < string_size(data)
129
+ data = data[nwritten..-1]
130
+ nwritten = @sock.write_nonblock(data)
131
+ end
132
+ rescue Errno::EAGAIN
133
+ if IO.select([], [@sock], [], timeout)
134
+ # Writable, try again
135
+ retry
136
+ else
137
+ # Timed out, raise
138
+ raise Errno::EAGAIN
139
+ end
140
+ end
141
+ end
142
+
143
+ def _connect_sockaddr(af, sockaddr, timeout)
144
+ sock = Socket.new(af, Socket::SOCK_STREAM, 0)
145
+
146
+ begin
147
+ sock.connect_nonblock(sockaddr)
148
+ rescue Errno::EINPROGRESS
149
+ if IO.select(nil, [sock], nil, timeout)
150
+ # Writable, check for errors
151
+ optval = sock.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR)
152
+ errno = optval.unpack("i").first
153
+
154
+ # Raise socket error if there is any
155
+ raise self.class.errno_to_class[errno] if errno > 0
156
+ else
157
+ # Timeout (TODO: replace with own Timeout class)
158
+ raise Errno::ETIMEDOUT
159
+ end
160
+ end
161
+
162
+ sock
163
+ rescue
164
+ sock.close if sock
165
+
166
+ # Re-raise
167
+ raise
168
+ end
169
+
170
+ private :_connect_sockaddr
171
+
172
+ end
173
+
174
+ attr_reader :sock
175
+
176
+ def initialize
177
+ @sock = nil
178
+ @timeout = nil
179
+ end
180
+
181
+ def connected?
182
+ !! @sock
183
+ end
184
+
185
+ def connect(host, port, usecs = nil)
186
+ # Temporarily override timeout on #connect
187
+ timeout = usecs ? (usecs / 1_000_000.0) : @timeout
188
+
189
+ # Optionally disconnect current socket
190
+ disconnect if connected?
191
+
192
+ sock = _connect(host, port, timeout)
193
+ sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
194
+
195
+ @reader = ::Hiredis::Ruby::Reader.new
196
+ @sock = sock
197
+
198
+ nil
199
+ end
200
+
201
+ def connect_unix(path, usecs = 0)
202
+ # Temporarily override timeout on #connect
203
+ timeout = usecs ? (usecs / 1_000_000.0) : @timeout
204
+
205
+ # Optionally disconnect current socket
206
+ disconnect if connected?
207
+
208
+ sock = _connect_unix(path, timeout)
209
+
210
+ @reader = ::Hiredis::Ruby::Reader.new
211
+ @sock = sock
212
+
213
+ nil
214
+ end
215
+
216
+ def disconnect
217
+ @sock.close
218
+ rescue
219
+ ensure
220
+ @sock = nil
221
+ end
222
+
223
+ def timeout=(usecs)
224
+ raise ArgumentError.new("timeout cannot be negative") if usecs < 0
225
+
226
+ if usecs == 0
227
+ @timeout = nil
228
+ else
229
+ @timeout = usecs / 1_000_000.0
230
+ end
231
+
232
+ nil
233
+ end
234
+
235
+ def fileno
236
+ raise "not connected" unless connected?
237
+
238
+ @sock.fileno
239
+ end
240
+
241
+ COMMAND_DELIMITER = "\r\n".freeze
242
+
243
+ def write(args)
244
+ command = []
245
+ command << "*#{args.size}"
246
+ args.each do |arg|
247
+ arg = arg.to_s
248
+ command << "$#{string_size arg}"
249
+ command << arg
250
+ end
251
+
252
+ data = command.join(COMMAND_DELIMITER) + COMMAND_DELIMITER
253
+
254
+ _write(@sock, data, @timeout)
255
+
256
+ nil
257
+ end
258
+
259
+ # No-op for now..
260
+ def flush
261
+ end
262
+
263
+ def read
264
+ raise "not connected" unless connected?
265
+
266
+ while (reply = @reader.gets) == false
267
+ begin
268
+ @reader.feed @sock.read_nonblock(1024)
269
+ rescue Errno::EAGAIN
270
+ if IO.select([@sock], [], [], @timeout)
271
+ # Readable, try again
272
+ retry
273
+ else
274
+ # Timed out, raise
275
+ raise Errno::EAGAIN
276
+ end
277
+ end
278
+ end
279
+
280
+ reply
281
+ rescue ::EOFError
282
+ raise Errno::ECONNRESET
283
+ end
284
+
285
+ protected
286
+
287
+ if "".respond_to?(:bytesize)
288
+ def string_size(string)
289
+ string.to_s.bytesize
290
+ end
291
+ else
292
+ def string_size(string)
293
+ string.to_s.size
294
+ end
295
+ end
296
+ end
297
+ end
298
+ end
@@ -0,0 +1,164 @@
1
+ require "hiredis/version"
2
+
3
+ module Hiredis
4
+ module Ruby
5
+ class Reader
6
+
7
+ def initialize
8
+ @buffer = Buffer.new
9
+ @task = Task.new(@buffer)
10
+ end
11
+
12
+ def feed(data)
13
+ @buffer << data
14
+ end
15
+
16
+ def gets
17
+ reply = @task.process
18
+ @buffer.discard!
19
+ reply
20
+ end
21
+
22
+ protected
23
+
24
+ class Task
25
+
26
+ # Use lookup table to map reply types to methods
27
+ method_index = {}
28
+ method_index[?-] = :process_error_reply
29
+ method_index[?+] = :process_status_reply
30
+ method_index[?:] = :process_integer_reply
31
+ method_index[?$] = :process_bulk_reply
32
+ method_index[?*] = :process_multi_bulk_reply
33
+ METHOD_INDEX = method_index.freeze
34
+
35
+ attr_accessor :parent, :child
36
+ attr_accessor :multi_bulk
37
+
38
+ def initialize(buffer, parent = nil, depth = 0)
39
+ @buffer, @parent = buffer, parent
40
+
41
+ # Require 3 nested tasks
42
+ @child = Task.new(@buffer, self, depth + 1) if depth < 2
43
+ end
44
+
45
+ def root
46
+ parent ? parent.root : self
47
+ end
48
+
49
+ def reset!
50
+ @line = @type = @multi_bulk = nil
51
+ end
52
+
53
+ def process_error_reply
54
+ RuntimeError.new(@line)
55
+ end
56
+
57
+ def process_status_reply
58
+ @line
59
+ end
60
+
61
+ def process_integer_reply
62
+ @line.to_i
63
+ end
64
+
65
+ def process_bulk_reply
66
+ bulk_length = @line.to_i
67
+ return nil if bulk_length < 0
68
+
69
+ # Caught by caller function when false
70
+ @buffer.read(bulk_length, 2)
71
+ end
72
+
73
+ def process_multi_bulk_reply
74
+ multi_bulk_length = @line.to_i
75
+
76
+ if multi_bulk_length > 0
77
+ @multi_bulk ||= []
78
+
79
+ # We know the multi bulk is not complete when this path is taken.
80
+ while (element = child.process) != false
81
+ @multi_bulk << element
82
+ return @multi_bulk if @multi_bulk.length == multi_bulk_length
83
+ end
84
+
85
+ false
86
+ elsif multi_bulk_length == 0
87
+ []
88
+ else
89
+ nil
90
+ end
91
+ end
92
+
93
+ def process_protocol_error
94
+ raise "Protocol error"
95
+ end
96
+
97
+ def process
98
+ @line ||= @buffer.read_line
99
+ return false if @line == false
100
+
101
+ @type ||= @line.slice!(0)
102
+ reply = send(METHOD_INDEX[@type] || :process_protocol_error)
103
+
104
+ reset! if reply != false
105
+ reply
106
+ end
107
+ end
108
+
109
+ class Buffer
110
+
111
+ CRLF = "\r\n".freeze
112
+
113
+ def initialize
114
+ @buffer = ""
115
+ @length = @pos = 0
116
+ end
117
+
118
+ def <<(data)
119
+ @length += data.length
120
+ @buffer << data
121
+ end
122
+
123
+ def length
124
+ @length
125
+ end
126
+
127
+ def empty?
128
+ @length == 0
129
+ end
130
+
131
+ def discard!
132
+ if @length == 0
133
+ @buffer = ""
134
+ @length = @pos = 0
135
+ else
136
+ if @pos >= 1024
137
+ @buffer.slice!(0, @pos)
138
+ @length -= @pos
139
+ @pos = 0
140
+ end
141
+ end
142
+ end
143
+
144
+ def read(bytes, skip = 0)
145
+ start = @pos
146
+ stop = start + bytes + skip
147
+ return false if @length < stop
148
+
149
+ @pos = stop
150
+ @buffer[start, bytes]
151
+ end
152
+
153
+ def read_line
154
+ start = @pos
155
+ stop = @buffer.index(CRLF, @pos)
156
+ return false unless stop
157
+
158
+ @pos = stop + 2 # include CRLF
159
+ @buffer[start, stop - start]
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,3 @@
1
+ module Hiredis
2
+ VERSION = "0.4.1"
3
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hiredis
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.4.1
6
+ platform: java
7
+ authors:
8
+ - Pieter Noordhuis
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-10-26 00:00:00 -07:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rake-compiler
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 0.7.1
25
+ type: :development
26
+ version_requirements: *id001
27
+ description: Ruby extension that wraps Hiredis (blocking connection and reply parsing)
28
+ email:
29
+ - pcnoordhuis@gmail.com
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files: []
35
+
36
+ files:
37
+ - lib/hiredis.rb
38
+ - lib/hiredis/connection.rb
39
+ - lib/hiredis/reader.rb
40
+ - lib/hiredis/version.rb
41
+ - lib/hiredis/ext/connection.rb
42
+ - lib/hiredis/ext/reader.rb
43
+ - lib/hiredis/ruby/connection.rb
44
+ - lib/hiredis/ruby/reader.rb
45
+ - COPYING
46
+ - Rakefile
47
+ has_rdoc: true
48
+ homepage: http://github.com/pietern/hiredis-rb
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: "0"
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: "0"
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.6.2
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Ruby extension that wraps Hiredis (blocking connection and reply parsing)
75
+ test_files: []
76
+