=begin #DevCycle Bucketing API #Documents the DevCycle Bucketing API which provides and API interface to User Bucketing and for generated SDKs. The version of the OpenAPI document: 1.0.0 Generated by: https://openapi-generator.tech OpenAPI Generator version: 5.3.0 =end require 'cgi' require 'logger' module DevCycle class DVCClient def initialize(sdkKey, dvc_options = DVCOptions.new, wait_for_init = false) if sdkKey.nil? raise ArgumentError.new('Missing SDK key!') elsif !sdkKey.start_with?('server') && !sdkKey.start_with?('dvc_server') raise ArgumentError.new('Invalid SDK key!') end @sdkKey = sdkKey @dvc_options = dvc_options @logger = dvc_options.logger if @dvc_options.enable_cloud_bucketing @api_client = ApiClient.default @api_client.config.api_key['bearerAuth'] = @sdkKey @api_client.config.enable_edge_db = @dvc_options.enable_edge_db @api_client.config.logger = @logger else @local_bucketing = LocalBucketing.new(@sdkKey, dvc_options, wait_for_init) @event_queue = EventQueue.new(@sdkKey, dvc_options.event_queue_options, @local_bucketing) end end def close if @dvc_options.enable_cloud_bucketing @logger.info("Cloud Bucketing does not require closing.") return end if @local_bucketing != nil if !@local_bucketing.initialized @logger.info("Awaiting client initialization before closing") while !@local_bucketing.initialized sleep(0.5) end end @local_bucketing.close @local_bucketing = nil @logger.info("Closed DevCycle Local Bucketing Engine.") end @event_queue.close @logger.info("Closed DevCycle Client.") nil end def set_client_custom_data(custom_data) if @dvc_options.enable_cloud_bucketing raise StandardError.new("Client Custom Data is only available in Local bucketing mode.") end if local_bucketing_initialized? @local_bucketing.set_client_custom_data(custom_data) else @logger.warn("Local bucketing not initialized. Unable to set client custom data.") end nil end def validate_model(model) return if model.valid? fail ArgumentError, "Invalid data provided for model #{model.class.name}: #{model.list_invalid_properties()}" end # Get all features by key for user data # @param user_data [UserData] # @param [Hash] opts the optional parameters # @return [Hash] def all_features(user_data, opts = {}) if !user_data.is_a?(DevCycle::UserData) fail ArgumentError, "user_data param must be an instance of UserData!" end validate_model(user_data) if @dvc_options.enable_cloud_bucketing data, _status_code, _headers = all_features_with_http_info(user_data, opts) return data end if local_bucketing_initialized? && @local_bucketing.has_config bucketed_config = @local_bucketing.generate_bucketed_config(user_data) bucketed_config.features else {} end end # Get all features by key for user data # @param user_data [UserData] # @param [Hash] opts the optional parameters # @return [Array<(Hash, Integer, Hash)>] Hash data, response status code and response headers def all_features_with_http_info(user_data, opts = {}) if @api_client.config.debugging @api_client.config.logger.debug 'Calling API: DVCClient.all_features ...' end # verify the required parameter 'user_data' is set if @api_client.config.client_side_validation && user_data.nil? fail ArgumentError, "Missing the required parameter 'user_data' when calling DVCClient.all_features" end # resource path local_var_path = '/v1/features' # query parameters query_params = opts[:query_params] || {} # header parameters header_params = opts[:header_params] || {} # HTTP header 'Accept' (if needed) header_params['Accept'] = @api_client.select_header_accept(['application/json']) # HTTP header 'Content-Type' content_type = @api_client.select_header_content_type(['application/json']) if !content_type.nil? header_params['Content-Type'] = content_type end # form parameters form_params = opts[:form_params] || {} # http body (model) post_body = opts[:debug_body] || user_data.to_json # return_type return_type = opts[:debug_return_type] || 'Hash' # auth_names auth_names = opts[:debug_auth_names] || ['bearerAuth'] new_options = opts.merge( :operation => :"DVCClient.all_features", :header_params => header_params, :query_params => query_params, :form_params => form_params, :body => post_body, :auth_names => auth_names, :return_type => return_type ) data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options) if @api_client.config.debugging @api_client.config.logger.debug "API called: DVCClient#all_features\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end # Get variable by key for user data # @param user_data [UserData] # @param key [String] Variable key # @param default Default value for variable if none is retrieved # @param [Hash] opts the optional parameters # @return [Variable] def variable(user_data, key, default, opts = {}) if !user_data.is_a?(DevCycle::UserData) fail ArgumentError, "user_data param must be an instance of UserData!" end validate_model(user_data) if @dvc_options.enable_cloud_bucketing data, _status_code, _headers = variable_with_http_info(key, user_data, default, opts) return data end value = default type = determine_variable_type(default) defaulted = true if local_bucketing_initialized? && @local_bucketing.has_config type_code = variable_type_code_from_type(type) variable_pb = variable_for_user_pb(user_data, key, type_code) if variable_pb == nil @logger.warn("No variable found or type mismatch for key #{key}, returning default value") else value = get_variable_value(variable_pb) defaulted = false end else @logger.warn("Local bucketing not initialized, returning default value for variable #{key}") variable_event = Event.new({ type: DevCycle::EventTypes[:agg_variable_defaulted], target: key }) bucketed_config = BucketedUserConfig.new({}, {}, {}, {}, {}, {}, []) @event_queue.queue_aggregate_event(variable_event, bucketed_config) end Variable.new({ key: key, value: value, type: type, defaultValue: default, isDefaulted: defaulted }) end def variable_for_user(user, key, variable_type_code) json_str = @local_bucketing.variable_for_user(user, key, variable_type_code) return nil if json_str.nil? JSON.parse(json_str) end def variable_for_user_pb(user, key, variable_type_code) user_data_pb = user.to_pb_user_data params_pb = Proto::VariableForUserParams_PB.new( sdkKey: @sdkKey, variableKey: key, variableType: variable_type_pb_code_from_type_code(variable_type_code), user: user_data_pb, shouldTrackEvent: true ) param_bin_string = Proto::VariableForUserParams_PB.encode(params_pb) var_bin_string = @local_bucketing.variable_for_user_pb(param_bin_string) if var_bin_string.nil? return nil end Proto::SDKVariable_PB.decode(var_bin_string) end # Get variable by key for user data # @param key [String] Variable key # @param user_data [UserData] # @param default Default value for variable if none is retrieved # @param [Hash] opts the optional parameters # @return [Array<(Variable, Integer, Hash)>] Variable data, response status code and response headers def variable_with_http_info(key, user_data, default, opts = {}) if @api_client.config.debugging @api_client.config.logger.debug 'Calling API: DVCClient.variable ...' end # verify the required parameter 'key' is set if @api_client.config.client_side_validation && key.nil? fail ArgumentError, "Missing the required parameter 'key' when calling DVCClient.variable" end # verify the required parameter 'user_data' is set if @api_client.config.client_side_validation && user_data.nil? fail ArgumentError, "Missing the required parameter 'user_data' when calling DVCClient.variable" end # resource path local_var_path = '/v1/variables/{key}'.sub('{' + 'key' + '}', CGI.escape(key.to_s)) # query parameters query_params = opts[:query_params] || {} # header parameters header_params = opts[:header_params] || {} # HTTP header 'Accept' (if needed) header_params['Accept'] = @api_client.select_header_accept(['application/json']) # HTTP header 'Content-Type' content_type = @api_client.select_header_content_type(['application/json']) if !content_type.nil? header_params['Content-Type'] = content_type end # form parameters form_params = opts[:form_params] || {} # http body (model) post_body = opts[:debug_body] || user_data.to_json # return_type return_type = opts[:debug_return_type] || 'Variable' # auth_names auth_names = opts[:debug_auth_names] || ['bearerAuth'] new_options = opts.merge( :operation => :"DVCClient.variable", :header_params => header_params, :query_params => query_params, :form_params => form_params, :body => post_body, :auth_names => auth_names, :return_type => return_type ) begin data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options) if @api_client.config.debugging @api_client.config.logger.debug "API called: DVCClient#variable\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data rescue ApiError => error if error.code != 404 @api_client.config.logger.error("Failed to retrieve variable value: #{error.message}") end return Variable.new(key: key, value: default, isDefaulted: true) end end # Get all variables by key for user data # @param user_data [UserData] # @param [Hash] opts the optional parameters # @return [Hash] def all_variables(user_data, opts = {}) if !user_data.is_a?(DevCycle::UserData) fail ArgumentError, "user_data param must be an instance of UserData!" end validate_model(user_data) if @dvc_options.enable_cloud_bucketing data, _status_code, _headers = all_variables_with_http_info(user_data, opts) return data end if local_bucketing_initialized? && @local_bucketing.has_config bucketed_config = @local_bucketing.generate_bucketed_config(user_data) bucketed_config.variables else {} end end # Get all variables by key for user data # @param user_data [UserData] # @param [Hash] opts the optional parameters # @return [Array<(Hash, Integer, Hash)>] Hash data, response status code and response headers def all_variables_with_http_info(user_data, opts = {}) if @api_client.config.debugging @api_client.config.logger.debug 'Calling API: DVCClient.all_variables ...' end # verify the required parameter 'user_data' is set if @api_client.config.client_side_validation && user_data.nil? fail ArgumentError, "Missing the required parameter 'user_data' when calling DVCClient.all_variables" end # resource path local_var_path = '/v1/variables' # query parameters query_params = opts[:query_params] || {} # header parameters header_params = opts[:header_params] || {} # HTTP header 'Accept' (if needed) header_params['Accept'] = @api_client.select_header_accept(['application/json']) # HTTP header 'Content-Type' content_type = @api_client.select_header_content_type(['application/json']) if !content_type.nil? header_params['Content-Type'] = content_type end # form parameters form_params = opts[:form_params] || {} # http body (model) post_body = opts[:debug_body] || user_data.to_json # return_type return_type = opts[:debug_return_type] || 'Hash' # auth_names auth_names = opts[:debug_auth_names] || ['bearerAuth'] new_options = opts.merge( :operation => :"DVCClient.all_variables", :header_params => header_params, :query_params => query_params, :form_params => form_params, :body => post_body, :auth_names => auth_names, :return_type => return_type ) data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options) if @api_client.config.debugging @api_client.config.logger.debug "API called: DVCClient#all_variables\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end # Post events to DevCycle for user # @param user_data [UserData] # @param event_data [Event] # @param [Hash] opts the optional parameters # @return [InlineResponse201] def track(user_data, event_data, opts = {}) if !user_data.is_a?(DevCycle::UserData) fail ArgumentError, "user_data param must be an instance of UserData!" end validate_model(user_data) if !event_data.is_a?(DevCycle::Event) fail ArgumentError, "event_data param must be an instance of Event!" end validate_model(event_data) if @dvc_options.enable_cloud_bucketing track_with_http_info(user_data, event_data, opts) return end if local_bucketing_initialized? @event_queue.queue_event(user_data, event_data) else @logger.warn('track called before DVCClient initialized, event will not be tracked') end end # Post events to DevCycle for user # @param user_data [UserData] # @param event_data [Event] # @param [Hash] opts the optional parameters # @return [Array<(InlineResponse201, Integer, Hash)>] InlineResponse201 data, response status code and response headers def track_with_http_info(user_data, event_data, opts = {}) if @api_client.config.debugging @api_client.config.logger.debug 'Calling API: DVCClient.post_events ...' end # verify the required parameter 'user_data_and_events_body' is set if @api_client.config.client_side_validation && (user_data.nil? || event_data.nil?) fail ArgumentError, "Missing the required parameter 'user_data_and_events_body' when calling DVCClient.post_events" end user_data_and_events_body = DevCycle::UserDataAndEventsBody.new({ user: user_data, events: [event_data] }) # resource path local_var_path = '/v1/track' # query parameters query_params = opts[:query_params] || {} # header parameters header_params = opts[:header_params] || {} # HTTP header 'Accept' (if needed) header_params['Accept'] = @api_client.select_header_accept(['application/json']) # HTTP header 'Content-Type' content_type = @api_client.select_header_content_type(['application/json']) if !content_type.nil? header_params['Content-Type'] = content_type end # form parameters form_params = opts[:form_params] || {} # http body (model) post_body = opts[:debug_body] || @api_client.object_to_http_body(user_data_and_events_body) # if post_body.user.respond_to?(:to_hash) # post_body.user = post_body.user.to_hash() # return_type return_type = opts[:debug_return_type] || 'InlineResponse201' # auth_names auth_names = opts[:debug_auth_names] || ['bearerAuth'] new_options = opts.merge( :operation => :"DVCClient.post_events", :header_params => header_params, :query_params => query_params, :form_params => form_params, :body => post_body, :auth_names => auth_names, :return_type => return_type ) data, status_code, headers = @api_client.call_api(:POST, local_var_path, new_options) if @api_client.config.debugging @api_client.config.logger.debug "API called: DVCClient#post_events\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}" end return data, status_code, headers end def flush_events @event_queue.flush_events end def local_bucketing_initialized? !@local_bucketing.nil? && @local_bucketing.initialized end def determine_variable_type(variable_value) if variable_value.is_a?(String) 'String' elsif variable_value.is_a?(TrueClass) || variable_value.is_a?(FalseClass) 'Boolean' elsif variable_value.is_a?(Integer) || variable_value.is_a?(Float) 'Number' elsif variable_value.is_a?(Hash) 'JSON' else raise ArgumentError, "Invalid type for variable: #{variable_value}" end end def variable_type_code_from_type(type) case type when 'String' @local_bucketing.variable_type_codes[:string] when 'Boolean' @local_bucketing.variable_type_codes[:boolean] when 'Number' @local_bucketing.variable_type_codes[:number] when 'JSON' @local_bucketing.variable_type_codes[:json] else raise ArgumentError.new("Invalid type for variable: #{type}") end end def variable_type_pb_code_from_type_code(type_code) case type_code when @local_bucketing.variable_type_codes[:string] Proto::VariableType_PB::String when @local_bucketing.variable_type_codes[:boolean] Proto::VariableType_PB::Boolean when @local_bucketing.variable_type_codes[:number] Proto::VariableType_PB::Number when @local_bucketing.variable_type_codes[:json] Proto::VariableType_PB::JSON else raise ArgumentError.new("Invalid type code for variable: #{type_code}") end end end end