hiredis 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -47
- data/ext/hiredis_ext/connection.c +104 -35
- data/ext/hiredis_ext/extconf.rb +1 -1
- data/ext/hiredis_ext/hiredis_ext.c +4 -2
- data/ext/hiredis_ext/hiredis_ext.h +0 -1
- data/ext/hiredis_ext/reader.c +0 -20
- data/lib/hiredis.rb +2 -10
- data/lib/hiredis/connection.rb +7 -14
- data/lib/hiredis/ext/connection.rb +16 -0
- data/lib/hiredis/ext/reader.rb +2 -0
- data/lib/hiredis/reader.rb +10 -1
- data/lib/hiredis/ruby/connection.rb +113 -0
- data/lib/hiredis/ruby/reader.rb +164 -0
- data/lib/hiredis/version.rb +1 -1
- data/vendor/hiredis/Makefile +4 -5
- data/vendor/hiredis/async.c +2 -0
- data/vendor/hiredis/async.h +3 -3
- data/vendor/hiredis/dict.c +27 -77
- data/vendor/hiredis/dict.h +12 -16
- data/vendor/hiredis/hiredis.c +26 -17
- data/vendor/hiredis/hiredis.h +4 -2
- data/vendor/hiredis/net.c +85 -18
- data/vendor/hiredis/net.h +2 -2
- data/vendor/hiredis/sds.c +129 -4
- data/vendor/hiredis/sds.h +2 -1
- data/vendor/hiredis/test.c +14 -5
- metadata +15 -29
- data/lib/hiredis/em.rb +0 -1
- data/lib/hiredis/em/base.rb +0 -36
- data/lib/hiredis/em/connection.rb +0 -25
data/Rakefile
CHANGED
@@ -1,57 +1,11 @@
|
|
1
1
|
require 'rake'
|
2
|
-
require 'rake/gempackagetask'
|
3
2
|
require 'rake/testtask'
|
4
|
-
|
5
|
-
gem 'rake-compiler', '~> 0.7.1'
|
6
3
|
require "rake/extensiontask"
|
7
4
|
|
8
|
-
$:.unshift File.join(File.dirname(__FILE__), 'lib')
|
9
|
-
require 'hiredis/version'
|
10
|
-
|
11
|
-
GEM = 'hiredis'
|
12
|
-
GEM_VERSION = Hiredis::VERSION
|
13
|
-
AUTHORS = ['Pieter Noordhuis']
|
14
|
-
EMAIL = "pcnoordhuis@gmail.com"
|
15
|
-
HOMEPAGE = "http://github.com/pietern/hiredis-rb"
|
16
|
-
SUMMARY = "Ruby extension that wraps Hiredis (blocking connection and reply parsing)"
|
17
|
-
|
18
|
-
spec = Gem::Specification.new do |s|
|
19
|
-
s.name = GEM
|
20
|
-
s.version = GEM_VERSION
|
21
|
-
s.platform = Gem::Platform::RUBY
|
22
|
-
s.has_rdoc = true
|
23
|
-
s.extra_rdoc_files = ["COPYING"]
|
24
|
-
s.summary = SUMMARY
|
25
|
-
s.description = s.summary
|
26
|
-
s.authors = AUTHORS
|
27
|
-
s.email = EMAIL
|
28
|
-
s.homepage = HOMEPAGE
|
29
|
-
s.require_path = 'lib'
|
30
|
-
s.extensions = FileList["ext/**/extconf.rb"]
|
31
|
-
|
32
|
-
ext_files = Dir.glob("ext/**/*.{rb,c,h}")
|
33
|
-
lib_files = Dir.glob("lib/**/*.rb")
|
34
|
-
hiredis_files = Dir.glob("vendor/hiredis/*.{c,h}") -
|
35
|
-
Dir.glob("vendor/hiredis/example*") +
|
36
|
-
Dir.glob("vendor/hiredis/COPYING") +
|
37
|
-
Dir.glob("vendor/hiredis/Makefile")
|
38
|
-
s.files = %w(COPYING Rakefile) + ext_files + lib_files + hiredis_files
|
39
|
-
|
40
|
-
s.add_runtime_dependency "rake-compiler", "~> 0.7.1"
|
41
|
-
s.add_runtime_dependency "redis", "~> 2.1.1"
|
42
|
-
end
|
43
|
-
|
44
|
-
desc "create a gemspec file"
|
45
|
-
task :gemspec do
|
46
|
-
File.open("#{GEM}.gemspec", "w") do |file|
|
47
|
-
file.puts spec.to_ruby
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
5
|
Rake::ExtensionTask.new('hiredis_ext') do |task|
|
52
6
|
# Pass --with-foo-config args to extconf.rb
|
53
7
|
task.config_options = ARGV[1..-1]
|
54
|
-
task.lib_dir = File.join(*['lib', 'hiredis'])
|
8
|
+
task.lib_dir = File.join(*['lib', 'hiredis', 'ext'])
|
55
9
|
end
|
56
10
|
|
57
11
|
namespace :hiredis do
|
@@ -28,24 +28,43 @@ static void parent_context_free(redisParentContext *pc) {
|
|
28
28
|
free(pc);
|
29
29
|
}
|
30
30
|
|
31
|
+
static void parent_context_raise(redisParentContext *pc) {
|
32
|
+
int err;
|
33
|
+
char errstr[1024];
|
34
|
+
|
35
|
+
/* Copy error and free context */
|
36
|
+
err = pc->context->err;
|
37
|
+
snprintf(errstr,sizeof(errstr),"%s",pc->context->errstr);
|
38
|
+
parent_context_try_free(pc);
|
39
|
+
|
40
|
+
switch(err) {
|
41
|
+
case REDIS_ERR_IO:
|
42
|
+
/* Raise native Ruby I/O error */
|
43
|
+
rb_sys_fail(0);
|
44
|
+
break;
|
45
|
+
case REDIS_ERR_EOF:
|
46
|
+
/* Raise our own EOF error */
|
47
|
+
rb_raise(error_eof,"%s",errstr);
|
48
|
+
break;
|
49
|
+
default:
|
50
|
+
/* Raise something else */
|
51
|
+
rb_raise(rb_eRuntimeError,"%s",errstr);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
31
55
|
static VALUE connection_parent_context_alloc(VALUE klass) {
|
32
56
|
redisParentContext *pc = malloc(sizeof(*pc));
|
33
57
|
pc->context = NULL;
|
34
58
|
return Data_Wrap_Struct(klass, parent_context_mark, parent_context_free, pc);
|
35
59
|
}
|
36
60
|
|
37
|
-
static VALUE
|
61
|
+
static VALUE connection_generic_connect(VALUE self, redisContext *c) {
|
38
62
|
redisParentContext *pc;
|
39
|
-
redisContext *c;
|
40
|
-
char *host = StringValuePtr(_host);
|
41
|
-
int port = NUM2INT(_port);
|
42
63
|
int err;
|
43
64
|
char errstr[1024];
|
44
65
|
|
45
66
|
Data_Get_Struct(self,redisParentContext,pc);
|
46
|
-
parent_context_try_free(pc);
|
47
67
|
|
48
|
-
c = redisConnect(host,port);
|
49
68
|
if (c->err) {
|
50
69
|
/* Copy error and free context */
|
51
70
|
err = c->err;
|
@@ -66,6 +85,79 @@ static VALUE connection_connect(VALUE self, VALUE _host, VALUE _port) {
|
|
66
85
|
return Qnil;
|
67
86
|
}
|
68
87
|
|
88
|
+
static struct timeval __timeout_from_robj(VALUE usecs) {
|
89
|
+
int s = NUM2INT(usecs)/1000000;
|
90
|
+
int us = NUM2INT(usecs)-(s*1000000);
|
91
|
+
struct timeval timeout = { s, us };
|
92
|
+
return timeout;
|
93
|
+
}
|
94
|
+
|
95
|
+
static VALUE connection_connect(int argc, VALUE *argv, VALUE self) {
|
96
|
+
redisParentContext *pc;
|
97
|
+
redisContext *c;
|
98
|
+
VALUE *_host = NULL;
|
99
|
+
VALUE *_port = NULL;
|
100
|
+
VALUE *_timeout = NULL;
|
101
|
+
char *host;
|
102
|
+
int port;
|
103
|
+
struct timeval timeout;
|
104
|
+
|
105
|
+
if (argc == 2 || argc == 3) {
|
106
|
+
_host = &argv[0];
|
107
|
+
_port = &argv[1];
|
108
|
+
if (argc == 3)
|
109
|
+
_timeout = &argv[2];
|
110
|
+
} else {
|
111
|
+
rb_raise(rb_eArgError, "invalid number of arguments");
|
112
|
+
return Qnil;
|
113
|
+
}
|
114
|
+
|
115
|
+
Data_Get_Struct(self,redisParentContext,pc);
|
116
|
+
parent_context_try_free(pc);
|
117
|
+
|
118
|
+
host = StringValuePtr(*_host);
|
119
|
+
port = NUM2INT(*_port);
|
120
|
+
if (_timeout != NULL) {
|
121
|
+
timeout = __timeout_from_robj(*_timeout);
|
122
|
+
c = redisConnectWithTimeout(host,port,timeout);
|
123
|
+
} else {
|
124
|
+
c = redisConnect(host,port);
|
125
|
+
}
|
126
|
+
|
127
|
+
return connection_generic_connect(self,c);
|
128
|
+
}
|
129
|
+
|
130
|
+
static VALUE connection_connect_unix(int argc, VALUE *argv, VALUE self) {
|
131
|
+
redisParentContext *pc;
|
132
|
+
redisContext *c;
|
133
|
+
VALUE *_path = NULL;
|
134
|
+
VALUE *_timeout = NULL;
|
135
|
+
char *path;
|
136
|
+
struct timeval timeout;
|
137
|
+
|
138
|
+
if (argc == 1 || argc == 2) {
|
139
|
+
_path = &argv[0];
|
140
|
+
if (argc == 2)
|
141
|
+
_timeout = &argv[1];
|
142
|
+
} else {
|
143
|
+
rb_raise(rb_eArgError, "invalid number of arguments");
|
144
|
+
return Qnil;
|
145
|
+
}
|
146
|
+
|
147
|
+
Data_Get_Struct(self,redisParentContext,pc);
|
148
|
+
parent_context_try_free(pc);
|
149
|
+
|
150
|
+
path = StringValuePtr(*_path);
|
151
|
+
if (_timeout != NULL) {
|
152
|
+
timeout = __timeout_from_robj(*_timeout);
|
153
|
+
c = redisConnectUnixWithTimeout(path,timeout);
|
154
|
+
} else {
|
155
|
+
c = redisConnectUnix(path);
|
156
|
+
}
|
157
|
+
|
158
|
+
return connection_generic_connect(self,c);
|
159
|
+
}
|
160
|
+
|
69
161
|
static VALUE connection_is_connected(VALUE self) {
|
70
162
|
redisParentContext *pc;
|
71
163
|
Data_Get_Struct(self,redisParentContext,pc);
|
@@ -145,33 +237,13 @@ static int __get_reply(redisParentContext *pc, VALUE *reply) {
|
|
145
237
|
static VALUE connection_read(VALUE self) {
|
146
238
|
redisParentContext *pc;
|
147
239
|
VALUE reply;
|
148
|
-
int err;
|
149
|
-
char errstr[1024];
|
150
240
|
|
151
241
|
Data_Get_Struct(self,redisParentContext,pc);
|
152
242
|
if (!pc->context)
|
153
243
|
rb_raise(rb_eRuntimeError, "not connected");
|
154
244
|
|
155
|
-
if (__get_reply(pc,&reply) == -1)
|
156
|
-
|
157
|
-
err = pc->context->err;
|
158
|
-
snprintf(errstr,sizeof(errstr),"%s",pc->context->errstr);
|
159
|
-
parent_context_try_free(pc);
|
160
|
-
|
161
|
-
switch(err) {
|
162
|
-
case REDIS_ERR_IO:
|
163
|
-
/* Raise native Ruby I/O error */
|
164
|
-
rb_sys_fail(0);
|
165
|
-
break;
|
166
|
-
case REDIS_ERR_EOF:
|
167
|
-
/* Raise our own EOF error */
|
168
|
-
rb_raise(error_eof,"%s",errstr);
|
169
|
-
break;
|
170
|
-
default:
|
171
|
-
/* Raise something else */
|
172
|
-
rb_raise(rb_eRuntimeError,"%s",errstr);
|
173
|
-
}
|
174
|
-
}
|
245
|
+
if (__get_reply(pc,&reply) == -1)
|
246
|
+
parent_context_raise(pc);
|
175
247
|
|
176
248
|
return reply;
|
177
249
|
}
|
@@ -181,17 +253,13 @@ static VALUE connection_set_timeout(VALUE self, VALUE usecs) {
|
|
181
253
|
int s = NUM2INT(usecs)/1000000;
|
182
254
|
int us = NUM2INT(usecs)-(s*1000000);
|
183
255
|
struct timeval timeout = { s, us };
|
184
|
-
char errstr[1024];
|
185
256
|
|
186
257
|
Data_Get_Struct(self,redisParentContext,pc);
|
187
258
|
if (!pc->context)
|
188
259
|
rb_raise(rb_eRuntimeError, "not connected");
|
189
260
|
|
190
|
-
if (redisSetTimeout(pc->context,timeout) == REDIS_ERR)
|
191
|
-
|
192
|
-
parent_context_try_free(pc);
|
193
|
-
rb_raise(rb_eRuntimeError,"%s",errstr);
|
194
|
-
}
|
261
|
+
if (redisSetTimeout(pc->context,timeout) == REDIS_ERR)
|
262
|
+
parent_context_raise(pc);
|
195
263
|
|
196
264
|
return usecs;
|
197
265
|
}
|
@@ -202,7 +270,8 @@ VALUE error_eof;
|
|
202
270
|
void InitConnection(VALUE mod) {
|
203
271
|
klass_connection = rb_define_class_under(mod, "Connection", rb_cObject);
|
204
272
|
rb_define_alloc_func(klass_connection, connection_parent_context_alloc);
|
205
|
-
rb_define_method(klass_connection, "connect", connection_connect,
|
273
|
+
rb_define_method(klass_connection, "connect", connection_connect, -1);
|
274
|
+
rb_define_method(klass_connection, "connect_unix", connection_connect_unix, -1);
|
206
275
|
rb_define_method(klass_connection, "connected?", connection_is_connected, 0);
|
207
276
|
rb_define_method(klass_connection, "disconnect", connection_disconnect, 0);
|
208
277
|
rb_define_method(klass_connection, "timeout=", connection_set_timeout, 1);
|
data/ext/hiredis_ext/extconf.rb
CHANGED
@@ -4,8 +4,10 @@
|
|
4
4
|
#include "hiredis_ext.h"
|
5
5
|
|
6
6
|
VALUE mod_hiredis;
|
7
|
+
VALUE mod_ext;
|
7
8
|
void Init_hiredis_ext() {
|
8
9
|
mod_hiredis = rb_define_module("Hiredis");
|
9
|
-
|
10
|
-
|
10
|
+
mod_ext = rb_define_module_under(mod_hiredis,"Ext");
|
11
|
+
InitReader(mod_ext);
|
12
|
+
InitConnection(mod_ext);
|
11
13
|
}
|
@@ -10,7 +10,6 @@ extern VALUE mod_hiredis;
|
|
10
10
|
/* Defined in reader.c */
|
11
11
|
extern redisReplyObjectFunctions redisExtReplyObjectFunctions;
|
12
12
|
extern VALUE klass_reader;
|
13
|
-
extern ID ivar_hiredis_error; /* ivar used to store error reply ("-ERR message") */
|
14
13
|
extern void InitReader(VALUE module);
|
15
14
|
|
16
15
|
/* Defined in connection.c */
|
data/ext/hiredis_ext/reader.c
CHANGED
@@ -6,9 +6,6 @@ static VALUE enc_klass;
|
|
6
6
|
static ID enc_default_external = 0;
|
7
7
|
static ID str_force_encoding = 0;
|
8
8
|
|
9
|
-
/* Singleton method to test if the reply contains an error. */
|
10
|
-
ID ivar_hiredis_error;
|
11
|
-
|
12
9
|
/* Add VALUE to parent when the redisReadTask has a parent.
|
13
10
|
* Note that the parent should always be of type T_ARRAY. */
|
14
11
|
static void *tryParentize(const redisReadTask *task, VALUE v) {
|
@@ -20,10 +17,6 @@ static void *tryParentize(const redisReadTask *task, VALUE v) {
|
|
20
17
|
return (void*)v;
|
21
18
|
}
|
22
19
|
|
23
|
-
static VALUE object_contains_error(VALUE self) {
|
24
|
-
return Qtrue;
|
25
|
-
}
|
26
|
-
|
27
20
|
static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
|
28
21
|
VALUE v, enc;
|
29
22
|
v = rb_str_new(str,len);
|
@@ -36,17 +29,6 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
|
|
36
29
|
|
37
30
|
if (task->type == REDIS_REPLY_ERROR) {
|
38
31
|
v = rb_funcall(rb_eRuntimeError,rb_intern("new"),1,v);
|
39
|
-
rb_ivar_set(v,ivar_hiredis_error,v);
|
40
|
-
|
41
|
-
if (task && task->parent != NULL) {
|
42
|
-
/* Also make the parent respond to this method. Redis currently
|
43
|
-
* only emits nested multi bulks of depth 2, so we don't need
|
44
|
-
* to cascade setting this ivar. Make sure to only set the first
|
45
|
-
* error reply on the parent. */
|
46
|
-
VALUE parent = (VALUE)task->parent->obj;
|
47
|
-
if (!rb_ivar_defined(parent,ivar_hiredis_error))
|
48
|
-
rb_ivar_set(parent,ivar_hiredis_error,v);
|
49
|
-
}
|
50
32
|
}
|
51
33
|
|
52
34
|
return tryParentize(task,v);
|
@@ -93,7 +75,6 @@ static VALUE reader_allocate(VALUE klass) {
|
|
93
75
|
|
94
76
|
static VALUE reader_feed(VALUE klass, VALUE str) {
|
95
77
|
void *reader;
|
96
|
-
unsigned int size;
|
97
78
|
|
98
79
|
if (TYPE(str) != T_STRING)
|
99
80
|
rb_raise(rb_eTypeError, "not a string");
|
@@ -122,7 +103,6 @@ void InitReader(VALUE mod) {
|
|
122
103
|
rb_define_alloc_func(klass_reader, reader_allocate);
|
123
104
|
rb_define_method(klass_reader, "feed", reader_feed, 1);
|
124
105
|
rb_define_method(klass_reader, "gets", reader_gets, 0);
|
125
|
-
ivar_hiredis_error = rb_intern("@__hiredis_error");
|
126
106
|
|
127
107
|
/* If the Encoding class is present, #default_external should be used to
|
128
108
|
* determine the encoding for new strings. The "enc_default_external"
|
data/lib/hiredis.rb
CHANGED
@@ -1,10 +1,2 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
|
4
|
-
# Make redis-rb use the Hiredis Connection class
|
5
|
-
class Redis
|
6
|
-
Connection = ::Hiredis::Connection
|
7
|
-
end
|
8
|
-
|
9
|
-
# Load redis
|
10
|
-
require 'redis'
|
1
|
+
require "hiredis/version"
|
2
|
+
require "hiredis/connection"
|
data/lib/hiredis/connection.rb
CHANGED
@@ -1,17 +1,10 @@
|
|
1
|
-
require 'hiredis/hiredis_ext'
|
2
|
-
|
3
1
|
module Hiredis
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
reply
|
13
|
-
rescue EOFError
|
14
|
-
raise Errno::ECONNRESET
|
15
|
-
end
|
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
|
16
9
|
end
|
17
10
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "hiredis/ext/hiredis_ext"
|
2
|
+
require "hiredis/version"
|
3
|
+
|
4
|
+
module Hiredis
|
5
|
+
module Ext
|
6
|
+
class Connection
|
7
|
+
# Raise CONNRESET on EOF
|
8
|
+
alias :_read :read
|
9
|
+
def read
|
10
|
+
_read
|
11
|
+
rescue EOFError
|
12
|
+
raise Errno::ECONNRESET
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/hiredis/reader.rb
CHANGED
@@ -1 +1,10 @@
|
|
1
|
-
|
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,113 @@
|
|
1
|
+
require "socket"
|
2
|
+
require "timeout"
|
3
|
+
require "hiredis/ruby/reader"
|
4
|
+
require "hiredis/version"
|
5
|
+
|
6
|
+
module Hiredis
|
7
|
+
module Ruby
|
8
|
+
class Connection
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@sock = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def connected?
|
15
|
+
!! @sock
|
16
|
+
end
|
17
|
+
|
18
|
+
def connect(host, port, usecs = 0)
|
19
|
+
@reader = ::Hiredis::Ruby::Reader.new
|
20
|
+
|
21
|
+
begin
|
22
|
+
begin
|
23
|
+
Timeout.timeout(usecs.to_f / 1_000_000) do
|
24
|
+
@sock = TCPSocket.new(host, port)
|
25
|
+
@sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
26
|
+
end
|
27
|
+
rescue Timeout::Error
|
28
|
+
raise Errno::ETIMEDOUT
|
29
|
+
end
|
30
|
+
rescue SocketError => error
|
31
|
+
# Raise RuntimeError when host cannot be resolved
|
32
|
+
if error.message.start_with?("getaddrinfo:")
|
33
|
+
raise error.message
|
34
|
+
else
|
35
|
+
raise error
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def connect_unix(path, usecs = 0)
|
41
|
+
@reader = ::Hiredis::Ruby::Reader.new
|
42
|
+
|
43
|
+
begin
|
44
|
+
Timeout.timeout(usecs.to_f / 1_000_000) do
|
45
|
+
@sock = UNIXSocket.new(path)
|
46
|
+
end
|
47
|
+
rescue Timeout::Error
|
48
|
+
raise Errno::ETIMEDOUT
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def disconnect
|
53
|
+
@sock.close
|
54
|
+
rescue
|
55
|
+
ensure
|
56
|
+
@sock = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def timeout=(usecs)
|
60
|
+
raise "not connected" unless connected?
|
61
|
+
|
62
|
+
secs = Integer(usecs / 1_000_000)
|
63
|
+
usecs = Integer(usecs - (secs * 1_000_000)) # 0 - 999_999
|
64
|
+
|
65
|
+
optval = [secs, usecs].pack("l_2")
|
66
|
+
|
67
|
+
begin
|
68
|
+
@sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
|
69
|
+
@sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
|
70
|
+
rescue Errno::ENOPROTOOPT
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
COMMAND_DELIMITER = "\r\n".freeze
|
75
|
+
|
76
|
+
def write(args)
|
77
|
+
command = []
|
78
|
+
command << "*#{args.size}"
|
79
|
+
args.each do |arg|
|
80
|
+
arg = arg.to_s
|
81
|
+
command << "$#{string_size arg}"
|
82
|
+
command << arg
|
83
|
+
end
|
84
|
+
|
85
|
+
@sock.syswrite(command.join(COMMAND_DELIMITER) + COMMAND_DELIMITER)
|
86
|
+
end
|
87
|
+
|
88
|
+
def read
|
89
|
+
raise "not connected" unless connected?
|
90
|
+
|
91
|
+
while (reply = @reader.gets) == false
|
92
|
+
@reader.feed @sock.sysread(1024)
|
93
|
+
end
|
94
|
+
|
95
|
+
reply
|
96
|
+
rescue EOFError
|
97
|
+
raise Errno::ECONNRESET
|
98
|
+
end
|
99
|
+
|
100
|
+
protected
|
101
|
+
|
102
|
+
if "".respond_to?(:bytesize)
|
103
|
+
def string_size(string)
|
104
|
+
string.to_s.bytesize
|
105
|
+
end
|
106
|
+
else
|
107
|
+
def string_size(string)
|
108
|
+
string.to_s.size
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|