Kouhei Sutou
null+****@clear*****
Fri Oct 25 18:45:26 JST 2013
Kouhei Sutou 2013-10-25 18:45:26 +0900 (Fri, 25 Oct 2013) New Revision: 7bcc690f9388a0f1c6c26cc4b3120ccc3800afd5 https://github.com/droonga/fluent-plugin-droonga/commit/7bcc690f9388a0f1c6c26cc4b3120ccc3800afd5 Message: Extract watch operations to Watcher It improves testability. Copied files: lib/droonga/watcher.rb (from lib/droonga/plugin/handler_watch.rb) Modified files: lib/droonga/plugin/handler_watch.rb Modified: lib/droonga/plugin/handler_watch.rb (+23 -130) =================================================================== --- lib/droonga/plugin/handler_watch.rb 2013-10-25 18:48:24 +0900 (59ef1bd) +++ lib/droonga/plugin/handler_watch.rb 2013-10-25 18:45:26 +0900 (47dbe36) @@ -15,65 +15,50 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +require "droonga/watcher" require "droonga/handler" module Droonga class WatchHandler < Droonga::Handler Droonga::HandlerPlugin.register("watch", self) - EXACT_MATCH = false + + def initialize(*args) + super + @watcher = Watcher.new(@context) + end command "watch.subscribe" => :subscribe def subscribe(request) subscriber, condition, query, route = parse_request(request) - query_table = @context["Query"] - query_record = query_table[query] - unless query_record - keywords = pick_keywords([], condition) - query_record = query_table.add(query, :keywords => keywords) - end - subscriber_table = @context["Subscriber"] - subscriber_record = subscriber_table[subscriber] - if subscriber_record - subscriptions = subscriber_record.subscriptions.collect do |query| - return if query == query_record - query - end - subscriptions << query_record - subscriber_record.subscriptions = subscriptions - else - subscriber_table.add(subscriber, - :subscriptions => [query_record], - :route => route) - end + normalized_request = { + :subscriber => subscriber, + :condition => condition, + :query => query, + :route => route, + } + @watcher.subscribe(normalized_request) emit([true]) end command "watch.unsubscribe" => :unsubscribe def unsubscribe(request) subscriber, condition, query, route = parse_request(request) - query_table = @context["Query"] - query_record = query_table[query] - return unless query_record - subscriber_table = @context["Subscriber"] - subscriber_record = subscriber_table[subscriber] - return unless subscriber_record - subscriptions = subscriber_record.subscriptions.select do |query| - query != query_record - end - subscriber_record.subscriptions = subscriptions + normalized_request = { + :subscriber => subscriber, + :condition => condition, + :query => query, + } + @watcher.unsubscribe(normalized_request) emit([true]) end command "watch.feed" => :feed def feed(request) - targets = request["targets"] - - hits = [] - targets.each do |key, target| - scan_body(hits, target) + @watcher.feed(:targets => request["targets"]) do |route, subscribers| + message = request # return request itself + envelope["to"] = subscribers + post(message, "to" => route, "type" => "watch.notification") end - - publish(hits, request) end private @@ -86,97 +71,5 @@ module Droonga raise "too long query" if query.size > 4095 [subscriber, condition, query, route] end - - def pick_keywords(memo, condition) - case condition - when Hash - memo << condition["query"] - when String - memo << condition - when Array - condition[1..-1].each do |element| - pick_keywords(memo, element) - end - end - memo - end - - def scan_body(hits, body) - trimmed = body.strip - candidates = {} - # FIXME scan reports the longest keyword matched only - @context["Keyword"].scan(trimmed).each do |keyword, word, start, length| - @context["Query"].select do |query| - query.keywords =~ keyword - end.each do |record| - candidates[record.key] ||= [] - candidates[record.key] << keyword - end - end - candidates.each do |query, keywords| - hits << query if query_match(query, keywords) - end - end - - def query_match(query, keywords) - return true unless EXACT_MATCH - @conditions = {} unless @conditions - condition = @conditions[query.id] - unless condition - condition = JSON.parse(query.key) - @conditions[query.id] = condition - # CAUTION: @conditions can be huge. - end - words = {} - keywords.each do |keyword| - words[keyword.key] = true - end - eval_condition(condition, words) - end - - def eval_condition(condition, words) - case condition - when Hash - # todo - when String - words[condition] - when Array - case condition.first - when "||" - condition[1..-1].each do |element| - return true if eval_condition(element, words) - end - false - when "&&" - condition[1..-1].each do |element| - return false unless eval_condition(element, words) - end - true - when "-" - return false unless eval_condition(condition[1], words) - condition[2..-1].each do |element| - return false if eval_condition(element, words) - end - true - end - end - end - - def publish(hits, request) - routes = {} - hits.each do |query| - @context["Subscriber"].select do |subscriber| - subscriber.subscriptions =~ query - end.each do |subscriber| - routes[subscriber.route.key] ||= [] - routes[subscriber.route.key] << subscriber.key.key - end - end - routes.each do |route, subscribers| - message = request # return request itself - envelope["to"] = subscribers - post(message, "to" => route, "type" => "watch.notification") - end - end end end Copied: lib/droonga/watcher.rb (+18 -28) 81% =================================================================== --- lib/droonga/plugin/handler_watch.rb 2013-10-25 18:48:24 +0900 (59ef1bd) +++ lib/droonga/watcher.rb 2013-10-25 18:45:26 +0900 (7916aab) @@ -15,16 +15,20 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -require "droonga/handler" - module Droonga - class WatchHandler < Droonga::Handler - Droonga::HandlerPlugin.register("watch", self) + class Watcher EXACT_MATCH = false - command "watch.subscribe" => :subscribe + def initialize(context) + @context = context + end + def subscribe(request) - subscriber, condition, query, route = parse_request(request) + subscriber = request[:subscriber] + condition = request[:condition] + query = request[:query] + route = request[:route] + query_table = @context["Query"] query_record = query_table[query] unless query_record @@ -45,12 +49,13 @@ module Droonga :subscriptions => [query_record], :route => route) end - emit([true]) end - command "watch.unsubscribe" => :unsubscribe def unsubscribe(request) - subscriber, condition, query, route = parse_request(request) + subscriber = request[:subscriber] + condition = request[:condition] + query = request[:query] + query_table = @context["Query"] query_record = query_table[query] return unless query_record @@ -61,30 +66,17 @@ module Droonga query != query_record end subscriber_record.subscriptions = subscriptions - emit([true]) end - command "watch.feed" => :feed - def feed(request) - targets = request["targets"] + def feed(request, &block) + targets = request[:targets] hits = [] targets.each do |key, target| scan_body(hits, target) end - publish(hits, request) - end - - private - def parse_request(request) - subscriber = request["subscriber"] - condition = request["condition"] - route = request["route"] || envelope["from"] - raise "invalid request" if subscriber.nil? || subscriber.empty? || condition.nil? - query = condition.to_json - raise "too long query" if query.size > 4095 - [subscriber, condition, query, route] + publish(hits, request, &block) end def pick_keywords(memo, condition) @@ -173,9 +165,7 @@ module Droonga end end routes.each do |route, subscribers| - message = request # return request itself - envelope["to"] = subscribers - post(message, "to" => route, "type" => "watch.notification") + yield(route, subscribers) end end end -------------- next part -------------- HTML����������������������������...Download