require "active_support/core_ext/hash" require "json" require "curl" require_relative "client_signer" module PortalConnectors class BaseClient def self.singleton @singleton ||= new end def signer return if secret.blank? @_signer ||= ClientSigner.new(portal_name) end def sign(params) signer.sign(params) end def self.cached_stocks=(json_stocks) PortalConnectors.redis.set(cached_key_for(["stocks"]), json_stocks.to_json) end def self.cached_stocks cached_key = cached_key_for(["stocks"]) return nil unless PortalConnectors.redis.exists(cached_key) begin JSON.parse(PortalConnectors.redis.get(cached_key)) rescue StandardError nil end end protected def return_error(error) raise error if error.is_a? KeyError Rollbar.error(error) [error.inspect, false] end def normalize_params(params) case params when Hash params.each do |key, value| params[key] = normalize_params(value) end when Array params.each_with_index do |value, index| params[index] = normalize_params(value) end when BigDecimal params.to_s("F") else params end end def get_with_signature(url, params = {}, curl_options = {}) puts "get #{url}" if PortalConnectors.verbose nparams = normalize_params(params) url = "#{url}?#{nparams.to_query}" Curl::Easy.perform(url) do |c| c.timeout = curl_options[:timeout] || 10 c.headers["Authorization"] = signature_for(nparams) c.headers["Appname"] = PortalConnectors.requester c.ssl_verify_peer = false if curl_options[:skip_ssl] == true end end def post_with_signature(url, params = {}, curl_options = {}) puts "post #{url}" if PortalConnectors.verbose nparams = normalize_params(params) Curl.post(url, nparams.to_json) do |c| c.timeout = curl_options[:timeout] || 10 c.headers["Content-Type"] = "application/json" c.headers["Authorization"] = signature_for(nparams) c.headers["Appname"] = PortalConnectors.requester c.ssl_verify_peer = false if curl_options[:skip_ssl] == true end end def patch_with_signature(url, params = {}) puts "patch #{url}" if PortalConnectors.verbose nparams = normalize_params(params) Curl.patch(url, nparams.to_json) do |c| c.timeout = 10 c.headers["Content-Type"] = "application/json" c.headers["Authorization"] = signature_for(nparams) c.headers["Appname"] = PortalConnectors.requester end end def signature_for(params) signer.try(:sign, params).tap do |signature| p [:sign, params, :signature, signature] if PortalConnectors.verbose end end def next_nonce [PortalConnectors.requester, PortalConnectors.redis.incr(nonce_key)].join("-") end def portal_name self.class.name.demodulize.underscore.sub(/_client$/, "") end def cached_key_for(fields) [portal_name].concat(fields).join("-") end def host PortalConnectors.hosts[portal_name] end def nonce_key "#{portal_name}:nonce" end def secret PortalConnectors.secrets[portal_name] end def self.cached_key_for(fields) "Class-#{self}##{fields.join('-')}" end end end