diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a04ad02..9cab4081 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change Log +## [4.9.0](https://github.com/plivo/plivo-ruby/releases/tag/v4.9.0) (2020-07-23) +- Add retries to multiple regions for voice requests. + ## [4.8.1](https://github.com/plivo/plivo-ruby/releases/tag/v4.8.1) (2020-06-05) - Fix Record a Conference API response. diff --git a/README.md b/README.md index 6304d076..4a7f7673 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ The Plivo Ruby SDK makes it simpler to integrate communications into your Ruby a Add this line to your application's Gemfile: ```ruby -gem 'plivo', '>= 4.8.1' +gem 'plivo', '>= 4.9.0' ``` And then execute: diff --git a/lib/plivo/base.rb b/lib/plivo/base.rb index 03584f84..2d7c126f 100644 --- a/lib/plivo/base.rb +++ b/lib/plivo/base.rb @@ -5,6 +5,11 @@ module Plivo module Base PLIVO_API_URL = 'https://api.plivo.com'.freeze + + API_VOICE = 'https://voice.plivo.com'.freeze + API_VOICE_FALLBACK_1 = 'https://voice-usw1.plivo.com'.freeze + API_VOICE_FALLBACK_2 = 'https://voice-use1.plivo.com'.freeze + CALLINSIGHTS_API_URL = 'https://stats.plivo.com'.freeze PHLO_API_URL = 'https://phlorunner.plivo.com'.freeze end diff --git a/lib/plivo/base/resource.rb b/lib/plivo/base/resource.rb index 94f189b5..6fe33bec 100644 --- a/lib/plivo/base/resource.rb +++ b/lib/plivo/base/resource.rb @@ -8,6 +8,7 @@ def initialize(client, options = nil) configure_client(client) configure_options(options) if options configure_resource_uri + @_is_voice_request = false end private @@ -56,7 +57,7 @@ def perform_update(params, use_multipart_conn = false) 'without an identifier') end - response_json = @_client.send_request(@_resource_uri, 'POST', params, nil, use_multipart_conn) + response_json = @_client.send_request(@_resource_uri, 'POST', params, nil, use_multipart_conn, is_voice_request: @_is_voice_request) parse_and_set(params) parse_and_set(response_json) @@ -65,7 +66,7 @@ def perform_update(params, use_multipart_conn = false) def perform_action(action = nil, method = 'GET', params = nil, parse = false) resource_path = action ? @_resource_uri + action + '/' : @_resource_uri - response = @_client.send_request(resource_path, method, params) + response = @_client.send_request(resource_path, method, params,nil,false,is_voice_request: @_is_voice_request) parse ? parse_and_set(response) : self method == 'POST' ? parse_and_set(params) : self self @@ -73,7 +74,7 @@ def perform_action(action = nil, method = 'GET', params = nil, parse = false) def perform_custome_action(action = nil, method = 'GET', params = nil, parse = false) resource_path = action ? @_resource_uri + action + '/' : @_resource_uri - response = @_client.send_request(resource_path, method, params) + response = @_client.send_request(resource_path, method, params,nil,false,is_voice_request: @_is_voice_request) parse ? parse_and_set(response) : self method == 'POST' ? parse_and_set(params) : self self @@ -81,7 +82,7 @@ def perform_custome_action(action = nil, method = 'GET', params = nil, parse = f def perform_action_apiresponse(action = nil, method = 'GET', params = nil, parse = false) resource_path = action ? @_resource_uri + action + '/' : @_resource_uri - response = @_client.send_request(resource_path, method, params) + response = @_client.send_request(resource_path, method, params,nil,false,is_voice_request: @_is_voice_request) parse ? parse_and_set(response) : self method == 'POST' ? parse_and_set(params) : self method == 'DELETE' ? parse_and_set(params) : self @@ -90,7 +91,7 @@ def perform_action_apiresponse(action = nil, method = 'GET', params = nil, parse def perform_custom_action_apiresponse(action = nil, method = 'GET', params = nil, parse = false) resource_path = action ? '/v1/Account/' + @_client.auth_id + '/'+ action + '/' : @_resource_uri - response = @_client.send_request(resource_path, method, params) + response = @_client.send_request(resource_path, method, params,nil,false,is_voice_request: @_is_voice_request) parse ? parse_and_set(response) : self method == 'POST' ? parse_and_set(params) : self method == 'DELETE' ? parse_and_set(params) : self @@ -103,12 +104,12 @@ def perform_delete(params=nil) 'without an identifier') end - Response.new(@_client.send_request(@_resource_uri, 'DELETE', params), + Response.new(@_client.send_request(@_resource_uri, 'DELETE', params, nil, false, is_voice_request: @_is_voice_request), @_identifier_string) end def perform_run(params) - response_json = @_client.send_request(@_resource_uri, 'POST', params, nil) + response_json = @_client.send_request(@_resource_uri, 'POST', params, nil,false,is_voice_request: @_is_voice_request) parse_and_set(response_json) Response.new(response_json, @_identifier_string) end diff --git a/lib/plivo/base/resource_interface.rb b/lib/plivo/base/resource_interface.rb index 84b7a466..7d67c962 100644 --- a/lib/plivo/base/resource_interface.rb +++ b/lib/plivo/base/resource_interface.rb @@ -6,6 +6,7 @@ def initialize(client, resource_list_json = nil) configure_client(client) configure_resource_uri parse_and_set(resource_list_json) if resource_list_json + @_is_voice_request = false end private @@ -41,25 +42,25 @@ def parse_and_set(resource_list_json) def perform_get(identifier, params = nil) valid_param?(:identifier, identifier, [String, Symbol], true) - response_json = @_client.send_request(@_resource_uri + identifier.to_s + '/', 'GET', params) + response_json = @_client.send_request(@_resource_uri + identifier.to_s + '/', 'GET', params, nil, false, is_voice_request: @_is_voice_request) @_resource_type.new(@_client, resource_json: response_json) end def perform_get_without_identifier(params) valid_param?(:params, params, Hash, true) - response_json = @_client.send_request(@_resource_uri, 'GET', params) + response_json = @_client.send_request(@_resource_uri, 'GET', params, nil, false, is_voice_request: @_is_voice_request) @_resource_type.new(@_client, resource_json: response_json) end def perform_create(params, use_multipart_conn=false) Response.new( - @_client.send_request(@_resource_uri, 'POST', params, nil, use_multipart_conn), + @_client.send_request(@_resource_uri, 'POST', params, nil, use_multipart_conn, is_voice_request: @_is_voice_request), @_identifier_string ) end def perform_post(params) - response_json = @_client.send_request(@_resource_uri, 'POST', params) + response_json = @_client.send_request(@_resource_uri, 'POST', params, nil, false, is_voice_request: @_is_voice_request) parse_and_set(response_json) self @@ -74,7 +75,7 @@ def parse_and_set_list(list_json) end def perform_list(params = nil) - response_json = @_client.send_request(@_resource_uri, 'GET', params) + response_json = @_client.send_request(@_resource_uri, 'GET', params, nil, false, is_voice_request: @_is_voice_request) parse_and_set(response_json) { api_id: @api_id, @@ -85,14 +86,14 @@ def perform_list(params = nil) def perform_action(action = nil, method = 'GET', params = nil, parse = false) resource_path = action ? @_resource_uri + action + '/' : @_resource_uri - response = @_client.send_request(resource_path, method, params) + response = @_client.send_request(resource_path, method, params, nil, false, is_voice_request: @_is_voice_request) parse ? parse_and_set(response) : self method == 'POST' ? parse_and_set(params) : self self end def perform_list_without_object(params = nil) - response_json = @_client.send_request(@_resource_uri, 'GET', params) + response_json = @_client.send_request(@_resource_uri, 'GET', params, nil, false, is_voice_request: @_is_voice_request) parse_and_set(response_json) response_json end diff --git a/lib/plivo/base_client.rb b/lib/plivo/base_client.rb index 21bed846..06868d08 100644 --- a/lib/plivo/base_client.rb +++ b/lib/plivo/base_client.rb @@ -13,7 +13,7 @@ module Plivo class BaseClient # Base stuff attr_reader :headers, :auth_credentials - + @@voice_retry_count = 0 def initialize(auth_id = nil, auth_token = nil, proxy_options = nil, timeout=5) configure_credentials(auth_id, auth_token) configure_proxies(proxy_options) @@ -36,21 +36,42 @@ def process_response(method, response) elsif !([200, 201, 202, 207].include? response[:status]) raise Exceptions::PlivoRESTError, "Received #{response[:status]} for #{method}" end - + @@voice_retry_count = 0 response[:body] end - def send_request(resource_path, method = 'GET', data = {}, timeout = nil, use_multipart_conn = false) + def send_request(resource_path, method = 'GET', data = {}, timeout = nil, use_multipart_conn = false, options = nil) timeout ||= @timeout - response = case method - when 'GET' then send_get(resource_path, data, timeout) - when 'POST' then send_post(resource_path, data, timeout, use_multipart_conn) - when 'DELETE' then send_delete(resource_path, data, timeout) - else raise_invalid_request("#{method} not supported by Plivo, yet") - end + if options[:is_voice_request] == true + response = case method + when 'GET' then send_get(resource_path, data, timeout, is_voice_request: options[:is_voice_request], voice_retry_count: @@voice_retry_count) + when 'POST' then send_post(resource_path, data, timeout, use_multipart_conn, is_voice_request: options[:is_voice_request], voice_retry_count: @@voice_retry_count) + when 'DELETE' then send_delete(resource_path, data, timeout, is_voice_request: options[:is_voice_request], voice_retry_count: @@voice_retry_count) + else raise_invalid_request("#{method} not supported by Plivo, yet") + end + + if response.status >= 500 + @@voice_retry_count += 1 + if @@voice_retry_count > 2 + return process_response(method, response.to_hash) + end + is_voice_request = true + send_request(resource_path, method, data, timeout, use_multipart_conn, is_voice_request: is_voice_request) + else + process_response(method, response.to_hash) + end - process_response(method, response.to_hash) + else + response = case method + when 'GET' then send_get(resource_path, data, timeout) + when 'POST' then send_post(resource_path, data, timeout, use_multipart_conn) + when 'DELETE' then send_delete(resource_path, data, timeout) + else raise_invalid_request("#{method} not supported by Plivo, yet") + end + + process_response(method, response.to_hash) + end end private @@ -118,6 +139,45 @@ def configure_connection faraday.adapter Faraday.default_adapter end + @voice_conn_no_retry = Faraday.new(@voice_base_uri) do |faraday| + faraday.headers = @headers + + # DANGER: Basic auth should always come after headers, else + # The headers will replace the basic_auth + + faraday.basic_auth(auth_id, auth_token) + + faraday.proxy=@proxy_hash if @proxy_hash + faraday.response :json, content_type: /\bjson$/ + faraday.adapter Faraday.default_adapter + end + + @voice_conn_retry_1 = Faraday.new(@voice_base_uri_fallback_1) do |faraday| + faraday.headers = @headers + + # DANGER: Basic auth should always come after headers, else + # The headers will replace the basic_auth + + faraday.basic_auth(auth_id, auth_token) + + faraday.proxy=@proxy_hash if @proxy_hash + faraday.response :json, content_type: /\bjson$/ + faraday.adapter Faraday.default_adapter + end + + @voice_conn_retry_2 = Faraday.new(@voice_base_uri_fallback_2) do |faraday| + faraday.headers = @headers + + # DANGER: Basic auth should always come after headers, else + # The headers will replace the basic_auth + + faraday.basic_auth(auth_id, auth_token) + + faraday.proxy=@proxy_hash if @proxy_hash + faraday.response :json, content_type: /\bjson$/ + faraday.adapter Faraday.default_adapter + end + @callinsights_conn = Faraday.new(@callinsights_base_uri) do |faraday| faraday.headers = @headers @@ -133,15 +193,34 @@ def configure_connection end - def send_get(resource_path, data, timeout) - response = @conn.get do |req| - req.url resource_path, data - req.options.timeout = timeout if timeout + def send_get(resource_path, data, timeout, options = nil) + if options + if options[:voice_retry_count] == 0 and options[:is_voice_request] == true + response = @voice_conn_no_retry.get do |req| + req.url resource_path, data + req.options.timeout = timeout if timeout + end + elsif options[:voice_retry_count] == 1 and options[:is_voice_request] == true + response = @voice_conn_retry_1.get do |req| + req.url resource_path, data + req.options.timeout = timeout if timeout + end + elsif options[:voice_retry_count] == 2 and options[:is_voice_request] == true + response = @voice_conn_retry_2.get do |req| + req.url resource_path, data + req.options.timeout = timeout if timeout + end + end + else + response = @conn.get do |req| + req.url resource_path, data + req.options.timeout = timeout if timeout + end end response end - def send_post(resource_path, data, timeout, use_multipart_conn) + def send_post(resource_path, data, timeout, use_multipart_conn, options = nil) if use_multipart_conn multipart_conn = Faraday.new(@base_uri) do |faraday| faraday.headers = { @@ -178,7 +257,26 @@ def send_post(resource_path, data, timeout, use_multipart_conn) req.options.timeout = timeout if timeout req.body = JSON.generate(data) if data end - + elsif options + if options[:voice_retry_count] == 0 and options[:is_voice_request] == true + response = @voice_conn_no_retry.post do |req| + req.url resource_path + req.options.timeout = timeout if timeout + req.body = JSON.generate(data) if data + end + elsif options[:voice_retry_count] == 1 and options[:is_voice_request] == true + response = @voice_conn_retry_1.post do |req| + req.url resource_path + req.options.timeout = timeout if timeout + req.body = JSON.generate(data) if data + end + elsif options[:voice_retry_count] == 2 and options[:is_voice_request] == true + response = @voice_conn_retry_2.post do |req| + req.url resource_path + req.options.timeout = timeout if timeout + req.body = JSON.generate(data) if data + end + end else response = @conn.post do |req| req.url resource_path @@ -190,11 +288,33 @@ def send_post(resource_path, data, timeout, use_multipart_conn) response end - def send_delete(resource_path, data, timeout) - response = @conn.delete do |req| - req.url resource_path - req.options.timeout = timeout if timeout - req.body = JSON.generate(data) if data + def send_delete(resource_path, data, timeout, options = nil) + if options + if options[:voice_retry_count] == 0 and options[:is_voice_request] == true + response = @voice_conn_no_retry.delete do |req| + req.url resource_path + req.options.timeout = timeout if timeout + req.body = JSON.generate(data) if data + end + elsif options[:voice_retry_count] == 1 and options[:is_voice_request] == true + response = @voice_conn_retry_1.delete do |req| + req.url resource_path + req.options.timeout = timeout if timeout + req.body = JSON.generate(data) if data + end + elsif options[:voice_retry_count] == 2 and options[:is_voice_request] == true + response = @voice_conn_retry_2.delete do |req| + req.url resource_path + req.options.timeout = timeout if timeout + req.body = JSON.generate(data) if data + end + end + else + response = @conn.delete do |req| + req.url resource_path + req.options.timeout = timeout if timeout + req.body = JSON.generate(data) if data + end end response end diff --git a/lib/plivo/resources/applications.rb b/lib/plivo/resources/applications.rb index a63dcb56..1313c73b 100644 --- a/lib/plivo/resources/applications.rb +++ b/lib/plivo/resources/applications.rb @@ -8,6 +8,7 @@ def initialize(client, options = nil) @_name = 'Application' @_identifier_string = 'app_id' super + @_is_voice_request = true end # @param [Hash] options @@ -109,6 +110,7 @@ def initialize(client, resource_list_json = nil) @_resource_type = Application @_identifier_string = 'app_id' super + @_is_voice_request = true end # @param [String] app_id diff --git a/lib/plivo/resources/calls.rb b/lib/plivo/resources/calls.rb index 116d5e03..15c4edd8 100644 --- a/lib/plivo/resources/calls.rb +++ b/lib/plivo/resources/calls.rb @@ -6,6 +6,7 @@ def initialize(client, options = nil) @_name = 'Call' @_identifier_string = 'call_uuid' super + @_is_voice_request = true end def update(options) @@ -199,7 +200,7 @@ def send_digits(digits, leg = nil) def cancel_request resource_path = @_resource_uri.sub('Call', 'Request') - @_client.send_request(resource_path, 'DELETE', nil) + @_client.send_request(resource_path, 'DELETE', nil, nil, false , is_voice_request: @_is_voice_request) end def to_s @@ -240,6 +241,7 @@ def initialize(client, resource_list_json = nil) @_resource_type = Call @_identifier_string = 'call_uuid' super + @_is_voice_request = true end ## @@ -288,9 +290,9 @@ def create(from, to, answer_url, answer_method = 'POST', options = nil) answer_method: answer_method } - return perform_create(params) if options.nil? + return perform_create(params, false) if options.nil? - perform_create(params.merge(options)) + perform_create(params.merge(options), false) end ## diff --git a/lib/plivo/resources/conferences.rb b/lib/plivo/resources/conferences.rb index f5d66ba1..1a50a1c1 100644 --- a/lib/plivo/resources/conferences.rb +++ b/lib/plivo/resources/conferences.rb @@ -6,6 +6,7 @@ def initialize(client, options = nil) @_name = 'Conference' @_identifier_string = 'conference_name' super + @_is_voice_request = true end def delete @@ -215,6 +216,7 @@ def initialize(client, resource_list_json = nil) @_resource_type = Conference @_identifier_string = 'conference_name' super + @_is_voice_request = true end def get(conference_name) diff --git a/lib/plivo/resources/endpoints.rb b/lib/plivo/resources/endpoints.rb index ff9654a3..8d6eead0 100644 --- a/lib/plivo/resources/endpoints.rb +++ b/lib/plivo/resources/endpoints.rb @@ -6,6 +6,7 @@ def initialize(client, options = nil) @_name = 'Endpoint' @_identifier_string = 'endpoint_id' super + @_is_voice_request = true end # @param [Hash] options @@ -71,6 +72,7 @@ def initialize(client, resource_list_json = nil) @_resource_type = Endpoint @_identifier_string = 'endpoint_id' super + @_is_voice_request = true end # @param [String] endpoint_id diff --git a/lib/plivo/resources/recordings.rb b/lib/plivo/resources/recordings.rb index 5fc580bd..b0dc6e52 100644 --- a/lib/plivo/resources/recordings.rb +++ b/lib/plivo/resources/recordings.rb @@ -6,6 +6,7 @@ def initialize(client, options = nil) @_name = 'Recording' @_identifier_string = 'recording_id' super + @_is_voice_request = true end def delete @@ -36,6 +37,7 @@ def initialize(client, resource_list_json = nil) @_resource_type = Recording @_identifier_string = 'recording_id' super + @_is_voice_request = true end # @param [Hash] options diff --git a/lib/plivo/rest_client.rb b/lib/plivo/rest_client.rb index f8004b97..c4cf550c 100644 --- a/lib/plivo/rest_client.rb +++ b/lib/plivo/rest_client.rb @@ -24,6 +24,9 @@ def initialize(auth_id = nil, auth_token = nil, proxy_options = nil, timeout=5) def configure_base_uri @base_uri = Base::PLIVO_API_URL + @voice_base_uri = Base::API_VOICE + @voice_base_uri_fallback_1 = Base::API_VOICE_FALLBACK_1 + @voice_base_uri_fallback_2 = Base::API_VOICE_FALLBACK_2 @callinsights_base_uri = Base::CALLINSIGHTS_API_URL end diff --git a/lib/plivo/version.rb b/lib/plivo/version.rb index 9ac99268..6e9d5e89 100644 --- a/lib/plivo/version.rb +++ b/lib/plivo/version.rb @@ -1,3 +1,3 @@ module Plivo - VERSION = '4.8.1'.freeze + VERSION = '4.9.0'.freeze end