fluent-plugin-droonga 0.9.0 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -0
  3. data/Gemfile +8 -1
  4. data/fluent-plugin-droonga.gemspec +2 -2
  5. data/lib/droonga/adapter.rb +39 -0
  6. data/lib/droonga/adapter_runner.rb +99 -0
  7. data/lib/droonga/catalog/base.rb +11 -11
  8. data/lib/droonga/catalog/dataset.rb +54 -0
  9. data/lib/droonga/catalog/version1.rb +1 -1
  10. data/lib/droonga/collector.rb +5 -7
  11. data/lib/droonga/collector_plugin.rb +7 -7
  12. data/lib/droonga/command.rb +36 -0
  13. data/lib/droonga/{plugin/input_adapter/crud.rb → command_repository.rb} +14 -8
  14. data/lib/droonga/dispatcher.rb +86 -54
  15. data/lib/droonga/distributed_command_planner.rb +183 -0
  16. data/lib/droonga/distributor.rb +43 -17
  17. data/lib/droonga/handler.rb +13 -72
  18. data/lib/droonga/handler_message.rb +5 -5
  19. data/lib/droonga/handler_messenger.rb +4 -1
  20. data/lib/droonga/handler_plugin.rb +2 -2
  21. data/lib/droonga/handler_runner.rb +104 -0
  22. data/lib/droonga/input_message.rb +4 -4
  23. data/lib/droonga/legacy_pluggable.rb +66 -0
  24. data/lib/droonga/{input_adapter.rb → legacy_plugin.rb} +27 -22
  25. data/lib/droonga/{plugin_repository.rb → legacy_plugin_repository.rb} +2 -4
  26. data/lib/droonga/message_matcher.rb +101 -0
  27. data/lib/droonga/{input_adapter_plugin.rb → planner.rb} +14 -10
  28. data/lib/droonga/planner_plugin.rb +54 -0
  29. data/lib/droonga/pluggable.rb +9 -45
  30. data/lib/droonga/plugin.rb +9 -33
  31. data/lib/droonga/plugin/collector/basic.rb +2 -0
  32. data/lib/droonga/plugin/collector/search.rb +31 -37
  33. data/lib/droonga/plugin/{handler/groonga/table_remove.rb → metadata/adapter_message.rb} +23 -18
  34. data/lib/droonga/plugin/{handler/search.rb → metadata/handler_action.rb} +19 -15
  35. data/lib/droonga/plugin/metadata/input_message.rb +39 -0
  36. data/lib/droonga/plugin/planner/crud.rb +49 -0
  37. data/lib/droonga/plugin/{distributor → planner}/distributed_search_planner.rb +62 -70
  38. data/lib/droonga/plugin/{distributor → planner}/groonga.rb +11 -32
  39. data/lib/droonga/plugin/{distributor → planner}/search.rb +5 -5
  40. data/lib/droonga/plugin/{distributor → planner}/watch.rb +15 -6
  41. data/lib/droonga/plugin_loader.rb +10 -0
  42. data/lib/droonga/plugin_registerable.rb +34 -10
  43. data/lib/droonga/plugin_registry.rb +58 -0
  44. data/lib/droonga/plugins/crud.rb +124 -0
  45. data/lib/droonga/plugins/error.rb +50 -0
  46. data/lib/droonga/{output_adapter_plugin.rb → plugins/groonga.rb} +9 -13
  47. data/lib/droonga/plugins/groonga/column_create.rb +123 -0
  48. data/lib/droonga/plugins/groonga/generic_command.rb +65 -0
  49. data/lib/droonga/{plugin/output_adapter/groonga.rb → plugins/groonga/generic_response.rb} +16 -15
  50. data/lib/droonga/plugins/groonga/select.rb +124 -0
  51. data/lib/droonga/plugins/groonga/table_create.rb +106 -0
  52. data/lib/droonga/plugins/groonga/table_remove.rb +57 -0
  53. data/lib/droonga/plugins/search.rb +40 -0
  54. data/lib/droonga/plugins/watch.rb +156 -0
  55. data/lib/droonga/processor.rb +8 -10
  56. data/lib/droonga/searcher.rb +14 -4
  57. data/lib/droonga/searcher/mecab_filter.rb +67 -0
  58. data/lib/droonga/session.rb +5 -5
  59. data/lib/droonga/test.rb +1 -1
  60. data/lib/droonga/test/stub_handler_message.rb +1 -1
  61. data/lib/droonga/test/{stub_distributor.rb → stub_planner.rb} +1 -1
  62. data/lib/droonga/worker.rb +7 -8
  63. data/lib/fluent/plugin/out_droonga.rb +0 -1
  64. data/sample/cluster/catalog.json +2 -4
  65. data/sample/mecab_filter/data.grn +7 -0
  66. data/sample/mecab_filter/ddl.grn +7 -0
  67. data/sample/mecab_filter/search_with_mecab_filter.json +21 -0
  68. data/sample/mecab_filter/search_without_mecab_filter.json +21 -0
  69. data/test/command/config/default/catalog.json +2 -5
  70. data/test/command/suite/search/error/no-query.expected +13 -0
  71. data/test/command/suite/search/error/no-query.test +7 -0
  72. data/test/command/suite/search/error/unknown-source.expected +26 -0
  73. data/test/command/suite/watch/subscribe.expected +3 -3
  74. data/test/command/suite/watch/unsubscribe.expected +3 -3
  75. data/test/unit/catalog/test_dataset.rb +385 -0
  76. data/test/unit/catalog/test_version1.rb +111 -45
  77. data/test/unit/fixtures/catalog/version1.json +0 -3
  78. data/test/unit/helper.rb +2 -1
  79. data/test/unit/helper/distributed_search_planner_helper.rb +83 -0
  80. data/test/unit/plugin/collector/test_basic.rb +233 -376
  81. data/test/unit/plugin/collector/test_search.rb +8 -17
  82. data/test/unit/plugin/planner/search_planner/test_basic.rb +120 -0
  83. data/test/unit/plugin/planner/search_planner/test_group_by.rb +573 -0
  84. data/test/unit/plugin/planner/search_planner/test_output.rb +388 -0
  85. data/test/unit/plugin/planner/search_planner/test_sort_by.rb +938 -0
  86. data/test/unit/plugin/{distributor → planner}/test_search.rb +20 -75
  87. data/test/unit/{plugin/handler → plugins/crud}/test_add.rb +11 -11
  88. data/test/unit/plugins/groonga/select/test_adapter_input.rb +213 -0
  89. data/test/unit/{plugin/output_adapter/groonga/test_select.rb → plugins/groonga/select/test_adapter_output.rb} +12 -13
  90. data/test/unit/{plugin/handler → plugins}/groonga/test_column_create.rb +20 -5
  91. data/test/unit/{plugin/handler → plugins}/groonga/test_table_create.rb +5 -0
  92. data/test/unit/{plugin/handler → plugins}/groonga/test_table_remove.rb +8 -1
  93. data/test/unit/{plugin/handler → plugins}/test_groonga.rb +5 -5
  94. data/test/unit/{plugin/handler → plugins}/test_search.rb +21 -5
  95. data/test/unit/{plugin/handler → plugins}/test_watch.rb +29 -10
  96. data/{lib/droonga/command_mapper.rb → test/unit/test_command_repository.rb} +16 -22
  97. data/test/unit/{test_plugin.rb → test_legacy_plugin.rb} +3 -3
  98. data/test/unit/{test_plugin_repository.rb → test_legacy_plugin_repository.rb} +3 -3
  99. data/test/unit/test_message_matcher.rb +137 -0
  100. metadata +86 -66
  101. data/bin/grn2jsons +0 -82
  102. data/lib/droonga/distribution_planner.rb +0 -76
  103. data/lib/droonga/distributor_plugin.rb +0 -95
  104. data/lib/droonga/output_adapter.rb +0 -53
  105. data/lib/droonga/plugin/collector/groonga.rb +0 -83
  106. data/lib/droonga/plugin/distributor/crud.rb +0 -84
  107. data/lib/droonga/plugin/handler/add.rb +0 -109
  108. data/lib/droonga/plugin/handler/forward.rb +0 -75
  109. data/lib/droonga/plugin/handler/groonga.rb +0 -99
  110. data/lib/droonga/plugin/handler/groonga/column_create.rb +0 -106
  111. data/lib/droonga/plugin/handler/groonga/table_create.rb +0 -91
  112. data/lib/droonga/plugin/handler/watch.rb +0 -108
  113. data/lib/droonga/plugin/input_adapter/groonga.rb +0 -49
  114. data/lib/droonga/plugin/input_adapter/groonga/select.rb +0 -63
  115. data/lib/droonga/plugin/output_adapter/crud.rb +0 -51
  116. data/lib/droonga/plugin/output_adapter/groonga/select.rb +0 -54
  117. data/lib/groonga_command_converter.rb +0 -143
  118. data/sample/fluentd.conf +0 -8
  119. data/test/unit/plugin/distributor/test_search_planner.rb +0 -1102
  120. data/test/unit/plugin/input_adapter/groonga/test_select.rb +0 -248
  121. data/test/unit/test_command_mapper.rb +0 -44
  122. data/test/unit/test_groonga_command_converter.rb +0 -242
@@ -0,0 +1,65 @@
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 "groonga"
17
+
18
+ module Droonga
19
+ module Plugins
20
+ module Groonga
21
+ module Status
22
+ SUCCESS = 0
23
+ INVALID_ARGUMENT = -22
24
+ end
25
+
26
+ class GenericCommand
27
+ class CommandError < StandardError
28
+ attr_reader :status, :message, :result
29
+
30
+ def initialize(params={})
31
+ @status = params[:status]
32
+ @message = params[:message]
33
+ @result = params[:result]
34
+ end
35
+ end
36
+
37
+ def initialize(context)
38
+ @context = context
39
+ end
40
+
41
+ def execute(request)
42
+ @start_time = Time.now.to_f
43
+ result = process_request(request)
44
+ format(header(Status::SUCCESS), result)
45
+ rescue CommandError => error
46
+ format(header(error.status, error.message), error.result)
47
+ end
48
+
49
+ private
50
+ def header(return_code, error_message="")
51
+ elapsed_time = Time.now.to_f - @start_time
52
+ header = [return_code, @start_time, elapsed_time]
53
+ header.push(error_message) unless error_message.empty?
54
+ header
55
+ end
56
+
57
+ def format(header, body)
58
+ {
59
+ "result" => [header, body],
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -13,25 +13,26 @@
13
13
  # License along with this library; if not, write to the Free Software
14
14
  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
15
 
16
- require "droonga/output_adapter_plugin"
16
+ require "droonga/plugin"
17
17
 
18
18
  module Droonga
19
- class GroongaOutputAdapter < Droonga::OutputAdapterPlugin
20
- repository.register("groonga", self)
19
+ module Plugins
20
+ module Groonga
21
+ module Generic
22
+ class Adapter < Droonga::Adapter
23
+ groonga_commands = [
24
+ "table_create",
25
+ "table_remove",
26
+ "column_create",
27
+ ]
28
+ message.input_pattern = ["type", :in, groonga_commands]
29
+ message.output_pattern = ["body.result", :exist?]
21
30
 
22
- command :select_response
23
- def select_response(output_message)
24
- command = Select.new
25
- output_message.body = command.convert(output_message.body)
26
- end
27
-
28
- command :groonga_generic_response
29
- def groonga_generic_response(output_message)
30
- if output_message.body.include?("result")
31
- output_message.body = output_message.body["result"]
31
+ def adapt_output(output_message)
32
+ output_message.body = output_message.body["result"]
33
+ end
34
+ end
32
35
  end
33
36
  end
34
37
  end
35
38
  end
36
-
37
- require "droonga/plugin/output_adapter/groonga/select"
@@ -0,0 +1,124 @@
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 "droonga/plugin"
17
+
18
+ module Droonga
19
+ module Plugins
20
+ module Groonga
21
+ module Select
22
+ class RequestConverter
23
+ def convert(select_request)
24
+ table = select_request["table"]
25
+ result_name = table + "_result"
26
+ match_columns = select_request["match_columns"]
27
+ match_to = match_columns ? match_columns.split(/ *\|\| */) : []
28
+ query = select_request["query"]
29
+ output_columns = select_request["output_columns"] || ""
30
+ attributes = output_columns.split(/, */)
31
+ offset = (select_request["offset"] || "0").to_i
32
+ limit = (select_request["limit"] || "10").to_i
33
+
34
+ search_request = {
35
+ "queries" => {
36
+ result_name => {
37
+ "source" => table,
38
+ "output" => {
39
+ "elements" => [
40
+ "startTime",
41
+ "elapsedTime",
42
+ "count",
43
+ "attributes",
44
+ "records",
45
+ ],
46
+ "attributes" => attributes,
47
+ "offset" => offset,
48
+ "limit" => limit,
49
+ },
50
+ }
51
+ }
52
+ }
53
+ if query
54
+ condition = {
55
+ "query" => query,
56
+ "matchTo"=> match_to,
57
+ "defaultOperator"=> "&&",
58
+ "allowPragma"=> false,
59
+ "allowColumn"=> true,
60
+ }
61
+ search_request["queries"][result_name]["condition"] = condition
62
+ end
63
+ search_request
64
+ end
65
+ end
66
+
67
+ class ResponseConverter
68
+ def convert(search_response)
69
+ select_responses = search_response.collect do |key, value|
70
+ status_code = 0
71
+
72
+ start_time = value["startTime"]
73
+ start_time_in_unix_time = if start_time
74
+ Time.parse(start_time).to_f
75
+ else
76
+ Time.now.to_f
77
+ end
78
+ elapsed_time = value["elapsedTime"] || 0
79
+ count = value["count"]
80
+
81
+ attributes = value["attributes"] || []
82
+ converted_attributes = attributes.collect do |attribute|
83
+ name = attribute["name"]
84
+ type = attribute["type"]
85
+ [name, type]
86
+ end
87
+
88
+ header = [status_code, start_time_in_unix_time, elapsed_time]
89
+ records = value["records"]
90
+ if records.empty?
91
+ results = [[count], converted_attributes]
92
+ else
93
+ results = [[count], converted_attributes, records]
94
+ end
95
+ body = [results]
96
+
97
+ [header, body]
98
+ end
99
+ select_responses.first
100
+ end
101
+ end
102
+
103
+ class Adapter < Droonga::Adapter
104
+ message.input_pattern = ["type", :equal, "select"]
105
+
106
+ def adapt_input(input_message)
107
+ converter = RequestConverter.new
108
+ select_request = input_message.body
109
+ search_request = converter.convert(select_request)
110
+ input_message.command = "search"
111
+ input_message.body = search_request
112
+ end
113
+
114
+ def adapt_output(output_message)
115
+ converter = ResponseConverter.new
116
+ search_response = output_message.body
117
+ select_response = converter.convert(search_response)
118
+ output_message.body = select_response
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,106 @@
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 "groonga/command/table-create"
17
+
18
+ require "droonga/plugin"
19
+ require "droonga/plugins/groonga/generic_command"
20
+
21
+ module Droonga
22
+ module Plugins
23
+ module Groonga
24
+ module TableCreate
25
+ class Command < GenericCommand
26
+ def process_request(request)
27
+ command_class = ::Groonga::Command.find("table_create")
28
+ @command = command_class.new("table_create", request)
29
+
30
+ name = @command["name"]
31
+ unless name
32
+ message = "Should not create anonymous table"
33
+ raise CommandError.new(:status => Status::INVALID_ARGUMENT,
34
+ :message => message,
35
+ :result => false)
36
+ end
37
+
38
+ options = parse_command
39
+ ::Groonga::Schema.define(:context => @context) do |schema|
40
+ schema.create_table(name, options)
41
+ end
42
+ true
43
+ end
44
+
45
+ private
46
+ def parse_command
47
+ options = {}
48
+ parse_flags(options)
49
+ parse_key_type(options)
50
+ parse_value_type(options)
51
+ parse_default_tokenizer(options)
52
+ parse_normalizer(options)
53
+ options
54
+ end
55
+
56
+ def parse_flags(options)
57
+ options[:type] = :hash
58
+ if @command.table_no_key?
59
+ options[:type] = :array
60
+ elsif @command.table_hash_key?
61
+ options[:type] = :hash
62
+ elsif @command.table_pat_key?
63
+ options[:type] = :patricia_trie
64
+ elsif @command.table_dat_key?
65
+ options[:type] = :double_array_trie
66
+ end
67
+ if @command.key_with_sis? and @command.table_pat_key?
68
+ options[:key_with_sis] = true
69
+ end
70
+ end
71
+
72
+ def parse_key_type(options)
73
+ return unless @command["key_type"]
74
+ options[:key_type] = @command["key_type"]
75
+ end
76
+
77
+ def parse_value_type(options)
78
+ return unless @command["value_type"]
79
+ options[:value_type] = @command["value_type"]
80
+ end
81
+
82
+ def parse_default_tokenizer(options)
83
+ return unless @command["default_tokenizer"]
84
+ options[:default_tokenizer] = @command["default_tokenizer"]
85
+ end
86
+
87
+ def parse_normalizer(options)
88
+ return unless @command["normalizer"]
89
+ options[:normalizer] = @command["normalizer"]
90
+ end
91
+ end
92
+
93
+ class Handler < Droonga::Handler
94
+ message.type = "table_create"
95
+ action.synchronous = true
96
+
97
+ def handle(message, messenger)
98
+ command = Command.new(@context)
99
+ outputs = command.execute(message.request)
100
+ messenger.emit(outputs)
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,57 @@
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 "groonga/command/table-remove"
17
+
18
+ require "droonga/plugin"
19
+ require "droonga/plugins/groonga/generic_command"
20
+
21
+ module Droonga
22
+ module Plugins
23
+ module Groonga
24
+ module TableRemove
25
+ class Command < GenericCommand
26
+ def process_request(request)
27
+ command_class = ::Groonga::Command.find("table_remove")
28
+ @command = command_class.new("table_remove", request)
29
+
30
+ name = @command["name"]
31
+ if name.nil? || @context[name].nil?
32
+ raise CommandError.new(:status => Status::INVALID_ARGUMENT,
33
+ :message => "table not found",
34
+ :result => false)
35
+ end
36
+
37
+ ::Groonga::Schema.define(:context => @context) do |schema|
38
+ schema.remove_table(name)
39
+ end
40
+ true
41
+ end
42
+ end
43
+
44
+ class Handler < Droonga::Handler
45
+ message.type = "table_remove"
46
+ action.synchronous = true
47
+
48
+ def handle(message, messenger)
49
+ command = Command.new(@context)
50
+ outputs = command.execute(message.request)
51
+ messenger.emit(outputs)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,40 @@
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 "droonga/plugin"
17
+ require "droonga/searcher"
18
+
19
+ module Droonga
20
+ module Plugins
21
+ module Search
22
+ Plugin.registry.register("search", self)
23
+
24
+ class Handler < Droonga::Handler
25
+ message.type = "search"
26
+
27
+ def handle(message, messenger)
28
+ searcher = Droonga::Searcher.new(@context)
29
+ values = {}
30
+ request = message.request
31
+ raise Droonga::Searcher::NoQuery.new unless request
32
+ searcher.search(request["queries"]).each do |output, value|
33
+ values[output] = value
34
+ end
35
+ messenger.emit(values)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,156 @@
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 "droonga/plugin"
17
+ require "droonga/watcher"
18
+ require "droonga/sweeper"
19
+ require "droonga/watch_schema"
20
+
21
+ module Droonga
22
+ module Plugins
23
+ module Watch
24
+ Plugin.registry.register("watch", self)
25
+
26
+ module SchemaCreatable
27
+ private
28
+ def ensure_schema_created
29
+ # XXX just workaround. This must be re-written.
30
+ # When secondary and later processes opens the database,
31
+ # creation processes of tables by the first process is
32
+ # not finished yet. Then secondary and others tries to
33
+ # create tables and raises errors. To avoid such a problem,
34
+ # the creation processes of tables is disabled on workers.
35
+ if $0 !~ /\AServer/
36
+ schema = WatchSchema.new(@context)
37
+ schema.ensure_created
38
+ else
39
+ until @context["Keyword"]
40
+ sleep 0.1
41
+ end
42
+ sleep 1
43
+ end
44
+ end
45
+ end
46
+
47
+ module MessageParsable
48
+ private
49
+ def parse_message(message)
50
+ request = message.request
51
+ subscriber = request["subscriber"]
52
+ condition = request["condition"]
53
+ route = request["route"] || message["from"]
54
+ query = condition && condition.to_json
55
+ [subscriber, condition, query, route]
56
+ end
57
+ end
58
+
59
+ class SubscribeHandler < Droonga::Handler
60
+ include SchemaCreatable
61
+ include MessageParsable
62
+
63
+ message.type = "watch.subscribe"
64
+
65
+ def initialize(*args)
66
+ super
67
+ ensure_schema_created # TODO: REMOVE ME
68
+ end
69
+
70
+ def handle(message, messenger)
71
+ subscriber, condition, query, route = parse_message(message)
72
+ normalized_request = {
73
+ :subscriber => subscriber,
74
+ :condition => condition,
75
+ :query => query,
76
+ :route => route,
77
+ }
78
+ watcher = Watcher.new(@context)
79
+ watcher.subscribe(normalized_request)
80
+ outputs = {
81
+ "success" => true,
82
+ }
83
+ messenger.emit(outputs)
84
+ end
85
+ end
86
+
87
+ class UnsubscribeHandler < Droonga::Handler
88
+ include SchemaCreatable
89
+ include MessageParsable
90
+
91
+ message.type = "watch.unsubscribe"
92
+
93
+ def initialize(*args)
94
+ super
95
+ ensure_schema_created # TODO: REMOVE ME
96
+ end
97
+
98
+ def handle(message, messenger)
99
+ subscriber, condition, query, route = parse_message(message)
100
+ normalized_request = {
101
+ :subscriber => subscriber,
102
+ :condition => condition,
103
+ :query => query,
104
+ }
105
+ watcher = Watcher.new(@context)
106
+ watcher.unsubscribe(normalized_request)
107
+ outputs = {
108
+ "success" => true,
109
+ }
110
+ messenger.emit(outputs)
111
+ end
112
+ end
113
+
114
+ class FeedHandler < Droonga::Handler
115
+ include SchemaCreatable
116
+
117
+ message.type = "watch.feed"
118
+
119
+ def initialize(*args)
120
+ super
121
+ ensure_schema_created # TODO: REMOVE ME
122
+ end
123
+
124
+ def handle(message, messenger)
125
+ request = message.request
126
+ watcher = Watcher.new(@context)
127
+ watcher.feed(:targets => request["targets"]) do |route, subscribers|
128
+ published_message = {
129
+ "to" => subscribers,
130
+ "body" => request,
131
+ }
132
+ published_message = message.raw.merge(published_message)
133
+ messenger.forward(published_message,
134
+ "to" => route, "type" => "watch.publish")
135
+ end
136
+ end
137
+ end
138
+
139
+ class SweepHandler < Droonga::Handler
140
+ include SchemaCreatable
141
+
142
+ message.type = "watch.sweep"
143
+
144
+ def initialize(*args)
145
+ super
146
+ ensure_schema_created # TODO: REMOVE ME
147
+ end
148
+
149
+ def sweep(message, messenger)
150
+ sweeper = Sweeper.new(@context)
151
+ sweeper.sweep_expired_subscribers
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end