aspera-cli 4.6.0 → 4.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +427 -300
  3. data/bin/ascli +2 -1
  4. data/bin/asession +1 -0
  5. data/docs/test_env.conf +2 -0
  6. data/examples/aoc.rb +4 -3
  7. data/examples/faspex4.rb +21 -19
  8. data/examples/proxy.pac +1 -1
  9. data/examples/transfer.rb +15 -15
  10. data/lib/aspera/aoc.rb +135 -124
  11. data/lib/aspera/ascmd.rb +85 -75
  12. data/lib/aspera/ats_api.rb +11 -10
  13. data/lib/aspera/cli/basic_auth_plugin.rb +13 -14
  14. data/lib/aspera/cli/extended_value.rb +42 -33
  15. data/lib/aspera/cli/formater.rb +138 -111
  16. data/lib/aspera/cli/info.rb +17 -0
  17. data/lib/aspera/cli/listener/line_dump.rb +3 -2
  18. data/lib/aspera/cli/listener/logger.rb +2 -1
  19. data/lib/aspera/cli/listener/progress.rb +16 -18
  20. data/lib/aspera/cli/listener/progress_multi.rb +13 -16
  21. data/lib/aspera/cli/main.rb +122 -130
  22. data/lib/aspera/cli/manager.rb +146 -154
  23. data/lib/aspera/cli/plugin.rb +38 -34
  24. data/lib/aspera/cli/plugins/alee.rb +6 -6
  25. data/lib/aspera/cli/plugins/aoc.rb +273 -276
  26. data/lib/aspera/cli/plugins/ats.rb +82 -76
  27. data/lib/aspera/cli/plugins/bss.rb +14 -16
  28. data/lib/aspera/cli/plugins/config.rb +350 -306
  29. data/lib/aspera/cli/plugins/console.rb +23 -19
  30. data/lib/aspera/cli/plugins/cos.rb +18 -18
  31. data/lib/aspera/cli/plugins/faspex.rb +180 -159
  32. data/lib/aspera/cli/plugins/faspex5.rb +64 -54
  33. data/lib/aspera/cli/plugins/node.rb +147 -140
  34. data/lib/aspera/cli/plugins/orchestrator.rb +68 -66
  35. data/lib/aspera/cli/plugins/preview.rb +92 -96
  36. data/lib/aspera/cli/plugins/server.rb +79 -75
  37. data/lib/aspera/cli/plugins/shares.rb +23 -24
  38. data/lib/aspera/cli/plugins/sync.rb +20 -22
  39. data/lib/aspera/cli/transfer_agent.rb +40 -39
  40. data/lib/aspera/cli/version.rb +2 -1
  41. data/lib/aspera/colors.rb +35 -27
  42. data/lib/aspera/command_line_builder.rb +48 -34
  43. data/lib/aspera/cos_node.rb +29 -21
  44. data/lib/aspera/data_repository.rb +3 -2
  45. data/lib/aspera/environment.rb +50 -45
  46. data/lib/aspera/fasp/agent_base.rb +22 -20
  47. data/lib/aspera/fasp/agent_connect.rb +13 -11
  48. data/lib/aspera/fasp/agent_direct.rb +48 -59
  49. data/lib/aspera/fasp/agent_httpgw.rb +33 -39
  50. data/lib/aspera/fasp/agent_node.rb +15 -13
  51. data/lib/aspera/fasp/agent_trsdk.rb +12 -14
  52. data/lib/aspera/fasp/error.rb +2 -1
  53. data/lib/aspera/fasp/error_info.rb +68 -52
  54. data/lib/aspera/fasp/installation.rb +106 -94
  55. data/lib/aspera/fasp/listener.rb +1 -0
  56. data/lib/aspera/fasp/parameters.rb +83 -92
  57. data/lib/aspera/fasp/parameters.yaml +305 -249
  58. data/lib/aspera/fasp/resume_policy.rb +11 -14
  59. data/lib/aspera/fasp/transfer_spec.rb +26 -0
  60. data/lib/aspera/fasp/uri.rb +22 -21
  61. data/lib/aspera/faspex_gw.rb +55 -90
  62. data/lib/aspera/hash_ext.rb +4 -3
  63. data/lib/aspera/id_generator.rb +8 -7
  64. data/lib/aspera/keychain/encrypted_hash.rb +17 -16
  65. data/lib/aspera/keychain/macos_security.rb +6 -10
  66. data/lib/aspera/log.rb +25 -20
  67. data/lib/aspera/nagios.rb +13 -12
  68. data/lib/aspera/node.rb +30 -22
  69. data/lib/aspera/oauth.rb +175 -226
  70. data/lib/aspera/open_application.rb +4 -3
  71. data/lib/aspera/persistency_action_once.rb +6 -6
  72. data/lib/aspera/persistency_folder.rb +5 -9
  73. data/lib/aspera/preview/file_types.rb +6 -5
  74. data/lib/aspera/preview/generator.rb +25 -24
  75. data/lib/aspera/preview/options.rb +16 -14
  76. data/lib/aspera/preview/utils.rb +98 -98
  77. data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
  78. data/lib/aspera/proxy_auto_config.rb +111 -20
  79. data/lib/aspera/rest.rb +115 -113
  80. data/lib/aspera/rest_call_error.rb +2 -2
  81. data/lib/aspera/rest_error_analyzer.rb +23 -25
  82. data/lib/aspera/rest_errors_aspera.rb +15 -14
  83. data/lib/aspera/ssh.rb +12 -10
  84. data/lib/aspera/sync.rb +42 -41
  85. data/lib/aspera/temp_file_manager.rb +18 -14
  86. data/lib/aspera/timer_limiter.rb +2 -1
  87. data/lib/aspera/uri_reader.rb +7 -5
  88. data/lib/aspera/web_auth.rb +79 -76
  89. metadata +64 -21
  90. data/docs/Makefile +0 -65
  91. data/docs/README.erb.md +0 -4424
  92. data/docs/README.md +0 -13
  93. data/docs/diagrams.txt +0 -49
  94. data/docs/doc_tools.rb +0 -58
  95. data/lib/aspera/cli/plugins/shares2.rb +0 -114
  96. data/lib/aspera/fasp/default.rb +0 -17
@@ -1,34 +1,125 @@
1
+ # frozen_string_literal: true
1
2
  require 'uri'
2
3
  require 'resolv'
3
- require 'erb'
4
+
5
+ module URI
6
+ class Generic
7
+ # save original method that finds proxy in URI::Generic, it uses env var http_proxy
8
+ alias :find_proxy_orig find_proxy
9
+ def self.register_proxy_finder(&block)
10
+ # overload the method
11
+ define_method(:find_proxy) {|envars=ENV| block.call(to_s) || find_proxy_orig(envars)}
12
+ end
13
+ end
14
+ end
4
15
 
5
16
  module Aspera
6
- # evaluate a proxy autoconfig script
17
+ # Evaluate a proxy autoconfig script
7
18
  class ProxyAutoConfig
8
19
  # template file is read once, it contains functions that can be used in a proxy autoconf script
9
- PAC_FUNC_TEMPLATE=File.read(__FILE__.gsub(/\.rb$/,'.erb.js'))
10
- private_constant :PAC_FUNC_TEMPLATE
11
- # @param proxy_auto_config the proxy auto config script to be evaluated
12
- def initialize(proxy_auto_config)
13
- @proxy_auto_config=proxy_auto_config
14
- end
20
+ # it is similar to mozilla ascii_pac_utils.inc
21
+ PAC_FUNCTIONS_FILE=__FILE__.gsub(/\.rb$/,'.js').freeze
22
+ PAC_MAIN_FUNCTION='FindProxyForURL'
23
+ private_constant :PAC_FUNCTIONS_FILE,:PAC_MAIN_FUNCTION
24
+
25
+ private
15
26
 
16
- # execut proxy auto config script for the given URL
17
- def get_proxy(service_url)
18
- # require at runtime, in case there is no js engine
19
- require 'execjs'
20
- # variables starting with "context_" are replaced in the ERB template file
21
- # I did not find an easy way for the javascript to callback ruby
22
- # and anyway, it only needs to get DNS translation
27
+ # variables starting with "context_" are replaced in the ERB template file
28
+ # I did not find an easy way for the javascript to callback ruby
29
+ # and anyway, it only needs to get DNS translation
30
+ def pac_dns_functions(context_host)
23
31
  context_self='127.0.0.1'
24
- context_host=URI.parse(service_url).host
25
32
  context_ip=nil
26
33
  Resolv::DNS.open{|dns|dns.each_address(context_host){|r_addr|context_ip=r_addr.to_s if r_addr.is_a?(Resolv::IPv4)}}
27
34
  raise "DNS name not found: #{context_host}" if context_ip.nil?
28
- pac_functions=ERB.new(PAC_FUNC_TEMPLATE).result(binding)
29
- context = ExecJS.compile(pac_functions+@proxy_auto_config)
30
- return context.call("FindProxyForURL", service_url, context_host)
35
+ # NOTE: Javascript code here with string inclusions
36
+ javascript=<<END_OF_JAVASCRIPT
37
+ function dnsResolve(host) {
38
+ if (host == '#{context_host}' || host == '#{context_ip}')
39
+ return '#{context_ip}';
40
+ throw 'only DNS for initial host, not ' + host;
41
+ }
42
+ function myIpAddress() {
43
+ return '#{context_self}';
44
+ }
45
+ END_OF_JAVASCRIPT
46
+ return javascript
47
+ end
48
+
49
+ public
50
+
51
+ # @param proxy_auto_config the proxy auto config script to be evaluated
52
+ def initialize(proxy_auto_config)
53
+ # user provided javascript with FindProxyForURL function
54
+ @proxy_auto_config=proxy_auto_config
55
+ # avoid multiple execution, this does not support load balancing
56
+ @cache={}
57
+ @pac_functions=nil
58
+ end
59
+
60
+ def register_uri_generic
61
+ URI::Generic.register_proxy_finder{|url_str|get_proxies(url_str).first}
62
+ # allow chaining
63
+ return self
64
+ end
65
+
66
+ # execute proxy auto config script for the given URL : https://en.wikipedia.org/wiki/Proxy_auto-config
67
+ # @return either nil, or a String formated following PAC standard
68
+ def find_proxy_for_url(service_url)
69
+ uri=URI.parse(service_url)
70
+ simple_url="#{uri.scheme}://#{uri.host}"
71
+ if !@cache.has_key?(simple_url)
72
+ Log.log.debug("PAC: starting javascript for #{service_url}")
73
+ # require at runtime, in case there is no js engine
74
+ require 'execjs'
75
+ # read template lib
76
+ @pac_functions=File.read(PAC_FUNCTIONS_FILE).freeze if @pac_functions.nil?
77
+ # to be executed is dns + utils + user function
78
+ js_to_execute="#{pac_dns_functions(uri.host)}#{@pac_functions}#{@proxy_auto_config}"
79
+ executable_js = ExecJS.compile(js_to_execute)
80
+ @cache[simple_url]=executable_js.call(PAC_MAIN_FUNCTION, simple_url, uri.host)
81
+ Log.log.debug("PAC: result: #{@cache[simple_url]}")
82
+ end
83
+ return @cache[simple_url]
84
+ end
85
+
86
+ # used to replace URI::Generic.find_proxy
87
+ # @return Array of URI, possibly empty
88
+ def get_proxies(service_url)
89
+ # prepare result
90
+ uri_list=[]
91
+ # execute PAC script
92
+ proxy_list_str=find_proxy_for_url(service_url)
93
+ if !proxy_list_str.is_a?(String)
94
+ Log.log.warn("PAC: did not return a String, returned #{proxy_list_str.class}")
95
+ return uri_list
96
+ end
97
+ proxy_list_str.strip!
98
+ proxy_list_str.gsub!(/\s+/,' ')
99
+ proxy_list_str.split(';').each do |item|
100
+ # strip and split by space
101
+ parts=item.strip.split
102
+ case parts.shift
103
+ when 'DIRECT'
104
+ raise 'DIRECT has no param' unless parts.empty?
105
+ when 'PROXY'
106
+ addr_port=parts.shift
107
+ raise 'PROXY shall have one param' unless addr_port.is_a?(String) && parts.empty?
108
+ begin
109
+ # PAC proxy addresses are <host>:<port>
110
+ if addr_port.match(/:[0-9]+$/)
111
+ # we want to return URIs, so add dummy scheme
112
+ uri_list.push(URI.parse("proxy://#{addr_port}"))
113
+ else
114
+ Log.log.warn("PAC: PROXY must be <address>:<port>, ignoring #{addr_port}")
115
+ end
116
+ rescue StandardError
117
+ Log.log.warn("PAC: cannot parse #{addr_port}")
118
+ end
119
+ else Log.log.warn("PAC: ignoring proxy type #{parts.first}: not supported")
120
+ end
121
+ end
122
+ return uri_list
31
123
  end
32
124
  end
33
125
  end
34
-
data/lib/aspera/rest.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'aspera/log'
2
3
  require 'aspera/oauth'
3
4
  require 'aspera/rest_error_analyzer'
@@ -28,58 +29,52 @@ module Aspera
28
29
  # rest call errors are raised as exception RestCallError
29
30
  # and error are analyzed in RestErrorAnalyzer
30
31
  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
45
-
46
- def self.insecure=(v); @@insecure=v;Log.log.debug("insecure => #{@@insecure}".red);end
32
+ # global settings also valid for any subclass
33
+ @@global={ # rubocop:disable Style/ClassVars
34
+ debug: false,
35
+ # true if https ignore certificate
36
+ insecure: false,
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
+ }
47
42
 
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)' unless ['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
@@ -91,10 +86,10 @@ module Aspera
91
86
  # this honors http_proxy env var
92
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
89
+ @http_session.verify_mode = OpenSSL::SSL::VERIFY_NONE if self.class.insecure
90
+ @http_session.set_debug_output($stdout) if self.class.debug
96
91
  # set http options in callback, such as timeout and cert. verification
97
- @@session_cb.call(@http_session) unless @@session_cb.nil?
92
+ self.class.session_cb.call(@http_session) unless self.class.session_cb.nil?
98
93
  # manually start session for keep alive (if supported by server, else, session is closed every time)
99
94
  @http_session.start
100
95
  end
@@ -104,32 +99,34 @@ module Aspera
104
99
  public
105
100
 
106
101
  attr_reader :params
107
- attr_reader :oauth
108
102
 
109
- # @param a_rest_params default call parameters (merged at call) and (+) authentication (:auth) :
110
- # :type (:basic, :oauth2, :url, :none)
111
- # :username [:basic]
112
- # :password [:basic]
113
- # :url_creds [:url]
114
- # :* [:oauth2] see Oauth class
103
+ def oauth
104
+ if @oauth.nil?
105
+ raise 'ERROR: no OAuth defined' unless @params[:auth][:type].eql?(:oauth2)
106
+ @oauth=Oauth.new(@params[:auth])
107
+ end
108
+ return @oauth
109
+ end
110
+
111
+ # @param a_rest_params [Hash] default call parameters (merged at call)
115
112
  def initialize(a_rest_params)
116
- raise "ERROR: expecting Hash" unless a_rest_params.is_a?(Hash)
117
- raise "ERROR: expecting base_url" unless a_rest_params[:base_url].is_a?(String)
113
+ raise 'ERROR: expecting Hash' unless a_rest_params.is_a?(Hash)
114
+ raise 'ERROR: expecting base_url' unless a_rest_params[:base_url].is_a?(String)
118
115
  @params=a_rest_params.clone
119
116
  Log.dump('REST params',@params)
120
117
  # base url without trailing slashes (note: string may be frozen)
121
118
  @params[:base_url]=@params[:base_url].gsub(/\/+$/,'')
122
119
  @http_session=nil
123
120
  # default is no auth
124
- @params[:auth]||={:type=>:none}
121
+ @params[:auth]||={type: :none}
125
122
  @params[:not_auth_codes]||=['401']
126
- @oauth=Oauth.new(@params[:auth]) if @params[:auth][:type].eql?(:oauth2)
123
+ @oauth=nil
127
124
  Log.dump('REST params(2)',@params)
128
125
  end
129
126
 
130
- def oauth_token(options={})
131
- raise "ERROR: expecting Oauth, have #{@oauth.class}" unless @oauth.is_a?(Oauth)
132
- return @oauth.get_authorization(options)
127
+ def oauth_token(force_refresh: false)
128
+ raise "ERROR: expecting boolean, have #{force_refresh}" unless [true,false].include?(force_refresh)
129
+ return oauth.get_authorization(use_refresh_token: force_refresh)
133
130
  end
134
131
 
135
132
  def build_request(call_data)
@@ -139,28 +136,28 @@ module Aspera
139
136
  Log.log.debug("URI=#{uri}")
140
137
  begin
141
138
  # instanciate request object based on string name
142
- req=Object::const_get('Net::HTTP::'+call_data[:operation].capitalize).new(uri)#.request_uri
143
- rescue NameError => e
139
+ req=Net::HTTP.const_get(call_data[:operation].capitalize).new(uri)
140
+ rescue NameError
144
141
  raise "unsupported operation : #{call_data[:operation]}"
145
142
  end
146
- if call_data.has_key?(:json_params) and !call_data[:json_params].nil? then
143
+ if call_data.has_key?(:json_params) && !call_data[:json_params].nil?
147
144
  req.body=JSON.generate(call_data[:json_params])
148
145
  Log.dump('body JSON data',call_data[:json_params])
149
146
  #Log.log.debug("body JSON data=#{JSON.pretty_generate(call_data[:json_params])}")
150
147
  req['Content-Type'] = 'application/json'
151
148
  #call_data[:headers]['Accept']='application/json'
152
149
  end
153
- if call_data.has_key?(:www_body_params) then
150
+ if call_data.has_key?(:www_body_params)
154
151
  req.body=URI.encode_www_form(call_data[:www_body_params])
155
152
  Log.log.debug("body www data=#{req.body.chomp}")
156
153
  req['Content-Type'] = 'application/x-www-form-urlencoded'
157
154
  end
158
- if call_data.has_key?(:text_body_params) then
155
+ if call_data.has_key?(:text_body_params)
159
156
  req.body=call_data[:text_body_params]
160
157
  Log.log.debug("body data=#{req.body.chomp}")
161
158
  end
162
159
  # set headers
163
- if call_data.has_key?(:headers) then
160
+ if call_data.has_key?(:headers)
164
161
  call_data[:headers].keys.each do |key|
165
162
  req[key] = call_data[:headers][key]
166
163
  end
@@ -180,22 +177,30 @@ module Aspera
180
177
  # :url_params
181
178
  # :www_body_params
182
179
  # :text_body_params
183
- # :save_to_file (filepath)
184
- # :return_error (bool)
185
- # :redirect_max (int)
180
+ # :save_to_file (filepath) default: nil
181
+ # :return_error (bool) default: nil
182
+ # :redirect_max (int) default: 0
183
+ # :not_auth_codes (array)
184
+ # ----
185
+ # authentication (:auth) :
186
+ # :type (:none, :basic, :oauth2, :url)
187
+ # :username [:basic]
188
+ # :password [:basic]
189
+ # :url_creds [:url] a hash
190
+ # :* [:oauth2] see Oauth class
186
191
  def call(call_data)
187
192
  raise "Hash call parameter is required (#{call_data.class})" unless call_data.is_a?(Hash)
188
193
  call_data[:subpath]='' if call_data[:subpath].nil?
189
194
  Log.log.debug("accessing #{call_data[:subpath]}".red.bold.bg_green)
190
195
  call_data[:headers]||={}
191
- call_data[:headers]['User-Agent'] ||= @@user_agent
196
+ call_data[:headers]['User-Agent'] ||= self.class.user_agent
192
197
  # defaults from @params are overriden by call data
193
198
  call_data=@params.deep_merge(call_data)
194
199
  case call_data[:auth][:type]
195
200
  when :none
196
201
  # no auth
197
202
  when :basic
198
- Log.log.debug("using Basic auth")
203
+ Log.log.debug('using Basic auth')
199
204
  # done in build_req
200
205
  when :oauth2
201
206
  call_data[:headers]['Authorization']=oauth_token unless call_data[:headers].has_key?('Authorization')
@@ -208,31 +213,31 @@ module Aspera
208
213
  end
209
214
  req=build_request(call_data)
210
215
  Log.log.debug("call_data = #{call_data}")
211
- result={:http=>nil}
216
+ result={http: nil}
212
217
  # start a block to be able to retry the actual HTTP request
213
218
  begin
214
219
  # we try the call, and will retry only if oauth, as we can, first with refresh, and then re-auth if refresh is bad
215
220
  oauth_tries ||= 2
216
221
  tries_remain_redirect||=call_data[:redirect_max].nil? ? 0 : call_data[:redirect_max].to_i
217
- Log.log.debug("send request")
222
+ Log.log.debug('send request')
218
223
  # make http request (pipelined)
219
224
  http_session.request(req) do |response|
220
225
  result[:http] = response
221
- if call_data.has_key?(:save_to_file) and result[:http].code.to_s.start_with?('2')
226
+ if !call_data[:save_to_file].nil? && result[:http].code.to_s.start_with?('2')
222
227
  total_size=result[:http]['Content-Length'].to_i
223
228
  progress=ProgressBar.create(
224
- :format => '%a %B %p%% %r KB/sec %e',
225
- :rate_scale => lambda{|rate|rate/1024},
226
- :title => 'progress',
227
- :total => total_size)
228
- Log.log.debug("before write file")
229
+ format: '%a %B %p%% %r KB/sec %e',
230
+ rate_scale: lambda{|rate|rate/1024},
231
+ title: 'progress',
232
+ total: total_size)
233
+ Log.log.debug('before write file')
229
234
  target_file=call_data[:save_to_file]
230
235
  # override user's path to path in header
231
- if !response['Content-Disposition'].nil? and m=response['Content-Disposition'].match(/filename="([^"]+)"/)
236
+ if !response['Content-Disposition'].nil? && (m=response['Content-Disposition'].match(/filename="([^"]+)"/))
232
237
  target_file=File.join(File.dirname(target_file),m[1])
233
238
  end
234
239
  # download with temp filename
235
- target_file_tmp="#{target_file}#{@@download_partial_suffix}"
240
+ target_file_tmp="#{target_file}#{self.class.download_partial_suffix}"
236
241
  Log.log.debug("saving to: #{target_file}")
237
242
  File.open(target_file_tmp, 'wb') do |file|
238
243
  result[:http].read_body do |fragment|
@@ -248,26 +253,26 @@ module Aspera
248
253
  end # save_to_file
249
254
  end
250
255
  # sometimes there is a UTF8 char (e.g. (c) )
251
- result[:http].body.force_encoding("UTF-8") if result[:http].body.is_a?(String)
256
+ result[:http].body.force_encoding('UTF-8') if result[:http].body.is_a?(String)
252
257
  Log.log.debug("result: body=#{result[:http].body}")
253
258
  result_mime=(result[:http]['Content-Type']||'text/plain').split(';').first
254
- case result_mime
259
+ result[:data]=case result_mime
255
260
  when 'application/json','application/vnd.api+json'
256
- result[:data]=JSON.parse(result[:http].body) rescue nil
261
+ JSON.parse(result[:http].body) rescue nil
257
262
  else #when 'text/plain'
258
- result[:data]=result[:http].body
263
+ result[:http].body
259
264
  end
260
265
  Log.dump("result: parsed: #{result_mime}",result[:data])
261
266
  Log.log.debug("result: code=#{result[:http].code}")
262
- RestErrorAnalyzer.instance.raiseOnError(req,result)
267
+ RestErrorAnalyzer.instance.raise_on_error(req,result)
263
268
  rescue RestCallError => e
264
269
  # not authorized: oauth token expired
265
- if @params[:not_auth_codes].include?(result[:http].code.to_s) and call_data[:auth][:type].eql?(:oauth2)
270
+ if call_data[:not_auth_codes].include?(result[:http].code.to_s) && call_data[:auth][:type].eql?(:oauth2)
266
271
  begin
267
272
  # try to use refresh token
268
- req['Authorization']=oauth_token(refresh: true)
273
+ req['Authorization']=oauth_token(force_refresh: true)
269
274
  rescue RestCallError => e
270
- Log.log.error("refresh failed".bg_red)
275
+ Log.log.error('refresh failed'.bg_red)
271
276
  # regenerate a brand new token
272
277
  req['Authorization']=oauth_token
273
278
  end
@@ -275,27 +280,24 @@ module Aspera
275
280
  retry unless (oauth_tries -= 1).zero?
276
281
  end # if oauth
277
282
  # moved ?
278
- if e.response.is_a?(Net::HTTPRedirection)
279
- if tries_remain_redirect > 0
280
- tries_remain_redirect-=1
281
- Log.log.info("URL is moved: #{e.response['location']}")
282
- current_uri=URI.parse(call_data[:base_url])
283
- redir_uri=URI.parse(e.response['location'])
284
- call_data[:base_url]=e.response['location']
285
- call_data[:subpath]=''
286
- if current_uri.host.eql?(redir_uri.host) and current_uri.port.eql?(redir_uri.port)
287
- req=build_request(call_data)
288
- retry
289
- else
290
- # change host
291
- Log.log.info("Redirect changes host: #{current_uri.host} -> #{redir_uri.host}")
292
- return self.class.new(call_data).call(call_data)
293
- end
283
+ raise e unless e.response.is_a?(Net::HTTPRedirection)
284
+ if tries_remain_redirect.positive?
285
+ tries_remain_redirect-=1
286
+ Log.log.info("URL is moved: #{e.response['location']}")
287
+ current_uri=URI.parse(call_data[:base_url])
288
+ redir_uri=URI.parse(e.response['location'])
289
+ call_data[:base_url]=e.response['location']
290
+ call_data[:subpath]=''
291
+ if current_uri.host.eql?(redir_uri.host) && current_uri.port.eql?(redir_uri.port)
292
+ req=build_request(call_data)
293
+ retry
294
294
  else
295
- raise "too many redirect"
295
+ # change host
296
+ Log.log.info("Redirect changes host: #{current_uri.host} -> #{redir_uri.host}")
297
+ return self.class.new(call_data).call(call_data)
296
298
  end
297
299
  else
298
- raise e
300
+ raise e unless call_data[:return_error]
299
301
  end
300
302
  # raise exception if could not retry and not return error in result
301
303
  raise e unless call_data[:return_error]
@@ -310,23 +312,23 @@ module Aspera
310
312
 
311
313
  # @param encoding : one of: :json_params, :url_params
312
314
  def create(subpath,params,encoding=:json_params)
313
- return call({:operation=>'POST',:subpath=>subpath,:headers=>{'Accept'=>'application/json'},encoding=>params})
315
+ return call({operation: 'POST',subpath: subpath,headers: {'Accept'=>'application/json'},encoding=>params})
314
316
  end
315
317
 
316
318
  def read(subpath,args=nil)
317
- return call({:operation=>'GET',:subpath=>subpath,:headers=>{'Accept'=>'application/json'},:url_params=>args})
319
+ return call({operation: 'GET',subpath: subpath,headers: {'Accept'=>'application/json'},url_params: args})
318
320
  end
319
321
 
320
322
  def update(subpath,params)
321
- return call({:operation=>'PUT',:subpath=>subpath,:headers=>{'Accept'=>'application/json'},:json_params=>params})
323
+ return call({operation: 'PUT',subpath: subpath,headers: {'Accept'=>'application/json'},json_params: params})
322
324
  end
323
325
 
324
326
  def delete(subpath)
325
- return call({:operation=>'DELETE',:subpath=>subpath,:headers=>{'Accept'=>'application/json'}})
327
+ return call({operation: 'DELETE',subpath: subpath,headers: {'Accept'=>'application/json'}})
326
328
  end
327
329
 
328
330
  def cancel(subpath)
329
- return call({:operation=>'CANCEL',:subpath=>subpath,:headers=>{'Accept'=>'application/json'}})
331
+ return call({operation: 'CANCEL',subpath: subpath,headers: {'Accept'=>'application/json'}})
330
332
  end
331
333
  end
332
334
  end #module Aspera
@@ -1,8 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module Aspera
2
3
  # raised on error after REST call
3
4
  class RestCallError < StandardError
4
- attr_accessor :request
5
- attr_accessor :response
5
+ attr_accessor :request, :response
6
6
  # @param http response
7
7
  def initialize(req,resp,msg)
8
8
  @request = req
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'aspera/log'
2
3
  require 'aspera/rest_call_error'
3
4
  require 'singleton'
@@ -12,10 +13,10 @@ module Aspera
12
13
  # list of handlers
13
14
  @error_handlers=[]
14
15
  @log_file=nil
15
- self.add_handler('Type Generic') do |type,context|
16
- if !context[:response].code.start_with?('2')
16
+ add_handler('Type Generic') do |type,call_context|
17
+ if !call_context[:response].code.start_with?('2')
17
18
  # add generic information
18
- RestErrorAnalyzer.add_error(context,type,"#{context[:request]['host']} #{context[:response].code} #{context[:response].message}")
19
+ RestErrorAnalyzer.add_error(call_context,type,"#{call_context[:request]['host']} #{call_context[:response].code} #{call_context[:response].message}")
19
20
  end
20
21
  end
21
22
  end
@@ -23,8 +24,8 @@ module Aspera
23
24
  # Use this method to analyze a EST result and raise an exception
24
25
  # Analyzes REST call response and raises a RestCallError exception
25
26
  # if HTTP result code is not 2XX
26
- def raiseOnError(req,res)
27
- context={
27
+ def raise_on_error(req,res)
28
+ call_context={
28
29
  messages: [],
29
30
  request: req,
30
31
  response: res[:http],
@@ -36,21 +37,19 @@ module Aspera
36
37
  @error_handlers.each do |handler|
37
38
  begin
38
39
  #Log.log.debug("test exception: #{handler[:name]}")
39
- handler[:block].call(handler[:name],context)
40
- rescue => e
40
+ handler[:block].call(handler[:name],call_context)
41
+ rescue StandardError => e
41
42
  Log.log.error("ERROR in handler:\n#{e.message}\n#{e.backtrace}")
42
43
  end
43
44
  end
44
- unless context[:messages].empty?
45
- raise RestCallError.new(context[:request],context[:response],context[:messages].join("\n"))
46
- end
45
+ raise RestCallError.new(call_context[:request],call_context[:response],call_context[:messages].join("\n")) unless call_context[:messages].empty?
47
46
  end
48
47
 
49
48
  # add a new error handler (done at application initialisation)
50
49
  # @param name : name of error handler (for logs)
51
- # @param block : processing of response: takes two parameters: name, context
50
+ # @param block : processing of response: takes two parameters: name, call_context
52
51
  # name is the one provided here
53
- # context is built in method raiseOnError
52
+ # call_context is built in method raise_on_error
54
53
  def add_handler(name,&block)
55
54
  @error_handlers.unshift({name: name, block: block})
56
55
  end
@@ -59,21 +58,21 @@ module Aspera
59
58
  # check that key exists and is string under specified path (hash)
60
59
  # adds other keys as secondary information
61
60
  def add_simple_handler(name,*args)
62
- add_handler(name) do |type,context|
61
+ add_handler(name) do |type,call_context|
63
62
  # need to clone because we modify and same array is used subsequently
64
63
  path=args.clone
65
64
  #Log.log.debug("path=#{path}")
66
65
  # if last in path is boolean it tells if the error is only with http error code or always
67
66
  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)
67
+ if call_context[:data].is_a?(Hash) && (!call_context[:response].code.start_with?('2') || always)
69
68
  msg_key=path.pop
70
69
  # 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])
70
+ error_struct=path.inject(call_context[:data]) { |subhash, key| subhash.respond_to?(:keys) ? subhash[key] : nil }
71
+ if error_struct.is_a?(Hash) && error_struct[msg_key].is_a?(String)
72
+ RestErrorAnalyzer.add_error(call_context,type,error_struct[msg_key])
74
73
  error_struct.each do |k,v|
75
74
  next if k.eql?(msg_key)
76
- RestErrorAnalyzer.add_error(context,"#{type}(sub)","#{k}: #{v}") if [String,Integer].include?(v.class)
75
+ RestErrorAnalyzer.add_error(call_context,"#{type}(sub)","#{k}: #{v}") if [String,Integer].include?(v.class)
77
76
  end
78
77
  end
79
78
  end
@@ -82,17 +81,16 @@ module Aspera
82
81
 
83
82
  # used by handler to add an error description to list of errors
84
83
  # for logging and tracing : collect error descriptions (create file to activate)
85
- # @param context a Hash containing the result context, provided to handler
84
+ # @param call_context a Hash containing the result call_context, provided to handler
86
85
  # @param type a string describing type of exception, for logging purpose
87
86
  # @param msg one error message to add to list
88
- def self.add_error(context,type,msg)
89
- context[:messages].push(msg)
87
+ def self.add_error(call_context,type,msg)
88
+ call_context[:messages].push(msg)
90
89
  logfile=instance.log_file
91
90
  # 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
91
+ return if logfile.nil? || !File.exist?(logfile)
92
+ File.open(logfile,'a+') do |f|
93
+ f.write("\n=#{type}=====\n#{call_context[:request].method} #{call_context[:request].path}\n#{call_context[:response].code}\n#{JSON.generate(call_context[:data])}\n#{call_context[:messages].join("\n")}")
96
94
  end
97
95
  end
98
96
  end