class Fusuma::Runner

main class

Public Class Methods

new() click to toggle source
# File lib/fusuma.rb, line 57
def initialize
  @inputs = Plugin::Inputs::Input.plugins.map(&:new)
  @filters = Plugin::Filters::Filter.plugins.map(&:new)
  @parsers = Plugin::Parsers::Parser.plugins.map(&:new)
  @buffers = Plugin::Buffers::Buffer.plugins.map(&:new)
  @detectors = Plugin::Detectors::Detector.plugins.map(&:new)
  @executors = Plugin::Executors::Executor.plugins.map(&:new)
end
run(option = {}) click to toggle source
# File lib/fusuma.rb, line 15
def run(option = {})
  set_trap
  read_options(option)
  instance = new
  ## NOTE: Uncomment following line to measure performance
  # instance.run_with_lineprof
  instance.run
end

Private Class Methods

load_custom_config(config_path = nil) click to toggle source
# File lib/fusuma.rb, line 52
def load_custom_config(config_path = nil)
  Config.custom_path = config_path
end
read_options(option) click to toggle source
# File lib/fusuma.rb, line 31
def read_options(option)
  MultiLogger.instance.debug_mode = option[:verbose]

  load_custom_config(option[:config_path])

  Plugin::Manager.require_base_plugins

  Environment.dump_information
  Kernel.exit(0) if option[:version]

  if option[:list]
    Environment.print_device_list
    Kernel.exit(0)
  end

  # TODO: remove keep_device_from_option from command line options
  Plugin::Filters::LibinputDeviceFilter::KeepDevice.from_option = option[:device]

  Process.daemon if option[:daemon]
end
set_trap() click to toggle source
# File lib/fusuma.rb, line 26
def set_trap
  Signal.trap('INT') { puts exit } # Trap ^C
  Signal.trap('TERM') { puts exit } # Trap `Kill `
end

Public Instance Methods

buffer(event) click to toggle source

@param [Plugin::Events::Event] @return [Array<Plugin::Buffers::Buffer>] @return [NilClass]

# File lib/fusuma.rb, line 113
def buffer(event)
  @buffers.select { |b| b.buffer(event) }
end
clear_expired_events() click to toggle source
# File lib/fusuma.rb, line 190
def clear_expired_events
  @buffers.each(&:clear_expired)
end
detect(buffers) click to toggle source

@param buffers [Array<Buffer>] @return [Array<Event>]

# File lib/fusuma.rb, line 119
def detect(buffers)
  matched_detectors = @detectors.select do |detector|
    detector.watch? ||
      buffers.any? { |b| detector.sources.include?(b.type) }
  end

  events = matched_detectors.each_with_object([]) do |detector, detected|
    Array(detector.detect(@buffers)).each { |e| detected << e }
  end

  return if events.empty?

  events
end
execute(condition, context, event) click to toggle source

@param event [Plugin::Events::Event]

# File lib/fusuma.rb, line 168
def execute(condition, context, event)
  return unless event

  # Find executable condition and executor
  executor = Config::Searcher.with_context(context) do
    Config::Searcher.with_condition(condition) do
      @executors.find { |e| e.executable?(event) }
    end
  end

  return if executor.nil?

  # Check interval and execute
  Config::Searcher.with_context(context) do
    Config::Searcher.with_condition(condition) do
      executor.enough_interval?(event) &&
        executor.update_interval(event) &&
        executor.execute(event)
    end
  end
end
filter(event) click to toggle source

@param [Plugin::Events::Event] @return [Plugin::Events::Event]

# File lib/fusuma.rb, line 100
def filter(event)
  event if @filters.any? { |f| f.filter(event) }
end
input() click to toggle source

@return [Plugin::Events::Event]

# File lib/fusuma.rb, line 94
def input
  Plugin::Inputs::Input.select(@inputs)
end
merge(events) click to toggle source

@param events [Array<Plugin::Events::Event>] @return [Plugin::Events::Event] Event merged all records from arguments @return [NilClass] when event is NOT given

# File lib/fusuma.rb, line 137
def merge(events)
  index_events, context_events = events.partition { |event| event.record.type == :index }
  main_events, modifiers = index_events.partition { |event| event.record.mergable? }
  request_context = context_events.each_with_object({}) do |e, results|
    results[e.record.name] = e.record.value
  end
  main_events.sort_by! { |e| e.record.trigger_priority }

  matched_condition = nil
  matched_context = nil
  event = main_events.find do |main_event|
    matched_context = Config::Searcher.find_context(request_context) do
      matched_condition, modified_record = Config::Searcher.find_condition do
        main_event.record.merge(records: modifiers.map(&:record))
      end
      if matched_condition && modified_record
        main_event.record = modified_record
      else
        matched_condition, = Config::Searcher.find_condition do
          Config.search(main_event.record.index) &&
            Config.find_execute_key(main_event.record.index)
        end
      end
    end
  end
  return if event.nil?

  [matched_condition, matched_context, event]
end
parse(event) click to toggle source

@param [Plugin::Events::Event] @return [Plugin::Events::Event]

# File lib/fusuma.rb, line 106
def parse(event)
  @parsers.reduce(event) { |e, p| p.parse(e) if e }
end
pipeline() click to toggle source
# File lib/fusuma.rb, line 70
def pipeline
  event = input || return
  clear_expired_events
  filtered = filter(event) || return
  parsed = parse(filtered) || return
  buffered = buffer(parsed) || return
  detected = detect(buffered) || return
  condition, context, event = merge(detected) || return
  execute(condition, context, event)
end
run() click to toggle source
# File lib/fusuma.rb, line 66
def run
  loop { pipeline }
end
run_with_lineprof(count: 1000) click to toggle source

For performance monitoring

# File lib/fusuma.rb, line 82
def run_with_lineprof(count: 1000)
  require 'rblineprof'
  require 'rblineprof-report'

  profile = lineprof(%r{#{Pathname.new(__FILE__).parent}/.}) do
    count.times { pipeline }
  end
  LineProf.report(profile)
  exit 0
end