awis-sdk-ruby 0.0.1

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.
@@ -0,0 +1,33 @@
1
+ module Awis
2
+ module API
3
+ class UrlInfo < Base
4
+ DEFAULT_RESPONSE_GROUP = %w(related_links categories rank rank_by_country usage_stats adult_content speed language owned_domains links_in_count site_data).freeze
5
+
6
+ def fetch(arguments = {})
7
+ raise ArgumentError, "Any valid URL." unless arguments.has_key?(:url)
8
+ @arguments = arguments
9
+ @arguments[:response_group] = Array(arguments.fetch(:response_group, DEFAULT_RESPONSE_GROUP))
10
+
11
+ loading_response_data
12
+ self
13
+ end
14
+
15
+ def loading_response_data
16
+ @response_body = Awis::Connection.new.get(params)
17
+ end
18
+
19
+ private
20
+ def params
21
+ {
22
+ "Action" => action_name,
23
+ "Url" => arguments[:url],
24
+ "ResponseGroup" => response_groups,
25
+ }
26
+ end
27
+
28
+ def response_groups
29
+ arguments[:response_group].sort.map { |group| camelize(group) }.join(",")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,44 @@
1
+ module Awis
2
+ class Client
3
+
4
+ def initialize
5
+ raise CertificateError.new("Amazon access certificate is missing!") if Awis.config.access_key_id.nil? || Awis.config.secret_access_key.nil?
6
+ end
7
+
8
+ def url_info(args)
9
+ parse_response_with_request("UrlInfo", args)
10
+ end
11
+
12
+ def traffic_history(args)
13
+ parse_response_with_request("TrafficHistory", args)
14
+ end
15
+
16
+ def sites_linking_in(args)
17
+ parse_response_with_request("SitesLinkingIn", args)
18
+ end
19
+
20
+ def category_browse(args)
21
+ parse_response_with_request("CategoryBrowse", args)
22
+ end
23
+
24
+ def category_listings(args)
25
+ parse_response_with_request("CategoryListings", args)
26
+ end
27
+
28
+ private
29
+ def parse_response_with_request(kclass, args)
30
+ case kclass
31
+ when 'UrlInfo'
32
+ Awis::Models::UrlInfo.new Awis::API::UrlInfo.new.fetch(args)
33
+ when 'SitesLinkingIn'
34
+ Awis::Models::SitesLinkingIn.new Awis::API::SitesLinkingIn.new.fetch(args)
35
+ when 'TrafficHistory'
36
+ Awis::Models::TrafficHistory.new Awis::API::TrafficHistory.new.fetch(args)
37
+ when 'CategoryBrowse'
38
+ Awis::Models::CategoryBrowse.new Awis::API::CategoryBrowse.new.fetch(args)
39
+ when 'CategoryListings'
40
+ Awis::Models::CategoryListings.new Awis::API::CategoryListings.new.fetch(args)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,15 @@
1
+ require "singleton"
2
+
3
+ module Awis
4
+ class Config
5
+ include Singleton
6
+ attr_accessor :access_key_id, :secret_access_key, :proxy, :debug
7
+ end
8
+
9
+ def self.config
10
+ if block_given?
11
+ yield Config.instance
12
+ end
13
+ Config.instance
14
+ end
15
+ end
@@ -0,0 +1,90 @@
1
+ require "cgi"
2
+ require "base64"
3
+ require "openssl"
4
+ require "digest/sha1"
5
+ require "faraday"
6
+ require "time"
7
+
8
+ module Awis
9
+ class Connection
10
+ attr_accessor :access_key_id, :secret_access_key, :proxy, :debug
11
+ attr_writer :params
12
+
13
+ RFC_3986_UNRESERVED_CHARS = "-_.~a-zA-Z\\d".freeze
14
+
15
+ def initialize
16
+ raise CertificateError.new("Amazon access certificate is missing!") if Awis.config.access_key_id.nil? || Awis.config.secret_access_key.nil?
17
+
18
+ @access_key_id = Awis.config.access_key_id
19
+ @secret_access_key = Awis.config.secret_access_key
20
+ @debug = Awis.config.debug || nil
21
+ end
22
+
23
+ def params
24
+ @params ||= {}
25
+ end
26
+
27
+ def get(params = {})
28
+ self.params = params
29
+
30
+ handle_response(request).body.force_encoding(Encoding::UTF_8)
31
+ end
32
+
33
+ def handle_response(response)
34
+ case response.status.to_i
35
+ when 200...300
36
+ response
37
+ when 300...600
38
+ if response.body.nil?
39
+ raise ResponseError.new(nil, response)
40
+ else
41
+ xml = MultiXml.parse(response.body)
42
+ message = xml["Response"]["Errors"]["Error"]["Message"]
43
+ raise ResponseError.new(message, response)
44
+ end
45
+ else
46
+ raise ResponseError.new("Unknown code: #{respnse.code}", response)
47
+ end
48
+ end
49
+
50
+ def request
51
+ puts "[DEBUG] -> #{uri}" if debug
52
+
53
+ Faraday.get(uri)
54
+ end
55
+
56
+ def timestamp
57
+ @timestamp ||= Time::now.utc.strftime("%Y-%m-%dT%H:%M:%S.000Z")
58
+ end
59
+
60
+ def signature
61
+ Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new("sha256"), secret_access_key, sign)).strip
62
+ end
63
+
64
+ def uri
65
+ URI.parse("http://#{Awis::API_HOST}/?" + query + "&Signature=" + CGI::escape(signature))
66
+ end
67
+
68
+ def default_params
69
+ {
70
+ "AWSAccessKeyId" => access_key_id,
71
+ "SignatureMethod" => "HmacSHA256",
72
+ "SignatureVersion" => "2",
73
+ "Timestamp" => timestamp,
74
+ "Version" => Awis::API_VERSION
75
+ }
76
+ end
77
+
78
+ def sign
79
+ "GET\n" + Awis::API_HOST + "\n/\n" + query
80
+ end
81
+
82
+ def query
83
+ default_params.merge(params).map { |key, value| "#{key}=#{regexp_params(value)}" }.sort.join("&")
84
+ end
85
+
86
+ def regexp_params(value)
87
+ URI.escape(value.to_s, Regexp.new("[^#{RFC_3986_UNRESERVED_CHARS}]"))
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,16 @@
1
+ module Awis
2
+ # Awis exceptions can be cought by rescuing: Awis::StandardError
3
+
4
+ class StandardError < StandardError; end
5
+ class ArgumentError < StandardError; end
6
+ class CertificateError < StandardError; end
7
+
8
+ class ResponseError < StandardError
9
+ attr_reader :response
10
+
11
+ def initialize(message, response)
12
+ @response = response
13
+ super(message)
14
+ end
15
+ end
16
+ end
data/lib/awis/hash.rb ADDED
@@ -0,0 +1,9 @@
1
+ class Hash
2
+ def deep_find(key)
3
+ key?(key) ? self[key] : self.values.inject(nil) { |memo, v| memo ||= v.deep_find(key) if v.respond_to?(:deep_find) }
4
+ end
5
+
6
+ def array_slice_merge!(key, array, count)
7
+ self[key] = array.each_slice(count).collect { |e| e.reduce({}, :merge) }
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module Awis
2
+ module Models
3
+ autoload :Base, "awis/models/base"
4
+ autoload :UrlInfo, "awis/models/url_info"
5
+ autoload :TrafficHistory, "awis/models/traffic_history"
6
+ autoload :SitesLinkingIn, "awis/models/sites_linking_in"
7
+ autoload :CategoryListings, "awis/models/category_listings"
8
+ autoload :CategoryBrowse, "awis/models/category_browse"
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ module Awis
2
+ module Models
3
+ class Base
4
+ attr_accessor :response, :status_code, :request_id
5
+
6
+ def loading_response(response)
7
+ Awis::Utils::XML.new(response.response_body)
8
+ end
9
+
10
+ def root_node_name
11
+ "/aws:#{action_name}Response/aws:Response/aws:#{action_name}Result/aws:Alexa"
12
+ end
13
+
14
+ def action_name
15
+ self.class.name.split(/\:\:/)[-1]
16
+ end
17
+
18
+ def relationship_collections(_object, items, items_count, kclass)
19
+ return if items.empty?
20
+
21
+ all_items = {}.array_slice_merge!(:item, items, items_count)
22
+ all_items.map { |item| _object << kclass.new(item) }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,123 @@
1
+ module Awis
2
+ module Models
3
+ class CategoryBrowse < Base
4
+ attr_accessor :categories, :language_categories, :related_categories, :letter_bars
5
+
6
+ def initialize(response)
7
+ @categories = []
8
+ @language_categories = []
9
+ @related_categories = []
10
+ @letter_bars = []
11
+
12
+ setup_data!( loading_response(response) )
13
+ end
14
+
15
+ def setup_data!(response)
16
+ categories = []
17
+ language_categories = []
18
+ related_categories = []
19
+ letter_bars = []
20
+
21
+ response.each_node do |node, path|
22
+ text = node.inner_xml
23
+ text = text.to_i if text.to_i.to_s === text
24
+
25
+ if node.name == 'aws:RequestId'
26
+ @request_id ||= text
27
+ elsif node.name == 'aws:StatusCode'
28
+ @status_code ||= text
29
+ elsif node.name == 'aws:Path' && path == "#{category_node_name}/aws:Path"
30
+ categories << { path: text }
31
+ elsif node.name == 'aws:Title' && path == "#{category_node_name}/aws:Title"
32
+ categories << { title: text }
33
+ elsif node.name == 'aws:SubCategoryCount' && path == "#{category_node_name}/aws:SubCategoryCount"
34
+ categories << { sub_category_count: text }
35
+ elsif node.name == 'aws:TotalListingCount' && path == "#{category_node_name}/aws:TotalListingCount"
36
+ categories << { total_listing_count: text }
37
+ elsif node.name == 'aws:Path' && path == "#{language_category_node_name}/aws:Path"
38
+ language_categories << { path: text }
39
+ elsif node.name == 'aws:Title' && path == "#{language_category_node_name}/aws:Title"
40
+ language_categories << { title: text }
41
+ elsif node.name == 'aws:SubCategoryCount' && path == "#{language_category_node_name}/aws:SubCategoryCount"
42
+ language_categories << { sub_category_count: text }
43
+ elsif node.name == 'aws:TotalListingCount' && path == "#{language_category_node_name}/aws:TotalListingCount"
44
+ language_categories << { total_listing_count: text }
45
+ elsif node.name == 'aws:Path' && path == "#{related_category_node_name}/aws:Path"
46
+ related_categories << { path: text }
47
+ elsif node.name == 'aws:Title' && path == "#{related_category_node_name}/aws:Title"
48
+ related_categories << { title: text }
49
+ elsif node.name == 'aws:SubCategoryCount' && path == "#{related_category_node_name}/aws:SubCategoryCount"
50
+ related_categories << { sub_category_count: text }
51
+ elsif node.name == 'aws:TotalListingCount' && path == "#{related_category_node_name}/aws:TotalListingCount"
52
+ related_categories << { total_listing_count: text }
53
+ elsif node.name == 'aws:Path' && path == "#{letter_bars_node_name}/aws:Path"
54
+ letter_bars << { path: text }
55
+ elsif node.name == 'aws:Title' && path == "#{letter_bars_node_name}/aws:Title"
56
+ letter_bars << { title: text }
57
+ elsif node.name == 'aws:SubCategoryCount' && path == "#{letter_bars_node_name}/aws:SubCategoryCount"
58
+ letter_bars << { sub_category_count: text }
59
+ elsif node.name == 'aws:TotalListingCount' && path == "#{letter_bars_node_name}/aws:TotalListingCount"
60
+ letter_bars << { total_listing_count: text }
61
+ end
62
+ end
63
+
64
+ relationship_collections(@categories, categories, 4, Category)
65
+ relationship_collections(@language_categories, language_categories, 4, LanguageCategory)
66
+ relationship_collections(@related_categories, related_categories, 4, RelatedCategory)
67
+ relationship_collections(@letter_bars, letter_bars, 4, LetterBar)
68
+ end
69
+
70
+ def base_node_name
71
+ "#{root_node_name}/aws:CategoryBrowse"
72
+ end
73
+
74
+ def category_node_name
75
+ "#{base_node_name}/aws:Categories/aws:Category"
76
+ end
77
+
78
+ def language_category_node_name
79
+ "#{base_node_name}/aws:LanguageCategories/aws:Category"
80
+ end
81
+
82
+ def related_category_node_name
83
+ "#{base_node_name}/aws:RelatedCategories/aws:Category"
84
+ end
85
+
86
+ def letter_bars_node_name
87
+ "#{base_node_name}/aws:LetterBars/aws:Category"
88
+ end
89
+ end
90
+
91
+ class Category
92
+ attr_accessor :path, :title, :sub_category_count, :total_listing_count
93
+
94
+ def initialize(hash)
95
+ hash.map { |k, v| instance_variable_set("@#{k}", v) }
96
+ end
97
+ end
98
+
99
+ class LanguageCategory
100
+ attr_accessor :path, :title, :sub_category_count, :total_listing_count
101
+
102
+ def initialize(hash)
103
+ hash.map { |k, v| instance_variable_set("@#{k}", v) }
104
+ end
105
+ end
106
+
107
+ class RelatedCategory
108
+ attr_accessor :path, :title, :sub_category_count, :total_listing_count
109
+
110
+ def initialize(hash)
111
+ hash.map { |k, v| instance_variable_set("@#{k}", v) }
112
+ end
113
+ end
114
+
115
+ class LetterBar
116
+ attr_accessor :path, :title, :sub_category_count, :total_listing_count
117
+
118
+ def initialize(hash)
119
+ hash.map { |k, v| instance_variable_set("@#{k}", v) }
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,53 @@
1
+ module Awis
2
+ module Models
3
+ class CategoryListings < Base
4
+ attr_accessor :count, :recursive_count, :listings
5
+
6
+ def initialize(response)
7
+ @listings = []
8
+ setup_data!( loading_response(response) )
9
+ end
10
+
11
+ def setup_data!(response)
12
+ category_listings = []
13
+
14
+ response.each_node do |node, path|
15
+ text = node.inner_xml
16
+ text = text.to_i if text.to_i.to_s === text
17
+
18
+ if node.name == 'aws:RequestId'
19
+ @request_id ||= text
20
+ elsif node.name == 'aws:StatusCode'
21
+ @status_code ||= text
22
+ elsif node.name == 'aws:Count'
23
+ @count ||= text
24
+ elsif node.name == 'aws:RecursiveCount'
25
+ @recursive_count ||= text
26
+ elsif node.name == 'aws:DataUrl' && path == "#{base_node_name}/aws:DataUrl"
27
+ category_listings << { data_url: text }
28
+ elsif node.name == 'aws:Title' && path == "#{base_node_name}/aws:Title"
29
+ category_listings << { title: text }
30
+ elsif node.name == 'aws:PopularityRank' && path == "#{base_node_name}/aws:PopularityRank"
31
+ category_listings << { popularity_rank: text }
32
+ elsif node.name == 'aws:Description' && path == "#{base_node_name}/aws:Description"
33
+ category_listings << { description: text }
34
+ end
35
+ end
36
+
37
+ relationship_collections(@listings, category_listings, 4, Listing)
38
+ end
39
+
40
+ def base_node_name
41
+ "#{root_node_name}/aws:CategoryListings/aws:Listings/aws:Listing"
42
+ end
43
+ end
44
+
45
+ class Listing
46
+ attr_accessor :data_url, :title, :popularity_rank, :description
47
+
48
+ def initialize(hash)
49
+ hash.map { |k, v| instance_variable_set("@#{k}", v) }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,40 @@
1
+ module Awis
2
+ module Models
3
+ class SitesLinkingIn < Base
4
+ attr_accessor :sites
5
+
6
+ def initialize(response)
7
+ @sites = []
8
+ setup_data!( loading_response(response) )
9
+ end
10
+
11
+ def setup_data!(response)
12
+ sites = []
13
+
14
+ response.each_node do |node, path|
15
+ text = node.inner_xml
16
+
17
+ if node.name == 'aws:RequestId'
18
+ @request_id ||= text
19
+ elsif node.name == 'aws:StatusCode'
20
+ @status_code ||= text
21
+ elsif node.name == 'aws:Title'
22
+ sites << { title: text }
23
+ elsif node.name == 'aws:Url'
24
+ sites << { url: text }
25
+ end
26
+ end
27
+
28
+ relationship_collections(@sites, sites, 2, Site)
29
+ end
30
+ end
31
+
32
+ class Site
33
+ attr_accessor :title, :url
34
+
35
+ def initialize(hash)
36
+ hash.map { |k, v| instance_variable_set("@#{k}", v) }
37
+ end
38
+ end
39
+ end
40
+ end