fluent-plugin-droonga 0.9.0 → 0.9.9

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.
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