Skip to content

Commit

Permalink
feat: adddig ruby client for cac and experimentation system
Browse files Browse the repository at this point in the history
  • Loading branch information
Subhash703 committed Jul 29, 2024
1 parent 73b5dbc commit 5b144fe
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 0 deletions.
112 changes: 112 additions & 0 deletions clients/ruby/cac-client/cacclient.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
require 'ffi'
require 'os'

module MergeStrategy
REPLACE = "REPLACE"
MERGE = "MERGE"
end

module CACLib
extend FFI::Library

extension = "dylib"
if OS.windows?
extension = "dll"
elsif OS.mac?
extension = "dylib"
else
extension = "so"
end
libpath = File.expand_path(File.join(__dir__, "/../../../target/debug/libcac_client.#{extension}"))
ffi_lib libpath

class ArcClient < FFI::Struct
layout :dummy, :int
end

# Attach C functions
attach_function :cac_last_error_length, [], :int
attach_function :cac_last_error_message, [], :string
attach_function :cac_free_string, [:pointer], :void
attach_function :cac_new_client, [:string, :ulong, :string], :int
attach_function :cac_start_polling_update, [:string], :void
attach_function :cac_free_client, [ArcClient.by_ref], :void
attach_function :cac_get_client, [:string], ArcClient.by_ref
attach_function :cac_get_last_modified, [ArcClient.by_ref], :string
attach_function :cac_get_config, [ArcClient.by_ref, :string, :string], :string
attach_function :cac_get_resolved_config, [ArcClient.by_ref, :string, :string, :string], :string
attach_function :cac_get_default_config, [ArcClient.by_ref, :string], :string
end

class CACClient
def initialize(tenant, update_frequency, hostname)
result = CACLib.cac_new_client(tenant, update_frequency, hostname)
raise "Failed to create client: #{last_error_message}" if result != 0
@client = CACLib.cac_get_client(tenant)
raise "Failed to get client: #{last_error_message}" if @client.null?
@tenant = tenant
end

def start_polling_update
CACLib.cac_start_polling_update(@tenant)
end

def get_last_modified
result = CACLib.cac_get_last_modified(@client)
raise "Failed to get last modified time: #{last_error_message}" if result.nil?
result
end

def get_config(filter_query, filter_prefix)
result = CACLib.cac_get_config(@client, filter_query, filter_prefix)
puts "Filter query : #{result}"
raise "Failed to get config: #{last_error_message}" if result.nil?
result
ensure
# CACLib.cac_free_string(result) if result // No need to free as its handled internally
end

def get_resolved_config(query, filter_keys, merge_strategy)
result = CACLib.cac_get_resolved_config(@client, query, filter_keys, merge_strategy)
raise "Failed to get resolved config: #{last_error_message}" if result.nil?
result
end

def get_default_config(filter_keys)
result = CACLib.cac_get_default_config(@client, filter_keys)
raise "Failed to get default config: #{last_error_message}" if result.nil?
result
end

def last_error_message
CACLib.cac_last_error_message
end

def close
CACLib.cac_free_client(@client) unless @client.null?
end
end

# Example usage
begin
client = CACClient.new("dev", 60000, "http://localhost:8080")
puts "Starting the client"

client.start_polling_update

puts "Last Modified: #{client.get_last_modified}"

config = client.get_config('{"country": "India"}', 'country')
puts "Config: #{config}"

resolved_config = client.get_resolved_config('{"country": "India"}',
"country_image_url,hyperpay_version", MergeStrategy::REPLACE)
puts "Resolved Config: #{resolved_config}"

default_config = client.get_default_config("your_filter_keys")
puts "Default Config: #{default_config}"
rescue StandardError => e
puts "Error: #{e.message}"
ensure
client.close if client
end
110 changes: 110 additions & 0 deletions clients/ruby/exp-client/expclient.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
require 'ffi'
require 'os'
require 'thread'

module ExpClientLib
extend FFI::Library
extension = if OS.windows?
"dll"
elsif OS.mac?
"dylib"
else
"so"
end
libpath = File.expand_path(File.join(__dir__, "/../../../target/debug/libexperimentation_client.#{extension}"))
ffi_lib libpath

attach_function :expt_new_client, [:string, :int, :string], :int
attach_function :expt_start_polling_update, [:string], :void
attach_function :expt_get_client, [:string], :string
attach_function :expt_get_applicable_variant, [:string, :string, :int], :string
attach_function :expt_get_satisfied_experiments, [:string, :string, :string], :string
attach_function :expt_get_filtered_satisfied_experiments, [:string, :string, :string], :string
attach_function :expt_get_running_experiments, [:string], :string
attach_function :expt_free_string, [:string], :void
attach_function :expt_last_error_message, [], :string
attach_function :expt_last_error_length, [], :int
attach_function :expt_free_client, [:string], :void

class ExperimentationClient
def initialize(tenant_name, polling_frequency, cac_host_name)
@tenant = tenant_name
@polling_frequency = polling_frequency
@cac_host_name = cac_host_name
@polling_thread = nil
end

def get_experimentation_last_error_message
ExpClientLib.expt_last_error_message
end

def create_new_experimentation_client
resp_code = ExpClientLib.expt_new_client(@tenant, @polling_frequency, @cac_host_name)
if resp_code == 1
error_message = get_experimentation_last_error_message
puts "Some Error Occurred while creating new experimentation client: #{error_message}"
raise "Client Creation Error"
end
resp_code
end

def get_experimentation_client
ExpClientLib.expt_get_client(@tenant)
end

def get_running_experiments
client_ptr = get_experimentation_client
ExpClientLib.expt_get_running_experiments(client_ptr)
end

def free_string(str)
ExpClientLib.expt_free_string(str)
end

def start_experimentation_polling_update
@polling_thread = Thread.new do
ExpClientLib.expt_start_polling_update(@tenant)
end
end

def get_experimentation_last_error_length
ExpClientLib.expt_last_error_length
end

def free_experimentation_client
ExpClientLib.expt_free_client(get_experimentation_client)
end

def get_filtered_satisfied_experiments(context, filter_prefix)
ExpClientLib.expt_get_filtered_satisfied_experiments(
get_experimentation_client, context, filter_prefix
)
end

def get_applicable_variant(context, toss)
ExpClientLib.expt_get_applicable_variant(
get_experimentation_client, context, toss
)
end

def get_satisfied_experiments(context, filter_prefix)
ExpClientLib.expt_get_satisfied_experiments(
get_experimentation_client, context, filter_prefix
)
end
end
end

# Example usage
begin
client = ExpClientLib::ExperimentationClient.new('dev', 10, 'http://localhost:8080')
client.create_new_experimentation_client
puts "Running experiments :: #{client.get_running_experiments}"
client.start_experimentation_polling_update
puts "After starting the polling"
puts "Running get_filtered_satisfied_experiments :: #{client.get_filtered_satisfied_experiments("juspay", "key1")}"
rescue StandardError => e
puts "Error: #{e.message}"
ensure
client.close if client
end

0 comments on commit 5b144fe

Please sign in to comment.