fluent-plugin-droonga 0.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +40 -0
- data/LICENSE.txt +14 -0
- data/README.md +18 -0
- data/Rakefile +25 -0
- data/benchmark/benchmark.rb +123 -0
- data/benchmark/utils.rb +243 -0
- data/benchmark/watch/benchmark-notify.rb +143 -0
- data/benchmark/watch/benchmark-notify.sh +19 -0
- data/benchmark/watch/benchmark-publish.rb +120 -0
- data/benchmark/watch/benchmark-scan.rb +210 -0
- data/benchmark/watch/catalog.json +32 -0
- data/benchmark/watch/fluentd.conf +12 -0
- data/bin/grn2jsons +85 -0
- data/fluent-plugin-droonga.gemspec +41 -0
- data/lib/droonga/adapter.rb +156 -0
- data/lib/droonga/catalog.rb +153 -0
- data/lib/droonga/command_mapper.rb +45 -0
- data/lib/droonga/engine.rb +83 -0
- data/lib/droonga/executor.rb +289 -0
- data/lib/droonga/handler.rb +140 -0
- data/lib/droonga/handler_plugin.rb +35 -0
- data/lib/droonga/job_queue.rb +83 -0
- data/lib/droonga/job_queue_schema.rb +65 -0
- data/lib/droonga/logger.rb +34 -0
- data/lib/droonga/plugin.rb +41 -0
- data/lib/droonga/plugin/adapter/groonga/select.rb +88 -0
- data/lib/droonga/plugin/adapter_groonga.rb +40 -0
- data/lib/droonga/plugin/handler/groonga/column_create.rb +103 -0
- data/lib/droonga/plugin/handler/groonga/table_create.rb +100 -0
- data/lib/droonga/plugin/handler_add.rb +44 -0
- data/lib/droonga/plugin/handler_forward.rb +70 -0
- data/lib/droonga/plugin/handler_groonga.rb +52 -0
- data/lib/droonga/plugin/handler_proxy.rb +82 -0
- data/lib/droonga/plugin/handler_search.rb +33 -0
- data/lib/droonga/plugin/handler_watch.rb +102 -0
- data/lib/droonga/proxy.rb +371 -0
- data/lib/droonga/searcher.rb +415 -0
- data/lib/droonga/server.rb +112 -0
- data/lib/droonga/sweeper.rb +42 -0
- data/lib/droonga/watch_schema.rb +88 -0
- data/lib/droonga/watcher.rb +256 -0
- data/lib/droonga/worker.rb +51 -0
- data/lib/fluent/plugin/out_droonga.rb +56 -0
- data/lib/groonga_command_converter.rb +137 -0
- data/sample/cluster/catalog.json +43 -0
- data/sample/cluster/fluentd.conf +12 -0
- data/sample/fluentd.conf +8 -0
- data/test/fixtures/catalog.json +43 -0
- data/test/fixtures/document.grn +23 -0
- data/test/helper.rb +24 -0
- data/test/helper/fixture.rb +28 -0
- data/test/helper/sandbox.rb +73 -0
- data/test/helper/stub_worker.rb +27 -0
- data/test/helper/watch_helper.rb +35 -0
- data/test/plugin/adapter/groonga/test_select.rb +176 -0
- data/test/plugin/handler/groonga/test_column_create.rb +127 -0
- data/test/plugin/handler/groonga/test_table_create.rb +140 -0
- data/test/plugin/handler/test_handler_add.rb +135 -0
- data/test/plugin/handler/test_handler_groonga.rb +64 -0
- data/test/plugin/handler/test_handler_search.rb +512 -0
- data/test/plugin/handler/test_handler_watch.rb +168 -0
- data/test/run-test.rb +55 -0
- data/test/test_adapter.rb +48 -0
- data/test/test_catalog.rb +59 -0
- data/test/test_command_mapper.rb +44 -0
- data/test/test_groonga_command_converter.rb +242 -0
- data/test/test_handler.rb +53 -0
- data/test/test_job_queue_schema.rb +45 -0
- data/test/test_output.rb +99 -0
- data/test/test_sweeper.rb +95 -0
- data/test/test_watch_schema.rb +57 -0
- data/test/test_watcher.rb +336 -0
- data/test/test_worker.rb +144 -0
- metadata +299 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 99aed806731b4f63bdefc707bddd4fb9c6f1d105
|
4
|
+
data.tar.gz: 0a4ad0ab5c237b44a81656a489744aac4b264a64
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dbeb3a6142fe82e708355ef091ecb2789aa2f18058ac5a9b66089828c91bbfc1237b8f4c5b0998e7fee55a8188f321ac394a547a1608a2e4b15bd6036d24b8e5
|
7
|
+
data.tar.gz: 1db4e2fe92124dbd2d259dad398fb54868214e339319286ca2ce2c3bd7128b7b76b4cde19b5c6f6f262c6a703142a7a8ebd2b2c80021b381cf024d9c61f558ca
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
/Gemfile.lock
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Copyright (C) 2013 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
|
+
source "https://rubygems.org"
|
17
|
+
|
18
|
+
gemspec
|
19
|
+
|
20
|
+
parent_dir = File.join(File.dirname(__FILE__), "..")
|
21
|
+
local_rroonga_path = File.join(parent_dir, "rroonga")
|
22
|
+
local_groonga_command_path = File.join(parent_dir, "groonga-command")
|
23
|
+
local_groonga_command_parser_path = File.join(parent_dir,
|
24
|
+
"groonga-command-parser")
|
25
|
+
if File.exist?(local_rroonga_path)
|
26
|
+
gem "rroonga", :path => local_rroonga_path
|
27
|
+
gem "groonga-command", :path => local_groonga_command_path
|
28
|
+
gem "groonga-command-parser", :path => local_groonga_command_parser_path
|
29
|
+
elsif ENV["TRAVIS"] == "true"
|
30
|
+
require_unreleased_gems = false
|
31
|
+
if require_unreleased_gems
|
32
|
+
gem "rroonga", :git => "git://github.com/ranguba/rroonga.git"
|
33
|
+
gem "groonga-command",
|
34
|
+
:git => "git://github.com/groonga/groonga-command.git"
|
35
|
+
gem "groonga-command-parser",
|
36
|
+
:git => "git://github.com/groonga/groonga-command-parser.git"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
gem "droonga-client", github: "droonga/droonga-client-ruby"
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Copyright (C) 2013 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
|
data/README.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Fluent::Plugin::Droonga
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## What's "droonga"?
|
6
|
+
|
7
|
+
Droonga is a distributed fulltext search engine, named from "distributed-groonga".
|
8
|
+
This package provides droonga plugin for Fluent event collector.
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
TODO: Write usage.
|
13
|
+
|
14
|
+
## Copyright
|
15
|
+
|
16
|
+
* Copyright (c) 2013 droonga project
|
17
|
+
* License
|
18
|
+
* GNU Lesser General Public License version 2.1
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2013 droonga project
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License version 2.1 as published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
|
18
|
+
require "bundler/gem_tasks"
|
19
|
+
|
20
|
+
desc "Run test"
|
21
|
+
task :test do
|
22
|
+
ruby(File.join(File.dirname(__FILE__), "test", "run-test.rb"))
|
23
|
+
end
|
24
|
+
|
25
|
+
task :default => :test
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2013 droonga project
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License version 2.1 as published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
|
18
|
+
require "droonga/client"
|
19
|
+
|
20
|
+
module Droonga
|
21
|
+
class Benchmark
|
22
|
+
class Terms
|
23
|
+
class << self
|
24
|
+
def generate
|
25
|
+
new.to_enum(:each)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
FIRST_INITIAL_LETTER = "㐀"
|
30
|
+
SUFFIX = "あいうえおかきくけこ"
|
31
|
+
def each
|
32
|
+
initial_letter = FIRST_INITIAL_LETTER
|
33
|
+
while true do
|
34
|
+
yield "#{initial_letter}#{SUFFIX}"
|
35
|
+
initial_letter.succ!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
TERMS_STEP = 1000
|
41
|
+
|
42
|
+
N_TARGETS = 1000
|
43
|
+
TARGET_PADDING = "パディング"
|
44
|
+
TARGET_TITLE_SIZE = 100
|
45
|
+
TARGET_BODY_SIZE = 1000
|
46
|
+
|
47
|
+
def initialize(params)
|
48
|
+
@params = params
|
49
|
+
@terms = Terms.generate
|
50
|
+
@client = Droonga::Client.new(tag: @params[:tag], port: @params[:port])
|
51
|
+
end
|
52
|
+
|
53
|
+
def run
|
54
|
+
prepare_watching_subscribers(TERMS_STEP)
|
55
|
+
populate_feeds(0.1)
|
56
|
+
start_at = Time.now
|
57
|
+
@feeds.each do |feed|
|
58
|
+
@client.send(feed)
|
59
|
+
end
|
60
|
+
end_at = Time.now
|
61
|
+
end
|
62
|
+
|
63
|
+
def prepare_watching_subscribers(step)
|
64
|
+
step.times do
|
65
|
+
term = @terms.next
|
66
|
+
add_subscriber(term)
|
67
|
+
@watching_terms << term
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_subscriber(term)
|
72
|
+
subscribe_envelope = envelope_to_subscribe(term)
|
73
|
+
@client.connection.send_receive(subscribe_envelope)
|
74
|
+
end
|
75
|
+
|
76
|
+
def envelope_to_subscribe(term, route=nil)
|
77
|
+
message = {
|
78
|
+
"id" => Time.now.to_f.to_s,
|
79
|
+
"date" => Time.now,
|
80
|
+
"statusCode" => 200,
|
81
|
+
"type" => "watch.subscribe",
|
82
|
+
"body" => {
|
83
|
+
"condition" => term,
|
84
|
+
"subscriber" => term,
|
85
|
+
},
|
86
|
+
}
|
87
|
+
unless route.nil?
|
88
|
+
message["body"]["route"] = route
|
89
|
+
end
|
90
|
+
message
|
91
|
+
end
|
92
|
+
|
93
|
+
def populate_feeds(incidence)
|
94
|
+
@feeds = []
|
95
|
+
|
96
|
+
n_matched_targets = (N_TARGETS.to_f * incidence).to_i
|
97
|
+
n_unmatched_targets = (N_TARGETS - n_matched_targets)
|
98
|
+
|
99
|
+
n_matched_targets.times do
|
100
|
+
@feeds << envelope_to_feed(@watching_terms.sample(1))
|
101
|
+
end
|
102
|
+
|
103
|
+
n_unmatched_targets.times do
|
104
|
+
@feeds << envelope_to_feed(@terms.next)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def envelope_to_feed(term)
|
109
|
+
{
|
110
|
+
"id" => Time.now.to_f.to_s,
|
111
|
+
"date" => Time.now,
|
112
|
+
"statusCode" => 200,
|
113
|
+
"type" => "watch.feed",
|
114
|
+
"body" => {
|
115
|
+
"targets" => {
|
116
|
+
"title" => TARGET_PADDING * (TARGET_TITLE_SIZE / TARGET_PADDING.size),
|
117
|
+
"body" => term + (TARGET_PADDING * (TARGET_BODY_SIZE / TARGET_PADDING.size)),
|
118
|
+
},
|
119
|
+
},
|
120
|
+
}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
data/benchmark/utils.rb
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2013 droonga project
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License version 2.1 as published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
|
18
|
+
require "json"
|
19
|
+
require "thread"
|
20
|
+
require "droonga/watch_schema"
|
21
|
+
|
22
|
+
module DroongaBenchmark
|
23
|
+
WATCH_DATASET = "Watch"
|
24
|
+
|
25
|
+
class WatchDatabase
|
26
|
+
attr_reader :context
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
@database_dir = "/tmp/watch-benchmark"
|
30
|
+
@database_path = "#{@database_dir}/db"
|
31
|
+
FileUtils.rm_rf(@database_dir)
|
32
|
+
FileUtils.mkdir_p(@database_dir)
|
33
|
+
|
34
|
+
Groonga::Database.create(:path => @database_path)
|
35
|
+
|
36
|
+
@context = Groonga::Context.new
|
37
|
+
@context.open_database(@database_path)
|
38
|
+
schema = Droonga::WatchSchema.new(@context)
|
39
|
+
schema.ensure_created
|
40
|
+
end
|
41
|
+
|
42
|
+
=begin
|
43
|
+
def subscribe_to(keywords)
|
44
|
+
@context.send("load --table Query")
|
45
|
+
@context.send("[")
|
46
|
+
keywords.each do |keyword|
|
47
|
+
@context.send("{'_key':'#{keyword}'," +
|
48
|
+
"'keywords':['#{keyword}']},")
|
49
|
+
end
|
50
|
+
@context.send("]")
|
51
|
+
|
52
|
+
@context.send("load --table Subscriber")
|
53
|
+
@context.send("[")
|
54
|
+
keywords.each do |keyword|
|
55
|
+
@context.send("{'_key':'subscriber for #{keyword}'," +
|
56
|
+
"'subscriptions':['#{keyword}']," +
|
57
|
+
"'route':'0.0.0.0:0/benchamrk'},")
|
58
|
+
end
|
59
|
+
@context.send("]")
|
60
|
+
end
|
61
|
+
=end
|
62
|
+
|
63
|
+
def subscribe_to(keywords)
|
64
|
+
queries = []
|
65
|
+
subscribers = []
|
66
|
+
keywords.each do |keyword|
|
67
|
+
queries << {:_key => keyword,
|
68
|
+
:keywords => [keyword]}
|
69
|
+
subscribers << {:_key => "subscriber for #{keyword}",
|
70
|
+
:subscriptions => [keyword],
|
71
|
+
:route => "0.0.0.0:0/benchamrk"}
|
72
|
+
end
|
73
|
+
|
74
|
+
command_load_queries = [
|
75
|
+
"load --table Query",
|
76
|
+
JSON.generate(queries)
|
77
|
+
]
|
78
|
+
command_load_subscribers = [
|
79
|
+
"load --table Subscriber",
|
80
|
+
JSON.generate(subscribers)
|
81
|
+
]
|
82
|
+
|
83
|
+
@context.restore(command_load_queries.join("\n"))
|
84
|
+
@context.restore(command_load_subscribers.join("\n"))
|
85
|
+
end
|
86
|
+
|
87
|
+
def subscribe(keyword)
|
88
|
+
queries = @context["Query"]
|
89
|
+
query = queries.add(keyword, :keywords => [keyword])
|
90
|
+
|
91
|
+
subscribers = @context["Subscriber"]
|
92
|
+
subscribers.add("subscriber for #{keyword}",
|
93
|
+
:subscriptions => [query],
|
94
|
+
:route => "0.0.0.0:0/benchamrk")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class KeywordsGenerator
|
99
|
+
class << self
|
100
|
+
def generate(n_keywords)
|
101
|
+
new.generate(n_keywords)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def initialize
|
106
|
+
@generator = to_enum(:each)
|
107
|
+
end
|
108
|
+
|
109
|
+
def generate(n_keywords)
|
110
|
+
keywords = []
|
111
|
+
n_keywords.times do
|
112
|
+
keywords << @generator.next
|
113
|
+
end
|
114
|
+
keywords
|
115
|
+
end
|
116
|
+
|
117
|
+
def next
|
118
|
+
@generator.next
|
119
|
+
end
|
120
|
+
|
121
|
+
FIRST_INITIAL_LETTER = "㐀"
|
122
|
+
SUFFIX = "あいうえおかきくけこ"
|
123
|
+
def each
|
124
|
+
initial_letter = FIRST_INITIAL_LETTER
|
125
|
+
while true do
|
126
|
+
yield "#{initial_letter}#{SUFFIX}"
|
127
|
+
initial_letter.succ!
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class TargetsGenerator
|
133
|
+
class << self
|
134
|
+
def generate(n_keywords, params)
|
135
|
+
new(params).generate(n_keywords)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
PADDING = "パディング"
|
140
|
+
SIZE = 1000
|
141
|
+
|
142
|
+
def initialize(params)
|
143
|
+
@keywords = params[:keywords]
|
144
|
+
@incidence = params[:incidence]
|
145
|
+
@matched_keywords = params[:matched_keywords] || 1
|
146
|
+
end
|
147
|
+
|
148
|
+
def generate(n_targets)
|
149
|
+
targets = []
|
150
|
+
|
151
|
+
n_matched_targets = (n_targets.to_f * @incidence).to_i
|
152
|
+
n_unmatched_targets = (n_targets - n_matched_targets)
|
153
|
+
|
154
|
+
n_matched_targets.times do
|
155
|
+
targets << generate_target(@keywords.sample(@matched_keywords))
|
156
|
+
end
|
157
|
+
|
158
|
+
n_unmatched_targets.times do
|
159
|
+
targets << generate_target
|
160
|
+
end
|
161
|
+
|
162
|
+
targets
|
163
|
+
end
|
164
|
+
|
165
|
+
def generate_target(keywords=[])
|
166
|
+
(PADDING * (SIZE / PADDING.size)) + keywords.join("/")
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class MessageCreator
|
171
|
+
class << self
|
172
|
+
def envelope_to_subscribe(keyword, route=nil)
|
173
|
+
message = {
|
174
|
+
"id" => Time.now.to_f.to_s,
|
175
|
+
"dataset" => WATCH_DATASET,
|
176
|
+
"date" => Time.now,
|
177
|
+
"statusCode" => 200,
|
178
|
+
"type" => "watch.subscribe",
|
179
|
+
"body" => {
|
180
|
+
"condition" => keyword,
|
181
|
+
"subscriber" => "subscriber for #{keyword}",
|
182
|
+
},
|
183
|
+
}
|
184
|
+
message
|
185
|
+
end
|
186
|
+
|
187
|
+
def envelope_to_feed(keyword)
|
188
|
+
{
|
189
|
+
"id" => Time.now.to_f.to_s,
|
190
|
+
"dataset" => WATCH_DATASET,
|
191
|
+
"date" => Time.now,
|
192
|
+
"statusCode" => 200,
|
193
|
+
"type" => "watch.feed",
|
194
|
+
"body" => {
|
195
|
+
"targets" => {
|
196
|
+
"keyword" => keyword,
|
197
|
+
},
|
198
|
+
},
|
199
|
+
}
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
class MessageReceiver
|
205
|
+
def initialize(options={})
|
206
|
+
default_options = {
|
207
|
+
:host => "0.0.0.0",
|
208
|
+
:port => 0,
|
209
|
+
}
|
210
|
+
options = default_options.merge(options)
|
211
|
+
@socket = TCPServer.new(options[:host], options[:port])
|
212
|
+
start
|
213
|
+
end
|
214
|
+
|
215
|
+
def close
|
216
|
+
@socket.close
|
217
|
+
end
|
218
|
+
|
219
|
+
def host
|
220
|
+
@socket.addr[3]
|
221
|
+
end
|
222
|
+
|
223
|
+
def port
|
224
|
+
@socket.addr[1]
|
225
|
+
end
|
226
|
+
|
227
|
+
def new_message
|
228
|
+
@messages.pop
|
229
|
+
end
|
230
|
+
|
231
|
+
def start
|
232
|
+
@messages = Queue.new
|
233
|
+
Thread.new do
|
234
|
+
client = @socket.accept
|
235
|
+
unpacker = MessagePack::Unpacker.new(client)
|
236
|
+
unpacker.each do |object|
|
237
|
+
@messages.push(object)
|
238
|
+
end
|
239
|
+
client.close
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|