class Makitoo::FeatureFlag::Client

Public Class Methods

new(application_id, options = {}) click to toggle source
# File lib/makitoo/feature_flag.rb, line 13
def initialize(application_id, options = {})
  @logger = if options.has_key?(:logger)
    options[:logger]
  elsif defined?(Rails)
    Rails.logger
  else
    logger = Logger.new STDOUT
    logger.progname = 'Makitoo::FeatureFlag'
    logger
  end
  @logger.debug 'Initializing makitoo feature flag'
  @application_id = application_id
  @server = if options.has_key?(:server)
    options[:server]
  elsif options[:ssl]
    'https://features.makitoo.com/api/v1'
  else
    'http://features.makitoo.com/api/v1'
  end
  @cache = options[:cache] || MemoryCache.new(@logger)
  @environment_name = options[:environment_name] || 'production'
  @concurrency = options[:concurrency] || 1
  @force_sync = options[:force_sync] || @concurrency < 1
  start_background_threads
  @logger.debug 'Makitoo initialized'
end

Public Instance Methods

init_segment(segment_id, user_or_id) click to toggle source
# File lib/makitoo/feature_flag.rb, line 71
def init_segment(segment_id, user_or_id)
  @logger.debug 'Start init_segment'
  post_json(@server + '/associate-foreign-id', {
    foreignId: segment_id,
    source: 'segment.com',
    installationId: User.of(user_or_id).id
  })
  @logger.debug 'Stop init_segment'
end
is_active(feature_name, user_or_id, default_state = false) click to toggle source
# File lib/makitoo/feature_flag.rb, line 40
def is_active(feature_name, user_or_id, default_state = false)
  @logger.debug 'Start is_active'
  user = User.of(user_or_id)
  feature_configuration = get_feature_configuration(feature_name, user)
  is_visible = if feature_configuration.nil?
    default_state
  else
    feature_configuration[:state] == 'ON'
  end
  event = if is_visible
    create_seen_event(feature_name, user)
  else
    create_skip_event(feature_name, user)
  end
  send_event(event)
  @logger.debug 'Stop is_active'
  is_visible
end
success(feature_name, user_or_id) click to toggle source
# File lib/makitoo/feature_flag.rb, line 59
def success(feature_name, user_or_id)
  @logger.debug 'Start is_active'
  send_event(create_success_event(feature_name, User.of(user_or_id)))
  @logger.debug 'Stop success'
end
track(event_name, user_or_id, properties = {}) click to toggle source
# File lib/makitoo/feature_flag.rb, line 65
def track(event_name, user_or_id, properties = {})
  @logger.debug 'Start is_active'
  send_event(create_track_event(event_name, User.of(user_or_id), properties))
  @logger.debug 'Stop track'
end

Private Instance Methods

create_context(user) click to toggle source
# File lib/makitoo/feature_flag.rb, line 220
def create_context(user)
  {
    user: user.as_json
  }
end
create_event(event_type, user) click to toggle source
# File lib/makitoo/feature_flag.rb, line 166
def create_event(event_type, user)
  {
    eventType: event_type,
    date: Time.now().iso8601,
    count: 1,
    installationId: user.id,
    context: create_context(user),
    lib: {
      version: '0.0.1',
      type: 'ruby'
    }
  }
end
create_execution_event(feature_name, event_type, user) click to toggle source
# File lib/makitoo/feature_flag.rb, line 149
def create_execution_event(feature_name, event_type, user)
  event = create_event(event_type, user)
  event[:featureName] = feature_name
  event
end
create_refresh_event(user) click to toggle source
# File lib/makitoo/feature_flag.rb, line 162
def create_refresh_event(user)
  create_event('REFRESH', user)
end
create_seen_event(feature_name, user) click to toggle source
# File lib/makitoo/feature_flag.rb, line 137
def create_seen_event(feature_name, user)
  create_execution_event(feature_name, 'SEEN', user)
end
create_skip_event(feature_name, user) click to toggle source
# File lib/makitoo/feature_flag.rb, line 141
def create_skip_event(feature_name, user)
  create_execution_event(feature_name, 'SKIP', user)
end
create_success_event(feature_name, user) click to toggle source
# File lib/makitoo/feature_flag.rb, line 145
def create_success_event(feature_name, user)
  create_execution_event(feature_name, 'SUCCESS', user)
end
create_track_event(event_name, user, properties) click to toggle source
# File lib/makitoo/feature_flag.rb, line 155
def create_track_event(event_name, user, properties)
  event = create_event('TRACK', user)
  event[:eventName] = event_name
  event[:properties] = properties
  event
end
get_feature_configuration(feature_name, user) click to toggle source
# File lib/makitoo/feature_flag.rb, line 125
def get_feature_configuration(feature_name, user)
  feature_configurations = @cache.get('features.' + user.id)
  if feature_configurations.nil?
    feature_configurations = refresh_feature_configurations_cache(user)
  end
  if feature_configurations.nil?
    nil
  else
    feature_configurations[feature_name]
  end
end
log_error(e) click to toggle source
# File lib/makitoo/feature_flag.rb, line 113
def log_error(e)
  @logger.error 'Exception'
  @logger.error e.message
  e.backtrace.each { |line| @logger.error line }
end
post_json(url_str, data, async) click to toggle source
# File lib/makitoo/feature_flag.rb, line 180
def post_json(url_str, data, async)
  url = URI.parse(url_str)
  req = Net::HTTP::Post.new(url.to_s, 'Content-Type' => 'application/json')
  req.body = data.to_json
  if async && !@force_sync
    @logger.debug 'Queue async event'
    @queue << {url: url, req: req}
    nil
  else
    @logger.debug 'Sync request start'
    res = Net::HTTP.start(url.host, url.port, use_ssl: url.scheme == 'https') {|http|
      http.request(req)
    }
    @logger.debug 'Sync request end'
    res.body
  end
end
refresh_feature_configurations_cache(user) click to toggle source
# File lib/makitoo/feature_flag.rb, line 119
def refresh_feature_configurations_cache(user)
  feature_configurations = send_event(create_refresh_event(user), false)
  @cache.put('features.' + user.id, feature_configurations)
  feature_configurations
end
send_event(event, async = true) click to toggle source
# File lib/makitoo/feature_flag.rb, line 198
def send_event(event, async = true)
  begin
    body = post_json(@server + '/event?' + URI.encode_www_form({
      application: @application_id,
      environmentName: @environment_name
    }), event, async)
    if !body.nil?
      result = JSON.parse(body);
      feature_configurations = {}
      result['features'].each{|feature|
        feature_configurations[feature['name']] = {
          name: feature['name'],
          state: feature['state']
        }
      }
      feature_configurations
    end
  rescue => e
    log_error(e)
  end
end
start_background_threads() click to toggle source
# File lib/makitoo/feature_flag.rb, line 83
def start_background_threads
  if !@force_sync
    @queue = Queue.new
    @logger.debug 'Background threads starting'
    (1..@concurrency).each do
      Thread.new do
        @logger.debug 'Background thread started'
        begin
          loop do
            begin
              @logger.debug 'Async request waiting for task'
              val = @queue.pop
              @logger.debug 'Async request start'
              res = Net::HTTP.start(val[:url].host, val[:url].port, use_ssl: val[:url].scheme == 'https') {|http|
                http.request(val[:req])
              }
              @logger.debug 'Async request end'
            rescue Exception => e
              @logger.debug 'Error !!!'
              log_error(e)
            end
          end
        ensure
          @logger.debug 'Background thread stopped'
        end
      end
    end
  end
end