require 'rest' require 'json' require 'yaml' require 'iron_core/response_error' module IronCore class Client attr_accessor :content_type attr_accessor :env def initialize(company, product, options = {}, default_options = {}, extra_options_list = []) @options_list = [:scheme, :host, :port, :user_agent, :http_gem] + extra_options_list metaclass = class << self self end @options_list.each do |option| metaclass.send(:define_method, option.to_s) do instance_variable_get('@' + option.to_s) end metaclass.send(:define_method, option.to_s + '=') do |value| instance_variable_set('@' + option.to_s, value) end end @env = options[:env] || options['env'] @env ||= ENV[company.upcase + '_' + product.upcase + '_ENV'] || ENV[company.upcase + '_ENV'] IronCore::Logger.info 'IronCore', "Setting env to '#{@env}'" unless @env.nil? load_from_hash('params', options) load_from_config(company, product, options[:config] || options['config']) load_from_config(company, product, ENV[company.upcase + '_' + product.upcase + '_CONFIG']) load_from_config(company, product, ENV[company.upcase + '_CONFIG']) load_from_env(company.upcase + '_' + product.upcase) load_from_env(company.upcase) suffixes = [] unless @env.nil? suffixes << "-#{@env}" suffixes << "_#{@env}" end suffixes << '' suffixes.each do |suffix| ['.json', '.yml'].each do |ext| ["#{company}-#{product}", "#{company}_#{product}", company].each do |config_base| load_from_config(company, product, "#{Dir.pwd}/#{config_base}#{suffix}#{ext}") load_from_config(company, product, "#{Dir.pwd}/.#{config_base}#{suffix}#{ext}") load_from_config(company, product, "#{Dir.pwd}/config/#{config_base}#{suffix}#{ext}") load_from_config(company, product, "#{Dir.pwd}/config/.#{config_base}#{suffix}#{ext}") begin load_from_config(company, product, "~/#{config_base}#{suffix}#{ext}") load_from_config(company, product, "~/.#{config_base}#{suffix}#{ext}") rescue Exception => ex puts "Warning -- Unable to load from HOME: #{ex.message}" end end end end load_from_hash('defaults', default_options) load_from_hash('defaults', {:user_agent => 'iron_core_ruby-' + IronCore.version}) @content_type = 'application/json' default_http_gem = RUBY_VERSION.split('.')[1].to_i == 8 ? :rest_client : nil http_gem = @http_gem.nil? ? default_http_gem : @http_gem.to_sym @rest = Rest::Client.new(:gem => http_gem) end def set_option(source, name, value) if send(name.to_s).nil? && (not value.nil?) IronCore::Logger.debug 'IronCore', "Setting #{name} to '#{value}' from #{source}" send(name.to_s + '=', value) end end def load_from_hash(source, hash) return if hash.nil? @options_list.each do |o| set_option(source, o, hash[o.to_sym] || hash[o.to_s]) end end def load_from_env(prefix) @options_list.each do |o| set_option('environment variable', o, ENV[prefix + '_' + o.to_s.upcase]) end end def get_sub_hash(hash, subs) return nil if hash.nil? subs.each do |sub| return nil if hash[sub].nil? hash = hash[sub] end hash end def load_from_config(company, product, config_file) return if config_file.nil? if File.exists?(File.expand_path(config_file)) config_data = '{}' begin config_data = File.read(File.expand_path(config_file)) rescue return end config = nil if config_file.end_with?('.yml') config = YAML.load(config_data) else config = JSON.parse(config_data) end unless @env.nil? load_from_hash(config_file, get_sub_hash(config, [@env, "#{company}_#{product}"])) load_from_hash(config_file, get_sub_hash(config, [@env, company, product])) load_from_hash(config_file, get_sub_hash(config, [@env, product])) load_from_hash(config_file, get_sub_hash(config, [@env, company])) load_from_hash(config_file, get_sub_hash(config, ["#{company}_#{product}", @env])) load_from_hash(config_file, get_sub_hash(config, [company, product, @env])) load_from_hash(config_file, get_sub_hash(config, [product, @env])) load_from_hash(config_file, get_sub_hash(config, [company, @env])) load_from_hash(config_file, get_sub_hash(config, [@env])) end load_from_hash(config_file, get_sub_hash(config, ["#{company}_#{product}"])) load_from_hash(config_file, get_sub_hash(config, [company, product])) load_from_hash(config_file, get_sub_hash(config, [product])) load_from_hash(config_file, get_sub_hash(config, [company])) load_from_hash(config_file, get_sub_hash(config, [])) end end def options(return_strings = false) res = {} @options_list.each do |option| res[return_strings ? option.to_s : option.to_sym] = send(option.to_s) end res end def headers {'User-Agent' => @user_agent} end def base_url "#{scheme}://#{host}:#{port}/" end def url(method) base_url + method end def get(method, params = {}) request_hash = {} request_hash[:headers] = headers request_hash[:params] = params IronCore::Logger.debug 'IronCore', "GET #{url(method)} with params='#{request_hash.to_s}'" begin @rest.get(url(method), request_hash) rescue Rest::HttpError => ex extract_error_msg(ex) end end def extract_error_msg(ex) if ex.response && ex.response.body begin bodyparsed = JSON.parse(ex.response.body) msg = bodyparsed["msg"] if msg ex.msg = msg end rescue => ex # ignore end end raise ex end def post(method, params = {}) request_hash = {} request_hash[:headers] = headers.merge({'Content-Type' => @content_type}) request_hash[:body] = params.to_json IronCore::Logger.debug 'IronCore', "POST #{base_url + method} with params='#{request_hash.to_s}'" begin @rest.post(base_url + method, request_hash) rescue Rest::HttpError => ex extract_error_msg(ex) end end def put(method, params={}) request_hash = {} request_hash[:headers] = headers.merge({'Content-Type' => @content_type}) request_hash[:body] = params.to_json IronCore::Logger.debug 'IronCore', "PUT #{base_url + method} with params='#{request_hash.to_s}'" begin @rest.put(base_url + method, request_hash) rescue Rest::HttpError => ex extract_error_msg(ex) end end def patch(method, params={}) request_hash = {} request_hash[:headers] = headers.merge({'Content-Type' => @content_type}) request_hash[:body] = params.to_json IronCore::Logger.debug 'IronCore', "PUT #{base_url + method} with params='#{request_hash.to_s}'" begin @rest.patch(base_url + method, request_hash) rescue Rest::HttpError => ex extract_error_msg(ex) end end def delete(method, params = {}, headers2={}) request_hash = {} request_hash[:headers] = headers.merge(headers2) if params.size > 0 request_hash[:headers].merge!({'Content-Type' => @content_type}) end request_hash[:body] = params.to_json IronCore::Logger.debug 'IronCore', "DELETE #{base_url + method} with params='#{request_hash.to_s}'" begin @rest.delete(base_url + method, request_hash) rescue Rest::HttpError => ex extract_error_msg(ex) end end def post_file(method, file_field, file, params_field, params = {}) request_hash = {} request_hash[:headers] = headers request_hash[:body] = {params_field => params.to_json, file_field => file} IronCore::Logger.debug 'IronCore', "POST #{base_url + method} with params='#{request_hash.to_s}'" begin @rest.post_file(base_url + method, request_hash) rescue Rest::HttpError => ex extract_error_msg(ex) end end def stream_get(method, params = {}) request_hash = {} request_hash[:headers] = headers request_hash[:params] = params uri = url(method) unless request_hash[:params].empty? query_string = request_hash[:params].collect { |k, v| "#{k.to_s}=#{CGI::escape(v.to_s)}" }.join('&') uri += "?#{query_string}" end IronCore::Logger.debug 'IronCore', "Streaming GET #{uri} with params='#{request_hash.to_s}'" req = URI(uri) Net::HTTP.start(req.hostname, req.port, :use_ssl => (req.scheme == 'https')) do |http| http.request_get(req, request_hash[:headers]) do |res| res.read_body do |chunk| yield(chunk) end end end end def parse_response(response, parse_json = true) IronCore::Logger.debug 'IronCore', "GOT #{response.code} with params='#{response.body}'" raise IronCore::ResponseError.new(response) if (response.code < 200 || response.code >= 300) body = String.new(response.body) return body unless parse_json JSON.parse(body) end def check_id(id, name = 'id', length = 24) if (not id.is_a?(String)) || id.length != length IronCore::Logger.error 'IronCore', "Expecting #{length} symbol #{name} string", IronCore::Error end end end end