Class: Protocol::Redis::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/protocol/redis/connection.rb

Overview

Represents a Redis protocol connection handling low-level communication.

Constant Summary collapse

CRLF =
"\r\n".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(stream) ⇒ Connection

Initialize a new connection with the provided stream.



16
17
18
19
20
21
# File 'lib/protocol/redis/connection.rb', line 16

def initialize(stream)
	@stream = stream
	
	# Number of requests sent:
	@count = 0
end

Instance Attribute Details

#countObject (readonly)



26
27
28
# File 'lib/protocol/redis/connection.rb', line 26

def count
  @count
end

#streamObject (readonly)

Returns the value of attribute stream.



23
24
25
# File 'lib/protocol/redis/connection.rb', line 23

def stream
  @stream
end

Instance Method Details

#closeObject

Close the underlying stream connection.



29
30
31
# File 'lib/protocol/redis/connection.rb', line 29

def close
	@stream.close
end

#closed?Boolean

Check if the connection is closed.

Returns:

  • (Boolean)


45
46
47
# File 'lib/protocol/redis/connection.rb', line 45

def closed?
	@stream.closed?
end

#flushObject

Flush any buffered data to the stream.



39
40
41
# File 'lib/protocol/redis/connection.rb', line 39

def flush
	@stream.flush
end

#read_data(length) ⇒ Object

Read data of specified length from the stream.



92
93
94
95
96
97
98
99
# File 'lib/protocol/redis/connection.rb', line 92

def read_data(length)
	buffer = @stream.read(length) or @stream.eof!
	
	# Eat trailing whitespace because length does not include the CRLF:
	@stream.read(2) or @stream.eof!
	
	return buffer
end

#read_objectObject Also known as: read_response

Read and parse a Redis object from the stream.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/protocol/redis/connection.rb', line 105

def read_object
	line = read_line or raise EOFError
	
	token = line.slice!(0, 1)
	
	case token
	when "$"
		length = line.to_i
		
		if length == -1
			return nil
		else
			return read_data(length)
		end
	when "*"
		count = line.to_i
		
		# Null array (https://redis.io/topics/protocol#resp-arrays):
		return nil if count == -1
		
		array = Array.new(count) {read_object}
		
		return array
	when ":"
		return line.to_i
		
	when "-"
		raise ServerError.new(line)
		
	when "+"
		return line
		
	else
		@stream.flush
		
		raise UnknownTokenError, token.inspect
	end
	
	# TODO: If an exception (e.g. Async::TimeoutError) propagates out of this function, perhaps @stream should be closed? Otherwise it might be in a weird state.
end

#write_array(array) ⇒ Object

Write a Redis array to the stream.



81
82
83
84
85
86
87
# File 'lib/protocol/redis/connection.rb', line 81

def write_array(array)
	write_lines("*#{array.size}")
	
	array.each do |element|
		write_object(element)
	end
end

#write_object(object) ⇒ Object

Write a Redis object to the stream.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/protocol/redis/connection.rb', line 64

def write_object(object)
	case object
	when String
		write_lines("$#{object.bytesize}", object)
	when Array
		write_array(object)
	when Integer
		write_lines(":#{object}")
	when nil
		write_lines("$-1")
	else
		write_object(object.to_redis)
	end
end

#write_request(arguments) ⇒ Object

The redis server doesn’t want actual objects (e.g. integers) but only bulk strings. So, we inline it for performance.



50
51
52
53
54
55
56
57
58
59
60
# File 'lib/protocol/redis/connection.rb', line 50

def write_request(arguments)
	write_lines("*#{arguments.size}")
	
	@count += 1
	
	arguments.each do |argument|
		string = argument.to_s
		
		write_lines("$#{string.bytesize}", string)
	end
end