Class: Aspera::Rest
- Inherits:
-
Object
- Object
- Aspera::Rest
- Defined in:
- lib/aspera/rest.rb
Overview
a simple class to make HTTP calls, equivalent to rest-client rest call errors are raised as exception RestCallError and error are analyzed in RestErrorAnalyzer
Instance Attribute Summary collapse
-
#params ⇒ Object
readonly
Returns the value of attribute params.
Class Method Summary collapse
- .basic_creds(user, pass) ⇒ Object
-
.build_uri(url, params = nil) ⇒ Object
build URI from URL and parameters and check it is http or https.
- .debug=(flag) ⇒ Object
- .insecure ⇒ Object
- .insecure=(v) ⇒ Object
- .user_agent ⇒ Object
- .user_agent=(v) ⇒ Object
Instance Method Summary collapse
-
#call(call_data) ⇒ Object
HTTP/S REST call call_data has keys: :auth :operation :subpath :headers :json_params :url_params :www_body_params :text_body_params :save_to_file (filepath) :return_error (bool).
- #cancel(subpath) ⇒ Object
- #create(subpath, params, encoding = :json_params) ⇒ Object
- #delete(subpath) ⇒ Object
-
#initialize(a_rest_params) ⇒ Rest
constructor
:type (:basic, :oauth2, :url) :username [:basic] :password [:basic] :url_creds [:url] :session_cb a lambda which takes @http_session as arg, use this to change parameters :* [:oauth2] see Oauth class.
- #oauth_token(options = {}) ⇒ Object
- #read(subpath, args = nil) ⇒ Object
- #update(subpath, params) ⇒ Object
Constructor Details
#initialize(a_rest_params) ⇒ Rest
:type (:basic, :oauth2, :url) :username [:basic] :password [:basic] :url_creds [:url] :session_cb a lambda which takes @http_session as arg, use this to change parameters :* [:oauth2] see Oauth class
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/aspera/rest.rb', line 109 def initialize(a_rest_params) raise "ERROR: expecting Hash" unless a_rest_params.is_a?(Hash) raise "ERROR: expecting base_url" unless a_rest_params[:base_url].is_a?(String) @params=a_rest_params.clone Log.dump('REST params',@params) # base url without trailing slashes (note: string may be frozen) @params[:base_url]=@params[:base_url].gsub(/\/+$/,'') @http_session=nil # default is no auth @params[:auth]||={:type=>:none} @params[:not_auth_codes]||=['401'] # translate old auth parameters, remove prefix, place in auth [:auth,:basic,:oauth].each do |p_sym| p_str=p_sym.to_s+'_' @params.keys.select{|k|k.to_s.start_with?(p_str)}.each do |k_sym| name=k_sym.to_s[p_str.length..-1] name='grant' if k_sym.eql?(:oauth_type) @params[:auth][name.to_sym]=@params[k_sym] @params.delete(k_sym) end end @oauth=Oauth.new(@params[:auth]) if @params[:auth][:type].eql?(:oauth2) Log.dump('REST params(2)',@params) end |
Instance Attribute Details
#params ⇒ Object (readonly)
Returns the value of attribute params.
100 101 102 |
# File 'lib/aspera/rest.rb', line 100 def params @params end |
Class Method Details
.basic_creds(user, pass) ⇒ Object
48 |
# File 'lib/aspera/rest.rb', line 48 def self.basic_creds(user,pass); return "Basic #{Base64.strict_encode64("#{user}:#{pass}")}";end |
.build_uri(url, params = nil) ⇒ Object
build URI from URL and parameters and check it is http or https
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/aspera/rest.rb', line 51 def self.build_uri(url,params=nil) uri=URI.parse(url) raise "REST endpoint shall be http(s)" unless ['http','https'].include?(uri.scheme) if !params.nil? # support array url params, there is no standard. Either p[]=1&p[]=2, or p=1&p=2 if params.is_a?(Hash) orig=params params=[] orig.each do |k,v| case v when Array suffix=v.first.eql?('[]') ? v.shift : '' v.each do |e| params.push([k+suffix,e]) end else params.push([k,v]) end end end # CGI.unescape to transform back %5D into [] uri.query=CGI.unescape(URI.encode_www_form(params)) end return uri end |
.debug=(flag) ⇒ Object
46 |
# File 'lib/aspera/rest.rb', line 46 def self.debug=(flag); @@debug=flag; Log.log.debug("debug http => #{flag}"); end |
.insecure ⇒ Object
40 |
# File 'lib/aspera/rest.rb', line 40 def self.insecure; @@insecure;end |
.insecure=(v) ⇒ Object
38 |
# File 'lib/aspera/rest.rb', line 38 def self.insecure=(v); @@insecure=v;Log.log.debug("insecure => #{@@insecure}".red);end |
.user_agent ⇒ Object
44 |
# File 'lib/aspera/rest.rb', line 44 def self.user_agent; @@user_agent;end |
Instance Method Details
#call(call_data) ⇒ Object
HTTP/S REST call call_data has keys: :auth :operation :subpath :headers :json_params :url_params :www_body_params :text_body_params :save_to_file (filepath) :return_error (bool)
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/aspera/rest.rb', line 151 def call(call_data) raise "Hash call parameter is required (#{call_data.class})" unless call_data.is_a?(Hash) Log.log.debug("accessing #{call_data[:subpath]}".red.bold.bg_green) call_data[:headers]||={} call_data[:headers]['User-Agent'] ||= @@user_agent call_data=@params.deep_merge(call_data) case call_data[:auth][:type] when :none # no auth when :basic Log.log.debug("using Basic auth") basic_auth_data=[call_data[:auth][:username],call_data[:auth][:password]] when :oauth2 call_data[:headers]['Authorization']=oauth_token unless call_data[:headers].has_key?('Authorization') when :url call_data[:url_params]||={} call_data[:auth][:url_creds].each do |key, value| call_data[:url_params][key]=value end else raise "unsupported auth type: [#{call_data[:auth][:type]}]" end # TODO: shall we percent encode subpath (spaces) test with access key delete with space in id # URI.escape() uri=self.class.build_uri("#{@params[:base_url]}#{call_data[:subpath].nil? ? '' : '/'}#{call_data[:subpath]}",call_data[:url_params]) Log.log.debug("URI=#{uri}") begin # instanciate request object based on string name req=Object::const_get('Net::HTTP::'+call_data[:operation].capitalize).new(uri.request_uri) rescue NameError => e raise "unsupported operation : #{call_data[:operation]}" end if call_data.has_key?(:json_params) and !call_data[:json_params].nil? then req.body=JSON.generate(call_data[:json_params]) Log.dump('body JSON data',call_data[:json_params]) #Log.log.debug("body JSON data=#{JSON.pretty_generate(call_data[:json_params])}") req['Content-Type'] = 'application/json' #call_data[:headers]['Accept']='application/json' end if call_data.has_key?(:www_body_params) then req.body=URI.encode_www_form(call_data[:www_body_params]) Log.log.debug("body www data=#{req.body.chomp}") req['Content-Type'] = 'application/x-www-form-urlencoded' end if call_data.has_key?(:text_body_params) then req.body=call_data[:text_body_params] Log.log.debug("body data=#{req.body.chomp}") end # set headers if call_data.has_key?(:headers) then call_data[:headers].keys.each do |key| req[key] = call_data[:headers][key] end end # :type = :basic req.basic_auth(*basic_auth_data) unless basic_auth_data.nil? Log.log.debug("call_data = #{call_data}") result={:http=>nil} begin # we try the call, and will retry only if oauth, as we can, first with refresh, and then re-auth if refresh is bad oauth_tries ||= 2 Log.log.debug("send request") http_session.request(req) do |response| result[:http] = response if call_data.has_key?(:save_to_file) total_size=result[:http]['Content-Length'].to_i progress=ProgressBar.create( :format => '%a %B %p%% %r KB/sec %e', :rate_scale => lambda{|rate|rate/1024}, :title => 'progress', :total => total_size) Log.log.debug("before write file") target_file=call_data[:save_to_file] # override user's path to path in header if !response['Content-Disposition'].nil? and m=response['Content-Disposition'].match(/filename="([^"]+)"/) target_file=m[1] end # download with temp filename target_file_tmp=target_file+'.http.partial' Log.log.debug("saving to: #{target_file}") File.open(target_file_tmp, "wb") do |file| result[:http].read_body do |fragment| file.write(fragment) new_process=progress.progress+fragment.length new_process = total_size if new_process > total_size progress.progress=new_process end end # rename at the end File.rename(target_file_tmp, target_file) progress=nil end end # sometimes there is a ITF8 char (e.g. (c) ) result[:http].body.force_encoding("UTF-8") if result[:http].body.is_a?(String) Log.log.debug("result: body=#{result[:http].body}") result_mime=(result[:http]['Content-Type']||'text/plain').split(';').first case result_mime when 'application/json','application/vnd.api+json' result[:data]=JSON.parse(result[:http].body) rescue nil else #when 'text/plain' result[:data]=result[:http].body end Log.dump("result: parsed: #{result_mime}",result[:data]) Log.log.debug("result: code=#{result[:http].code}") RestErrorAnalyzer.instance.raiseOnError(req,result) rescue RestCallError => e # not authorized: oauth token expired if @params[:not_auth_codes].include?(result[:http].code.to_s) and call_data[:auth][:type].eql?(:oauth2) begin # try to use refresh token req['Authorization']=oauth_token(refresh: true) rescue RestCallError => e Log.log.error("refresh failed".bg_red) # regenerate a brand new token req['Authorization']=oauth_token end Log.log.debug("using new token=#{call_data[:headers]['Authorization']}") retry unless (oauth_tries -= 1).zero? end # if # raise exception if could not retry and not return error in result raise e unless call_data[:return_error] end Log.log.debug("result=#{result}") return result end |
#cancel(subpath) ⇒ Object
300 301 302 |
# File 'lib/aspera/rest.rb', line 300 def cancel(subpath) return call({:operation=>'CANCEL',:subpath=>subpath,:headers=>{'Accept'=>'application/json'}}) end |
#create(subpath, params, encoding = :json_params) ⇒ Object
284 285 286 |
# File 'lib/aspera/rest.rb', line 284 def create(subpath,params,encoding=:json_params) return call({:operation=>'POST',:subpath=>subpath,:headers=>{'Accept'=>'application/json'},encoding=>params}) end |
#delete(subpath) ⇒ Object
296 297 298 |
# File 'lib/aspera/rest.rb', line 296 def delete(subpath) return call({:operation=>'DELETE',:subpath=>subpath,:headers=>{'Accept'=>'application/json'}}) end |
#oauth_token(options = {}) ⇒ Object
134 135 136 137 |
# File 'lib/aspera/rest.rb', line 134 def oauth_token(={}) raise "ERROR: not Oauth" unless @oauth.is_a?(Oauth) return @oauth.() end |
#read(subpath, args = nil) ⇒ Object
288 289 290 |
# File 'lib/aspera/rest.rb', line 288 def read(subpath,args=nil) return call({:operation=>'GET',:subpath=>subpath,:headers=>{'Accept'=>'application/json'},:url_params=>args}) end |
#update(subpath, params) ⇒ Object
292 293 294 |
# File 'lib/aspera/rest.rb', line 292 def update(subpath,params) return call({:operation=>'PUT',:subpath=>subpath,:headers=>{'Accept'=>'application/json'},:json_params=>params}) end |