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 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 = 5 # Default 5
24
- c.open_timeout = 5 # Default 2
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/Games/Card_Games")
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/Games/Card_Games")
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
@@ -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
File without changes
@@ -3,9 +3,7 @@ require "nokogiri"
3
3
 
4
4
  require "awis/version"
5
5
  require "awis/hash"
6
- require "awis/utils/xml"
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
- API_VERSION = "2005-07-11".freeze
18
- API_HOST = "awis.amazonaws.com".freeze
19
- API_SIGNATURE_VERSION = "2".freeze
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
@@ -34,7 +34,7 @@ module Awis
34
34
  def load_request_uri(params)
35
35
  collection = Awis::Connection.new
36
36
  collection.setup_params(params)
37
- collection.request_url
37
+ collection.uri
38
38
  end
39
39
 
40
40
  def before_validation_arguments(arguments)
@@ -28,15 +28,15 @@ module Awis
28
28
  def parse_response_with_request(kclass, args)
29
29
  case kclass
30
30
  when 'UrlInfo'
31
- Awis::Models::UrlInfo.new Awis::API::UrlInfo.new.fetch(args)
31
+ Models::UrlInfo.new API::UrlInfo.new.fetch(args)
32
32
  when 'SitesLinkingIn'
33
- Awis::Models::SitesLinkingIn.new Awis::API::SitesLinkingIn.new.fetch(args)
33
+ Models::SitesLinkingIn.new API::SitesLinkingIn.new.fetch(args)
34
34
  when 'TrafficHistory'
35
- Awis::Models::TrafficHistory.new Awis::API::TrafficHistory.new.fetch(args)
35
+ Models::TrafficHistory.new API::TrafficHistory.new.fetch(args)
36
36
  when 'CategoryBrowse'
37
- Awis::Models::CategoryBrowse.new Awis::API::CategoryBrowse.new.fetch(args)
37
+ Models::CategoryBrowse.new API::CategoryBrowse.new.fetch(args)
38
38
  when 'CategoryListings'
39
- Awis::Models::CategoryListings.new Awis::API::CategoryListings.new.fetch(args)
39
+ Models::CategoryListings.new API::CategoryListings.new.fetch(args)
40
40
  end
41
41
  end
42
42
  end
@@ -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 || 5
23
- @open_timeout = Awis.config.open_timeout || 2
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).body.force_encoding(Encoding::UTF_8)
38
- end
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
@@ -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
@@ -0,0 +1,9 @@
1
+ require "awis/utils/extra"
2
+ require "awis/utils/variable"
3
+ require "awis/utils/request"
4
+
5
+ module Awis
6
+ module Utils
7
+ autoload :XML, "awis/utils/xml"
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ class Hash
2
+ def deep_find(key, object = self, found = nil)
3
+ return object[key] if object.respond_to?(:key?) && object.key?(key)
4
+ return found unless object.is_a?(Enumerable)
5
+
6
+ object.find { |*a| found = deep_find(key, a.last) }
7
+ found
8
+ end
9
+ end
@@ -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
@@ -8,7 +8,7 @@ module Awis
8
8
  def each_node(attributes_in_path = false)
9
9
  reader = Nokogiri::XML::Reader(@data)
10
10
  nodes = ['']
11
-
11
+
12
12
  reader.each do |node|
13
13
  if node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
14
14
  if attributes_in_path && node.attributes.size > 0
@@ -1,3 +1,3 @@
1
1
  module Awis
2
- VERSION = "0.1.1"
2
+ VERSION = "1.0.0"
3
3
  end
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.1.1
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-08-24 00:00:00.000000000 Z
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: faraday
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: 0.9.0
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: 0.9.0
45
+ version: 1.6.8
46
46
  - !ruby/object:Gem::Dependency
47
- name: nokogiri
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: 1.6.8
54
- type: :runtime
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: 1.6.8
61
+ version: '0'
62
62
  - !ruby/object:Gem::Dependency
63
- name: minitest
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: mocha
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: webmock
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: 862568070736027421
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)