<commit_before>require 'forwardable'
require 'rgossip2'
require 'sqlite3'

require 'srv/murakumo_health_checker'
require 'misc/murakumo_const'

module Murakumo

  class Cloud
    extend Forwardable

    attr_reader :address
    attr_reader :gossip
    attr_reader :db
    attr_reader :hostname

    def initialize(options)
      # オプションはインスタンス変数に保存
      @options = options

      # リソースレコードからホストのアドレスとデータを取り出す
      host_data = options[:host]
      @address = host_data.shift
      host_data.concat [ORIGIN, 0, ACTIVE]
      alias_datas = options[:aliases].map {|r| r + [ACTIVE] }
      @logger = options[:logger]

      # 名前は小文字に変換
      datas = ([host_data] + alias_datas).map do |i|
        name, ttl, priority, weight, activity = i
        name = name.downcase
        [name, ttl, priority, weight, activity]
      end

      # データベースを作成してレコードを更新
      create_database
      update(@address, datas)

      # updateの後にホスト名をセットすること
      @hostname = host_data.first

      # ゴシップオブジェクトを生成
      @gossip = RGossip2.client({
        :initial_nodes   => options[:initial_nodes],
        :address         => @address,
        :data            => datas,
        :auth_key        => options[:auth_key],
        :port            => options[:gossip_port],
        :node_lifetime   => options[:gossip_node_lifetime],
        :gossip_interval => options[:gossip_send_interval],
        :receive_timeout => options[:gossip_receive_timeout],
        :logger          => @logger,
      })

      # ノードの更新をフック
      @gossip.context.callback_handler = lambda do |act, addr, ts, dt, old_dt|
        case act
        when :add, :comeback
          # 追加・復帰の時は無条件に更新
          update(addr, dt)
        when :update
          # 更新の時はデータが更新されたときのみ更新
          update(addr, dt) if dt != old_dt
        when :delete
          delete(addr)
        end
      end

      # ヘルスチェック
      @health_checkers = {}

      if options.config_file and options.config_file['health-check']
        health_check = options.config_file['health-check']

        if health_check.kind_of?(Hash)
          health_check.each do |name, conf|
            name = name.downcase

            if options[:notification]
              conf = conf.merge(:notification => options[:notification])
            end

            if datas.any? {|i| i[0] == name }
              checker = HealthChecker.new(@address, name, self, @logger, conf)
              @health_checkers[name] = checker
              # ヘルスチェックはまだ起動しない
            else
              # ホスト名になかったら警告
              @logger.warn("host for a health check is not found: #{name}")
            end
          end
        else
          @logger.warn('configuration of a health check is not right')
        end
      end

      # キャッシュ
      @cache = {} if options[:enable_cache]
    end

    # Control of service
    def_delegators :@gossip, :stop, :clear_dead_list

    def start
      # デーモン化すると子プロセスはすぐ死ぬので
      # このタイミングでヘルスチェックを起動
      @health_checkers.each do |name, checker|
        checker.start
      end

      @gossip.start
    end

    def to_hash
      keys = {
        :auth_key      => 'auth-key',
        :dns_address   => 'address',
        :dns_port      => 'port',
        :initial_nodes => lambda {|v| ['initial-nodes', v.join(',')] },
        :resolver      => lambda {|v| [
          'resolver',
          v.instance_variable_get(:@config).instance_variable_get(:@config_info)[:nameserver].join(',')
        ]},
        :socket        => 'socket',
        :max_ip_num    => 'max-ip-num',
        :domain        => 'domain',
        :enable_cache  => lambda {|v| ['enable-cache', !!v] },
        :log_path      => 'log-path',
        :log_level     => 'log-level',
        :gossip_port   => 'gossip-port',
        :gossip_node_lifetime => lambda {|v| [
          'gossip-node-lifetime',
          @gossip.context.node_lifetime
        ]},
        :gossip_send_interval => lambda {|v| [
          'gossip-send-interval',
          @gossip.context.gossip_interval
        ]},
        :gossip_receive_timeout => lambda {|v| [
          'gossip-receive-timeout',
          @gossip.context.receive_timeout
        ]},
      }

      hash = {}

      keys.each do |k, name|
        value = @options[k]

        if value and name.respond_to?(:call)
          name, value = name.call(value)
        end

        if value and (not value.kind_of?(String) or not value.empty?)
          hash[name] = value
        end
      end

      records = list_records.select {|r| r[0] == @address }

      hash['host'] = records.find {|r| r[3] == ORIGIN }[0..2].join(',')

      aliases = records.select {|r| r[3] != ORIGIN }.map do |r|
        [r[1], r[2], (r[3] == MASTER ? 'master' : 'backup'), r[4]].join(',')
      end

      hash['alias'] = aliases unless aliases.empty?

      # 設定ファイルのみの項目
      if @options.config_file
        if @options.config_file['health-check']
          hash['health-check'] = @options.config_file['health-check']
        end

        if @options.config_file['notification']
          hash['notification'] = @options.config_file['notification']
        end

        %w(name-includes name-excludes addr-includes addr-excludes).each do |key|
          if @options.config_file[key]
            hash[key] = @options.config_file[key]
          end
        end
      end # 設定ファイルのみの項目

      return hash
    end<commit_msg>add balancing option to to_hash<commit_after>require 'forwardable'
require 'rgossip2'
require 'sqlite3'

require 'srv/murakumo_health_checker'
require 'misc/murakumo_const'

module Murakumo

  class Cloud
    extend Forwardable

    attr_reader :address
    attr_reader :gossip
    attr_reader :db
    attr_reader :hostname

    def initialize(options)
      # オプションはインスタンス変数に保存
      @options = options

      # リソースレコードからホストのアドレスとデータを取り出す
      host_data = options[:host]
      @address = host_data.shift
      host_data.concat [ORIGIN, 0, ACTIVE]
      alias_datas = options[:aliases].map {|r| r + [ACTIVE] }
      @logger = options[:logger]

      # 名前は小文字に変換
      datas = ([host_data] + alias_datas).map do |i|
        name, ttl, priority, weight, activity = i
        name = name.downcase
        [name, ttl, priority, weight, activity]
      end

      # データベースを作成してレコードを更新
      create_database
      update(@address, datas)

      # updateの後にホスト名をセットすること
      @hostname = host_data.first

      # ゴシップオブジェクトを生成
      @gossip = RGossip2.client({
        :initial_nodes   => options[:initial_nodes],
        :address         => @address,
        :data            => datas,
        :auth_key        => options[:auth_key],
        :port            => options[:gossip_port],
        :node_lifetime   => options[:gossip_node_lifetime],
        :gossip_interval => options[:gossip_send_interval],
        :receive_timeout => options[:gossip_receive_timeout],
        :logger          => @logger,
      })

      # ノードの更新をフック
      @gossip.context.callback_handler = lambda do |act, addr, ts, dt, old_dt|
        case act
        when :add, :comeback
          # 追加・復帰の時は無条件に更新
          update(addr, dt)
        when :update
          # 更新の時はデータが更新されたときのみ更新
          update(addr, dt) if dt != old_dt
        when :delete
          delete(addr)
        end
      end

      # ヘルスチェック
      @health_checkers = {}

      if options.config_file and options.config_file['health-check']
        health_check = options.config_file['health-check']

        if health_check.kind_of?(Hash)
          health_check.each do |name, conf|
            name = name.downcase

            if options[:notification]
              conf = conf.merge(:notification => options[:notification])
            end

            if datas.any? {|i| i[0] == name }
              checker = HealthChecker.new(@address, name, self, @logger, conf)
              @health_checkers[name] = checker
              # ヘルスチェックはまだ起動しない
            else
              # ホスト名になかったら警告
              @logger.warn("host for a health check is not found: #{name}")
            end
          end
        else
          @logger.warn('configuration of a health check is not right')
        end
      end

      # キャッシュ
      @cache = {} if options[:enable_cache]
    end

    # Control of service
    def_delegators :@gossip, :stop, :clear_dead_list

    def start
      # デーモン化すると子プロセスはすぐ死ぬので
      # このタイミングでヘルスチェックを起動
      @health_checkers.each do |name, checker|
        checker.start
      end

      @gossip.start
    end

    def to_hash
      keys = {
        :auth_key      => 'auth-key',
        :dns_address   => 'address',
        :dns_port      => 'port',
        :initial_nodes => lambda {|v| ['initial-nodes', v.join(',')] },
        :resolver      => lambda {|v| [
          'resolver',
          v.instance_variable_get(:@config).instance_variable_get(:@config_info)[:nameserver].join(',')
        ]},
        :socket        => 'socket',
        :max_ip_num    => 'max-ip-num',
        :domain        => 'domain',
        :enable_cache  => lambda {|v| ['enable-cache', !!v] },
        :log_path      => 'log-path',
        :log_level     => 'log-level',
        :gossip_port   => 'gossip-port',
        :gossip_node_lifetime => lambda {|v| [
          'gossip-node-lifetime',
          @gossip.context.node_lifetime
        ]},
        :gossip_send_interval => lambda {|v| [
          'gossip-send-interval',
          @gossip.context.gossip_interval
        ]},
        :gossip_receive_timeout => lambda {|v| [
          'gossip-receive-timeout',
          @gossip.context.receive_timeout
        ]},
      }

      hash = {}

      keys.each do |k, name|
        value = @options[k]

        if value and name.respond_to?(:call)
          name, value = name.call(value)
        end

        if value and (not value.kind_of?(String) or not value.empty?)
          hash[name] = value
        end
      end

      records = list_records.select {|r| r[0] == @address }

      hash['host'] = records.find {|r| r[3] == ORIGIN }[0..2].join(',')

      aliases = records.select {|r| r[3] != ORIGIN }.map do |r|
        [r[1], r[2], (r[3] == MASTER ? 'master' : 'backup'), r[4]].join(',')
      end

      hash['alias'] = aliases unless aliases.empty?

      # 設定ファイルのみの項目
      if @options.config_file
        if @options.config_file['health-check']
          hash['health-check'] = @options.config_file['health-check']
        end

        if @options.config_file['notification']
          hash['notification'] = @options.config_file['notification']
        end

        %w(name-includes name-excludes addr-includes addr-excludes).each do |key|
          if @options.config_file[key]
            hash[key] = @options.config_file[key]
          end
        end

        if @options.config_file['balancing']
          hash['balancing'] = @options.config_file['balancing']
        end
      end # 設定ファイルのみの項目

      return hash
    end
{'fraction_non_alphanumeric': 0.12158923303834808, 'fraction_numerical': 0.0025811209439528023, 'mean_word_length': 1.9739583333333333, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2100731', 'n_tokens_mistral': 3763, 'n_tokens_neox': 3658, 'n_words': 700}