awis-sdk-ruby 0.1.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +8 -4
- data/awis.gemspec +1 -1
- data/bin/console +0 -0
- data/lib/awis.rb +7 -6
- data/lib/awis/api/base.rb +1 -1
- data/lib/awis/client.rb +5 -5
- data/lib/awis/connection.rb +6 -85
- data/lib/awis/hash.rb +8 -0
- data/lib/awis/utils.rb +9 -0
- data/lib/awis/utils/hash.rb +9 -0
- data/lib/awis/utils/request.rb +153 -0
- data/lib/awis/utils/xml.rb +1 -1
- data/lib/awis/version.rb +1 -1
- metadata +19 -16
data/README.md
CHANGED
@@ -20,8 +20,8 @@ Awis.config do |c|
|
|
20
20
|
c.secret_access_key = AWIS_CONFIG['secret_access_key']
|
21
21
|
c.debug = AWIS_CONFIG['debug']
|
22
22
|
c.protocol = 'https' # Default 'https'
|
23
|
-
c.timeout =
|
24
|
-
c.open_timeout =
|
23
|
+
c.timeout = 10 # Default 10
|
24
|
+
c.open_timeout = 10 # Default 10
|
25
25
|
c.logger = false # Default nil
|
26
26
|
end
|
27
27
|
```
|
@@ -116,7 +116,7 @@ You can specify options:
|
|
116
116
|
|
117
117
|
``` ruby
|
118
118
|
client = Awis::Client.new
|
119
|
-
category_listings = client.category_listings(path: "Top/
|
119
|
+
category_listings = client.category_listings(path: "Top/Arts")
|
120
120
|
```
|
121
121
|
|
122
122
|
If you looking for the API request URI:
|
@@ -136,7 +136,7 @@ Returns object that contains relationships:
|
|
136
136
|
|
137
137
|
``` ruby
|
138
138
|
client = Awis::Client.new
|
139
|
-
category_browses = client.category_browse(path: "Top/
|
139
|
+
category_browses = client.category_browse(path: "Top/Arts")
|
140
140
|
```
|
141
141
|
|
142
142
|
If you looking for the API request URI:
|
@@ -154,6 +154,10 @@ Returns object that contains relationships:
|
|
154
154
|
|
155
155
|
* listings [:data_url, :title, :popularity_rank, :description]
|
156
156
|
|
157
|
+
##### How to run test
|
158
|
+
|
159
|
+
* rake test
|
160
|
+
|
157
161
|
##### Request ID and Status Code
|
158
162
|
|
159
163
|
You can retrieve status code and requestID
|
data/awis.gemspec
CHANGED
@@ -23,10 +23,10 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.required_ruby_version = ">= 1.9.3"
|
24
24
|
|
25
25
|
spec.add_dependency "multi_xml", ">= 0.5.0"
|
26
|
-
spec.add_dependency "faraday", "~> 0.9.0"
|
27
26
|
spec.add_dependency "nokogiri", '~> 1.6.8'
|
28
27
|
|
29
28
|
spec.add_development_dependency "minitest"
|
30
29
|
spec.add_development_dependency "mocha"
|
31
30
|
spec.add_development_dependency "webmock"
|
31
|
+
spec.add_development_dependency "pry"
|
32
32
|
end
|
data/bin/console
CHANGED
File without changes
|
data/lib/awis.rb
CHANGED
@@ -3,9 +3,7 @@ require "nokogiri"
|
|
3
3
|
|
4
4
|
require "awis/version"
|
5
5
|
require "awis/hash"
|
6
|
-
require "awis/utils
|
7
|
-
require "awis/utils/extra"
|
8
|
-
require "awis/utils/variable"
|
6
|
+
require "awis/utils"
|
9
7
|
require "awis/exceptions"
|
10
8
|
require "awis/connection"
|
11
9
|
require "awis/config"
|
@@ -14,9 +12,12 @@ require "awis/api"
|
|
14
12
|
require "awis/models"
|
15
13
|
|
16
14
|
module Awis
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
SERVICE_HOST = "awis.amazonaws.com".freeze
|
16
|
+
SERVICE_ENDPOINT = "awis.us-west-1.amazonaws.com".freeze
|
17
|
+
SERVICE_PORT = 443
|
18
|
+
SERVICE_URI = "/api".freeze
|
19
|
+
SERVICE_REGION = "us-west-1".freeze
|
20
|
+
SERVICE_NAME = "awis".freeze
|
20
21
|
|
21
22
|
class << self
|
22
23
|
end
|
data/lib/awis/api/base.rb
CHANGED
data/lib/awis/client.rb
CHANGED
@@ -28,15 +28,15 @@ module Awis
|
|
28
28
|
def parse_response_with_request(kclass, args)
|
29
29
|
case kclass
|
30
30
|
when 'UrlInfo'
|
31
|
-
|
31
|
+
Models::UrlInfo.new API::UrlInfo.new.fetch(args)
|
32
32
|
when 'SitesLinkingIn'
|
33
|
-
|
33
|
+
Models::SitesLinkingIn.new API::SitesLinkingIn.new.fetch(args)
|
34
34
|
when 'TrafficHistory'
|
35
|
-
|
35
|
+
Models::TrafficHistory.new API::TrafficHistory.new.fetch(args)
|
36
36
|
when 'CategoryBrowse'
|
37
|
-
|
37
|
+
Models::CategoryBrowse.new API::CategoryBrowse.new.fetch(args)
|
38
38
|
when 'CategoryListings'
|
39
|
-
|
39
|
+
Models::CategoryListings.new API::CategoryListings.new.fetch(args)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
data/lib/awis/connection.rb
CHANGED
@@ -1,12 +1,7 @@
|
|
1
|
-
require "cgi"
|
2
|
-
require "base64"
|
3
|
-
require "openssl"
|
4
|
-
require "digest/sha1"
|
5
|
-
require "faraday"
|
6
|
-
require "time"
|
7
|
-
|
8
1
|
module Awis
|
9
2
|
class Connection
|
3
|
+
include Awis::Utils::Request
|
4
|
+
|
10
5
|
attr_accessor :debug, :protocol
|
11
6
|
attr_writer :params
|
12
7
|
|
@@ -19,8 +14,8 @@ module Awis
|
|
19
14
|
def setup_options!
|
20
15
|
@debug = Awis.config.debug || false
|
21
16
|
@protocol = Awis.config.protocol || 'https'
|
22
|
-
@timeout = Awis.config.timeout ||
|
23
|
-
@open_timeout = Awis.config.open_timeout ||
|
17
|
+
@timeout = Awis.config.timeout || 10
|
18
|
+
@open_timeout = Awis.config.open_timeout || 10
|
24
19
|
end
|
25
20
|
|
26
21
|
def params
|
@@ -34,82 +29,8 @@ module Awis
|
|
34
29
|
def get(params = {})
|
35
30
|
setup_params(params)
|
36
31
|
|
37
|
-
handle_response(request)
|
38
|
-
|
39
|
-
|
40
|
-
def handle_response(response)
|
41
|
-
case response.status.to_i
|
42
|
-
when 200...300
|
43
|
-
response
|
44
|
-
when 300...600
|
45
|
-
if response.body.nil?
|
46
|
-
raise ResponseError.new(nil, response)
|
47
|
-
else
|
48
|
-
xml = MultiXml.parse(response.body)
|
49
|
-
message = xml["Response"]["Errors"]["Error"]["Message"]
|
50
|
-
raise ResponseError.new(message, response)
|
51
|
-
end
|
52
|
-
else
|
53
|
-
raise ResponseError.new("Unknown code: #{respnse.code}", response)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def request
|
58
|
-
connection = Faraday.new(url: host_with_port) do |faraday|
|
59
|
-
faraday.request :url_encoded # form-encode POST params
|
60
|
-
faraday.response :logger do |logger|
|
61
|
-
logger.filter(/(AWSAccessKeyId=)(\w+)/, '\1[REMOVED]')
|
62
|
-
end if Awis.config.logger
|
63
|
-
faraday.adapter :net_http
|
64
|
-
end
|
65
|
-
|
66
|
-
connection.get do |req|
|
67
|
-
req.url url_params
|
68
|
-
req.options.open_timeout = @timeout
|
69
|
-
req.options.timeout = @open_timeout
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def host_with_port
|
74
|
-
protocol + '://' + Awis::API_HOST
|
75
|
-
end
|
76
|
-
|
77
|
-
def timestamp
|
78
|
-
@timestamp ||= Time::now.utc.strftime("%Y-%m-%dT%H:%M:%S.000Z")
|
79
|
-
end
|
80
|
-
|
81
|
-
def signature
|
82
|
-
Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha256"), Awis.config.secret_access_key, sign)).strip
|
83
|
-
end
|
84
|
-
|
85
|
-
def url_params
|
86
|
-
'?' + original_params
|
87
|
-
end
|
88
|
-
|
89
|
-
def request_url
|
90
|
-
URI.parse(host_with_port + url_params)
|
91
|
-
end
|
92
|
-
|
93
|
-
def default_params
|
94
|
-
{
|
95
|
-
"AWSAccessKeyId" => Awis.config.access_key_id,
|
96
|
-
"SignatureMethod" => "HmacSHA256",
|
97
|
-
"SignatureVersion" => Awis::API_SIGNATURE_VERSION,
|
98
|
-
"Timestamp" => timestamp,
|
99
|
-
"Version" => Awis::API_VERSION
|
100
|
-
}
|
101
|
-
end
|
102
|
-
|
103
|
-
def sign
|
104
|
-
"GET\n" + Awis::API_HOST + "\n/\n" + query_params
|
105
|
-
end
|
106
|
-
|
107
|
-
def query_params
|
108
|
-
default_params.merge(params).map { |key, value| "#{key}=#{CGI::escape(value.to_s)}" }.sort.join("&")
|
109
|
-
end
|
110
|
-
|
111
|
-
def original_params
|
112
|
-
query_params + "&Signature=" + CGI::escape(signature)
|
32
|
+
response = handle_response(request)
|
33
|
+
response.body.force_encoding(Encoding::UTF_8)
|
113
34
|
end
|
114
35
|
end
|
115
36
|
end
|
data/lib/awis/hash.rb
CHANGED
@@ -2,4 +2,12 @@ class Hash
|
|
2
2
|
def array_slice_merge!(key, array, count)
|
3
3
|
self[key] = array.each_slice(count).collect { |e| e.reduce({}, :merge) }
|
4
4
|
end
|
5
|
+
|
6
|
+
def deep_find(key, object = self, found = nil)
|
7
|
+
return object[key] if object.respond_to?(:key?) && object.key?(key)
|
8
|
+
return found unless object.is_a?(Enumerable)
|
9
|
+
|
10
|
+
object.find { |*a| found = deep_find(key, a.last) }
|
11
|
+
found
|
12
|
+
end
|
5
13
|
end
|
data/lib/awis/utils.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "base64"
|
3
|
+
require "openssl"
|
4
|
+
require "uri"
|
5
|
+
require "net/https"
|
6
|
+
require "time"
|
7
|
+
require 'pry'
|
8
|
+
|
9
|
+
module Awis
|
10
|
+
module Utils
|
11
|
+
module Request
|
12
|
+
def signature_key(key, date_stamp, region_name, service_name)
|
13
|
+
kDate = openssl_hmac_digest(encryption_method, aws4 + key, date_stamp)
|
14
|
+
kRegion = openssl_hmac_digest(encryption_method, kDate, region_name)
|
15
|
+
kService = openssl_hmac_digest(encryption_method, kRegion, service_name)
|
16
|
+
kSigning = openssl_hmac_digest(encryption_method, kService, aws4_request)
|
17
|
+
kSigning
|
18
|
+
end
|
19
|
+
|
20
|
+
# escape str to RFC 3986
|
21
|
+
def escapeRFC3986(str)
|
22
|
+
URI.escape(str, /[^A-Za-z0-9\-_.~]/)
|
23
|
+
end
|
24
|
+
|
25
|
+
def timestamp
|
26
|
+
Time::now.utc.strftime("%Y%m%dT%H%M%SZ")
|
27
|
+
end
|
28
|
+
|
29
|
+
def datestamp
|
30
|
+
Time::now.utc.strftime("%Y%m%d")
|
31
|
+
end
|
32
|
+
|
33
|
+
def headers
|
34
|
+
{
|
35
|
+
"host" => Awis::SERVICE_ENDPOINT,
|
36
|
+
"x-amz-date" => timestamp
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
def query_str
|
41
|
+
params.sort.map{|k,v| k + "=" + escapeRFC3986(v.to_s())}.join('&')
|
42
|
+
end
|
43
|
+
|
44
|
+
def headers_str
|
45
|
+
headers.sort.map{|k,v| k + ":" + v}.join("\n") + "\n"
|
46
|
+
end
|
47
|
+
|
48
|
+
def headers_lst
|
49
|
+
headers.sort.map{|k,v| k}.join(";")
|
50
|
+
end
|
51
|
+
|
52
|
+
def payload_hash
|
53
|
+
digest_sha256_hexdigest ""
|
54
|
+
end
|
55
|
+
|
56
|
+
def canonical_request
|
57
|
+
"GET" + "\n" + Awis::SERVICE_URI + "\n" + query_str + "\n" + headers_str + "\n" + headers_lst + "\n" + payload_hash
|
58
|
+
end
|
59
|
+
|
60
|
+
def algorithm
|
61
|
+
"AWS4-HMAC-SHA256"
|
62
|
+
end
|
63
|
+
|
64
|
+
def credential_scope
|
65
|
+
datestamp + "/" + Awis::SERVICE_REGION + "/" + Awis::SERVICE_NAME + "/" + aws4_request
|
66
|
+
end
|
67
|
+
|
68
|
+
def string_to_sign
|
69
|
+
algorithm + "\n" + timestamp + "\n" + credential_scope + "\n" + digest_sha256_hexdigest(canonical_request)
|
70
|
+
end
|
71
|
+
|
72
|
+
def signing_key
|
73
|
+
signature_key(Awis.config.secret_access_key, datestamp, Awis::SERVICE_REGION, Awis::SERVICE_NAME)
|
74
|
+
end
|
75
|
+
|
76
|
+
def signature
|
77
|
+
OpenSSL::HMAC.hexdigest(encryption_method, signing_key, string_to_sign)
|
78
|
+
end
|
79
|
+
|
80
|
+
def authorization_header
|
81
|
+
algorithm + " " +
|
82
|
+
"Credential=" + Awis.config.access_key_id + "/" + credential_scope + ", " +
|
83
|
+
"SignedHeaders=" + headers_lst + ", " +
|
84
|
+
"Signature=" + signature;
|
85
|
+
end
|
86
|
+
|
87
|
+
def uri
|
88
|
+
URI(url + url_params)
|
89
|
+
end
|
90
|
+
|
91
|
+
def request
|
92
|
+
req = Net::HTTP::Get.new(uri.to_s)
|
93
|
+
req["Accept"] = "application/xml"
|
94
|
+
req["Content-Type"] = "application/xml"
|
95
|
+
req["x-amz-date"] = timestamp
|
96
|
+
req["Authorization"] = authorization_header
|
97
|
+
|
98
|
+
response = Net::HTTP.start(uri.host, uri.port,
|
99
|
+
use_ssl: uri.scheme == 'https',
|
100
|
+
ssl_timeout: @timeout,
|
101
|
+
open_timeout: @open_timeout) { |http|
|
102
|
+
http.request(req)
|
103
|
+
}
|
104
|
+
|
105
|
+
response
|
106
|
+
end
|
107
|
+
|
108
|
+
def handle_response(response)
|
109
|
+
case response.code.to_i
|
110
|
+
when 200...300
|
111
|
+
response
|
112
|
+
when 300...600
|
113
|
+
if response.body.nil?
|
114
|
+
raise ResponseError.new(nil, response)
|
115
|
+
else
|
116
|
+
error_message = MultiXml.parse(response.body).deep_find('ErrorCode')
|
117
|
+
raise ResponseError.new(error_message, response)
|
118
|
+
end
|
119
|
+
else
|
120
|
+
raise ResponseError.new("Unknown code: #{respnse.code}", response)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def aws4
|
125
|
+
"AWS4"
|
126
|
+
end
|
127
|
+
|
128
|
+
def aws4_request
|
129
|
+
"aws4_request"
|
130
|
+
end
|
131
|
+
|
132
|
+
def encryption_method
|
133
|
+
'sha256'
|
134
|
+
end
|
135
|
+
|
136
|
+
def url
|
137
|
+
protocol + '://' + Awis::SERVICE_HOST + Awis::SERVICE_URI
|
138
|
+
end
|
139
|
+
|
140
|
+
def url_params
|
141
|
+
'?' + query_str
|
142
|
+
end
|
143
|
+
|
144
|
+
def openssl_hmac_digest(method, key, secret)
|
145
|
+
OpenSSL::HMAC.digest(method, key, secret)
|
146
|
+
end
|
147
|
+
|
148
|
+
def digest_sha256_hexdigest(key)
|
149
|
+
Digest::SHA256.hexdigest key
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/lib/awis/utils/xml.rb
CHANGED
data/lib/awis/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: awis-sdk-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-
|
12
|
+
date: 2017-12-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: multi_xml
|
@@ -28,13 +28,13 @@ dependencies:
|
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 0.5.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
31
|
+
name: nokogiri
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
35
|
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
37
|
+
version: 1.6.8
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,25 +42,25 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
45
|
+
version: 1.6.8
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
47
|
+
name: minitest
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ! '>='
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
54
|
-
type: :
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: '0'
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
63
|
+
name: mocha
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
66
66
|
requirements:
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
79
|
+
name: webmock
|
80
80
|
requirement: !ruby/object:Gem::Requirement
|
81
81
|
none: false
|
82
82
|
requirements:
|
@@ -92,7 +92,7 @@ dependencies:
|
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: '0'
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
95
|
+
name: pry
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
@@ -143,7 +143,10 @@ files:
|
|
143
143
|
- lib/awis/models/sites_linking_in.rb
|
144
144
|
- lib/awis/models/traffic_history.rb
|
145
145
|
- lib/awis/models/url_info.rb
|
146
|
+
- lib/awis/utils.rb
|
146
147
|
- lib/awis/utils/extra.rb
|
148
|
+
- lib/awis/utils/hash.rb
|
149
|
+
- lib/awis/utils/request.rb
|
147
150
|
- lib/awis/utils/variable.rb
|
148
151
|
- lib/awis/utils/xml.rb
|
149
152
|
- lib/awis/version.rb
|
@@ -167,10 +170,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
167
170
|
version: '0'
|
168
171
|
segments:
|
169
172
|
- 0
|
170
|
-
hash:
|
173
|
+
hash: -1995395337547775
|
171
174
|
requirements: []
|
172
175
|
rubyforge_project:
|
173
|
-
rubygems_version: 1.8.23
|
176
|
+
rubygems_version: 1.8.23.2
|
174
177
|
signing_key:
|
175
178
|
specification_version: 3
|
176
179
|
summary: Ruby - Amazon Alexa Web Information Service Library (AWIS)
|