aspera-cli 4.5.0 → 4.8.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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -0
  3. data/README.md +1894 -1574
  4. data/bin/ascli +21 -1
  5. data/bin/asession +38 -34
  6. data/docs/test_env.conf +14 -3
  7. data/examples/aoc.rb +17 -15
  8. data/examples/dascli +26 -0
  9. data/examples/faspex4.rb +42 -35
  10. data/examples/proxy.pac +1 -1
  11. data/examples/transfer.rb +38 -37
  12. data/lib/aspera/aoc.rb +245 -205
  13. data/lib/aspera/ascmd.rb +111 -90
  14. data/lib/aspera/ats_api.rb +16 -14
  15. data/lib/aspera/cli/basic_auth_plugin.rb +19 -18
  16. data/lib/aspera/cli/extended_value.rb +50 -39
  17. data/lib/aspera/cli/formater.rb +161 -135
  18. data/lib/aspera/cli/info.rb +18 -0
  19. data/lib/aspera/cli/listener/line_dump.rb +4 -2
  20. data/lib/aspera/cli/listener/logger.rb +3 -1
  21. data/lib/aspera/cli/listener/progress.rb +20 -21
  22. data/lib/aspera/cli/listener/progress_multi.rb +29 -31
  23. data/lib/aspera/cli/main.rb +194 -183
  24. data/lib/aspera/cli/manager.rb +213 -206
  25. data/lib/aspera/cli/plugin.rb +71 -49
  26. data/lib/aspera/cli/plugins/alee.rb +8 -7
  27. data/lib/aspera/cli/plugins/aoc.rb +675 -558
  28. data/lib/aspera/cli/plugins/ats.rb +116 -109
  29. data/lib/aspera/cli/plugins/bss.rb +35 -34
  30. data/lib/aspera/cli/plugins/config.rb +722 -542
  31. data/lib/aspera/cli/plugins/console.rb +28 -22
  32. data/lib/aspera/cli/plugins/cos.rb +28 -37
  33. data/lib/aspera/cli/plugins/faspex.rb +281 -227
  34. data/lib/aspera/cli/plugins/faspex5.rb +129 -84
  35. data/lib/aspera/cli/plugins/node.rb +426 -232
  36. data/lib/aspera/cli/plugins/orchestrator.rb +106 -98
  37. data/lib/aspera/cli/plugins/preview.rb +196 -191
  38. data/lib/aspera/cli/plugins/server.rb +131 -126
  39. data/lib/aspera/cli/plugins/shares.rb +49 -36
  40. data/lib/aspera/cli/plugins/sync.rb +27 -28
  41. data/lib/aspera/cli/transfer_agent.rb +84 -79
  42. data/lib/aspera/cli/version.rb +3 -1
  43. data/lib/aspera/colors.rb +37 -28
  44. data/lib/aspera/command_line_builder.rb +84 -63
  45. data/lib/aspera/cos_node.rb +68 -34
  46. data/lib/aspera/data_repository.rb +4 -2
  47. data/lib/aspera/environment.rb +61 -46
  48. data/lib/aspera/fasp/agent_base.rb +36 -31
  49. data/lib/aspera/fasp/agent_connect.rb +44 -37
  50. data/lib/aspera/fasp/agent_direct.rb +101 -104
  51. data/lib/aspera/fasp/agent_httpgw.rb +91 -90
  52. data/lib/aspera/fasp/agent_node.rb +36 -33
  53. data/lib/aspera/fasp/agent_trsdk.rb +28 -31
  54. data/lib/aspera/fasp/error.rb +3 -1
  55. data/lib/aspera/fasp/error_info.rb +81 -54
  56. data/lib/aspera/fasp/installation.rb +171 -151
  57. data/lib/aspera/fasp/listener.rb +2 -0
  58. data/lib/aspera/fasp/parameters.rb +105 -111
  59. data/lib/aspera/fasp/parameters.yaml +305 -249
  60. data/lib/aspera/fasp/resume_policy.rb +20 -20
  61. data/lib/aspera/fasp/transfer_spec.rb +27 -0
  62. data/lib/aspera/fasp/uri.rb +31 -29
  63. data/lib/aspera/faspex_gw.rb +95 -118
  64. data/lib/aspera/hash_ext.rb +12 -13
  65. data/lib/aspera/id_generator.rb +11 -9
  66. data/lib/aspera/keychain/encrypted_hash.rb +73 -57
  67. data/lib/aspera/keychain/macos_security.rb +27 -29
  68. data/lib/aspera/log.rb +40 -39
  69. data/lib/aspera/nagios.rb +24 -22
  70. data/lib/aspera/node.rb +38 -30
  71. data/lib/aspera/oauth.rb +217 -248
  72. data/lib/aspera/open_application.rb +9 -7
  73. data/lib/aspera/persistency_action_once.rb +15 -14
  74. data/lib/aspera/persistency_folder.rb +15 -18
  75. data/lib/aspera/preview/file_types.rb +266 -270
  76. data/lib/aspera/preview/generator.rb +94 -92
  77. data/lib/aspera/preview/image_error.png +0 -0
  78. data/lib/aspera/preview/options.rb +20 -17
  79. data/lib/aspera/preview/utils.rb +99 -102
  80. data/lib/aspera/preview/video_error.png +0 -0
  81. data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
  82. data/lib/aspera/proxy_auto_config.rb +114 -21
  83. data/lib/aspera/rest.rb +144 -142
  84. data/lib/aspera/rest_call_error.rb +3 -2
  85. data/lib/aspera/rest_error_analyzer.rb +31 -31
  86. data/lib/aspera/rest_errors_aspera.rb +18 -16
  87. data/lib/aspera/secret_hider.rb +68 -0
  88. data/lib/aspera/ssh.rb +20 -16
  89. data/lib/aspera/sync.rb +57 -54
  90. data/lib/aspera/temp_file_manager.rb +20 -14
  91. data/lib/aspera/timer_limiter.rb +10 -8
  92. data/lib/aspera/uri_reader.rb +14 -15
  93. data/lib/aspera/web_auth.rb +85 -80
  94. data.tar.gz.sig +0 -0
  95. metadata +169 -40
  96. metadata.gz.sig +2 -0
  97. data/bin/dascli +0 -13
  98. data/docs/Makefile +0 -63
  99. data/docs/README.erb.md +0 -4221
  100. data/docs/README.md +0 -13
  101. data/docs/diagrams.txt +0 -49
  102. data/docs/doc_tools.rb +0 -58
  103. data/lib/aspera/cli/plugins/shares2.rb +0 -114
  104. data/lib/aspera/fasp/default.rb +0 -17
data/lib/aspera/rest.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/log'
2
4
  require 'aspera/oauth'
3
5
  require 'aspera/rest_error_analyzer'
@@ -28,58 +30,51 @@ module Aspera
28
30
  # rest call errors are raised as exception RestCallError
29
31
  # and error are analyzed in RestErrorAnalyzer
30
32
  class Rest
31
- private
32
- # set to true enables debug in HTTP class
33
- @@debug=false
34
- # true if https ignore certificate
35
- @@insecure=false
36
- @@user_agent='Ruby'
37
- @@download_partial_suffix='.http_partial'
38
- # a lambda which takes the Net::HTTP as arg, use this to change parameters
39
- @@session_cb=nil
40
-
41
- public
42
- def self.session_cb=(v); @@session_cb=v;Log.log.debug("session_cb => #{@@session_cb}".red);end
43
-
44
- def self.session_cb; @@session_cb;end
33
+ # global settings also valid for any subclass
34
+ @@global = { # rubocop:disable Style/ClassVars
35
+ debug: false,
36
+ # true if https ignore certificate
37
+ user_agent: 'Ruby',
38
+ download_partial_suffix: '.http_partial',
39
+ # a lambda which takes the Net::HTTP as arg, use this to change parameters
40
+ session_cb: nil
41
+ }
45
42
 
46
- def self.insecure=(v); @@insecure=v;Log.log.debug("insecure => #{@@insecure}".red);end
47
-
48
- def self.insecure; @@insecure;end
49
-
50
- def self.user_agent=(v); @@user_agent=v;Log.log.debug("user_agent => #{@@user_agent}".red);end
51
-
52
- def self.user_agent; @@user_agent;end
53
-
54
- def self.debug=(flag); @@debug=flag; Log.log.debug("debug http => #{flag}"); end
43
+ class << self
44
+ # define accessors
45
+ @@global.keys.each do |p|
46
+ define_method(p){@@global[p]}
47
+ define_method("#{p}="){|val|Log.log.debug("#{p} => #{val}".red);@@global[p] = val}
48
+ end
55
49
 
56
- def self.basic_creds(user,pass); return "Basic #{Base64.strict_encode64("#{user}:#{pass}")}";end
50
+ def basic_creds(user,pass); return "Basic #{Base64.strict_encode64("#{user}:#{pass}")}";end
57
51
 
58
- # build URI from URL and parameters and check it is http or https
59
- def self.build_uri(url,params=nil)
60
- uri=URI.parse(url)
61
- raise "REST endpoint shall be http(s)" unless ['http','https'].include?(uri.scheme)
62
- if !params.nil?
63
- # support array url params, there is no standard. Either p[]=1&p[]=2, or p=1&p=2
64
- if params.is_a?(Hash)
65
- orig=params
66
- params=[]
67
- orig.each do |k,v|
68
- case v
69
- when Array
70
- suffix=v.first.eql?('[]') ? v.shift : ''
71
- v.each do |e|
72
- params.push([k+suffix,e])
52
+ # build URI from URL and parameters and check it is http or https
53
+ def build_uri(url,params=nil)
54
+ uri = URI.parse(url)
55
+ raise "REST endpoint shall be http/s not #{uri.scheme}" unless %w[http https].include?(uri.scheme)
56
+ if !params.nil?
57
+ # support array url params, there is no standard. Either p[]=1&p[]=2, or p=1&p=2
58
+ if params.is_a?(Hash)
59
+ orig = params
60
+ params = []
61
+ orig.each do |k,v|
62
+ case v
63
+ when Array
64
+ suffix = v.first.eql?('[]') ? v.shift : ''
65
+ v.each do |e|
66
+ params.push([k + suffix,e])
67
+ end
68
+ else
69
+ params.push([k,v])
73
70
  end
74
- else
75
- params.push([k,v])
76
71
  end
77
72
  end
73
+ # CGI.unescape to transform back %5D into []
74
+ uri.query = CGI.unescape(URI.encode_www_form(params))
78
75
  end
79
- # CGI.unescape to transform back %5D into []
80
- uri.query=CGI.unescape(URI.encode_www_form(params))
76
+ return uri
81
77
  end
82
- return uri
83
78
  end
84
79
 
85
80
  private
@@ -87,13 +82,13 @@ module Aspera
87
82
  # create and start keep alive connection on demand
88
83
  def http_session
89
84
  if @http_session.nil?
90
- uri=self.class.build_uri(@params[:base_url])
85
+ uri = self.class.build_uri(@params[:base_url])
91
86
  # this honors http_proxy env var
92
- @http_session=Net::HTTP.new(uri.host, uri.port)
87
+ @http_session = Net::HTTP.new(uri.host, uri.port)
93
88
  @http_session.use_ssl = uri.scheme.eql?('https')
94
- @http_session.verify_mode = OpenSSL::SSL::VERIFY_NONE if @@insecure
95
- @http_session.set_debug_output($stdout) if @@debug
96
- @@session_cb.call(@http_session) unless @@session_cb.nil?
89
+ @http_session.set_debug_output($stdout) if self.class.debug
90
+ # set http options in callback, such as timeout and cert. verification
91
+ self.class.session_cb&.call(@http_session)
97
92
  # manually start session for keep alive (if supported by server, else, session is closed every time)
98
93
  @http_session.start
99
94
  end
@@ -103,63 +98,65 @@ module Aspera
103
98
  public
104
99
 
105
100
  attr_reader :params
106
- attr_reader :oauth
107
101
 
108
- # @param a_rest_params default call parameters (merged at call) and (+) authentication (:auth) :
109
- # :type (:basic, :oauth2, :url, :none)
110
- # :username [:basic]
111
- # :password [:basic]
112
- # :url_creds [:url]
113
- # :* [:oauth2] see Oauth class
102
+ def oauth
103
+ if @oauth.nil?
104
+ raise 'ERROR: no OAuth defined' unless @params[:auth][:type].eql?(:oauth2)
105
+ @oauth = Oauth.new(@params[:auth])
106
+ end
107
+ return @oauth
108
+ end
109
+
110
+ # @param a_rest_params [Hash] default call parameters (merged at call)
114
111
  def initialize(a_rest_params)
115
- raise "ERROR: expecting Hash" unless a_rest_params.is_a?(Hash)
116
- raise "ERROR: expecting base_url" unless a_rest_params[:base_url].is_a?(String)
117
- @params=a_rest_params.clone
112
+ raise 'ERROR: expecting Hash' unless a_rest_params.is_a?(Hash)
113
+ raise 'ERROR: expecting base_url' unless a_rest_params[:base_url].is_a?(String)
114
+ @params = a_rest_params.clone
118
115
  Log.dump('REST params',@params)
119
116
  # base url without trailing slashes (note: string may be frozen)
120
- @params[:base_url]=@params[:base_url].gsub(/\/+$/,'')
121
- @http_session=nil
117
+ @params[:base_url] = @params[:base_url].gsub(/\/+$/,'')
118
+ @http_session = nil
122
119
  # default is no auth
123
- @params[:auth]||={:type=>:none}
124
- @params[:not_auth_codes]||=['401']
125
- @oauth=Oauth.new(@params[:auth]) if @params[:auth][:type].eql?(:oauth2)
120
+ @params[:auth] ||= {type: :none}
121
+ @params[:not_auth_codes] ||= ['401']
122
+ @oauth = nil
126
123
  Log.dump('REST params(2)',@params)
127
124
  end
128
125
 
129
- def oauth_token(options={})
130
- raise "ERROR: expecting Oauth, have #{@oauth.class}" unless @oauth.is_a?(Oauth)
131
- return @oauth.get_authorization(options)
126
+ def oauth_token(force_refresh: false)
127
+ raise "ERROR: expecting boolean, have #{force_refresh}" unless [true,false].include?(force_refresh)
128
+ return oauth.get_authorization(use_refresh_token: force_refresh)
132
129
  end
133
130
 
134
131
  def build_request(call_data)
135
132
  # TODO: shall we percent encode subpath (spaces) test with access key delete with space in id
136
133
  # URI.escape()
137
- uri=self.class.build_uri("#{call_data[:base_url]}#{['','/'].include?(call_data[:subpath]) ? '' : '/'}#{call_data[:subpath]}",call_data[:url_params])
134
+ uri = self.class.build_uri("#{call_data[:base_url]}#{['','/'].include?(call_data[:subpath]) ? '' : '/'}#{call_data[:subpath]}",call_data[:url_params])
138
135
  Log.log.debug("URI=#{uri}")
139
136
  begin
140
137
  # instanciate request object based on string name
141
- req=Object::const_get('Net::HTTP::'+call_data[:operation].capitalize).new(uri)#.request_uri
142
- rescue NameError => e
138
+ req = Net::HTTP.const_get(call_data[:operation].capitalize).new(uri)
139
+ rescue NameError
143
140
  raise "unsupported operation : #{call_data[:operation]}"
144
141
  end
145
- if call_data.has_key?(:json_params) and !call_data[:json_params].nil? then
146
- req.body=JSON.generate(call_data[:json_params])
142
+ if call_data.has_key?(:json_params) && !call_data[:json_params].nil?
143
+ req.body = JSON.generate(call_data[:json_params])
147
144
  Log.dump('body JSON data',call_data[:json_params])
148
145
  #Log.log.debug("body JSON data=#{JSON.pretty_generate(call_data[:json_params])}")
149
146
  req['Content-Type'] = 'application/json'
150
147
  #call_data[:headers]['Accept']='application/json'
151
148
  end
152
- if call_data.has_key?(:www_body_params) then
153
- req.body=URI.encode_www_form(call_data[:www_body_params])
149
+ if call_data.has_key?(:www_body_params)
150
+ req.body = URI.encode_www_form(call_data[:www_body_params])
154
151
  Log.log.debug("body www data=#{req.body.chomp}")
155
152
  req['Content-Type'] = 'application/x-www-form-urlencoded'
156
153
  end
157
- if call_data.has_key?(:text_body_params) then
158
- req.body=call_data[:text_body_params]
154
+ if call_data.has_key?(:text_body_params)
155
+ req.body = call_data[:text_body_params]
159
156
  Log.log.debug("body data=#{req.body.chomp}")
160
157
  end
161
158
  # set headers
162
- if call_data.has_key?(:headers) then
159
+ if call_data.has_key?(:headers)
163
160
  call_data[:headers].keys.each do |key|
164
161
  req[key] = call_data[:headers][key]
165
162
  end
@@ -179,122 +176,127 @@ module Aspera
179
176
  # :url_params
180
177
  # :www_body_params
181
178
  # :text_body_params
182
- # :save_to_file (filepath)
183
- # :return_error (bool)
184
- # :redirect_max (int)
179
+ # :save_to_file (filepath) default: nil
180
+ # :return_error (bool) default: nil
181
+ # :redirect_max (int) default: 0
182
+ # :not_auth_codes (array) codes that trigger a refresh/regeneration of bearer token
183
+ # ----
184
+ # authentication (:auth) :
185
+ # :type (:none, :basic, :oauth2, :url)
186
+ # :username [:basic]
187
+ # :password [:basic]
188
+ # :url_creds [:url] a hash
189
+ # :* [:oauth2] see Oauth class
185
190
  def call(call_data)
186
191
  raise "Hash call parameter is required (#{call_data.class})" unless call_data.is_a?(Hash)
187
- call_data[:subpath]='' if call_data[:subpath].nil?
192
+ call_data[:subpath] = '' if call_data[:subpath].nil?
188
193
  Log.log.debug("accessing #{call_data[:subpath]}".red.bold.bg_green)
189
- call_data[:headers]||={}
190
- call_data[:headers]['User-Agent'] ||= @@user_agent
194
+ call_data[:headers] ||= {}
195
+ call_data[:headers]['User-Agent'] ||= self.class.user_agent
191
196
  # defaults from @params are overriden by call data
192
- call_data=@params.deep_merge(call_data)
197
+ call_data = @params.deep_merge(call_data)
193
198
  case call_data[:auth][:type]
194
199
  when :none
195
200
  # no auth
196
201
  when :basic
197
- Log.log.debug("using Basic auth")
202
+ Log.log.debug('using Basic auth')
198
203
  # done in build_req
199
204
  when :oauth2
200
- call_data[:headers]['Authorization']=oauth_token unless call_data[:headers].has_key?('Authorization')
205
+ call_data[:headers]['Authorization'] = oauth_token unless call_data[:headers].has_key?('Authorization')
201
206
  when :url
202
- call_data[:url_params]||={}
207
+ call_data[:url_params] ||= {}
203
208
  call_data[:auth][:url_creds].each do |key, value|
204
- call_data[:url_params][key]=value
209
+ call_data[:url_params][key] = value
205
210
  end
206
211
  else raise "unsupported auth type: [#{call_data[:auth][:type]}]"
207
212
  end
208
- req=build_request(call_data)
213
+ req = build_request(call_data)
209
214
  Log.log.debug("call_data = #{call_data}")
210
- result={:http=>nil}
215
+ result = {http: nil}
211
216
  # start a block to be able to retry the actual HTTP request
212
217
  begin
213
218
  # we try the call, and will retry only if oauth, as we can, first with refresh, and then re-auth if refresh is bad
214
219
  oauth_tries ||= 2
215
- tries_remain_redirect||=call_data[:redirect_max].nil? ? 0 : call_data[:redirect_max].to_i
216
- Log.log.debug("send request")
220
+ tries_remain_redirect ||= call_data[:redirect_max].nil? ? 0 : call_data[:redirect_max].to_i
221
+ Log.log.debug('send request')
217
222
  # make http request (pipelined)
218
223
  http_session.request(req) do |response|
219
224
  result[:http] = response
220
- if call_data.has_key?(:save_to_file) and result[:http].code.to_s.start_with?('2')
221
- total_size=result[:http]['Content-Length'].to_i
222
- progress=ProgressBar.create(
223
- :format => '%a %B %p%% %r KB/sec %e',
224
- :rate_scale => lambda{|rate|rate/1024},
225
- :title => 'progress',
226
- :total => total_size)
227
- Log.log.debug("before write file")
228
- target_file=call_data[:save_to_file]
225
+ if !call_data[:save_to_file].nil? && result[:http].code.to_s.start_with?('2')
226
+ total_size = result[:http]['Content-Length'].to_i
227
+ progress = ProgressBar.create(
228
+ format: '%a %B %p%% %r KB/sec %e',
229
+ rate_scale: lambda{|rate|rate / 1024},
230
+ title: 'progress',
231
+ total: total_size)
232
+ Log.log.debug('before write file')
233
+ target_file = call_data[:save_to_file]
229
234
  # override user's path to path in header
230
- if !response['Content-Disposition'].nil? and m=response['Content-Disposition'].match(/filename="([^"]+)"/)
231
- target_file=File.join(File.dirname(target_file),m[1])
235
+ if !response['Content-Disposition'].nil? && (m = response['Content-Disposition'].match(/filename="([^"]+)"/))
236
+ target_file = File.join(File.dirname(target_file),m[1])
232
237
  end
233
238
  # download with temp filename
234
- target_file_tmp="#{target_file}#{@@download_partial_suffix}"
239
+ target_file_tmp = "#{target_file}#{self.class.download_partial_suffix}"
235
240
  Log.log.debug("saving to: #{target_file}")
236
241
  File.open(target_file_tmp, 'wb') do |file|
237
242
  result[:http].read_body do |fragment|
238
243
  file.write(fragment)
239
- new_process=progress.progress+fragment.length
244
+ new_process = progress.progress + fragment.length
240
245
  new_process = total_size if new_process > total_size
241
- progress.progress=new_process
246
+ progress.progress = new_process
242
247
  end
243
248
  end
244
249
  # rename at the end
245
250
  File.rename(target_file_tmp, target_file)
246
- progress=nil
251
+ progress = nil
247
252
  end # save_to_file
248
253
  end
249
254
  # sometimes there is a UTF8 char (e.g. (c) )
250
- result[:http].body.force_encoding("UTF-8") if result[:http].body.is_a?(String)
255
+ result[:http].body.force_encoding('UTF-8') if result[:http].body.is_a?(String)
251
256
  Log.log.debug("result: body=#{result[:http].body}")
252
- result_mime=(result[:http]['Content-Type']||'text/plain').split(';').first
253
- case result_mime
257
+ result_mime = (result[:http]['Content-Type'] || 'text/plain').split(';').first
258
+ result[:data] = case result_mime
254
259
  when 'application/json','application/vnd.api+json'
255
- result[:data]=JSON.parse(result[:http].body) rescue nil
260
+ JSON.parse(result[:http].body) rescue nil
256
261
  else #when 'text/plain'
257
- result[:data]=result[:http].body
262
+ result[:http].body
258
263
  end
259
264
  Log.dump("result: parsed: #{result_mime}",result[:data])
260
265
  Log.log.debug("result: code=#{result[:http].code}")
261
- RestErrorAnalyzer.instance.raiseOnError(req,result)
266
+ RestErrorAnalyzer.instance.raise_on_error(req,result)
262
267
  rescue RestCallError => e
263
268
  # not authorized: oauth token expired
264
- if @params[:not_auth_codes].include?(result[:http].code.to_s) and call_data[:auth][:type].eql?(:oauth2)
269
+ if call_data[:not_auth_codes].include?(result[:http].code.to_s) && call_data[:auth][:type].eql?(:oauth2)
265
270
  begin
266
271
  # try to use refresh token
267
- req['Authorization']=oauth_token(refresh: true)
268
- rescue RestCallError => e
269
- Log.log.error("refresh failed".bg_red)
272
+ req['Authorization'] = oauth_token(force_refresh: true)
273
+ rescue RestCallError => e_tok
274
+ e = e_tok
275
+ Log.log.error('refresh failed'.bg_red)
270
276
  # regenerate a brand new token
271
- req['Authorization']=oauth_token
277
+ req['Authorization'] = oauth_token(use_cache: false)
272
278
  end
273
279
  Log.log.debug("using new token=#{call_data[:headers]['Authorization']}")
274
280
  retry unless (oauth_tries -= 1).zero?
275
281
  end # if oauth
276
282
  # moved ?
277
- if e.response.is_a?(Net::HTTPRedirection)
278
- if tries_remain_redirect > 0
279
- tries_remain_redirect-=1
280
- Log.log.info("URL is moved: #{e.response['location']}")
281
- current_uri=URI.parse(call_data[:base_url])
282
- redir_uri=URI.parse(e.response['location'])
283
- call_data[:base_url]=e.response['location']
284
- call_data[:subpath]=''
285
- if current_uri.host.eql?(redir_uri.host) and current_uri.port.eql?(redir_uri.port)
286
- req=build_request(call_data)
287
- retry
288
- else
289
- # change host
290
- Log.log.info("Redirect changes host: #{current_uri.host} -> #{redir_uri.host}")
291
- return self.class.new(call_data).call(call_data)
292
- end
283
+ if e.response.is_a?(Net::HTTPRedirection) && tries_remain_redirect.positive?
284
+ tries_remain_redirect -= 1
285
+ current_uri = URI.parse(call_data[:base_url])
286
+ new_url=e.response['location']
287
+ new_url="#{current_uri.scheme}:#{new_url}" unless new_url.start_with?('http')
288
+ Log.log.info("URL is moved: #{new_url}")
289
+ redir_uri = URI.parse(new_url)
290
+ call_data[:base_url] = new_url
291
+ call_data[:subpath] = ''
292
+ if current_uri.host.eql?(redir_uri.host) && current_uri.port.eql?(redir_uri.port)
293
+ req = build_request(call_data)
294
+ retry
293
295
  else
294
- raise "too many redirect"
296
+ # change host
297
+ Log.log.info("Redirect changes host: #{current_uri.host} -> #{redir_uri.host}")
298
+ return self.class.new(call_data).call(call_data)
295
299
  end
296
- else
297
- raise e
298
300
  end
299
301
  # raise exception if could not retry and not return error in result
300
302
  raise e unless call_data[:return_error]
@@ -309,23 +311,23 @@ module Aspera
309
311
 
310
312
  # @param encoding : one of: :json_params, :url_params
311
313
  def create(subpath,params,encoding=:json_params)
312
- return call({:operation=>'POST',:subpath=>subpath,:headers=>{'Accept'=>'application/json'},encoding=>params})
314
+ return call({operation: 'POST',subpath: subpath,headers: {'Accept' => 'application/json'},encoding => params})
313
315
  end
314
316
 
315
317
  def read(subpath,args=nil)
316
- return call({:operation=>'GET',:subpath=>subpath,:headers=>{'Accept'=>'application/json'},:url_params=>args})
318
+ return call({operation: 'GET',subpath: subpath,headers: {'Accept' => 'application/json'},url_params: args})
317
319
  end
318
320
 
319
321
  def update(subpath,params)
320
- return call({:operation=>'PUT',:subpath=>subpath,:headers=>{'Accept'=>'application/json'},:json_params=>params})
322
+ return call({operation: 'PUT',subpath: subpath,headers: {'Accept' => 'application/json'},json_params: params})
321
323
  end
322
324
 
323
325
  def delete(subpath)
324
- return call({:operation=>'DELETE',:subpath=>subpath,:headers=>{'Accept'=>'application/json'}})
326
+ return call({operation: 'DELETE',subpath: subpath,headers: {'Accept' => 'application/json'}})
325
327
  end
326
328
 
327
329
  def cancel(subpath)
328
- return call({:operation=>'CANCEL',:subpath=>subpath,:headers=>{'Accept'=>'application/json'}})
330
+ return call({operation: 'CANCEL',subpath: subpath,headers: {'Accept' => 'application/json'}})
329
331
  end
330
332
  end
331
333
  end #module Aspera
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aspera
2
4
  # raised on error after REST call
3
5
  class RestCallError < StandardError
4
- attr_accessor :request
5
- attr_accessor :response
6
+ attr_accessor :request, :response
6
7
  # @param http response
7
8
  def initialize(req,resp,msg)
8
9
  @request = req
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/log'
2
4
  require 'aspera/rest_call_error'
3
5
  require 'singleton'
@@ -10,12 +12,12 @@ module Aspera
10
12
  # the singleton object is registered with application specific handlers
11
13
  def initialize
12
14
  # list of handlers
13
- @error_handlers=[]
14
- @log_file=nil
15
- self.add_handler('Type Generic') do |type,context|
16
- if !context[:response].code.start_with?('2')
15
+ @error_handlers = []
16
+ @log_file = nil
17
+ add_handler('Type Generic') do |type,call_context|
18
+ if !call_context[:response].code.start_with?('2')
17
19
  # add generic information
18
- RestErrorAnalyzer.add_error(context,type,"#{context[:request]['host']} #{context[:response].code} #{context[:response].message}")
20
+ RestErrorAnalyzer.add_error(call_context,type,"#{call_context[:request]['host']} #{call_context[:response].code} #{call_context[:response].message}")
19
21
  end
20
22
  end
21
23
  end
@@ -23,8 +25,8 @@ module Aspera
23
25
  # Use this method to analyze a EST result and raise an exception
24
26
  # Analyzes REST call response and raises a RestCallError exception
25
27
  # if HTTP result code is not 2XX
26
- def raiseOnError(req,res)
27
- context={
28
+ def raise_on_error(req,res)
29
+ call_context = {
28
30
  messages: [],
29
31
  request: req,
30
32
  response: res[:http],
@@ -36,21 +38,19 @@ module Aspera
36
38
  @error_handlers.each do |handler|
37
39
  begin
38
40
  #Log.log.debug("test exception: #{handler[:name]}")
39
- handler[:block].call(handler[:name],context)
40
- rescue => e
41
+ handler[:block].call(handler[:name],call_context)
42
+ rescue StandardError => e
41
43
  Log.log.error("ERROR in handler:\n#{e.message}\n#{e.backtrace}")
42
44
  end
43
45
  end
44
- unless context[:messages].empty?
45
- raise RestCallError.new(context[:request],context[:response],context[:messages].join("\n"))
46
- end
46
+ raise RestCallError.new(call_context[:request],call_context[:response],call_context[:messages].join("\n")) unless call_context[:messages].empty?
47
47
  end
48
48
 
49
49
  # add a new error handler (done at application initialisation)
50
50
  # @param name : name of error handler (for logs)
51
- # @param block : processing of response: takes two parameters: name, context
51
+ # @param block : processing of response: takes two parameters: name, call_context
52
52
  # name is the one provided here
53
- # context is built in method raiseOnError
53
+ # call_context is built in method raise_on_error
54
54
  def add_handler(name,&block)
55
55
  @error_handlers.unshift({name: name, block: block})
56
56
  end
@@ -59,21 +59,21 @@ module Aspera
59
59
  # check that key exists and is string under specified path (hash)
60
60
  # adds other keys as secondary information
61
61
  def add_simple_handler(name,*args)
62
- add_handler(name) do |type,context|
62
+ add_handler(name) do |type,call_context|
63
63
  # need to clone because we modify and same array is used subsequently
64
- path=args.clone
64
+ path = args.clone
65
65
  #Log.log.debug("path=#{path}")
66
66
  # if last in path is boolean it tells if the error is only with http error code or always
67
- always=[true, false].include?(path.last) ? path.pop : false
68
- if context[:data].is_a?(Hash) and (!context[:response].code.start_with?('2') or always)
69
- msg_key=path.pop
67
+ always = [true, false].include?(path.last) ? path.pop : false
68
+ if call_context[:data].is_a?(Hash) && (!call_context[:response].code.start_with?('2') || always)
69
+ msg_key = path.pop
70
70
  # dig and find sub entry corresponding to path in deep hash
71
- error_struct=path.inject(context[:data]) { |subhash, key| subhash.respond_to?(:keys) ? subhash[key] : nil }
72
- if error_struct.is_a?(Hash) and error_struct[msg_key].is_a?(String)
73
- RestErrorAnalyzer.add_error(context,type,error_struct[msg_key])
71
+ error_struct = path.inject(call_context[:data]) { |subhash, key| subhash.respond_to?(:keys) ? subhash[key] : nil }
72
+ if error_struct.is_a?(Hash) && error_struct[msg_key].is_a?(String)
73
+ RestErrorAnalyzer.add_error(call_context,type,error_struct[msg_key])
74
74
  error_struct.each do |k,v|
75
75
  next if k.eql?(msg_key)
76
- RestErrorAnalyzer.add_error(context,"#{type}(sub)","#{k}: #{v}") if [String,Integer].include?(v.class)
76
+ RestErrorAnalyzer.add_error(call_context,"#{type}(sub)","#{k}: #{v}") if [String,Integer].include?(v.class)
77
77
  end
78
78
  end
79
79
  end
@@ -82,17 +82,17 @@ module Aspera
82
82
 
83
83
  # used by handler to add an error description to list of errors
84
84
  # for logging and tracing : collect error descriptions (create file to activate)
85
- # @param context a Hash containing the result context, provided to handler
85
+ # @param call_context a Hash containing the result call_context, provided to handler
86
86
  # @param type a string describing type of exception, for logging purpose
87
87
  # @param msg one error message to add to list
88
- def self.add_error(context,type,msg)
89
- context[:messages].push(msg)
90
- logfile=instance.log_file
88
+ def self.add_error(call_context,type,msg)
89
+ call_context[:messages].push(msg)
90
+ logfile = instance.log_file
91
91
  # log error for further analysis (file must exist to activate)
92
- if !logfile.nil? and File.exist?(logfile)
93
- File.open(logfile,'a+') do |f|
94
- f.write("\n=#{type}=====\n#{context[:request].method} #{context[:request].path}\n#{context[:response].code}\n#{JSON.generate(context[:data])}\n#{context[:messages].join("\n")}")
95
- end
92
+ return if logfile.nil? || !File.exist?(logfile)
93
+ File.open(logfile,'a+') do |f|
94
+ f.write("\n=#{type}=====\n#{call_context[:request].method} #{call_context[:request].path}\n#{call_context[:response].code}\n"\
95
+ "#{JSON.generate(call_context[:data])}\n#{call_context[:messages].join("\n")}")
96
96
  end
97
97
  end
98
98
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/rest_error_analyzer'
2
4
  require 'aspera/log'
3
5
 
@@ -5,8 +7,8 @@ module Aspera
5
7
  # REST error handlers for various Aspera REST APIs
6
8
  class RestErrorsAspera
7
9
  # handlers should probably be defined by plugins for modularity
8
- def self.registerHandlers
9
- Log.log.debug("registering Aspera REST error handlers")
10
+ def self.register_handlers
11
+ Log.log.debug('registering Aspera REST error handlers')
10
12
  # Faspex 4: both user_message and internal_message, and code 200
11
13
  # example: missing meta data on package creation
12
14
  RestErrorAnalyzer.instance.add_simple_handler('Type 1: error:user_message','error','user_message',true)
@@ -16,23 +18,23 @@ module Aspera
16
18
  RestErrorAnalyzer.instance.add_simple_handler('AoC Automation','error')
17
19
  RestErrorAnalyzer.instance.add_simple_handler('Type 5','error_description')
18
20
  RestErrorAnalyzer.instance.add_simple_handler('Type 6','message')
19
- RestErrorAnalyzer.instance.add_handler('Type 7: errors[]') do |name,context|
20
- if context[:data].is_a?(Hash) and context[:data]['errors'].is_a?(Hash)
21
- context[:data]['errors'].each do |k,v|
22
- RestErrorAnalyzer.add_error(context,name,"#{k}: #{v}")
21
+ RestErrorAnalyzer.instance.add_handler('Type 7: errors[]') do |name,call_context|
22
+ if call_context[:data].is_a?(Hash) && call_context[:data]['errors'].is_a?(Hash)
23
+ call_context[:data]['errors'].each do |k,v|
24
+ RestErrorAnalyzer.add_error(call_context,name,"#{k}: #{v}")
23
25
  end
24
26
  end
25
27
  end
26
28
  # call to upload_setup and download_setup of node api
27
- RestErrorAnalyzer.instance.add_handler('T8:node: *_setup') do |type,context|
28
- if context[:data].is_a?(Hash)
29
- d_t_s=context[:data]['transfer_specs']
29
+ RestErrorAnalyzer.instance.add_handler('T8:node: *_setup') do |type,call_context|
30
+ if call_context[:data].is_a?(Hash)
31
+ d_t_s = call_context[:data]['transfer_specs']
30
32
  if d_t_s.is_a?(Array)
31
33
  d_t_s.each do |res|
32
34
  #r_err=res['transfer_spec']['error']
33
- r_err=res['error']
35
+ r_err = res['error']
34
36
  if r_err.is_a?(Hash)
35
- RestErrorAnalyzer.add_error(context,type,"#{r_err['code']}: #{r_err['reason']}: #{r_err['user_message']}")
37
+ RestErrorAnalyzer.add_error(call_context,type,"#{r_err['code']}: #{r_err['reason']}: #{r_err['user_message']}")
36
38
  end
37
39
  end
38
40
  end
@@ -40,14 +42,14 @@ module Aspera
40
42
  end
41
43
  RestErrorAnalyzer.instance.add_simple_handler('T9:IBM cloud IAM','errorMessage')
42
44
  RestErrorAnalyzer.instance.add_simple_handler('T10:faspex v4','user_message')
43
- RestErrorAnalyzer.instance.add_handler('bss graphql') do |type,context|
44
- if context[:data].is_a?(Hash)
45
- d_t_s=context[:data]['errors']
45
+ RestErrorAnalyzer.instance.add_handler('bss graphql') do |type,call_context|
46
+ if call_context[:data].is_a?(Hash)
47
+ d_t_s = call_context[:data]['errors']
46
48
  if d_t_s.is_a?(Array)
47
49
  d_t_s.each do |res|
48
- r_err=res['message']
50
+ r_err = res['message']
49
51
  if r_err.is_a?(String)
50
- RestErrorAnalyzer.add_error(context,type,r_err)
52
+ RestErrorAnalyzer.add_error(call_context,type,r_err)
51
53
  end
52
54
  end
53
55
  end