class SquashMatrix::Client

Client for retrieving player and club information from squashmatrix.com. If authentication credentials are provided squash matrix will allow considerably more requests for an IP address and allow forbidden conent to be requested.

Public Class Methods

new(player: nil, email: nil, password: nil, suppress_errors: false, timeout: 60, user_agent: nil, cookie: nil, expires: nil, proxy_port: nil, proxy_addr: nil, proxy_user: nil, proxy_pass: nil, proxy_custom_headers: nil) click to toggle source

Returns newly created Client @note If suppress_errors == false SquashMatrix::Errors::AuthorizationError will be raised if specified credentials are incorrect and squash matrix authentication returns forbidden @param [Hash] opts the options to create client @return [Client]

# File lib/squash_matrix/client.rb, line 42
def initialize(player: nil,
               email: nil,
               password: nil,
               suppress_errors: false,
               timeout: 60,
               user_agent: nil,
               cookie: nil,
               expires: nil,
               proxy_port: nil,
               proxy_addr: nil,
               proxy_user: nil,
               proxy_pass: nil,
               proxy_custom_headers: nil)
  @user_agent = user_agent || UserAgentRandomizer::UserAgent.fetch(type: 'desktop_browser').string
  @squash_matrix_home_uri = URI::HTTP.build(host: SquashMatrix::Constants::SQUASH_MATRIX_URL)
  @suppress_errors = suppress_errors
  @timeout = timeout
  @proxy_port = proxy_port
  @proxy_addr = proxy_addr
  @proxy_user = proxy_user
  @proxy_pass = proxy_pass
  @proxy_custom_headers = proxy_custom_headers
  @request_client = @proxy_addr.nil? ? Net::HTTP::Proxy(@proxy_addr, @proxy_port&.to_i, @proxy_user, @proxy_pass) : Net::HTTP
  return unless [player || email, password].none?(&:nil?)
  @cookie_jar = HTTP::CookieJar.new
  @player = player&.to_i
  @email = email
  @password = password
  @expires = !expires.to_s.empty? && Time.parse(expires).utc
  if cookie && @expires > Time.now.utc
    cookie.split('; ').each do |v|
      @cookie_jar.parse(v, @squash_matrix_home_uri)
    end
  else
    setup_authentication
  end
end

Public Instance Methods

get_club_info(id = nil) click to toggle source

Returns club info. @note If suppress_errors == false SquashMatrix Errors will be raised upon HttpNotFound, HttpConflict, Timeout::Error, etc… @param id [Fixnum] club id found on squash matrix @return [Hash] hash object containing club information

# File lib/squash_matrix/client.rb, line 85
def get_club_info(id = nil)
  return unless id.to_i.positive?
  uri = URI::HTTP.build(
    host: SquashMatrix::Constants::SQUASH_MATRIX_URL,
    path: SquashMatrix::Constants::CLUB_PATH.gsub(':id', id.to_s)
  )
  success_proc = lambda do |res|
    SquashMatrix::NokogiriParser.get_club_info(res.body)
  end
  handle_http_request(uri, success_proc)
end
get_player_info(id = nil) click to toggle source

Returns player info. @note If suppress_errors == false SquashMatrix Errors will be raised upon HttpNotFound, HttpConflict, Timeout::Error, etc… @param id [Fixnum] played id found on squash matrix @return [Hash] hash object containing player information

# File lib/squash_matrix/client.rb, line 120
def get_player_info(id = nil)
  return unless id.to_i.positive?
  uri = URI::HTTP.build(
    host: SquashMatrix::Constants::SQUASH_MATRIX_URL,
    path: SquashMatrix::Constants::PLAYER_HOME_PATH.gsub(':id', id.to_s)
  )
  success_proc = lambda do |res|
    SquashMatrix::NokogiriParser.get_player_info(res.body)
  end
  handle_http_request(uri, success_proc)
end
get_player_results(id = nil) click to toggle source

Returns player results. @note If suppress_errors == false SquashMatrix Errors will be raised upon HttpNotFound, HttpConflict, Timeout::Error, etc… @param id [Fixnum] played id found on squash matrix @return [Array<Hash>] Array of player match results

# File lib/squash_matrix/client.rb, line 102
def get_player_results(id = nil)
  return unless id.to_i.positive?
  uri = URI::HTTP.build(
    host: SquashMatrix::Constants::SQUASH_MATRIX_URL,
    path: SquashMatrix::Constants::PLAYER_RESULTS_PATH.gsub(':id', id.to_s),
    query: SquashMatrix::Constants::PLAYER_RSULTS_QUERY
  )
  success_proc = lambda do |res|
    SquashMatrix::NokogiriParser.get_player_results(res.body)
  end
  handle_http_request(uri, success_proc)
end
get_save_params() click to toggle source

Returns params to create existing authenticated client @return [Hash]

# File lib/squash_matrix/client.rb, line 22
def get_save_params
  {
    player: @player,
    email: @email,
    password: @password,
    suppress_errors: @suppress_errors,
    timeout: @timeout,
    user_agent: @user_agent,
    cookie: get_cookie_string,
    expires: @expires.to_s,
    proxy_addr: @proxy_addr,
    proxy_port: @proxy_port
  }.delete_if { |_k, v| v.nil? }
end
get_search_results(query = nil, squash_only: false, racquetball_only: false) click to toggle source

Returns get_search_results results @note If suppress_errors == false SquashMatrix Errors will be raised upon HttpNotFound, HttpConflict, Timeout::Error, etc… @param query [String] get_search_results query @return [Hash] hash object containing get_search_results results

# File lib/squash_matrix/client.rb, line 137
def get_search_results(query = nil,
                       squash_only: false,
                       racquetball_only: false)
  return if query.to_s.empty?
  uri = URI::HTTP.build(
    host: SquashMatrix::Constants::SQUASH_MATRIX_URL,
    path: SquashMatrix::Constants::SEARCH_RESULTS_PATH
  )
  query_params = {
    Criteria: query,
    SquashOnly: squash_only,
    RacquetballOnly: racquetball_only
  }
  success_proc = lambda do |res|
    SquashMatrix::NokogiriParser.get_search_results(res.body)
  end
  handle_http_request(uri, success_proc,
                      is_get_request: false,
                      query_params: query_params)
end

Private Instance Methods

check_authentication() click to toggle source
# File lib/squash_matrix/client.rb, line 160
def check_authentication
  return unless @expires && @cookie_jar && @expires <= (Time.now.utc + @timeout)
  @cookie_jar = HTTP::CookieJar.new
  setup_authentication && sleep(5)
end
handle_http_request(uri, success_proc, is_get_request: true, query_params: nil, headers: nil, is_authentication_request: false) click to toggle source
# File lib/squash_matrix/client.rb, line 166
def handle_http_request(uri, success_proc,
                        is_get_request: true,
                        query_params: nil,
                        headers: nil,
                        is_authentication_request: false)
  Timeout.timeout(@timeout) do
    check_authentication unless is_authentication_request
    if is_get_request
      req = Net::HTTP::Get.new(uri)
      set_headers(req, headers: headers)
    else
      req = Net::HTTP::Post.new(uri)
      set_headers(req)
      form_data = []
      query_params.each do |key, value|
        form_data.push([key.to_s, value.to_s])
      end
      set_headers(req, headers: headers)
      req.set_form(form_data, SquashMatrix::Constants::MULTIPART_FORM_DATA)
    end
    res = @request_client.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) }
    case res
    when Net::HTTPSuccess, Net::HTTPFound
      rtn = success_proc&.call(res) || res
      raise SquashMatrix::Errors::EntityNotFoundError if rtn.is_a?(Array) &&
        rtn.length == 0 &&
        SquashMatrix::Constants::NOT_FOUND_REGEX.match(res.body)
      return rtn
    when Net::HTTPConflict
      unless @suppress_errors
        raise SquashMatrix::Errors::ForbiddenError, res.body if SquashMatrix::Constants::FORBIDDEN_ERROR_REGEX.match(res.body)
        raise SquashMatrix::Errors::TooManyRequestsError, res.body if SquashMatrix::Constants::TOO_MANY_REQUESTS_ERROR_REGEX.match(res.body)
      end
    when Net::HTTPNotFound
      raise SquashMatrix::Errors::EntityNotFoundError
    else
      raise SquashMatrix::Errors::UnknownError, res unless @suppress_errors
    end
  end
rescue Timeout::Error => e
  raise e unless @suppress_errors
end
set_headers(req = nil, headers: nil) click to toggle source
# File lib/squash_matrix/client.rb, line 248
def set_headers(req = nil, headers: nil)
  return unless req
  headers_to_add = {
    SquashMatrix::Constants::USER_AGENT_HEADER => @user_agent,
    SquashMatrix::Constants::HOST_HEADER => SquashMatrix::Constants::SQUASH_MATRIX_URL
  }
  headers_to_add = headers_to_add.merge(headers) if headers
  headers_to_add = headers_to_add.merge(SquashMatrix::Constants::COOKIE_HEADER => get_cookie_string) if @cookie_jar
  headers_to_add = headers_to_add.merge(@proxy_custom_headers) if @proxy_custom_headers
  headers_to_add.each { |key, val| req[key.to_s] = val }
end
setup_authentication() click to toggle source
# File lib/squash_matrix/client.rb, line 209
def setup_authentication
  uri = URI::HTTPS.build(
    host: SquashMatrix::Constants::SQUASH_MATRIX_URL,
    path: SquashMatrix::Constants::LOGIN_PATH
  )
  query_params = {
    UserName: @player&.to_s || @email,
    Password: @password,
    RememberMe: true
  }
  headers = {
    SquashMatrix::Constants::CONTENT_TYPE_HEADER => SquashMatrix::Constants::MULTIPART_FORM_DATA
  }
  # need to retrieve the asp.net session id
  home_page_res = handle_http_request(@squash_matrix_home_uri,
                                      nil,
                                      is_authentication_request: true)
  raise SquashMatrix::Errors::AuthorizationError, SquashMatrix::Constants::ERROR_RETRIEVING_ASPNET_SESSION unless home_page_res
  home_page_res[SquashMatrix::Constants::SET_COOKIE_HEADER].split('; ').each do |v|
    @cookie_jar.parse(v, @squash_matrix_home_uri)
  end
  res = handle_http_request(uri, nil,
                            is_get_request: false,
                            query_params: query_params,
                            headers: headers,
                            is_authentication_request: true)
  raise SquashMatrix::Errors::AuthorizationError, SquashMatrix::Constants::ERROR_RETRIEVING_ASPAUX_TOKEN unless res
  res[SquashMatrix::Constants::SET_COOKIE_HEADER]&.split('; ')&.each do |v|
    parts = SquashMatrix::Constants::EXPIRES_FROM_COOKIE_REGEX.match(v)
    @expires = Time.parse(parts[1]).utc if parts
    @cookie_jar.parse(v, @squash_matrix_home_uri)
  end
  @expires ||= Time.now.utc + 60 * 60 * 24 * 2 # default expires in two days (usually 52 hours)
  @player = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(res[SquashMatrix::Constants::LOCATION_HEADER])[1] if @player.nil? && !res[SquashMatrix::Constants::LOCATION_HEADER].to_s.empty?
  return unless !@suppress_errors && !@cookie_jar&.cookies(@squash_matrix_home_uri)&.find { |c| c.name == SquashMatrix::Constants::ASPXAUTH_COOKIE_NAME && !c.value.to_s.empty? }
  error_string = SquashMatrix::NokogiriParser.get_log_on_error(res.body).join(', ')
  raise SquashMatrix::Errors::AuthorizationError, error_string
end