ibm_watson 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ibm_watson/assistant_v1.rb +84 -85
- data/lib/ibm_watson/assistant_v2.rb +8 -9
- data/lib/ibm_watson/common.rb +1 -1
- data/lib/ibm_watson/compare_comply_v1.rb +27 -28
- data/lib/ibm_watson/discovery_v1.rb +124 -125
- data/lib/ibm_watson/language_translator_v3.rb +17 -18
- data/lib/ibm_watson/natural_language_classifier_v1.rb +14 -15
- data/lib/ibm_watson/natural_language_understanding_v1.rb +9 -10
- data/lib/ibm_watson/personality_insights_v3.rb +5 -6
- data/lib/ibm_watson/speech_to_text_v1.rb +68 -69
- data/lib/ibm_watson/text_to_speech_v1.rb +27 -28
- data/lib/ibm_watson/tone_analyzer_v3.rb +7 -8
- data/lib/ibm_watson/version.rb +1 -1
- data/lib/ibm_watson/visual_recognition_v3.rb +24 -23
- data/test/integration/test_iam_assistant_v1.rb +1 -1
- data/test/integration/test_speech_to_text_v1.rb +1 -1
- data/test/unit/test_assistant_v1.rb +2 -2
- data/test/unit/test_configure_http_client.rb +1 -1
- data/test/unit/test_personality_insights_v3.rb +4 -4
- data/test/unit/test_tone_analyzer_v3.rb +4 -5
- data/test/unit/test_vcap_using_personality_insights.rb +4 -4
- metadata +16 -7
- data/lib/ibm_watson/detailed_response.rb +0 -21
- data/lib/ibm_watson/iam_token_manager.rb +0 -152
- data/lib/ibm_watson/watson_api_exception.rb +0 -41
- data/lib/ibm_watson/watson_service.rb +0 -285
- data/test/unit/test_iam_token_manager.rb +0 -175
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ibm_watson
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Max Nussbaum
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-03-
|
11
|
+
date: 2019-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 4.1.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ibm_cloud_sdk_core
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.1.1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.1.1
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -248,9 +262,7 @@ files:
|
|
248
262
|
- lib/ibm_watson/assistant_v2.rb
|
249
263
|
- lib/ibm_watson/common.rb
|
250
264
|
- lib/ibm_watson/compare_comply_v1.rb
|
251
|
-
- lib/ibm_watson/detailed_response.rb
|
252
265
|
- lib/ibm_watson/discovery_v1.rb
|
253
|
-
- lib/ibm_watson/iam_token_manager.rb
|
254
266
|
- lib/ibm_watson/language_translator_v3.rb
|
255
267
|
- lib/ibm_watson/natural_language_classifier_v1.rb
|
256
268
|
- lib/ibm_watson/natural_language_understanding_v1.rb
|
@@ -260,8 +272,6 @@ files:
|
|
260
272
|
- lib/ibm_watson/tone_analyzer_v3.rb
|
261
273
|
- lib/ibm_watson/version.rb
|
262
274
|
- lib/ibm_watson/visual_recognition_v3.rb
|
263
|
-
- lib/ibm_watson/watson_api_exception.rb
|
264
|
-
- lib/ibm_watson/watson_service.rb
|
265
275
|
- lib/ibm_watson/websocket/recognize_callback.rb
|
266
276
|
- lib/ibm_watson/websocket/speech_to_text_websocket_listener.rb
|
267
277
|
- rakefile
|
@@ -285,7 +295,6 @@ files:
|
|
285
295
|
- test/unit/test_compare_comply_v1.rb
|
286
296
|
- test/unit/test_configure_http_client.rb
|
287
297
|
- test/unit/test_discovery_v1.rb
|
288
|
-
- test/unit/test_iam_token_manager.rb
|
289
298
|
- test/unit/test_language_translator_v3.rb
|
290
299
|
- test/unit/test_natural_language_classifier_v1.rb
|
291
300
|
- test/unit/test_natural_language_understanding_v1.rb
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require("json")
|
4
|
-
|
5
|
-
# Custom class for objects returned from API calls
|
6
|
-
class DetailedResponse
|
7
|
-
attr_reader :status, :headers, :result
|
8
|
-
def initialize(status: nil, headers: nil, body: nil, response: nil)
|
9
|
-
if status.nil? || headers.nil? || body.nil?
|
10
|
-
@status = response.code
|
11
|
-
@headers = response.headers.to_h
|
12
|
-
@headers = response.headers.to_hash if response.headers.respond_to?("to_hash")
|
13
|
-
@result = response.body.to_s
|
14
|
-
@result = JSON.parse(response.body.to_s) if !response.body.to_s.empty? && @headers.key?("Content-Type") && @headers["Content-Type"].start_with?("application/json")
|
15
|
-
else
|
16
|
-
@status = status
|
17
|
-
@headers = headers
|
18
|
-
@result = body
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,152 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require("http")
|
4
|
-
require("json")
|
5
|
-
require("rbconfig")
|
6
|
-
require_relative("./version.rb")
|
7
|
-
|
8
|
-
# Class to manage IAM Token Authentication
|
9
|
-
class IAMTokenManager
|
10
|
-
DEFAULT_IAM_URL = "https://iam.bluemix.net/identity/token"
|
11
|
-
CONTENT_TYPE = "application/x-www-form-urlencoded"
|
12
|
-
ACCEPT = "application/json"
|
13
|
-
DEFAULT_AUTHORIZATION = "Basic Yng6Yng="
|
14
|
-
REQUEST_TOKEN_GRANT_TYPE = "urn:ibm:params:oauth:grant-type:apikey"
|
15
|
-
REQUEST_TOKEN_RESPONSE_TYPE = "cloud_iam"
|
16
|
-
REFRESH_TOKEN_GRANT_TYPE = "refresh_token"
|
17
|
-
|
18
|
-
attr_accessor :token_info, :user_access_token
|
19
|
-
def initialize(iam_apikey: nil, iam_access_token: nil, iam_url: nil)
|
20
|
-
@iam_apikey = iam_apikey
|
21
|
-
@user_access_token = iam_access_token
|
22
|
-
@iam_url = iam_url.nil? ? DEFAULT_IAM_URL : iam_url
|
23
|
-
@token_info = {
|
24
|
-
"access_token" => nil,
|
25
|
-
"refresh_token" => nil,
|
26
|
-
"token_type" => nil,
|
27
|
-
"expires_in" => nil,
|
28
|
-
"expiration" => nil
|
29
|
-
}
|
30
|
-
end
|
31
|
-
|
32
|
-
def request(method:, url:, headers: nil, params: nil, data: nil)
|
33
|
-
user_agent_string = "watson-apis-ruby-sdk-" + IBMWatson::VERSION
|
34
|
-
user_agent_string += " #{RbConfig::CONFIG["host"]}"
|
35
|
-
user_agent_string += " #{RbConfig::CONFIG["RUBY_BASE_NAME"]}-#{RbConfig::CONFIG["RUBY_PROGRAM_VERSION"]}"
|
36
|
-
headers["User-Agent"] = user_agent_string
|
37
|
-
response = nil
|
38
|
-
if headers.key?("Content-Type") && headers["Content-Type"] == CONTENT_TYPE
|
39
|
-
response = HTTP.request(
|
40
|
-
method,
|
41
|
-
url,
|
42
|
-
body: HTTP::URI.form_encode(data),
|
43
|
-
headers: headers,
|
44
|
-
params: params
|
45
|
-
)
|
46
|
-
end
|
47
|
-
return JSON.parse(response.body.to_s) if (200..299).cover?(response.code)
|
48
|
-
|
49
|
-
require_relative("./watson_api_exception.rb")
|
50
|
-
raise WatsonApiException.new(response: response)
|
51
|
-
end
|
52
|
-
|
53
|
-
# The source of the token is determined by the following logic:
|
54
|
-
# 1. If user provides their own managed access token, assume it is valid and send it
|
55
|
-
# 2. If this class is managing tokens and does not yet have one, make a request for one
|
56
|
-
# 3. If this class is managing tokens and the token has expired refresh it. In case the refresh token is expired, get a new one
|
57
|
-
# If this class is managing tokens and has a valid token stored, send it
|
58
|
-
def token
|
59
|
-
return @user_access_token unless @user_access_token.nil? || (@user_access_token.respond_to?(:empty?) && @user_access_token.empty?)
|
60
|
-
|
61
|
-
if @token_info.all? { |_k, v| v.nil? }
|
62
|
-
token_info = request_token
|
63
|
-
save_token_info(
|
64
|
-
token_info: token_info
|
65
|
-
)
|
66
|
-
return @token_info["access_token"]
|
67
|
-
elsif token_expired?
|
68
|
-
token_info = refresh_token_expired? ? request_token : refresh_token
|
69
|
-
save_token_info(
|
70
|
-
token_info: token_info
|
71
|
-
)
|
72
|
-
return @token_info["access_token"]
|
73
|
-
else
|
74
|
-
@token_info["access_token"]
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
# Request an IAM token using an API key
|
81
|
-
def request_token
|
82
|
-
headers = {
|
83
|
-
"Content-Type" => CONTENT_TYPE,
|
84
|
-
"Authorization" => DEFAULT_AUTHORIZATION,
|
85
|
-
"Accept" => ACCEPT
|
86
|
-
}
|
87
|
-
data = {
|
88
|
-
"grant_type" => REQUEST_TOKEN_GRANT_TYPE,
|
89
|
-
"apikey" => @iam_apikey,
|
90
|
-
"response_type" => REQUEST_TOKEN_RESPONSE_TYPE
|
91
|
-
}
|
92
|
-
response = request(
|
93
|
-
method: "POST",
|
94
|
-
url: @iam_url,
|
95
|
-
headers: headers,
|
96
|
-
data: data
|
97
|
-
)
|
98
|
-
response
|
99
|
-
end
|
100
|
-
|
101
|
-
# Refresh an IAM token using a refresh token
|
102
|
-
def refresh_token
|
103
|
-
headers = {
|
104
|
-
"Content-Type" => CONTENT_TYPE,
|
105
|
-
"Authorization" => DEFAULT_AUTHORIZATION,
|
106
|
-
"accept" => ACCEPT
|
107
|
-
}
|
108
|
-
data = {
|
109
|
-
"grant_type" => REFRESH_TOKEN_GRANT_TYPE,
|
110
|
-
"refresh_token" => @token_info["refresh_token"]
|
111
|
-
}
|
112
|
-
response = request(
|
113
|
-
method: "POST",
|
114
|
-
url: @iam_url,
|
115
|
-
headers: headers,
|
116
|
-
data: data
|
117
|
-
)
|
118
|
-
response
|
119
|
-
end
|
120
|
-
|
121
|
-
# Check if currently stored token is expired.
|
122
|
-
# Using a buffer to prevent the edge case of the
|
123
|
-
# token expiring before the request could be made.
|
124
|
-
# The buffer will be a fraction of the total TTL. Using 80%.
|
125
|
-
def token_expired?
|
126
|
-
return true if @token_info["expiration"].nil? || @token_info["expires_in"].nil?
|
127
|
-
|
128
|
-
fraction_of_ttl = 0.8
|
129
|
-
time_to_live = @token_info["expires_in"].nil? ? 0 : @token_info["expires_in"]
|
130
|
-
expire_time = @token_info["expiration"].nil? ? 0 : @token_info["expiration"]
|
131
|
-
refresh_time = expire_time - (time_to_live * (1.0 - fraction_of_ttl))
|
132
|
-
current_time = Time.now.to_i
|
133
|
-
refresh_time < current_time
|
134
|
-
end
|
135
|
-
|
136
|
-
# Used as a fail-safe to prevent the condition of a refresh token expiring,
|
137
|
-
# which could happen after around 30 days. This function will return true
|
138
|
-
# if it has been at least 7 days and 1 hour since the last token was set
|
139
|
-
def refresh_token_expired?
|
140
|
-
return true if @token_info["expiration"].nil?
|
141
|
-
|
142
|
-
seven_days = 7 * 24 * 3600
|
143
|
-
current_time = Time.now.to_i
|
144
|
-
new_token_time = @token_info["expiration"] + seven_days
|
145
|
-
new_token_time < current_time
|
146
|
-
end
|
147
|
-
|
148
|
-
# Save the response from the IAM service request to the object's state
|
149
|
-
def save_token_info(token_info:)
|
150
|
-
@token_info = token_info
|
151
|
-
end
|
152
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require("json")
|
4
|
-
# Custom exception class for errors returned from Watson APIs
|
5
|
-
class WatsonApiException < StandardError
|
6
|
-
attr_reader :code, :error, :info, :transaction_id, :global_transaction_id
|
7
|
-
# :param HTTP::Response response: The response object from the Watson API
|
8
|
-
def initialize(code: nil, error: nil, info: nil, transaction_id: nil, global_transaction_id: nil, response: nil)
|
9
|
-
if code.nil? || error.nil?
|
10
|
-
@code = response.code
|
11
|
-
@error = response.reason
|
12
|
-
unless response.body.empty?
|
13
|
-
body_hash = JSON.parse(response.body.to_s)
|
14
|
-
@code = body_hash["code"] || body_hash["error_code"] || body_hash["status"]
|
15
|
-
@error = body_hash["error"] || body_hash["error_message"] || body_hash["statusInfo"] || body_hash["description"]
|
16
|
-
%w[code error_code status error error_message statusInfo description].each { |k| body_hash.delete(k) }
|
17
|
-
@info = body_hash
|
18
|
-
end
|
19
|
-
@transaction_id = transaction_id
|
20
|
-
@global_transaction_id = global_transaction_id
|
21
|
-
@transaction_id = response.headers["X-DP-Watson-Tran-ID"] if response.headers.include?("X-DP-Watson-Tran-ID")
|
22
|
-
@global_transaction_id = response.headers["X-Global-Transaction-ID"] if response.headers.include?("X-Global-Transaction-ID")
|
23
|
-
else
|
24
|
-
# :nocov:
|
25
|
-
@code = code
|
26
|
-
@error = error
|
27
|
-
@info = info
|
28
|
-
@transaction_id = transaction_id
|
29
|
-
@global_transaction_id = global_transaction_id
|
30
|
-
# :nocov:
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def to_s
|
35
|
-
msg = "Error: #{@error}, Code: #{@code}"
|
36
|
-
msg += ", Information: #{@info}" unless @info.nil?
|
37
|
-
msg += ", X-dp-watson-tran-id: #{@transaction_id}" unless @transaction_id.nil?
|
38
|
-
msg += ", X-global-transaction-id: #{@global_transaction_id}" unless @global_transaction_id.nil?
|
39
|
-
msg
|
40
|
-
end
|
41
|
-
end
|
@@ -1,285 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require("http")
|
4
|
-
require("rbconfig")
|
5
|
-
require("stringio")
|
6
|
-
require("json")
|
7
|
-
require_relative("./detailed_response.rb")
|
8
|
-
require_relative("./watson_api_exception.rb")
|
9
|
-
require_relative("./iam_token_manager.rb")
|
10
|
-
require_relative("./version.rb")
|
11
|
-
require_relative("./common.rb")
|
12
|
-
# require("httplog")
|
13
|
-
# HttpLog.configure do |config|
|
14
|
-
# config.log_connect = true
|
15
|
-
# config.log_request = true
|
16
|
-
# config.log_headers = true
|
17
|
-
# config.log_data = true
|
18
|
-
# config.log_status = true
|
19
|
-
# config.log_response = true
|
20
|
-
# end
|
21
|
-
|
22
|
-
DEFAULT_CREDENTIALS_FILE_NAME = "ibm-credentials.env"
|
23
|
-
NORMALIZER = lambda do |uri| # Custom URI normalizer when using HTTP Client
|
24
|
-
HTTP::URI.parse uri
|
25
|
-
end
|
26
|
-
|
27
|
-
# Class for interacting with the Watson API
|
28
|
-
class WatsonService
|
29
|
-
attr_accessor :password, :url, :username, :display_name
|
30
|
-
attr_reader :conn, :token_manager
|
31
|
-
def initialize(vars)
|
32
|
-
defaults = {
|
33
|
-
vcap_services_name: nil,
|
34
|
-
username: nil,
|
35
|
-
password: nil,
|
36
|
-
use_vcap_services: true,
|
37
|
-
iam_apikey: nil,
|
38
|
-
iam_access_token: nil,
|
39
|
-
iam_url: nil,
|
40
|
-
display_name: nil
|
41
|
-
}
|
42
|
-
vars = defaults.merge(vars)
|
43
|
-
@url = vars[:url]
|
44
|
-
@username = nil
|
45
|
-
@password = nil
|
46
|
-
@iam_apikey = nil
|
47
|
-
@token_manager = nil
|
48
|
-
@temp_headers = nil
|
49
|
-
@icp_prefix = vars[:password]&.start_with?("icp-") ? true : false
|
50
|
-
@disable_ssl = false
|
51
|
-
@display_name = vars[:display_name]
|
52
|
-
|
53
|
-
if !vars[:iam_access_token].nil? || !vars[:iam_apikey].nil?
|
54
|
-
set_token_manager(iam_apikey: vars[:iam_apikey], iam_access_token: vars[:iam_access_token], iam_url: vars[:iam_url])
|
55
|
-
elsif !vars[:username].nil? && !vars[:password].nil?
|
56
|
-
if vars[:username] == "apikey" && !@icp_prefix
|
57
|
-
iam_apikey(iam_apikey: vars[:password])
|
58
|
-
else
|
59
|
-
@username = vars[:username]
|
60
|
-
@password = vars[:password]
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
if @display_name && !@username && !@iam_apikey
|
65
|
-
service_name = @display_name.sub(" ", "_").downcase
|
66
|
-
load_from_credential_file(service_name)
|
67
|
-
end
|
68
|
-
|
69
|
-
if vars[:use_vcap_services] && !@username && !@iam_apikey
|
70
|
-
@vcap_service_credentials = load_from_vcap_services(service_name: vars[:vcap_services_name])
|
71
|
-
if !@vcap_service_credentials.nil? && @vcap_service_credentials.instance_of?(Hash)
|
72
|
-
@url = @vcap_service_credentials["url"]
|
73
|
-
@username = @vcap_service_credentials["username"] if @vcap_service_credentials.key?("username")
|
74
|
-
@password = @vcap_service_credentials["password"] if @vcap_service_credentials.key?("password")
|
75
|
-
@iam_apikey = @vcap_service_credentials["iam_apikey"] if @vcap_service_credentials.key?("iam_apikey")
|
76
|
-
@iam_access_token = @vcap_service_credentials["iam_access_token"] if @vcap_service_credentials.key?("iam_access_token")
|
77
|
-
@iam_url = @vcap_service_credentials["iam_url"] if @vcap_service_credentials.key?("iam_url")
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
raise ArgumentError.new('The username shouldn\'t start or end with curly brackets or quotes. Be sure to remove any {} and \" characters surrounding your username') if check_bad_first_or_last_char(@username)
|
82
|
-
raise ArgumentError.new('The password shouldn\'t start or end with curly brackets or quotes. Be sure to remove any {} and \" characters surrounding your password') if check_bad_first_or_last_char(@password)
|
83
|
-
raise ArgumentError.new('The url shouldn\'t start or end with curly brackets or quotes. Be sure to remove any {} and \" characters surrounding your url') if check_bad_first_or_last_char(@url)
|
84
|
-
raise ArgumentError.new('The apikey shouldn\'t start or end with curly brackets or quotes. Be sure to remove any {} and \" characters surrounding your apikey') if check_bad_first_or_last_char(@iam_apikey)
|
85
|
-
|
86
|
-
@conn = HTTP::Client.new(
|
87
|
-
headers: {}
|
88
|
-
).use normalize_uri: { normalizer: NORMALIZER }
|
89
|
-
end
|
90
|
-
|
91
|
-
# Initiates the credentials based on the credential file
|
92
|
-
def load_from_credential_file(service_name, separator = "=")
|
93
|
-
credential_file_path = ENV["IBM_CREDENTIALS_FILE"]
|
94
|
-
|
95
|
-
# Home directory
|
96
|
-
if credential_file_path.nil?
|
97
|
-
file_path = ENV["HOME"] + DEFAULT_CREDENTIALS_FILE_NAME
|
98
|
-
credential_file_path = file_path if File.exist?(file_path)
|
99
|
-
end
|
100
|
-
|
101
|
-
# Top-level directory of the project
|
102
|
-
if credential_file_path.nil?
|
103
|
-
file_path = File.join(File.dirname(__FILE__), "/../../" + DEFAULT_CREDENTIALS_FILE_NAME)
|
104
|
-
credential_file_path = file_path if File.exist?(file_path)
|
105
|
-
end
|
106
|
-
|
107
|
-
return if credential_file_path.nil?
|
108
|
-
|
109
|
-
file_contents = File.open(credential_file_path, "r")
|
110
|
-
file_contents.each_line do |line|
|
111
|
-
key_val = line.strip.split(separator)
|
112
|
-
set_credential_based_on_type(service_name, key_val[0].downcase, key_val[1].downcase) if key_val.length == 2
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def load_from_vcap_services(service_name:)
|
117
|
-
vcap_services = ENV["VCAP_SERVICES"]
|
118
|
-
unless vcap_services.nil?
|
119
|
-
services = JSON.parse(vcap_services)
|
120
|
-
return services[service_name][0]["credentials"] if services.key?(service_name)
|
121
|
-
end
|
122
|
-
nil
|
123
|
-
end
|
124
|
-
|
125
|
-
def add_default_headers(headers: {})
|
126
|
-
raise TypeError unless headers.instance_of?(Hash)
|
127
|
-
|
128
|
-
headers.each_pair { |k, v| @conn.default_options.headers.add(k, v) }
|
129
|
-
end
|
130
|
-
|
131
|
-
def iam_access_token(iam_access_token:)
|
132
|
-
@token_manager = IAMTokenManager.new(iam_access_token: iam_access_token) if @token_manager.nil?
|
133
|
-
@iam_access_token = iam_access_token
|
134
|
-
end
|
135
|
-
|
136
|
-
def iam_apikey(iam_apikey:)
|
137
|
-
@token_manager = IAMTokenManager.new(iam_apikey: iam_apikey) if @token_manager.nil?
|
138
|
-
@iam_apikey = iam_apikey
|
139
|
-
end
|
140
|
-
|
141
|
-
# @return [DetailedResponse]
|
142
|
-
def request(args)
|
143
|
-
defaults = { method: nil, url: nil, accept_json: false, headers: nil, params: nil, json: {}, data: nil }
|
144
|
-
args = defaults.merge(args)
|
145
|
-
args[:data].delete_if { |_k, v| v.nil? } if args[:data].instance_of?(Hash)
|
146
|
-
args[:json] = args[:data].merge(args[:json]) if args[:data].respond_to?(:merge)
|
147
|
-
args[:json] = args[:data] if args[:json].empty? || (args[:data].instance_of?(String) && !args[:data].empty?)
|
148
|
-
args[:json].delete_if { |_k, v| v.nil? } if args[:json].instance_of?(Hash)
|
149
|
-
args[:headers]["Accept"] = "application/json" if args[:accept_json] && args[:headers]["Accept"].nil?
|
150
|
-
args[:headers]["Content-Type"] = "application/json" unless args[:headers].key?("Content-Type")
|
151
|
-
args[:json] = args[:json].to_json if args[:json].instance_of?(Hash)
|
152
|
-
args[:headers].delete_if { |_k, v| v.nil? } if args[:headers].instance_of?(Hash)
|
153
|
-
args[:params].delete_if { |_k, v| v.nil? } if args[:params].instance_of?(Hash)
|
154
|
-
args[:form].delete_if { |_k, v| v.nil? } if args.key?(:form)
|
155
|
-
args.delete_if { |_, v| v.nil? }
|
156
|
-
args[:headers].delete("Content-Type") if args.key?(:form) || args[:json].nil?
|
157
|
-
|
158
|
-
if @username == "apikey" && !@icp_prefix
|
159
|
-
iam_apikey(iam_apikey: @password)
|
160
|
-
@username = nil
|
161
|
-
end
|
162
|
-
|
163
|
-
conn = @conn
|
164
|
-
if !@token_manager.nil?
|
165
|
-
access_token = @token_manager.token
|
166
|
-
args[:headers]["Authorization"] = "Bearer #{access_token}"
|
167
|
-
elsif !@username.nil? && !@password.nil?
|
168
|
-
conn = @conn.basic_auth(user: @username, pass: @password)
|
169
|
-
end
|
170
|
-
|
171
|
-
args[:headers] = args[:headers].merge(@temp_headers) unless @temp_headers.nil?
|
172
|
-
@temp_headers = nil unless @temp_headers.nil?
|
173
|
-
|
174
|
-
if args.key?(:form)
|
175
|
-
response = conn.follow.request(
|
176
|
-
args[:method],
|
177
|
-
HTTP::URI.parse(@url + args[:url]),
|
178
|
-
headers: conn.default_options.headers.merge(HTTP::Headers.coerce(args[:headers])),
|
179
|
-
params: args[:params],
|
180
|
-
form: args[:form]
|
181
|
-
)
|
182
|
-
else
|
183
|
-
response = conn.follow.request(
|
184
|
-
args[:method],
|
185
|
-
HTTP::URI.parse(@url + args[:url]),
|
186
|
-
headers: conn.default_options.headers.merge(HTTP::Headers.coerce(args[:headers])),
|
187
|
-
body: args[:json],
|
188
|
-
params: args[:params]
|
189
|
-
)
|
190
|
-
end
|
191
|
-
return DetailedResponse.new(response: response) if (200..299).cover?(response.code)
|
192
|
-
|
193
|
-
raise WatsonApiException.new(response: response)
|
194
|
-
end
|
195
|
-
|
196
|
-
# @note Chainable
|
197
|
-
# @param headers [Hash] Custom headers to be sent with the request
|
198
|
-
# @return [self]
|
199
|
-
def headers(headers)
|
200
|
-
raise TypeError("Expected Hash type, received #{headers.class}") unless headers.instance_of?(Hash)
|
201
|
-
|
202
|
-
@temp_headers = headers
|
203
|
-
self
|
204
|
-
end
|
205
|
-
|
206
|
-
# @!method configure_http_client(proxy: {}, timeout: {}, disable_ssl: false)
|
207
|
-
# Sets the http client config, currently works with timeout and proxies
|
208
|
-
# @param proxy [Hash] The hash of proxy configurations
|
209
|
-
# @option proxy address [String] The address of the proxy
|
210
|
-
# @option proxy port [Integer] The port of the proxy
|
211
|
-
# @option proxy username [String] The username of the proxy, if authentication is needed
|
212
|
-
# @option proxy password [String] The password of the proxy, if authentication is needed
|
213
|
-
# @option proxy headers [Hash] The headers to be used with the proxy
|
214
|
-
# @param timeout [Hash] The hash for configuring timeouts. `per_operation` has priority over `global`
|
215
|
-
# @option timeout per_operation [Hash] Timeouts per operation. Requires `read`, `write`, `connect`
|
216
|
-
# @option timeout global [Integer] Upper bound on total request time
|
217
|
-
# @param disable_ssl [Boolean] Disable the SSL verification (Note that this has serious security implications - only do this if you really mean to!)
|
218
|
-
def configure_http_client(proxy: {}, timeout: {}, disable_ssl: false)
|
219
|
-
raise TypeError("proxy parameter must be a Hash") unless proxy.empty? || proxy.instance_of?(Hash)
|
220
|
-
|
221
|
-
raise TypeError("timeout parameter must be a Hash") unless timeout.empty? || timeout.instance_of?(Hash)
|
222
|
-
|
223
|
-
@disable_ssl = disable_ssl
|
224
|
-
if disable_ssl
|
225
|
-
ssl_context = OpenSSL::SSL::SSLContext.new
|
226
|
-
ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
227
|
-
@conn.default_options = { ssl_context: ssl_context }
|
228
|
-
end
|
229
|
-
add_proxy(proxy) unless proxy.empty? || !proxy.dig(:address).is_a?(String) || !proxy.dig(:port).is_a?(Integer)
|
230
|
-
add_timeout(timeout) unless timeout.empty? || (!timeout.key?(:per_operation) && !timeout.key?(:global))
|
231
|
-
end
|
232
|
-
|
233
|
-
private
|
234
|
-
|
235
|
-
def set_credential_based_on_type(service_name, key, value)
|
236
|
-
return unless key.include?(service_name)
|
237
|
-
|
238
|
-
@iam_apikey = value if key.include?("iam_apikey")
|
239
|
-
@iam_url = value if key.include?("iam_url")
|
240
|
-
@url = value if key.include?("url")
|
241
|
-
@username = value if key.include?("username")
|
242
|
-
@password = value if key.include?("password")
|
243
|
-
end
|
244
|
-
|
245
|
-
def check_bad_first_or_last_char(str)
|
246
|
-
return str.start_with?("{", "\"") || str.end_with?("}", "\"") unless str.nil?
|
247
|
-
end
|
248
|
-
|
249
|
-
def set_token_manager(iam_apikey: nil, iam_access_token: nil, iam_url: nil)
|
250
|
-
@iam_apikey = iam_apikey
|
251
|
-
@iam_access_token = iam_access_token
|
252
|
-
@iam_url = iam_url
|
253
|
-
@token_manager = IAMTokenManager.new(iam_apikey: iam_apikey, iam_access_token: iam_access_token, iam_url: iam_url)
|
254
|
-
end
|
255
|
-
|
256
|
-
def add_timeout(timeout)
|
257
|
-
if timeout.key?(:per_operation)
|
258
|
-
raise TypeError("per_operation in timeout must be a Hash") unless timeout[:per_operation].instance_of?(Hash)
|
259
|
-
|
260
|
-
defaults = {
|
261
|
-
write: 0,
|
262
|
-
connect: 0,
|
263
|
-
read: 0
|
264
|
-
}
|
265
|
-
time = defaults.merge(timeout[:per_operation])
|
266
|
-
@conn = @conn.timeout(write: time[:write], connect: time[:connect], read: time[:read])
|
267
|
-
else
|
268
|
-
raise TypeError("global in timeout must be an Integer") unless timeout[:global].is_a?(Integer)
|
269
|
-
|
270
|
-
@conn = @conn.timeout(timeout[:global])
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
def add_proxy(proxy)
|
275
|
-
if (proxy[:username].nil? || proxy[:password].nil?) && proxy[:headers].nil?
|
276
|
-
@conn = @conn.via(proxy[:address], proxy[:port])
|
277
|
-
elsif !proxy[:username].nil? && !proxy[:password].nil? && proxy[:headers].nil?
|
278
|
-
@conn = @conn.via(proxy[:address], proxy[:port], proxy[:username], proxy[:password])
|
279
|
-
elsif !proxy[:headers].nil? && (proxy[:username].nil? || proxy[:password].nil?)
|
280
|
-
@conn = @conn.via(proxy[:address], proxy[:port], proxy[:headers])
|
281
|
-
else
|
282
|
-
@conn = @conn.via(proxy[:address], proxy[:port], proxy[:username], proxy[:password], proxy[:headers])
|
283
|
-
end
|
284
|
-
end
|
285
|
-
end
|