redis-protocol 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/redis-protocol.rb +3 -136
- data/lib/redis-protocol/request.rb +134 -0
- data/lib/redis-protocol/static_request.rb +74 -0
- metadata +4 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/lib/redis-protocol.rb
CHANGED
@@ -1,142 +1,9 @@
|
|
1
1
|
# start with *, $, alpha-numeric, \r
|
2
2
|
|
3
3
|
module RedisProtocol
|
4
|
-
class Request
|
5
|
-
attr_reader :raw_data, :type, :component_count, :components
|
6
|
-
|
7
|
-
def initialize(data)
|
8
|
-
@raw_data = data
|
9
|
-
@type, @components, @component_count, @current = nil, [], 0, ''
|
10
|
-
@next_length = 0
|
11
|
-
parse
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def parse
|
17
|
-
@raw_data.chars.each do |c|
|
18
|
-
@type ||= c.eql?('*') ? :standard : :inline
|
19
|
-
|
20
|
-
send(@type, c)
|
21
|
-
end
|
22
|
-
|
23
|
-
complete_token
|
24
|
-
@component_count += @components.count if @type == :inline
|
25
|
-
end
|
26
|
-
=begin
|
27
|
-
Inline Parser
|
28
|
-
=end
|
29
|
-
def inline(char)
|
30
|
-
c = char.strip
|
31
|
-
|
32
|
-
if c.empty? and not @current.empty?
|
33
|
-
complete_token
|
34
|
-
else
|
35
|
-
@current += c
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
=begin
|
40
|
-
Standard Parser
|
41
|
-
=end
|
42
|
-
|
43
|
-
def standard(char)
|
44
|
-
@token_type ||= detect_token_type char
|
45
|
-
@doubt_str = ''
|
46
|
-
|
47
|
-
send(@token_type, char)
|
48
|
-
end
|
49
|
-
|
50
|
-
def args_counts(char)
|
51
|
-
return if char.eql? '*'
|
52
|
-
|
53
|
-
tokenize char do
|
54
|
-
@component_count = @current.to_i
|
55
|
-
clean_context
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def length(char)
|
60
|
-
return if char.eql? '$'
|
61
|
-
|
62
|
-
tokenize char do
|
63
|
-
@next_length = @current.to_i
|
64
|
-
clean_context
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def payload(char)
|
69
|
-
return if char.eql? '$'
|
70
|
-
|
71
|
-
@next_length = 0 if @current.length == @next_length
|
72
|
-
|
73
|
-
tokenize char do
|
74
|
-
@next_length = 0
|
75
|
-
complete_token
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def tokenize(char, &block)
|
80
|
-
reach_delimiter = consume_delimiter(char)
|
81
|
-
|
82
|
-
if reach_delimiter
|
83
|
-
if @doubt_str.empty?
|
84
|
-
block.call
|
85
|
-
end
|
86
|
-
return
|
87
|
-
end
|
88
|
-
|
89
|
-
@current += char
|
90
|
-
end
|
91
|
-
|
92
|
-
=begin
|
93
|
-
Common Utilities
|
94
|
-
=end
|
95
|
-
|
96
|
-
def complete_token
|
97
|
-
@components << @current
|
98
|
-
clean_context
|
99
|
-
end
|
100
|
-
|
101
|
-
def clean_context
|
102
|
-
@current = ''
|
103
|
-
@token_type = nil
|
104
|
-
end
|
105
|
-
|
106
|
-
def consume_delimiter(char)
|
107
|
-
return false if @next_length != 0
|
108
|
-
|
109
|
-
if @doubt and char.eql? "\n"
|
110
|
-
@doubt_str = ''
|
111
|
-
@doubt = false
|
112
|
-
return true
|
113
|
-
end
|
114
|
-
|
115
|
-
if not @doubt and char.eql? "\r"
|
116
|
-
@doubt_str = "\r"
|
117
|
-
@doubt = true
|
118
|
-
return true
|
119
|
-
end
|
120
|
-
|
121
|
-
@doubt = false
|
122
|
-
@current += @doubt_str unless @doubt_str.empty?
|
123
|
-
@doubt_str = ''
|
124
|
-
return false
|
125
|
-
end
|
126
|
-
|
127
|
-
def detect_token_type(char)
|
128
|
-
case char
|
129
|
-
when '*'
|
130
|
-
:args_counts
|
131
|
-
when '$'
|
132
|
-
:length
|
133
|
-
else
|
134
|
-
:payload
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
4
|
class Response
|
140
5
|
|
141
6
|
end
|
142
|
-
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'redis-protocol/request'
|
@@ -0,0 +1,134 @@
|
|
1
|
+
class RedisProtocol::Request
|
2
|
+
attr_reader :raw_data, :type, :component_count, :components
|
3
|
+
|
4
|
+
def initialize(data)
|
5
|
+
@raw_data = data
|
6
|
+
@type, @components, @component_count, @current = nil, [], 0, ''
|
7
|
+
@next_length = 0
|
8
|
+
parse
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def parse
|
14
|
+
@raw_data.chars.each do |c|
|
15
|
+
@type ||= c.eql?('*') ? :standard : :inline
|
16
|
+
|
17
|
+
send(@type, c)
|
18
|
+
end
|
19
|
+
|
20
|
+
complete_token
|
21
|
+
@component_count += @components.count if @type == :inline
|
22
|
+
end
|
23
|
+
=begin
|
24
|
+
Inline Parser
|
25
|
+
=end
|
26
|
+
def inline(char)
|
27
|
+
c = char.strip
|
28
|
+
|
29
|
+
if c.empty? and not @current.empty?
|
30
|
+
complete_token
|
31
|
+
else
|
32
|
+
@current += c
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
=begin
|
37
|
+
Standard Parser
|
38
|
+
=end
|
39
|
+
|
40
|
+
def standard(char)
|
41
|
+
@token_type ||= detect_token_type char
|
42
|
+
@doubt_str = ''
|
43
|
+
|
44
|
+
send(@token_type, char)
|
45
|
+
end
|
46
|
+
|
47
|
+
def args_counts(char)
|
48
|
+
return if char.eql? '*'
|
49
|
+
|
50
|
+
tokenize char do
|
51
|
+
@component_count = @current.to_i
|
52
|
+
clean_context
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def length(char)
|
57
|
+
return if char.eql? '$'
|
58
|
+
|
59
|
+
tokenize char do
|
60
|
+
@next_length = @current.to_i
|
61
|
+
clean_context
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def payload(char)
|
66
|
+
return if char.eql? '$'
|
67
|
+
|
68
|
+
@next_length = 0 if @current.length == @next_length
|
69
|
+
|
70
|
+
tokenize char do
|
71
|
+
@next_length = 0
|
72
|
+
complete_token
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def tokenize(char, &block)
|
77
|
+
reach_delimiter = consume_delimiter(char)
|
78
|
+
|
79
|
+
if reach_delimiter
|
80
|
+
if @doubt_str.empty?
|
81
|
+
block.call
|
82
|
+
end
|
83
|
+
return
|
84
|
+
end
|
85
|
+
|
86
|
+
@current += char
|
87
|
+
end
|
88
|
+
|
89
|
+
=begin
|
90
|
+
Common Utilities
|
91
|
+
=end
|
92
|
+
|
93
|
+
def complete_token
|
94
|
+
@components << @current
|
95
|
+
clean_context
|
96
|
+
end
|
97
|
+
|
98
|
+
def clean_context
|
99
|
+
@current = ''
|
100
|
+
@token_type = nil
|
101
|
+
end
|
102
|
+
|
103
|
+
def consume_delimiter(char)
|
104
|
+
return false if @next_length != 0
|
105
|
+
|
106
|
+
if @doubt and char.eql? "\n"
|
107
|
+
@doubt_str = ''
|
108
|
+
@doubt = false
|
109
|
+
return true
|
110
|
+
end
|
111
|
+
|
112
|
+
if not @doubt and char.eql? "\r"
|
113
|
+
@doubt_str = "\r"
|
114
|
+
@doubt = true
|
115
|
+
return true
|
116
|
+
end
|
117
|
+
|
118
|
+
@doubt = false
|
119
|
+
@current += @doubt_str unless @doubt_str.empty?
|
120
|
+
@doubt_str = ''
|
121
|
+
return false
|
122
|
+
end
|
123
|
+
|
124
|
+
def detect_token_type(char)
|
125
|
+
case char
|
126
|
+
when '*'
|
127
|
+
:args_counts
|
128
|
+
when '$'
|
129
|
+
:length
|
130
|
+
else
|
131
|
+
:payload
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
class RedisProtocol::StaticRequest
|
2
|
+
attr_reader :raw_data, :type
|
3
|
+
OP_DELIMITER = "\r\n"
|
4
|
+
|
5
|
+
def initialize(data)
|
6
|
+
@raw_data = data
|
7
|
+
parse_request
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse_request
|
11
|
+
@type = check_request_type
|
12
|
+
|
13
|
+
send @type, @raw_data
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.recognize(data)
|
17
|
+
(check_request_type == :inline) ? data.split[0] : data.split(OP_DELIMITER)[2]
|
18
|
+
end
|
19
|
+
|
20
|
+
def check_request_type
|
21
|
+
(@raw_data.start_with? '*') ? :standard : :inline
|
22
|
+
end
|
23
|
+
|
24
|
+
def standard
|
25
|
+
components = []
|
26
|
+
data = @raw_data.dup
|
27
|
+
operand_length, payload = operand_length_for data.split(OP_DELIMITER)
|
28
|
+
1.upto(operand_length).each do |_|
|
29
|
+
data, payload = unpack_payload(payload)
|
30
|
+
components << data
|
31
|
+
end
|
32
|
+
@components = components
|
33
|
+
end
|
34
|
+
|
35
|
+
def operand_length_for(data)
|
36
|
+
operand_length, payload = next_token data
|
37
|
+
raise "invalid packet : #{operand_length}" unless operand_length.start_with? '*'
|
38
|
+
operand_length = operand_length[1..-1].to_i
|
39
|
+
|
40
|
+
[operand_length, payload]
|
41
|
+
end
|
42
|
+
|
43
|
+
def unpack_payload(payload)
|
44
|
+
field_length, payload = next_token payload
|
45
|
+
raise "invalid length format : #{field_length}" unless field_length.start_with? '$'
|
46
|
+
field_length = field_length[1..-1].to_i
|
47
|
+
next_token payload, field_length
|
48
|
+
end
|
49
|
+
|
50
|
+
def inline(data)
|
51
|
+
data.split
|
52
|
+
end
|
53
|
+
|
54
|
+
def next_token(data, length = 0)
|
55
|
+
if data[0].length == length || length == 0
|
56
|
+
[data[0], data[1..-1]]
|
57
|
+
else
|
58
|
+
multiline_token(data, length)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def multiline_token(data, length)
|
63
|
+
val, index = '', 0
|
64
|
+
data.each do |token|
|
65
|
+
val.empty? ? val = token : val += "\r\n#{token}"
|
66
|
+
index += 1
|
67
|
+
|
68
|
+
break if val.length == length
|
69
|
+
end
|
70
|
+
[val, data[index..-1]]
|
71
|
+
end
|
72
|
+
|
73
|
+
private :next_token, :standard, :inline, :operand_length_for, :unpack_payload, :multiline_token
|
74
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-protocol
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -126,6 +126,8 @@ files:
|
|
126
126
|
- Rakefile
|
127
127
|
- VERSION
|
128
128
|
- lib/redis-protocol.rb
|
129
|
+
- lib/redis-protocol/request.rb
|
130
|
+
- lib/redis-protocol/static_request.rb
|
129
131
|
- spec/redis-protocol/request_spec.rb
|
130
132
|
- spec/redis-protocol_spec.rb
|
131
133
|
- spec/spec_helper.rb
|
@@ -144,7 +146,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
144
146
|
version: '0'
|
145
147
|
segments:
|
146
148
|
- 0
|
147
|
-
hash:
|
149
|
+
hash: 1791670625487340402
|
148
150
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
151
|
none: false
|
150
152
|
requirements:
|