require 'net/http' require 'time' require 'json' require "makitoo/feature_flag/version" module Makitoo module FeatureFlag class MemoryCache def initialize(ttl = 20.seconds) @cache = {} @ttl = ttl end def get(key) if @cache.has_key?(key) if @cache[key][:end] > Time.now() @cache[key][:value] else @cache.delete(key) nil end else nil end end def put(key, value) @cache[key] = { value: value, end: Time.now() + @ttl } end end class Client def initialize(application_id, options = {}) @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 = if options.has_key?(:cache) options[:cache] else MemoryCache.new end @environment_name = if options.has_key?(:environment_name) options[:environment_name] else 'production' end end def is_active(feature_name, installation_id, default_state = false) feature_configuration = get_feature_configuration(feature_name, installation_id) is_visible = if feature_configuration.nil? default_state else feature_configuration[:state] == 'ON' end event = if is_visible create_seen_event(feature_name, installation_id) else create_skip_event(feature_name, installation_id) end send_event(event) is_visible end def success(feature_name, installation_id) send_event(create_success_event(feature_name, installation_id)) end def track(event_name, installation_id, properties = {}) send_event(create_track_event(event_name, installation_id, properties)) end def init_segment(segment_id, makitoo_id) post_json(@server + '/associate-foreign-id', { foreignId: segment_id, source: 'segment.com', installationId: makitoo_id }) end def user #TODO end private def refresh_feature_configurations_cache(installation_id) feature_configurations = send_event(create_refresh_event(installation_id)) @cache.put('features.' + installation_id, feature_configurations) feature_configurations end def get_feature_configuration(feature_name, installation_id) feature_configurations = @cache.get('features.' + installation_id) if feature_configurations.nil? feature_configurations = refresh_feature_configurations_cache(installation_id) end if feature_configurations.nil? nil else feature_configurations[feature_name] end end def create_seen_event(feature_name, installation_id) create_execution_event(feature_name, 'SEEN', installation_id) end def create_skip_event(feature_name, installation_id) create_execution_event(feature_name, 'SKIP', installation_id) end def create_success_event(feature_name, installation_id) create_execution_event(feature_name, 'SUCCESS', installation_id) end def create_execution_event(feature_name, event_type, installation_id) event = create_event(event_type, installation_id) event[:featureName] = feature_name event end def create_track_event(event_name, installation_id, properties) event = create_event('TRACK', installation_id) event[:eventName] = event_name event[:properties] = properties event end def create_refresh_event(installation_id) create_event('REFRESH', installation_id) end def create_event(event_type, installation_id) { eventType: event_type, date: Time.now().iso8601, count: 1, installationId: installation_id, context: create_context, lib: { version: '0.0.1', type: 'ruby' } } end def post_json(url_str, data) puts url_str url = URI.parse(url_str) req = Net::HTTP::Post.new(url.to_s, 'Content-Type' => 'application/json') req.body = data.to_json res = Net::HTTP.start(url.host, url.port) {|http| http.request(req) } res end def send_event(event) res = post_json(@server + '/event?' + URI.encode_www_form({ application: @application_id, environmentName: @environment_name }), event) if !res.body.nil? begin result = JSON.parse(res.body); feature_configurations = {} result['features'].each{|feature| feature_configurations[feature['name']] = { name: feature['name'], state: feature['state'] } } feature_configurations rescue end end end def create_context {} end end end end