ubiquity-wiredrive 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.
@@ -0,0 +1,134 @@
1
+ class Ubiquity::Wiredrive::API::V3::Client::Paginator
2
+
3
+ attr_accessor :api_client
4
+
5
+ attr_reader :total_results, :last_page_number, :next_page_number, :prev_page_number, :page_size
6
+
7
+ def initialize(api_client)
8
+ @api_client = api_client
9
+
10
+ process_response
11
+ end
12
+
13
+ def logger
14
+ api_client.logger
15
+ end
16
+
17
+ def http_client
18
+ api_client.http_client
19
+ end
20
+
21
+ def process_response
22
+ http_response = http_client.response
23
+
24
+ @total_results = http_response['total']
25
+ @paginated = !!total_results
26
+
27
+ process_link_header(http_response['links']) if paginated?
28
+ end
29
+
30
+ def process_link_header(link)
31
+ links = link.split(',')
32
+ @next_page_number = nil
33
+ @prev_page_number = nil
34
+
35
+ links.map! do |k, v|
36
+ # href, rel = l.split('; ')
37
+ # rel = rel.match(/"(\w*)/)[1]
38
+ # href = href.match(/<(.*)>/)[1]
39
+ # _, query = href.split('?')
40
+ # query_as_hash = Hash[ query.split('&').map { |v| v.split('=') } ]
41
+ # @page_size = query_as_hash['_pageSize']
42
+ #
43
+ # case rel
44
+ # when 'next'
45
+ # @next_page_number = query_as_hash['_page']
46
+ # @next_page_href = href
47
+ # when 'last'
48
+ # @last_page_number = query_as_hash['_page']
49
+ # @last_page_href = href
50
+ # when 'prev'
51
+ # @prev_page_number = query_as_hash['_page']
52
+ # @prev_page_href = href
53
+ # end
54
+ #
55
+ # [ rel, href ]
56
+ [ k, v ]
57
+ end
58
+ @has_next_page = !!@next_page_number
59
+ @has_prev_page = !!@prev_page_number
60
+
61
+ Hash[links]
62
+ end
63
+
64
+ def request
65
+ @request ||= api_client.request
66
+ end
67
+
68
+ def request_args_out
69
+ @request_args_out ||= request.initial_arguments.dup
70
+ end
71
+
72
+ def request_options_out
73
+ @request_options_out ||= { :client => api_client }.merge request.initial_options.dup
74
+ end
75
+
76
+ def paginated?
77
+ @paginated
78
+ end
79
+
80
+ def next_page?
81
+ @has_next_page
82
+ end
83
+
84
+ def next_page_get(_next_page_number = @next_page_number)
85
+ page_get(_next_page_number)
86
+ end
87
+
88
+ def page_get(page_number)
89
+ logger.debug { "Getting Page #{page_number} of #{last_page_number}" }
90
+ new_request = request.class.new(request_args_out.merge('_page' => page_number), request_options_out)
91
+ _response = new_request.execute
92
+ process_response
93
+ _response
94
+ end
95
+
96
+ def pages_get(pages, options = { })
97
+ consolidate = options.fetch(:consolidate, true)
98
+ pages = pages.to_a if pages.respond_to?(:to_a)
99
+ pages_out = pages.map { |v| page_get(v) }
100
+ pages_out.flatten! if consolidate
101
+ pages_out
102
+ end
103
+
104
+ def prev_page?
105
+ @has_prev_page
106
+ end
107
+
108
+ def prev_page_get(_prev_page_number = @prev_page_number)
109
+ return [ ] unless paginated?
110
+ page_get(_prev_page_number)
111
+ end
112
+
113
+ def include_remaining_pages
114
+ response = api_client.response.dup
115
+ response.concat(remaining_pages_get)
116
+ end
117
+
118
+ def remaining_pages_get
119
+ return [ ] unless paginated? && next_page?
120
+ _next_page_number = @next_page_number
121
+ remaining_results = [ ]
122
+
123
+ loop do
124
+ response = next_page_get(_next_page_number)
125
+ break unless response.is_a?(Array)
126
+ remaining_results.concat(response)
127
+
128
+ break unless next_page?
129
+ _next_page_number = next_page_number
130
+ end
131
+ remaining_results
132
+ end
133
+
134
+ end
@@ -0,0 +1,3 @@
1
+ module Ubiquity::Wiredrive::API::V2::Client::Requests end
2
+
3
+ require 'ubiquity/wiredrive/api/v2/client/requests/base_request'
@@ -0,0 +1,225 @@
1
+ require 'cgi'
2
+
3
+ class Ubiquity::Wiredrive::API::V2::Client::Requests::BaseRequest
4
+
5
+ HTTP_METHOD = :get
6
+ HTTP_BASE_PATH = ''
7
+ HTTP_PATH = ''
8
+ HTTP_SUCCESS_CODE = 200
9
+
10
+ DEFAULT_PARAMETER_SEND_IN_VALUE = :query
11
+
12
+ PARAMETERS = [ ]
13
+
14
+ attr_accessor :client, :arguments, :options, :initial_arguments, :initial_options, :missing_required_arguments,
15
+ :default_parameter_send_in_value, :processed_parameters, :initialized, :response
16
+
17
+ attr_writer :parameters, :path, :body, :query
18
+
19
+ def self.normalize_argument_hash_keys(hash)
20
+ return hash unless hash.is_a?(Hash)
21
+ Hash[ hash.dup.map { |k,v| [ normalize_parameter_name(k), v ] } ]
22
+ end
23
+
24
+ def self.normalize_parameter_name(name)
25
+ (name || '').respond_to?(:to_s) ? name.to_s.gsub('_', '').gsub('-', '').downcase : name
26
+ end
27
+
28
+ def self.process_parameter(param, args = { }, args_out = { }, missing_required_arguments = [ ], processed_parameters = { }, default_parameter_send_in_value = DEFAULT_PARAMETER_SEND_IN_VALUE, options = { })
29
+ args = normalize_argument_hash_keys(args) || { } if options.fetch(:normalize_argument_hash_keys, false)
30
+
31
+ _k = param.is_a?(Hash) ? param : { :name => param, :required => false, :send_in => default_parameter_send_in_value }
32
+ _k[:send_in] ||= default_parameter_send_in_value
33
+
34
+ proper_parameter_name = _k[:name]
35
+ param_name = normalize_parameter_name(proper_parameter_name)
36
+ arg_key = (has_key = args.has_key?(param_name)) ?
37
+ param_name :
38
+ ( (_k[:aliases] || [ ]).map { |a| normalize_parameter_name(a) }.find { |a| has_key = args.has_key?(a) } || param_name )
39
+
40
+ value = has_key ? args[arg_key] : _k[:default_value]
41
+ is_set = has_key || _k.has_key?(:default_value)
42
+
43
+ processed_parameters[proper_parameter_name] = _k.merge(:value => value, :is_set => is_set)
44
+
45
+ unless is_set
46
+ missing_required_arguments << proper_parameter_name if _k[:required]
47
+ else
48
+ args_out[proper_parameter_name] = value
49
+ end
50
+
51
+ { :arguments_out => args_out, :processed_parameters => processed_parameters, :missing_required_arguments => missing_required_arguments }
52
+ rescue => e
53
+ raise e, "Error Processing Parameter: #{param.inspect} Args: #{args.inspect}. #{e.message}"
54
+ end
55
+
56
+ def self.process_parameters(params, args, options = { })
57
+ args = normalize_argument_hash_keys(args) || { }
58
+ args_out = options[:arguments_out] || { }
59
+ default_parameter_send_in_value = options[:default_parameter_send_in_value] || DEFAULT_PARAMETER_SEND_IN_VALUE
60
+ processed_parameters = options[:processed_parameters] || { }
61
+ missing_required_arguments = options[:missing_required_arguments] || [ ]
62
+
63
+ params.each do |param|
64
+ process_parameter(param, args, args_out, missing_required_arguments, processed_parameters, default_parameter_send_in_value)
65
+ end
66
+ { :arguments_out => args_out, :processed_parameters => processed_parameters, :missing_required_arguments => missing_required_arguments }
67
+ end
68
+
69
+ def initialize(args = { }, options = { })
70
+ @initial_arguments = args.dup
71
+ @initial_options = options.dup
72
+
73
+ @options = options.dup
74
+
75
+ initialize_attributes if options.fetch(:initialize_attributes, true)
76
+ after_initialize
77
+ end
78
+
79
+ def after_initialize
80
+ process_parameters if initialized
81
+ end
82
+
83
+ def initialize_attributes
84
+ @client = options[:client]
85
+ @missing_required_arguments = [ ]
86
+ @default_parameter_send_in_value = options[:default_parameter_send_in_value] || self.class::DEFAULT_PARAMETER_SEND_IN_VALUE
87
+ @processed_parameters = { }
88
+ @arguments = { }
89
+ @eval_http_path = options.fetch(:eval_http_path, true)
90
+ @base_path = options[:base_path]
91
+
92
+ @parameters = options[:parameters]
93
+ @http_method = options[:http_method]
94
+ @http_path = options[:http_path] ||= options[:path_raw]
95
+
96
+ @path = options[:path]
97
+ @path_arguments = nil
98
+ @path_only = nil
99
+
100
+ @query = options[:query]
101
+ @query_arguments = nil
102
+
103
+ @body = options[:body]
104
+ @body_arguments = nil
105
+
106
+ @response = nil
107
+
108
+ @http_success_code = options[:http_success_code] || HTTP_SUCCESS_CODE
109
+
110
+ @initialized = true
111
+ end
112
+ alias :reset_attributes :initialize_attributes
113
+
114
+ def process_parameters(params = parameters, args = @initial_arguments, _options = @options)
115
+ before_process_parameters unless _options.fetch(:skip_before_process_parameters, false)
116
+ self.class.process_parameters(params, args, _options.merge(:processed_parameters => processed_parameters, :missing_required_arguments => missing_required_arguments, :default_parameter_send_in_value => default_parameter_send_in_value, :arguments_out => arguments))
117
+ after_process_parameters unless _options.fetch(:skip_after_process_parameters, false)
118
+ end
119
+
120
+ def before_process_parameters
121
+ # TO BE IMPLEMENTED IN CHILD CLASS
122
+ end
123
+
124
+ def after_process_parameters
125
+ # TO BE IMPLEMENTED IN CHILD CLASS
126
+ end
127
+ alias :post_process_arguments :after_process_parameters
128
+
129
+ # @!group Attribute Readers
130
+
131
+ def http_success_code
132
+ @http_success_code
133
+ end
134
+
135
+ def arguments
136
+ @arguments ||= { }
137
+ end
138
+
139
+ def base_path
140
+ @base_path ||= self.class::HTTP_BASE_PATH
141
+ end
142
+
143
+ def body_arguments
144
+ @body_arguments ||= arguments.dup.delete_if { |k,_| processed_parameters[k][:send_in] != :body }
145
+ end
146
+
147
+ def body
148
+ @body ||= body_arguments.empty? ? nil : body_arguments
149
+ end
150
+
151
+ def client
152
+ @client ||= options[:client]
153
+ end
154
+
155
+ def eval_http_path?
156
+ @eval_http_path
157
+ end
158
+
159
+ def http_path
160
+ @http_path ||= self.class::HTTP_PATH
161
+ end
162
+
163
+ def http_method
164
+ @http_method ||= self.class::HTTP_METHOD
165
+ end
166
+
167
+ def parameters
168
+ @parameters ||= self.class::PARAMETERS.dup
169
+ end
170
+
171
+ def relative_path
172
+ @relative_path ||= (path.start_with?('/') ? path[1..-1] : path)
173
+ end
174
+
175
+ # The URI Path
176
+ def path
177
+ @path ||= File.join(base_path, (eval_http_path? ? eval(%("#{http_path}"), binding, __FILE__, __LINE__) : http_path))
178
+ end
179
+
180
+ def path_arguments
181
+ @path_arguments ||= Hash[
182
+ arguments.dup.delete_if { |k, _| processed_parameters[k][:send_in] != :path }.
183
+ map { |k,v| [ k, CGI.escape(v.respond_to?(:to_s) ? v.to_s : '').gsub('+', '%20') ] }
184
+ ]
185
+ end
186
+
187
+ def query
188
+ @query ||= begin
189
+ query_arguments.is_a?(Hash) ? query_arguments.map { |k,v| "#{CGI.escape(k.to_s).gsub('+', '%20')}=#{CGI.escape([*v].join(',')).gsub('+', '%20')}" }.join('&') : query_arguments
190
+ end
191
+ end
192
+
193
+ def query_arguments
194
+ @query_arguments ||= arguments.dup.delete_if { |k,_| processed_parameters[k][:send_in] != :query }
195
+ end
196
+
197
+ def uri_request_path
198
+ [ path ].concat( [*query].delete_if { |v| v.respond_to?(:empty?) and v.empty? } ).join('?')
199
+ end
200
+
201
+ # @!endgroup
202
+
203
+ # def response
204
+ # client.response if client
205
+ # end
206
+
207
+ def http_client
208
+ client.http_client
209
+ end
210
+
211
+ def http_response
212
+ @http_response ||= http_client.response.dup rescue nil
213
+ end
214
+
215
+ def execute
216
+ @response = http_client.call_method(http_method, { :path => relative_path, :query => query, :body => body }, options) if client
217
+ end
218
+
219
+ def success?
220
+ _response = http_response and ([*http_success_code].include?(http_response.code))
221
+ _response
222
+ end
223
+
224
+ end
225
+
@@ -0,0 +1,246 @@
1
+ require 'cgi'
2
+ require 'json'
3
+ require 'logger'
4
+ require 'net/http'
5
+ require 'net/https'
6
+ require 'net/http/post/multipart'
7
+
8
+ require 'ubiquity/wiredrive/version'
9
+
10
+ module Ubiquity
11
+ module Wiredrive
12
+ module API
13
+ module V2
14
+ class HTTPClient
15
+
16
+ class RateLimitException < StandardError; end
17
+
18
+ # Ruby uses all lower case headers but Jetty uses case sensitive headers
19
+ class CaseSensitiveHeaderKey < String
20
+ def downcase; self end
21
+ def capitalize; self end
22
+ end
23
+
24
+
25
+ attr_accessor :logger, :http, :http_host_address, :http_host_port, :base_uri
26
+ attr_accessor :hostname, :username, :password
27
+
28
+ attr_accessor :default_request_headers
29
+
30
+ attr_accessor :log_request_body, :log_response_body, :log_pretty_print_body
31
+
32
+ attr_accessor :request, :response
33
+
34
+ DEFAULT_HTTP_HOST_ADDRESS = 'api.wiredrive.rc'
35
+ DEFAULT_HTTP_HOST_PORT = 443
36
+
37
+ def initialize(args = { })
38
+ args = args.dup
39
+ initialize_logger(args)
40
+ initialize_http(args)
41
+
42
+ @auth_token = args[:auth_token]
43
+ @base_uri = args[:base_uri] || "http#{http.use_ssl? ? 's' : ''}://#{http.address}:#{http.port}/v2/"
44
+
45
+ @user_agent_default = "Ubiquity Wiredrive Ruby SDK Version #{Ubiquity::Wiredrive::VERSION}"
46
+
47
+ authorization_header_name = CaseSensitiveHeaderKey.new('Authorization')
48
+ authorization_header_value = "Bearer #{@auth_token}"
49
+
50
+
51
+ @default_request_headers = {
52
+ 'user-agent' => @user_agent_default,
53
+ 'Content-Type' => 'application/json; charset=utf-8',
54
+ 'Accept' => 'application/json',
55
+ authorization_header_name => authorization_header_value,
56
+ }
57
+
58
+ @log_request_body = args.fetch(:log_request_body, true)
59
+ @log_response_body = args.fetch(:log_response_body, true)
60
+ @log_pretty_print_body = args.fetch(:log_pretty_print_body, true)
61
+
62
+ @cancelled = false
63
+ @parse_response = args.fetch(:parse_response, true)
64
+ end
65
+
66
+ def initialize_logger(args = { })
67
+ @logger = args[:logger] ||= Logger.new(args[:log_to] || STDOUT)
68
+ log_level = args[:log_level]
69
+ if log_level
70
+ @logger.level = log_level
71
+ args[:logger] = @logger
72
+ end
73
+ @logger
74
+ end
75
+
76
+ def initialize_http(args = { })
77
+ @http_host_address = args[:http_host_address] ||= DEFAULT_HTTP_HOST_ADDRESS
78
+ @http_host_port = args[:http_host_port] ||= DEFAULT_HTTP_HOST_PORT
79
+ @http = Net::HTTP.new(http_host_address, http_host_port)
80
+ http.use_ssl = true
81
+
82
+ # TODO Add SSL Patch
83
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
84
+
85
+ http
86
+ end
87
+
88
+ # Formats a HTTPRequest or HTTPResponse body for log output.
89
+ # @param [HTTPRequest|HTTPResponse] obj
90
+ # @return [String]
91
+ def format_body_for_log_output(obj)
92
+ if obj.content_type == 'application/json'
93
+ if @log_pretty_print_body
94
+ _body = obj.body
95
+ output = "\n" << JSON.pretty_generate(JSON.parse(_body)) rescue _body
96
+ return output
97
+ else
98
+ return obj.body
99
+ end
100
+ else
101
+ return obj.body.inspect
102
+ end
103
+ end
104
+
105
+ # @param [Net::HTTPRequest] request
106
+ def send_request(request)
107
+ @response_parsed = nil
108
+ @request = request
109
+
110
+ begin
111
+ logger.debug { %(REQUEST: #{request.method} http#{http.use_ssl? ? 's' : ''}://#{http.address}:#{http.port}#{request.path} HEADERS: #{request.to_hash.inspect} #{log_request_body and request.request_body_permitted? ? "BODY: #{format_body_for_log_output(request)}" : ''}) }
112
+
113
+ @response = http.request(request)
114
+ logger.debug { %(RESPONSE: #{response.inspect} HEADERS: #{response.to_hash.inspect} #{log_response_body and response.respond_to?(:body) ? "BODY: #{format_body_for_log_output(response)}" : ''}) }
115
+ raise RateLimitException, "#{response.to_hash.inspect}" if response.code == '420'
116
+ rescue RateLimitException => e
117
+ logger.warn { "Rate Limited. Will retry in #{@delay_between_rate_limit_retries} seconds." }
118
+ sleep_break @delay_between_rate_limit_retries
119
+ retry unless @cancelled
120
+ end
121
+
122
+ @parse_response ? response_parsed : response.body
123
+ end
124
+
125
+ def sleep_break(seconds)
126
+ while (seconds > 0)
127
+ sleep(1)
128
+ seconds -= 1
129
+ break if @cancelled
130
+ end
131
+ end
132
+
133
+ def response_parsed
134
+ @response_parsed ||= begin
135
+ response_content_type = response.content_type
136
+ logger.debug { "Parsing Response: #{response_content_type}" }
137
+
138
+ case response_content_type
139
+ when 'application/json'
140
+ JSON.parse(response.body) rescue response
141
+ # when 'text/html'
142
+ # when 'text/plain'
143
+ else
144
+ response.body
145
+ end
146
+ end
147
+ end
148
+
149
+ def build_uri(path = '', query = nil)
150
+ _query = query.is_a?(Hash) ? query.map { |k,v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v)}" }.join('&') : query
151
+ _path = "#{path}#{_query and _query.respond_to?(:empty?) and !_query.empty? ? "?#{_query}" : ''}"
152
+ URI.parse(File.join(base_uri, _path))
153
+ end
154
+
155
+ if RUBY_VERSION.start_with? '1.8.'
156
+ def request_method_name_to_class_name(method_name)
157
+ method_name.to_s.capitalize
158
+ end
159
+ else
160
+ def request_method_name_to_class_name(method_name)
161
+ method_name.to_s.capitalize.to_sym
162
+ end
163
+ end
164
+
165
+ # @param [Symbol] method_name (:get)
166
+ # @param [Hash] args
167
+ # @option args [Hash] :headers ({})
168
+ # @option args [String] :path ('')
169
+ # @option args [Hash] :query ({})
170
+ # @option args [Any] :body (nil)
171
+ # @param [Hash] options
172
+ # @option options [Hash] :default_request_headers (@default_request_headers)
173
+ def call_method(method_name = :get, args = { }, options = { })
174
+ headers = args[:headers] || options[:headers] || { }
175
+ path = args[:path] || ''
176
+ query = args[:query] || { }
177
+ body = args[:body]
178
+
179
+ # Allow the default request headers to be overridden
180
+ _default_request_headers = options.fetch(:default_request_headers, default_request_headers)
181
+ _default_request_headers ||= { }
182
+ _headers = _default_request_headers.merge(headers)
183
+
184
+ @uri = build_uri(path, query)
185
+ klass_name = request_method_name_to_class_name(method_name)
186
+ klass = Net::HTTP.const_get(klass_name)
187
+
188
+ request = klass.new(@uri.request_uri, _headers)
189
+
190
+ if request.request_body_permitted?
191
+ _body = (body and !body.is_a?(String)) ? JSON.generate(body) : body
192
+ logger.debug { "Processing Body: '#{_body}'" }
193
+ request.body = _body if _body
194
+ end
195
+
196
+ send_request(request)
197
+ end
198
+
199
+ def delete(path, options = { })
200
+ query = options.fetch(:query, { })
201
+ @uri = build_uri(path, query)
202
+
203
+
204
+ request = Net::HTTP::Delete.new(@uri.request_uri, default_request_headers)
205
+ body = options[:body]
206
+ if body
207
+ body = JSON.generate(body) unless body.is_a?(String)
208
+ request.body = body
209
+ end
210
+
211
+ send_request(request)
212
+ end
213
+
214
+ def get(path, query = nil, options = { })
215
+ query ||= options.fetch(:query, { })
216
+ @uri = build_uri(path, query)
217
+ request = Net::HTTP::Get.new(@uri.request_uri, default_request_headers)
218
+ send_request(request)
219
+ end
220
+
221
+ def put(path, body, options = { })
222
+ query = options.fetch(:query, { })
223
+ @uri = build_uri(path, query)
224
+ body = JSON.generate(body) unless body.is_a?(String)
225
+
226
+ request = Net::HTTP::Put.new(@uri.request_uri, default_request_headers)
227
+ request.body = body
228
+ send_request(request)
229
+ end
230
+
231
+ def post(path, body, options = { })
232
+ query = options.fetch(:query, { })
233
+ @uri = build_uri(path, query)
234
+ body = JSON.generate(body) unless body.is_a?(String)
235
+
236
+ request = Net::HTTP::Post.new(@uri.request_uri, default_request_headers)
237
+ request.body = body
238
+ send_request(request)
239
+ end
240
+
241
+ end
242
+
243
+ end
244
+ end
245
+ end
246
+ end