droonga-client 0.1.5 → 0.1.6
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/bin/droonga-send +1 -0
- data/doc/text/news.md +4 -0
- data/droonga-client.gemspec +1 -0
- data/lib/droonga/client/connection/droonga-protocol.rb +20 -170
- data/lib/droonga/client/connection/droonga-protocol/coolio.rb +232 -0
- data/lib/droonga/client/connection/droonga-protocol/thread.rb +217 -0
- data/lib/droonga/client/connection/empty-request.rb +28 -0
- data/lib/droonga/client/connection/error.rb +10 -0
- data/lib/droonga/client/version.rb +1 -1
- metadata +30 -16
data/bin/droonga-send
CHANGED
data/doc/text/news.md
CHANGED
data/droonga-client.gemspec
CHANGED
@@ -39,6 +39,7 @@ Gem::Specification.new do |spec|
|
|
39
39
|
spec.add_runtime_dependency "fluent-logger"
|
40
40
|
spec.add_runtime_dependency "rack"
|
41
41
|
spec.add_runtime_dependency "yajl-ruby"
|
42
|
+
spec.add_runtime_dependency "droonga-message-pack-packer"
|
42
43
|
|
43
44
|
spec.add_development_dependency "bundler", "~> 1.3"
|
44
45
|
spec.add_development_dependency "rake"
|
@@ -15,36 +15,18 @@
|
|
15
15
|
# License along with this library; if not, write to the Free Software
|
16
16
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
17
|
|
18
|
-
require "
|
19
|
-
require "thread"
|
20
|
-
require "msgpack"
|
21
|
-
require "fluent-logger"
|
18
|
+
require "droonga/client/connection/error"
|
22
19
|
|
23
20
|
module Droonga
|
24
21
|
class Client
|
25
22
|
module Connection
|
26
23
|
class DroongaProtocol
|
27
|
-
class Request
|
28
|
-
def initialize(thread)
|
29
|
-
@thread = thread
|
30
|
-
end
|
31
|
-
|
32
|
-
def wait
|
33
|
-
@thread.join
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
24
|
def initialize(options={})
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
}
|
44
|
-
@options = default_options.merge(options)
|
45
|
-
@logger = Fluent::Logger::FluentLogger.new(@options.delete(:tag),
|
46
|
-
@options)
|
47
|
-
@timeout = @options[:timeout]
|
25
|
+
@host = options[:host] || "127.0.0.1"
|
26
|
+
@port = options[:port] || 24224
|
27
|
+
@tag = options[:tag] || "droonga"
|
28
|
+
@options = options
|
29
|
+
@backend = create_backend
|
48
30
|
end
|
49
31
|
|
50
32
|
# Sends a request message and receives one or more response
|
@@ -72,28 +54,7 @@ module Droonga
|
|
72
54
|
#
|
73
55
|
# @return [Request] The request object.
|
74
56
|
def request(message, options={}, &block)
|
75
|
-
|
76
|
-
message = message.dup
|
77
|
-
message["replyTo"] = "#{receiver.host}:#{receiver.port}/droonga"
|
78
|
-
send(message, options)
|
79
|
-
|
80
|
-
sync = block.nil?
|
81
|
-
if sync
|
82
|
-
responses = []
|
83
|
-
receive(receiver, options) do |response|
|
84
|
-
responses << response
|
85
|
-
end
|
86
|
-
if responses.size > 1
|
87
|
-
responses
|
88
|
-
else
|
89
|
-
responses.first
|
90
|
-
end
|
91
|
-
else
|
92
|
-
thread = Thread.new do
|
93
|
-
receive(receiver, options, &block)
|
94
|
-
end
|
95
|
-
Request.new(thread)
|
96
|
-
end
|
57
|
+
@backend.request(message, options, &block)
|
97
58
|
end
|
98
59
|
|
99
60
|
# Subscribes something and receives zero or more published
|
@@ -123,35 +84,7 @@ module Droonga
|
|
123
84
|
#
|
124
85
|
# @return [Request] The request object.
|
125
86
|
def subscribe(message, options={}, &block)
|
126
|
-
|
127
|
-
message = message.dup
|
128
|
-
message["from"] = "#{receiver.host}:#{receiver.port}/droonga"
|
129
|
-
send(message, options)
|
130
|
-
|
131
|
-
receive_options = {
|
132
|
-
:timeout => nil,
|
133
|
-
}
|
134
|
-
sync = block.nil?
|
135
|
-
if sync
|
136
|
-
Enumerator.new do |yielder|
|
137
|
-
loop do
|
138
|
-
receiver.receive(receive_options) do |object|
|
139
|
-
yielder << object
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
else
|
144
|
-
thread = Thread.new do
|
145
|
-
begin
|
146
|
-
loop do
|
147
|
-
receiver.receive(receive_options, &block)
|
148
|
-
end
|
149
|
-
ensure
|
150
|
-
receiver.close
|
151
|
-
end
|
152
|
-
end
|
153
|
-
Request.new(thread)
|
154
|
-
end
|
87
|
+
@backend.subscribe(message, options, &block)
|
155
88
|
end
|
156
89
|
|
157
90
|
# Sends low level request. Normally, you should use other
|
@@ -162,114 +95,31 @@ module Droonga
|
|
162
95
|
# TODO: WRITE ME
|
163
96
|
# @return [void]
|
164
97
|
def send(message, options={}, &block)
|
165
|
-
|
166
|
-
message = message.merge("id" => Time.now.to_f.to_s,
|
167
|
-
"date" => Time.now)
|
168
|
-
end
|
169
|
-
@logger.post("message", message)
|
98
|
+
@backend.send(message, options, &block)
|
170
99
|
end
|
171
100
|
|
172
101
|
# Close the connection. This connection can't be used anymore.
|
173
102
|
#
|
174
103
|
# @return [void]
|
175
104
|
def close
|
176
|
-
@
|
105
|
+
@backend.close
|
177
106
|
end
|
178
107
|
|
179
108
|
private
|
180
|
-
def
|
181
|
-
|
182
|
-
:port => @options[:receiver_port])
|
183
|
-
end
|
184
|
-
|
185
|
-
def receive(receiver, options)
|
186
|
-
timeout = options[:timeout] || @timeout
|
109
|
+
def create_backend
|
110
|
+
backend = @options[:backend] || :thread
|
187
111
|
|
188
|
-
receive_options = {
|
189
|
-
:timeout => timeout,
|
190
|
-
}
|
191
112
|
begin
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
class Receiver
|
201
|
-
def initialize(options={})
|
202
|
-
host = options[:host] || Socket.gethostname
|
203
|
-
port = options[:port] || 0
|
204
|
-
@socket = TCPServer.new(host, port)
|
205
|
-
@read_ios = [@socket]
|
206
|
-
@client_handlers = {}
|
207
|
-
end
|
208
|
-
|
209
|
-
def close
|
210
|
-
@socket.close
|
211
|
-
@client_handlers.each_key do |client|
|
212
|
-
client.close
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def host
|
217
|
-
@socket.addr[3]
|
218
|
-
end
|
219
|
-
|
220
|
-
def port
|
221
|
-
@socket.addr[1]
|
113
|
+
require "droonga/client/connection/droonga-protocol/#{backend}"
|
114
|
+
rescue LoadError
|
115
|
+
raise UnknownBackendError.new("Droonga protocol",
|
116
|
+
backend,
|
117
|
+
$!.message)
|
222
118
|
end
|
223
119
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
catch do |tag|
|
228
|
-
loop do
|
229
|
-
start = Time.new
|
230
|
-
readable_ios, = IO.select(@read_ios, nil, nil, timeout)
|
231
|
-
break if readable_ios.nil?
|
232
|
-
if timeout
|
233
|
-
timeout -= (Time.now - start)
|
234
|
-
timeout = 0 if timeout < 0
|
235
|
-
end
|
236
|
-
readable_ios.each do |readable_io|
|
237
|
-
on_readable(readable_io) do |object|
|
238
|
-
begin
|
239
|
-
yield(object)
|
240
|
-
rescue LocalJumpError
|
241
|
-
throw(tag)
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
private
|
250
|
-
def on_readable(io)
|
251
|
-
case io
|
252
|
-
when @socket
|
253
|
-
client = @socket.accept
|
254
|
-
@read_ios << client
|
255
|
-
@client_handlers[client] = lambda do
|
256
|
-
unpacker = MessagePack::Unpacker.new
|
257
|
-
loop do
|
258
|
-
readable, = IO.select([client], nil, nil, 0)
|
259
|
-
break unless readable
|
260
|
-
data = client.read_nonblock(BUFFER_SIZE)
|
261
|
-
unpacker.feed_each(data) do |object|
|
262
|
-
yield(object)
|
263
|
-
end
|
264
|
-
end
|
265
|
-
client.close
|
266
|
-
@read_ios.delete(client)
|
267
|
-
@client_handlers.delete(client)
|
268
|
-
end
|
269
|
-
else
|
270
|
-
@client_handlers[io].call
|
271
|
-
end
|
272
|
-
end
|
120
|
+
backend_name = backend.to_s.capitalize
|
121
|
+
backend_class = self.class.const_get(backend_name)
|
122
|
+
backend_class.new(@host, @port, @tag, @options)
|
273
123
|
end
|
274
124
|
end
|
275
125
|
end
|
@@ -0,0 +1,232 @@
|
|
1
|
+
# Copyright (C) 2014 Droonga Project
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License version 2.1 as published by the Free Software Foundation.
|
6
|
+
#
|
7
|
+
# This library is distributed in the hope that it will be useful,
|
8
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
9
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
10
|
+
# Lesser General Public License for more details.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU Lesser General Public
|
13
|
+
# License along with this library; if not, write to the Free Software
|
14
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
15
|
+
|
16
|
+
require "coolio"
|
17
|
+
require "droonga/message-pack-packer"
|
18
|
+
|
19
|
+
module Droonga
|
20
|
+
class Client
|
21
|
+
module Connection
|
22
|
+
class DroongaProtocol
|
23
|
+
class Coolio
|
24
|
+
class Request
|
25
|
+
def initialize(receiver, id, loop)
|
26
|
+
@receiver = receiver
|
27
|
+
@id = id
|
28
|
+
@loop = loop
|
29
|
+
end
|
30
|
+
|
31
|
+
def wait
|
32
|
+
return if @receiver.received?(@id)
|
33
|
+
until @receiver.received?(@id)
|
34
|
+
@loop.run_once
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class InfiniteRequest
|
40
|
+
def initialize(loop)
|
41
|
+
@loop = loop
|
42
|
+
end
|
43
|
+
|
44
|
+
def wait
|
45
|
+
@loop.run
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Sender < ::Coolio::TCPSocket
|
50
|
+
def initialize(socket)
|
51
|
+
super(socket)
|
52
|
+
end
|
53
|
+
|
54
|
+
def send(tag, data)
|
55
|
+
fluent_message = [tag, Time.now.to_i, data]
|
56
|
+
packed_fluent_message = MessagePackPacker.pack(fluent_message)
|
57
|
+
write(packed_fluent_message)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class Receiver < ::Coolio::TCPServer
|
62
|
+
def initialize(*args)
|
63
|
+
super(*args) do |engine|
|
64
|
+
@engines << engine
|
65
|
+
handle_engine(engine)
|
66
|
+
end
|
67
|
+
@requests = {}
|
68
|
+
@engines = []
|
69
|
+
end
|
70
|
+
|
71
|
+
def close
|
72
|
+
super
|
73
|
+
@engines.each do |engine|
|
74
|
+
engine.close
|
75
|
+
end
|
76
|
+
@engines.clear
|
77
|
+
end
|
78
|
+
|
79
|
+
def host
|
80
|
+
@listen_socket.addr[3]
|
81
|
+
end
|
82
|
+
|
83
|
+
def port
|
84
|
+
@listen_socket.addr[1]
|
85
|
+
end
|
86
|
+
|
87
|
+
def droonga_name
|
88
|
+
"#{host}:#{port}/droonga"
|
89
|
+
end
|
90
|
+
|
91
|
+
def register(id, &callback)
|
92
|
+
@requests[id] = {
|
93
|
+
:received => false,
|
94
|
+
:callback => callback,
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def unregister(id)
|
99
|
+
@requests.delete(id)
|
100
|
+
end
|
101
|
+
|
102
|
+
def received?(id)
|
103
|
+
if @requests.key?(id)
|
104
|
+
@requests[id][:received]
|
105
|
+
else
|
106
|
+
true
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
def handle_engine(engine)
|
112
|
+
unpacker = MessagePack::Unpacker.new
|
113
|
+
on_read = lambda do |data|
|
114
|
+
unpacker.feed_each(data) do |fluent_message|
|
115
|
+
tag, time, droonga_message = fluent_message
|
116
|
+
id = droonga_message["inReplyTo"]
|
117
|
+
request = @requests[id]
|
118
|
+
next if request.nil?
|
119
|
+
request[:received] = true
|
120
|
+
request[:callback].call(droonga_message)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
engine.on_read do |data|
|
124
|
+
on_read.call(data)
|
125
|
+
end
|
126
|
+
|
127
|
+
on_close = lambda do
|
128
|
+
@engines.delete(engine)
|
129
|
+
end
|
130
|
+
engine.on_close do
|
131
|
+
on_close.call
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def initialize(host, port, tag, options={})
|
137
|
+
@host = host
|
138
|
+
@port = port
|
139
|
+
@tag = tag
|
140
|
+
default_options = {
|
141
|
+
}
|
142
|
+
@options = default_options.merge(options)
|
143
|
+
@loop = options[:loop] || ::Coolio::Loop.default
|
144
|
+
|
145
|
+
@sender = Sender.connect(@host, @port)
|
146
|
+
@sender.attach(@loop)
|
147
|
+
@receiver_host = @options[:receiver_host] || Socket.gethostname
|
148
|
+
@receiver_port = @options[:receiver_port] || 0
|
149
|
+
@receiver = Receiver.new(@receiver_host, @receiver_port)
|
150
|
+
@receiver.attach(@loop)
|
151
|
+
end
|
152
|
+
|
153
|
+
def request(message, options={}, &block)
|
154
|
+
id = message["id"] || generate_id
|
155
|
+
message = message.merge("id" => id,
|
156
|
+
"replyTo" => @receiver.droonga_name)
|
157
|
+
send(message, options)
|
158
|
+
|
159
|
+
sync = block.nil?
|
160
|
+
if sync
|
161
|
+
response = nil
|
162
|
+
block = lambda do |_response|
|
163
|
+
response = _response
|
164
|
+
end
|
165
|
+
end
|
166
|
+
@receiver.register(id) do |response|
|
167
|
+
@receiver.unregister(id)
|
168
|
+
block.call(response)
|
169
|
+
end
|
170
|
+
request = Request.new(@receiver, id, @loop)
|
171
|
+
if sync
|
172
|
+
request.wait
|
173
|
+
response
|
174
|
+
else
|
175
|
+
request
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def subscribe(message, options={}, &block)
|
180
|
+
id = message["id"] || generate_id
|
181
|
+
message = message.merge("id" => id,
|
182
|
+
"from" => @receiver.droonga_name)
|
183
|
+
send(message, options)
|
184
|
+
|
185
|
+
request = InfiniteRequest.new(@loop)
|
186
|
+
sync = block.nil?
|
187
|
+
if sync
|
188
|
+
yielder = nil
|
189
|
+
buffer = []
|
190
|
+
@receiver.register(id) do |response|
|
191
|
+
if yielder
|
192
|
+
while (old_response = buffer.shift)
|
193
|
+
yielder << old_response
|
194
|
+
end
|
195
|
+
yielder << response
|
196
|
+
else
|
197
|
+
buffer << response
|
198
|
+
end
|
199
|
+
end
|
200
|
+
Enumerator.new do |_yielder|
|
201
|
+
yielder = _yielder
|
202
|
+
request.wait
|
203
|
+
end
|
204
|
+
else
|
205
|
+
@receiver.register(id, &block)
|
206
|
+
request
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def send(message, options={}, &block)
|
211
|
+
if message["id"].nil? or message["date"].nil?
|
212
|
+
id = message["id"] || generate_id
|
213
|
+
date = message["date"] || Time.now
|
214
|
+
message = message.merge("id" => id, "date" => date)
|
215
|
+
end
|
216
|
+
@sender.send("#{@tag}.message", message)
|
217
|
+
end
|
218
|
+
|
219
|
+
def close
|
220
|
+
@sender.close
|
221
|
+
@receiver.close
|
222
|
+
end
|
223
|
+
|
224
|
+
private
|
225
|
+
def generate_id
|
226
|
+
Time.now.to_f.to_s
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# Copyright (C) 2013-2014 Droonga Project
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License version 2.1 as published by the Free Software Foundation.
|
6
|
+
#
|
7
|
+
# This library is distributed in the hope that it will be useful,
|
8
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
9
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
10
|
+
# Lesser General Public License for more details.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU Lesser General Public
|
13
|
+
# License along with this library; if not, write to the Free Software
|
14
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
15
|
+
|
16
|
+
require "socket"
|
17
|
+
require "thread"
|
18
|
+
require "msgpack"
|
19
|
+
require "fluent-logger"
|
20
|
+
|
21
|
+
module Droonga
|
22
|
+
class Client
|
23
|
+
module Connection
|
24
|
+
class DroongaProtocol
|
25
|
+
class Thread
|
26
|
+
class Request
|
27
|
+
def initialize(thread)
|
28
|
+
@thread = thread
|
29
|
+
end
|
30
|
+
|
31
|
+
def wait
|
32
|
+
@thread.join
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(host, port, tag, options={})
|
37
|
+
@host = host
|
38
|
+
@port = port
|
39
|
+
@tag = tag
|
40
|
+
default_options = {
|
41
|
+
:timeout => 1,
|
42
|
+
}
|
43
|
+
@options = default_options.merge(options)
|
44
|
+
@logger = Fluent::Logger::FluentLogger.new(@tag, @options)
|
45
|
+
@timeout = @options[:timeout]
|
46
|
+
end
|
47
|
+
|
48
|
+
def request(message, options={}, &block)
|
49
|
+
receiver = create_receiver
|
50
|
+
message = message.dup
|
51
|
+
message["replyTo"] = "#{receiver.host}:#{receiver.port}/droonga"
|
52
|
+
send(message, options)
|
53
|
+
|
54
|
+
sync = block.nil?
|
55
|
+
if sync
|
56
|
+
responses = []
|
57
|
+
receive(receiver, options) do |response|
|
58
|
+
responses << response
|
59
|
+
end
|
60
|
+
if responses.size > 1
|
61
|
+
responses
|
62
|
+
else
|
63
|
+
responses.first
|
64
|
+
end
|
65
|
+
else
|
66
|
+
thread = ::Thread.new do
|
67
|
+
receive(receiver, options, &block)
|
68
|
+
end
|
69
|
+
Request.new(thread)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def subscribe(message, options={}, &block)
|
74
|
+
receiver = create_receiver
|
75
|
+
message = message.dup
|
76
|
+
message["from"] = "#{receiver.host}:#{receiver.port}/droonga"
|
77
|
+
send(message, options)
|
78
|
+
|
79
|
+
receive_options = {
|
80
|
+
:timeout => nil,
|
81
|
+
}
|
82
|
+
sync = block.nil?
|
83
|
+
if sync
|
84
|
+
Enumerator.new do |yielder|
|
85
|
+
loop do
|
86
|
+
receiver.receive(receive_options) do |object|
|
87
|
+
yielder << object
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
else
|
92
|
+
thread = ::Thread.new do
|
93
|
+
begin
|
94
|
+
loop do
|
95
|
+
receiver.receive(receive_options, &block)
|
96
|
+
end
|
97
|
+
ensure
|
98
|
+
receiver.close
|
99
|
+
end
|
100
|
+
end
|
101
|
+
Request.new(thread)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def send(message, options={}, &block)
|
106
|
+
if message["id"].nil? or message["date"].nil?
|
107
|
+
message = message.merge("id" => Time.now.to_f.to_s,
|
108
|
+
"date" => Time.now)
|
109
|
+
end
|
110
|
+
@logger.post("message", message)
|
111
|
+
end
|
112
|
+
|
113
|
+
def close
|
114
|
+
@logger.close
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
def create_receiver
|
119
|
+
Receiver.new(:host => @options[:receiver_host],
|
120
|
+
:port => @options[:receiver_port])
|
121
|
+
end
|
122
|
+
|
123
|
+
def receive(receiver, options)
|
124
|
+
timeout = options[:timeout] || @timeout
|
125
|
+
|
126
|
+
receive_options = {
|
127
|
+
:timeout => timeout,
|
128
|
+
}
|
129
|
+
begin
|
130
|
+
receiver.receive(receive_options) do |response|
|
131
|
+
yield(response)
|
132
|
+
end
|
133
|
+
ensure
|
134
|
+
receiver.close
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class Receiver
|
139
|
+
def initialize(options={})
|
140
|
+
host = options[:host] || Socket.gethostname
|
141
|
+
port = options[:port] || 0
|
142
|
+
@socket = TCPServer.new(host, port)
|
143
|
+
@read_ios = [@socket]
|
144
|
+
@client_handlers = {}
|
145
|
+
end
|
146
|
+
|
147
|
+
def close
|
148
|
+
@socket.close
|
149
|
+
@client_handlers.each_key do |client|
|
150
|
+
client.close
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def host
|
155
|
+
@socket.addr[3]
|
156
|
+
end
|
157
|
+
|
158
|
+
def port
|
159
|
+
@socket.addr[1]
|
160
|
+
end
|
161
|
+
|
162
|
+
BUFFER_SIZE = 8192
|
163
|
+
def receive(options={}, &block)
|
164
|
+
timeout = options[:timeout]
|
165
|
+
catch do |tag|
|
166
|
+
loop do
|
167
|
+
start = Time.new
|
168
|
+
readable_ios, = IO.select(@read_ios, nil, nil, timeout)
|
169
|
+
break if readable_ios.nil?
|
170
|
+
if timeout
|
171
|
+
timeout -= (Time.now - start)
|
172
|
+
timeout = 0 if timeout < 0
|
173
|
+
end
|
174
|
+
readable_ios.each do |readable_io|
|
175
|
+
on_readable(readable_io) do |object|
|
176
|
+
begin
|
177
|
+
yield(object)
|
178
|
+
rescue LocalJumpError
|
179
|
+
throw(tag)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
private
|
188
|
+
def on_readable(io)
|
189
|
+
case io
|
190
|
+
when @socket
|
191
|
+
client = @socket.accept
|
192
|
+
@read_ios << client
|
193
|
+
@client_handlers[client] = lambda do
|
194
|
+
unpacker = MessagePack::Unpacker.new
|
195
|
+
loop do
|
196
|
+
readable, = IO.select([client], nil, nil, 0)
|
197
|
+
break unless readable
|
198
|
+
data = client.read_nonblock(BUFFER_SIZE)
|
199
|
+
unpacker.feed_each(data) do |fluent_message|
|
200
|
+
tag, time, droonga_message = fluent_message
|
201
|
+
yield(droonga_message)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
client.close
|
205
|
+
@read_ios.delete(client)
|
206
|
+
@client_handlers.delete(client)
|
207
|
+
end
|
208
|
+
else
|
209
|
+
@client_handlers[io].call
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Copyright (C) 2014 Droonga Project
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License version 2.1 as published by the Free Software Foundation.
|
6
|
+
#
|
7
|
+
# This library is distributed in the hope that it will be useful,
|
8
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
9
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
10
|
+
# Lesser General Public License for more details.
|
11
|
+
#
|
12
|
+
# You should have received a copy of the GNU Lesser General Public
|
13
|
+
# License along with this library; if not, write to the Free Software
|
14
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
15
|
+
|
16
|
+
module Droonga
|
17
|
+
class Client
|
18
|
+
module Connection
|
19
|
+
class EmptyRequest
|
20
|
+
def initialize
|
21
|
+
end
|
22
|
+
|
23
|
+
def wait
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -23,6 +23,16 @@ module Droonga
|
|
23
23
|
# The top error class of connection module.
|
24
24
|
class Error < Client::Error
|
25
25
|
end
|
26
|
+
|
27
|
+
class UnknownBackendError < Error
|
28
|
+
attr_reader :protocol
|
29
|
+
attr_reader :backend
|
30
|
+
def initialize(protocol, backend, detail)
|
31
|
+
@protocol = protocol
|
32
|
+
@backend = backend
|
33
|
+
super("Unknown #{@protocol} backend: <#{backend}>: #{detail}")
|
34
|
+
end
|
35
|
+
end
|
26
36
|
end
|
27
37
|
end
|
28
38
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: droonga-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-04-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: msgpack
|
16
|
-
requirement: &
|
16
|
+
requirement: &76464960 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *76464960
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: fluent-logger
|
27
|
-
requirement: &
|
27
|
+
requirement: &76464730 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *76464730
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rack
|
38
|
-
requirement: &
|
38
|
+
requirement: &76464520 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *76464520
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: yajl-ruby
|
49
|
-
requirement: &
|
49
|
+
requirement: &76464310 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,21 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *76464310
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: droonga-message-pack-packer
|
60
|
+
requirement: &76464100 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *76464100
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: bundler
|
60
|
-
requirement: &
|
71
|
+
requirement: &76463850 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ~>
|
@@ -65,10 +76,10 @@ dependencies:
|
|
65
76
|
version: '1.3'
|
66
77
|
type: :development
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *76463850
|
69
80
|
- !ruby/object:Gem::Dependency
|
70
81
|
name: rake
|
71
|
-
requirement: &
|
82
|
+
requirement: &76463640 !ruby/object:Gem::Requirement
|
72
83
|
none: false
|
73
84
|
requirements:
|
74
85
|
- - ! '>='
|
@@ -76,10 +87,10 @@ dependencies:
|
|
76
87
|
version: '0'
|
77
88
|
type: :development
|
78
89
|
prerelease: false
|
79
|
-
version_requirements: *
|
90
|
+
version_requirements: *76463640
|
80
91
|
- !ruby/object:Gem::Dependency
|
81
92
|
name: packnga
|
82
|
-
requirement: &
|
93
|
+
requirement: &76463410 !ruby/object:Gem::Requirement
|
83
94
|
none: false
|
84
95
|
requirements:
|
85
96
|
- - ! '>='
|
@@ -87,7 +98,7 @@ dependencies:
|
|
87
98
|
version: '0'
|
88
99
|
type: :development
|
89
100
|
prerelease: false
|
90
|
-
version_requirements: *
|
101
|
+
version_requirements: *76463410
|
91
102
|
description: Droonga client for Ruby
|
92
103
|
email:
|
93
104
|
- droonga@groonga.org
|
@@ -109,6 +120,9 @@ files:
|
|
109
120
|
- droonga-client.gemspec
|
110
121
|
- lib/droonga/client.rb
|
111
122
|
- lib/droonga/client/connection/droonga-protocol.rb
|
123
|
+
- lib/droonga/client/connection/droonga-protocol/coolio.rb
|
124
|
+
- lib/droonga/client/connection/droonga-protocol/thread.rb
|
125
|
+
- lib/droonga/client/connection/empty-request.rb
|
112
126
|
- lib/droonga/client/connection/error.rb
|
113
127
|
- lib/droonga/client/connection/http.rb
|
114
128
|
- lib/droonga/client/error.rb
|