Class: GoogleMaps::Services::GoogleClient
- Inherits:
-
Object
- Object
- GoogleMaps::Services::GoogleClient
- Includes:
- Exceptions
- Defined in:
- lib/googlemaps/services/client.rb
Overview
Performs requests to the Google Maps API web services.
Instance Attribute Summary collapse
-
#channel ⇒ Symbol
Attribute used for tracking purposes.
-
#client_id ⇒ Symbol
Client ID (for Maps API for Work).
-
#client_secret ⇒ Symbol
Base64-encoded client secret (for Maps API for Work).
-
#connect_timeout ⇒ Symbol
Connect timeout for the HTTP request, in seconds.
-
#key ⇒ Symbol
API key.
-
#queries_per_second ⇒ Symbol
Number of queries per second permitted.
-
#read_timeout ⇒ Symbol
Read timeout for the HTTP request, in seconds.
-
#request_headers ⇒ Symbol
HTTP headers per request.
-
#response_format ⇒ Symbol
Response format.
-
#retry_over_query_limit ⇒ Symbol
Should retry request when exceeds the query rate limit.
-
#retry_timeout ⇒ Symbol
Timeout across multiple retriable requests, in seconds.
-
#sent_times ⇒ Symbol
Keeps track of sent queries.
-
#write_timeout ⇒ Symbol
Write timeout for the HTTP request, in seconds.
Instance Method Summary collapse
-
#initialize(key: nil, client_id: nil, client_secret: nil, write_timeout: 2, connect_timeout: 5, read_timeout: 10, retry_timeout: 60, request_headers: {}, queries_per_second: 50, channel: nil, retry_over_query_limit: true, response_format: :json) ⇒ GoogleClient
constructor
A new instance of GoogleClient.
-
#request(url:, params:, first_request_time: nil, retry_counter: 0, base_url: Constants::DEFAULT_BASE_URL, accepts_clientid: true, extract_body: nil, request_headers: nil, post_json: nil) ⇒ Hash, ...
Performs HTTP GET/POST requests with credentials, returning the body as JSON or XML.
Constructor Details
#initialize(key: nil, client_id: nil, client_secret: nil, write_timeout: 2, connect_timeout: 5, read_timeout: 10, retry_timeout: 60, request_headers: {}, queries_per_second: 50, channel: nil, retry_over_query_limit: true, response_format: :json) ⇒ GoogleClient
Returns a new instance of GoogleClient.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/googlemaps/services/client.rb', line 50 def initialize(key: nil, client_id: nil, client_secret: nil, write_timeout: 2, connect_timeout: 5, read_timeout: 10, retry_timeout: 60, request_headers: {}, queries_per_second: 50, channel: nil, retry_over_query_limit: true, response_format: :json) unless key || (client_secret && client_id) raise StandardError, 'Must provide API key or enterprise credentials when creating client.' end if key && !key.start_with?('AIza') raise StandardError, 'Invalid API key provided.' end if channel raise StandardError, 'The channel argument must be used with a client ID.' unless client_id unless /^[a-zA-Z0-9._-]*$/.match(channel) raise StandardError, 'The channel argument must be an ASCII alphanumeric string. The period (.), underscore (_) and hyphen (-) characters are allowed.' end end self.key = key # Set the timeout for write/connect/read calls self.write_timeout = write_timeout self.connect_timeout = connect_timeout self.read_timeout = read_timeout self.client_id = client_id self.client_secret = client_secret self.channel = channel self.retry_timeout = retry_timeout self.request_headers = request_headers.merge({'User-Agent' => Constants::USER_AGENT}) self.queries_per_second = queries_per_second self.sent_times = Array.new self.retry_over_query_limit = retry_over_query_limit if response_format raise StandardError, 'Unsupported response format. Should be either :json or :xml.' unless [:json, :xml].include? response_format self.response_format = response_format end end |
Instance Attribute Details
#channel ⇒ Symbol
Returns Attribute used for tracking purposes. Can only be used with a Client ID.
36 37 38 |
# File 'lib/googlemaps/services/client.rb', line 36 def channel @channel end |
#client_id ⇒ Symbol
Returns Client ID (for Maps API for Work).
32 33 34 |
# File 'lib/googlemaps/services/client.rb', line 32 def client_id @client_id end |
#client_secret ⇒ Symbol
Returns Base64-encoded client secret (for Maps API for Work).
34 35 36 |
# File 'lib/googlemaps/services/client.rb', line 34 def client_secret @client_secret end |
#connect_timeout ⇒ Symbol
Returns Connect timeout for the HTTP request, in seconds.
28 29 30 |
# File 'lib/googlemaps/services/client.rb', line 28 def connect_timeout @connect_timeout end |
#key ⇒ Symbol
Returns API key. Required, unless “client_id” and “client_secret” are set.
24 25 26 |
# File 'lib/googlemaps/services/client.rb', line 24 def key @key end |
#queries_per_second ⇒ Symbol
Returns Number of queries per second permitted. If the rate limit is reached, the client will sleep for the appropriate amount of time before it runs the current query.
42 43 44 |
# File 'lib/googlemaps/services/client.rb', line 42 def queries_per_second @queries_per_second end |
#read_timeout ⇒ Symbol
Returns Read timeout for the HTTP request, in seconds.
30 31 32 |
# File 'lib/googlemaps/services/client.rb', line 30 def read_timeout @read_timeout end |
#request_headers ⇒ Symbol
Returns HTTP headers per request.
40 41 42 |
# File 'lib/googlemaps/services/client.rb', line 40 def request_headers @request_headers end |
#response_format ⇒ Symbol
Returns Response format. Either :json or :xml.
48 49 50 |
# File 'lib/googlemaps/services/client.rb', line 48 def response_format @response_format end |
#retry_over_query_limit ⇒ Symbol
Returns Should retry request when exceeds the query rate limit.
46 47 48 |
# File 'lib/googlemaps/services/client.rb', line 46 def retry_over_query_limit @retry_over_query_limit end |
#retry_timeout ⇒ Symbol
Returns Timeout across multiple retriable requests, in seconds.
38 39 40 |
# File 'lib/googlemaps/services/client.rb', line 38 def retry_timeout @retry_timeout end |
#sent_times ⇒ Symbol
Returns keeps track of sent queries.
44 45 46 |
# File 'lib/googlemaps/services/client.rb', line 44 def sent_times @sent_times end |
#write_timeout ⇒ Symbol
Returns Write timeout for the HTTP request, in seconds.
26 27 28 |
# File 'lib/googlemaps/services/client.rb', line 26 def write_timeout @write_timeout end |
Instance Method Details
#request(url:, params:, first_request_time: nil, retry_counter: 0, base_url: Constants::DEFAULT_BASE_URL, accepts_clientid: true, extract_body: nil, request_headers: nil, post_json: nil) ⇒ Hash, ...
Performs HTTP GET/POST requests with credentials, returning the body as JSON or XML.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/googlemaps/services/client.rb', line 105 def request(url:, params:, first_request_time: nil, retry_counter: 0, base_url: Constants::DEFAULT_BASE_URL, accepts_clientid: true, extract_body: nil, request_headers: nil, post_json: nil) first_request_time = Util.current_time unless first_request_time elapsed = Time.now - first_request_time if elapsed > self.retry_timeout raise Timeout end if retry_counter && retry_counter > 0 # 0.5 * (1.5 ^ i) is an increased sleep time of 1.5x per iteration, # starting at 0.5s when retry_counter=0. The first retry will occur # at 1, so subtract that first. delay_seconds = 0.5 * 1.5 ** (retry_counter - 1) # Jitter this value by 50% and pause. sleep(delay_seconds * (Random.rand + 0.5)) end authed_url = generate_auth_url(url, params, accepts_clientid) # Default to the client-level self.request_headers, with method-level # request_headers arg overriding. request_headers = self.request_headers.merge(request_headers || {}) # Construct the Request URI uri = HTTP::URI.parse(base_url + authed_url) # Create the request, add the headers & timeouts req = HTTP.headers(request_headers) .timeout(:write => self.write_timeout, :connect => self.connect_timeout, :read => self.read_timeout) # Make the HTTP GET/POST request resp = post_json ? req.post(uri.to_s, :json => post_json) : req.get(uri.to_s) if Constants::RETRIABLE_STATUSES.include? resp.code.to_i # Retry request self.request(url: url, params: params, first_request_time: first_request_time, retry_counter: retry_counter + 1, base_url: base_url, accepts_clientid: accepts_clientid, extract_body: extract_body, request_headers: request_headers, post_json: post_json) end # Check if the time of the nth previous query (where n is queries_per_second) # is under a second ago - if so, sleep for the difference. if self.sent_times && (self.sent_times.length == self.queries_per_second) elapsed_since_earliest = Util.current_time - self.sent_times[0] if elapsed_since_earliest < 1 sleep(1 - elapsed_since_earliest) end end begin # Extract HTTP response body if extract_body result = extract_body.call(resp) else case resp.content_type.mime_type when 'application/xml' result = get_xml_body(resp) when 'application/json' result = get_json_body(resp) when 'text/html' result = get_redirection_url(resp) else result = get_map_image(resp) end end self.sent_times.push(Util.current_time) return result rescue RetriableRequest => e if e.is_a?(OverQueryLimit) && !self.retry_over_query_limit raise end # Retry request self.request(url: url, params: params, first_request_time: first_request_time, retry_counter: retry_counter + 1, base_url: base_url, accepts_clientid: accepts_clientid, extract_body: extract_body, request_headers: request_headers, post_json: post_json) end end |