class Ingenico::Direct::SDK::Communicator
Class responsible for facilitating communication with the Ingenico
ePayments platform. It combines the following classes to provide communication functionality:
api_endpoint
-
The base URI ({URI::HTTP}) to the
Ingenico
ePayments platform - connection
-
{Ingenico::Direct::SDK::Connection} used to communicate with the
Ingenico
ePayments platform - authenticator
-
{Ingenico::Direct::SDK::Authenticator} used for authenticating messages sent
meta_data_provider
-
{Ingenico::Direct::SDK::MetaDataProvider} object containing information relevant for sending requests
- marshaller
-
{Ingenico::Direct::SDK::Marshaller} that is used to marshal and unmarshal data to and from JSON format
@attr_reader [Ingenico::Direct::SDK::Marshaller] marshaller A Marshaller
instance used by the communicator for serializing/deserializing to/from JSON
Attributes
Public Class Methods
Creates a new Communicator
based on the given arguments.
@param api_endpoint
[String] the base URL to the Ingenico
ePayments platform @param connection [Ingenico::Direct::SDK::Connection] used to communicate with the Ingenico
ePayments platform @param authenticator [Ingenico::Direct::SDK::Authenticator] used for authenticating messages sent @param meta_data_provider
[Ingenico::Direct::SDK::MetaDataProvider] object containing information relevant for sending requests @param marshaller [Ingenico::Direct::SDK::Marshaller] used to marshal and unmarshal data to and from JSON format
# File lib/ingenico/direct/sdk/communicator.rb, line 26 def initialize(api_endpoint, connection, authenticator, meta_data_provider, marshaller) raise ArgumentError, 'api_endpoint is required' unless api_endpoint raise ArgumentError, 'connection is required' unless connection raise ArgumentError, 'authenticator is required' unless authenticator raise ArgumentError, 'meta_data_provider is required' unless meta_data_provider raise ArgumentError('marshaller is required') unless marshaller @api_endpoint = URI(api_endpoint) if @api_endpoint.path.length.positive? || @api_endpoint.query || @api_endpoint.fragment raise ArgumentError, "Base URL should not contain a path, query or fragment #{@api_endpoint}" end @connection = connection @authenticator = authenticator @meta_data_provider = meta_data_provider @marshaller = marshaller end
Public Instance Methods
Frees networking resources by closing the underlying network connections. After calling close, any use of the get, delete, post and put methods will not function and likely result in an error.
# File lib/ingenico/direct/sdk/communicator.rb, line 211 def close @connection.close end
Closes any connections that have expired. Will not have any effect if the connection is not a pooled connection (an instance of {Ingenico::Direct::SDK::PooledConnection}).
# File lib/ingenico/direct/sdk/communicator.rb, line 190 def close_expired_connections @connection.close_expired_connections if connection.is_a? PooledConnection end
Closes any connections idle for more than idle_time seconds. Will not have any effect if the connection is not a pooled connection (an instance of {Ingenico::Direct::SDK::PooledConnection}).
# File lib/ingenico/direct/sdk/communicator.rb, line 184 def close_idle_connections(idle_time) @connection.close_idle_connections(idle_time) if connection.is_a? PooledConnection end
Performs a DELETE request to the Ingenico
ePayments platform and returns the response as the given response type.
@param relative_path [String] Path relative to the API endpoint @param request_headers [Array<Ingenico::Direct::SDK::RequestHeader>, nil] Optional array of request headers @param request_parameters [Ingenico::Direct::SDK::ParamRequest, nil] Optional request parameters @param response_type [Type] The response type. @param context [Ingenico::Direct::SDK::CallContext, nil] Optional call context. @return The response of the DELETE request as the given response type @raise [Ingenico::Direct::SDK::ResponseException] if the request could not be fulfilled successfully.
This occurs for example if the request is not authenticated correctly
@raise [Ingenico::Direct::SDK::NotFoundException] if the requested resource is not found @raise [Ingenico::Direct::SDK::CommunicationException] if there is an error in communicating with the Ingenico
ePayments platform.
This occurs for example if a timeout occurs.
# File lib/ingenico/direct/sdk/communicator.rb, line 86 def delete(relative_path, request_headers, request_parameters, response_type, context) connection = @connection request_parameter_list = request_parameters&.to_request_parameters uri = to_absolute_uri(relative_path, request_parameter_list) request_headers ||= [] add_generic_headers('DELETE', uri, request_headers, context) response_status_code, response_headers, response_body = nil connection.delete(uri, request_headers) do |status_code, headers, content| response_status_code = status_code response_headers = headers response_body = content.read.force_encoding('UTF-8') end process_response(response_body, response_status_code, response_headers, response_type, relative_path, context) end
Disables logging by unregistering any previous logger that might be registered.
# File lib/ingenico/direct/sdk/communicator.rb, line 204 def disable_logging @connection.disable_logging end
Enables logging outgoing requests and incoming responses by registering the communicator_logger. Note that only one logger can be registered at a time and calling enable_logging a second time will override the old logger instance with the new one.
@param communicator_logger [Ingenico::Direct::SDK::Logging::CommunicatorLogger] The communicator logger the requests and responses are logged to
# File lib/ingenico/direct/sdk/communicator.rb, line 199 def enable_logging(communicator_logger) @connection.enable_logging(communicator_logger) end
Performs a GET request to the Ingenico
ePayments platform and returns the response as the given response type.
@param relative_path [String] path relative to the API endpoint @param request_headers [Array<Ingenico::Direct::SDK::RequestHeader>, nil] optional array of request headers @param request_parameters [Ingenico::Direct::SDK::ParamRequest, nil] optional request parameters @param response_type [Type] the response type. @param context [Ingenico::Direct::SDK::CallContext, nil] optional call context. @return the response of the GET request as the given response type @raise [Ingenico::Direct::SDK::ResponseException] if the request could not be fulfilled successfully.
This occurs for example if the request is not authenticated correctly
@raise [Ingenico::Direct::SDK::NotFoundException] if the requested resource is not found @raise [Ingenico::Direct::SDK::CommunicationException] if there is an error in communicating with the Ingenico
ePayments platform.
This occurs for example if a timeout occurs.
# File lib/ingenico/direct/sdk/communicator.rb, line 56 def get(relative_path, request_headers, request_parameters, response_type, context) connection = @connection request_parameter_list = request_parameters&.to_request_parameters uri = to_absolute_uri(relative_path, request_parameter_list) request_headers ||= [] add_generic_headers('GET', uri, request_headers, context) response_status_code, response_headers, response_body = nil connection.get(uri, request_headers) do |status_code, headers, content| response_status_code = status_code response_headers = headers response_body = content.read.force_encoding('UTF-8') end process_response(response_body, response_status_code, response_headers, response_type, relative_path, context) end
Performs a POST request to the Ingenico
ePayments platform and returns the response as the given response type.
@param relative_path [String] Path relative to the API endpoint @param request_headers [Array<Ingenico::Direct::SDK::RequestHeader>, nil] Optional array of request headers @param request_parameters [Ingenico::Direct::SDK::ParamRequest, nil] Optional request parameters @param request_body [Ingenico::Direct::SDK::DataObject] The optional request body @param response_type [Type] The response type. @param context [Ingenico::Direct::SDK::CallContext, nil] Optional call context. @return The response of the POST request as the given response type @raise [Ingenico::Direct::SDK::ResponseException] if the request could not be fulfilled successfully.
This occurs for example if the request is not authenticated correctly
@raise [Ingenico::Direct::SDK::NotFoundException] if the requested resource is not found @raise [Ingenico::Direct::SDK::CommunicationException] if there is an error in communicating with the Ingenico
ePayments platform.
This occurs for example if a timeout occurs.
# File lib/ingenico/direct/sdk/communicator.rb, line 116 def post(relative_path, request_headers, request_parameters, request_body, response_type, context) request_parameter_list = request_parameters&.to_request_parameters uri = to_absolute_uri(relative_path, request_parameter_list) request_headers ||= [] body = nil if request_body request_headers.push(RequestHeader.new('Content-Type', 'application/json')) body = @marshaller.marshal(request_body) else # Set the content-type, even though there is no body, to prevent the httpClient from # adding a content-type header after authentication has been generated. request_headers.push(RequestHeader.new('Content-Type', 'text/plain')) end add_generic_headers('POST', uri, request_headers, context) response_status_code, response_headers, response_body = nil @connection.post(uri, request_headers, body) do |status_code, headers, content| response_status_code = status_code response_headers = headers response_body = content.read.force_encoding('UTF-8') end process_response(response_body, response_status_code, response_headers, response_type, relative_path, context) end
Performs a PUT request to the Ingenico
ePayments platform and returns the response as the given response type.
@param relative_path [String] Path relative to the API endpoint @param request_headers [Array<Ingenico::Direct::SDK::RequestHeader>, nil] Optional array of request headers @param request_parameters [Ingenico::Direct::SDK::ParamRequest, nil] Optional request parameters @param request_body [Ingenico::Direct::SDK::DataObject]
The optional request body
@param response_type [Type] The response type. @param context [Ingenico::Direct::SDK::CallContext, nil] Optional call context. @return The response of the PUT request as the given response type @raise [Ingenico::Direct::SDK::ResponseException] if the request could not be fulfilled successfully.
This occurs for example if the request is not authenticated correctly
@raise [Ingenico::Direct::SDK::NotFoundException] if the requested resource is not found @raise [Ingenico::Direct::SDK::CommunicationException] if there is an error in communicating with the Ingenico
ePayments platform.
This occurs for example if a timeout occurs.
# File lib/ingenico/direct/sdk/communicator.rb, line 157 def put(relative_path, request_headers, request_parameters, request_body, response_type, context) request_parameter_list = request_parameters&.to_request_parameters uri = to_absolute_uri(relative_path, request_parameter_list) request_headers ||= [] body = nil if request_body request_headers.push(RequestHeader.new('Content-Type', 'application/json')) body = @marshaller.marshal(request_body) else # Set the content-type, even though there is no body, to prevent the httpClient from # adding a content-type header after authentication has been generated. request_headers.push(RequestHeader.new('Content-Type', 'text/plain')) end add_generic_headers('PUT', uri, request_headers, context) response_status_code, response_headers, response_body = nil @connection.put(uri, request_headers, body) do |status_code, headers, content| response_status_code = status_code response_headers = headers response_body = content.read.force_encoding('UTF-8') end process_response(response_body, response_status_code, response_headers, response_type, relative_path, context) end
Protected Instance Methods
Adds several standard headers to the http headers. This method will add the 'Date' and 'Authorization' header; the 'X-GCS-Idempotence-Key' header will also be added if an idempotence context is given
@param http_method [String] 'GET', 'DELETE', 'POST' or 'PUT' depending on the HTTP method being used @param uri [URI::HTTP] The full URI to the Ingenico
ePayments platform,
including the relative path and request parameters.
@param request_headers [Array<Ingenico::Direct::SDK::RequestHeader>] List of request headers in which which new headers will be added @param context [Ingenico::Direct::SDK::CallContext, nil] object that will be used to produce
an Idempotence header to prevent accidental request duplication.
# File lib/ingenico/direct/sdk/communicator.rb, line 256 def add_generic_headers(http_method, uri, request_headers, context = nil) request_headers.concat(meta_data_provider.meta_data_headers) request_headers.push(RequestHeader.new('Date', get_header_date_string)) if context&.idempotence_key request_headers.push(RequestHeader.new('X-GCS-Idempotence-Key', context.idempotence_key)) end authentication_signature = @authenticator.create_simple_authentication_signature(http_method, uri, request_headers) request_headers.push(RequestHeader.new('Authorization', authentication_signature)) end
# File lib/ingenico/direct/sdk/communicator.rb, line 266 def get_header_date_string Time.now.utc.strftime('%a, %d %b %Y %H:%M:%S GMT') end
# File lib/ingenico/direct/sdk/communicator.rb, line 270 def process_response(body, status, headers, response_type, request_path, context) update_context(headers, context) if context throw_exception_if_necessary(body, status, headers, request_path) @marshaller.unmarshal(body, response_type) end
# File lib/ingenico/direct/sdk/communicator.rb, line 281 def throw_exception_if_necessary(body, status_code, headers, request_path) return if status_code >= 200 && status_code < 300 raise ResponseException.new status_code, headers, body unless body && !is_json(headers) cause = ResponseException.new(status_code, headers, body) if status_code == 404 raise NotFoundException, cause, "The requested resource was not found; invalid path: #{request_path}" end raise CommunicationException, cause end
Constructs a full URL using the base URL and the given relative path and request_parameters. The returned URL is a URI object.
@param relative_path [String] The relative path of the URL. @param request_parameters [Array<Ingenico::Direct::SDK::RequestParam>, nil] A list of request parameters that each have name and value
which represent the parameter name and value respectively.
# File lib/ingenico/direct/sdk/communicator.rb, line 230 def to_absolute_uri(relative_path, request_parameters) raise RuntimeError('api_endpoint should not contain a path') unless @api_endpoint.path.nil? || @api_endpoint.path.empty? if @api_endpoint.userinfo || @api_endpoint.query || @api_endpoint.fragment raise RuntimeError, 'api_endpoint should not contain user info, query or fragment' end absolute_path = relative_path.start_with?('/') ? relative_path : "/#{relative_path}" uri = URI::HTTP.new(@api_endpoint.scheme, nil, @api_endpoint.host, @api_endpoint.port, nil, absolute_path, nil, nil, nil) request_parameters&.each do |nvp| parameters = URI.decode_www_form(uri.query || '') << [nvp.name, nvp.value] uri.query = URI.encode_www_form(parameters) end uri end
# File lib/ingenico/direct/sdk/communicator.rb, line 277 def update_context(headers, context) context.idempotence_request_timestamp = ResponseHeader.get_header_value(headers, 'X-GCS-Idempotence-Request-Timestamp') end
Private Instance Methods
# File lib/ingenico/direct/sdk/communicator.rb, line 295 def is_json(headers) content_type = ResponseHeader.get_header_value(headers, 'Content-Type') content_type.nil? || 'application/json'.casecmp(content_type).zero? || content_type.downcase.start_with?('application/json') end