aspera-cli 4.19.0 → 4.20.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 (80) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +20 -0
  4. data/CONTRIBUTING.md +16 -4
  5. data/README.md +344 -164
  6. data/bin/asession +26 -19
  7. data/examples/build_exec +65 -76
  8. data/examples/build_exec_rubyc +40 -0
  9. data/examples/get_proto_file.rb +7 -0
  10. data/lib/aspera/agent/alpha.rb +8 -8
  11. data/lib/aspera/agent/base.rb +2 -18
  12. data/lib/aspera/agent/connect.rb +14 -13
  13. data/lib/aspera/agent/direct.rb +23 -24
  14. data/lib/aspera/agent/httpgw.rb +2 -3
  15. data/lib/aspera/agent/node.rb +10 -10
  16. data/lib/aspera/agent/trsdk.rb +17 -20
  17. data/lib/aspera/api/alee.rb +15 -0
  18. data/lib/aspera/api/aoc.rb +126 -97
  19. data/lib/aspera/api/ats.rb +1 -1
  20. data/lib/aspera/api/cos_node.rb +1 -1
  21. data/lib/aspera/api/httpgw.rb +15 -10
  22. data/lib/aspera/api/node.rb +33 -12
  23. data/lib/aspera/ascmd.rb +56 -48
  24. data/lib/aspera/ascp/installation.rb +99 -42
  25. data/lib/aspera/ascp/management.rb +3 -2
  26. data/lib/aspera/ascp/products.rb +12 -0
  27. data/lib/aspera/assert.rb +10 -5
  28. data/lib/aspera/cli/formatter.rb +27 -17
  29. data/lib/aspera/cli/hints.rb +2 -1
  30. data/lib/aspera/cli/info.rb +12 -10
  31. data/lib/aspera/cli/main.rb +16 -13
  32. data/lib/aspera/cli/manager.rb +5 -0
  33. data/lib/aspera/cli/plugin.rb +15 -29
  34. data/lib/aspera/cli/plugins/alee.rb +3 -3
  35. data/lib/aspera/cli/plugins/aoc.rb +222 -194
  36. data/lib/aspera/cli/plugins/ats.rb +16 -14
  37. data/lib/aspera/cli/plugins/config.rb +53 -45
  38. data/lib/aspera/cli/plugins/console.rb +3 -3
  39. data/lib/aspera/cli/plugins/faspex.rb +11 -21
  40. data/lib/aspera/cli/plugins/faspex5.rb +44 -42
  41. data/lib/aspera/cli/plugins/faspio.rb +2 -2
  42. data/lib/aspera/cli/plugins/httpgw.rb +1 -1
  43. data/lib/aspera/cli/plugins/node.rb +153 -95
  44. data/lib/aspera/cli/plugins/orchestrator.rb +14 -13
  45. data/lib/aspera/cli/plugins/preview.rb +8 -9
  46. data/lib/aspera/cli/plugins/server.rb +5 -9
  47. data/lib/aspera/cli/plugins/shares.rb +2 -2
  48. data/lib/aspera/cli/sync_actions.rb +2 -2
  49. data/lib/aspera/cli/transfer_agent.rb +12 -14
  50. data/lib/aspera/cli/transfer_progress.rb +35 -17
  51. data/lib/aspera/cli/version.rb +1 -1
  52. data/lib/aspera/command_line_builder.rb +3 -4
  53. data/lib/aspera/coverage.rb +13 -1
  54. data/lib/aspera/environment.rb +34 -18
  55. data/lib/aspera/faspex_gw.rb +2 -2
  56. data/lib/aspera/json_rpc.rb +1 -1
  57. data/lib/aspera/keychain/macos_security.rb +7 -12
  58. data/lib/aspera/log.rb +3 -4
  59. data/lib/aspera/oauth/base.rb +39 -45
  60. data/lib/aspera/oauth/factory.rb +11 -4
  61. data/lib/aspera/oauth/generic.rb +4 -8
  62. data/lib/aspera/oauth/jwt.rb +3 -3
  63. data/lib/aspera/oauth/url_json.rb +1 -2
  64. data/lib/aspera/oauth/web.rb +5 -2
  65. data/lib/aspera/persistency_action_once.rb +16 -8
  66. data/lib/aspera/preview/utils.rb +5 -16
  67. data/lib/aspera/rest.rb +100 -76
  68. data/lib/aspera/transfer/faux_file.rb +4 -4
  69. data/lib/aspera/transfer/parameters.rb +14 -16
  70. data/lib/aspera/transfer/spec.rb +12 -12
  71. data/lib/aspera/transfer/sync.rb +1 -5
  72. data/lib/aspera/transfer/uri.rb +1 -1
  73. data/lib/aspera/uri_reader.rb +1 -1
  74. data/lib/aspera/web_auth.rb +166 -17
  75. data/lib/aspera/web_server_simple.rb +4 -3
  76. data/lib/transfer_pb.rb +84 -0
  77. data/lib/transfer_services_pb.rb +82 -0
  78. data.tar.gz.sig +0 -0
  79. metadata +24 -5
  80. metadata.gz.sig +0 -0
data/lib/aspera/rest.rb CHANGED
@@ -11,6 +11,8 @@ require 'net/https'
11
11
  require 'json'
12
12
  require 'base64'
13
13
  require 'cgi'
14
+ require 'singleton'
15
+ require 'securerandom'
14
16
 
15
17
  # Cancel method for HTTP
16
18
  class Net::HTTP::Cancel < Net::HTTPRequest # rubocop:disable Style/ClassAndModuleChildren
@@ -20,22 +22,32 @@ class Net::HTTP::Cancel < Net::HTTPRequest # rubocop:disable Style/ClassAndModul
20
22
  end
21
23
 
22
24
  module Aspera
25
+ # Global settings
26
+ # @param user_agent [String] HTTP request header: 'User-Agent'
27
+ # @param download_partial_suffix [String] suffix for partial download
28
+ # @param session_cb [lambda] lambda called on new HTTP session. Takes the Net::HTTP as arg. Used to change parameters on creation.
29
+ # @param progress_bar [Object] progress bar object
30
+ class RestParameters
31
+ include Singleton
32
+
33
+ attr_accessor :user_agent, :download_partial_suffix, :retry_on_error, :retry_sleep, :session_cb, :progress_bar
34
+
35
+ private
36
+
37
+ def initialize
38
+ @user_agent = 'RubyAsperaRest'
39
+ @download_partial_suffix = '.http_partial'
40
+ @retry_on_error = 0
41
+ @retry_sleep = nil
42
+ @session_cb = nil
43
+ @progress_bar = nil
44
+ end
45
+ end
46
+
23
47
  # a simple class to make HTTP calls, equivalent to rest-client
24
48
  # rest call errors are raised as exception RestCallError
25
49
  # and error are analyzed in RestErrorAnalyzer
26
50
  class Rest
27
- # Global settings also valid for any subclass
28
- # @param user_agent [String] HTTP request header: 'User-Agent'
29
- # @param download_partial_suffix [String] suffix for partial download
30
- # @param session_cb [lambda] lambda called on new HTTP session. Takes the Net::HTTP as arg. Used to change parameters on creation.
31
- # @param progress_bar [Object] progress bar object
32
- @@global = { # rubocop:disable Style/ClassVars
33
- user_agent: 'RubyAsperaRest',
34
- download_partial_suffix: '.http_partial',
35
- session_cb: nil,
36
- progress_bar: nil
37
- }
38
-
39
51
  # flag for array parameters prefixed with []
40
52
  ARRAY_PARAMS = '[]'
41
53
 
@@ -61,37 +73,45 @@ module Aspera
61
73
  return values.first.eql?(ARRAY_PARAMS)
62
74
  end
63
75
 
64
- # Build URI from URL and parameters and check it is http or https, encode array [] parameters
65
- def build_uri(url, query_hash=nil)
76
+ # Build URI from URL and parameters and check it is http or https
77
+ # encode array [] parameters
78
+ # @param query [Hash,Array]
79
+ def build_uri(url, query=nil)
66
80
  uri = URI.parse(url)
67
81
  Aspera.assert(%w[http https].include?(uri.scheme)){"REST endpoint shall be http/s not #{uri.scheme}"}
68
- return uri if query_hash.nil?
69
- Log.log.debug{Log.dump('query', query_hash)}
70
- Aspera.assert_type(query_hash, Hash)
71
- return uri if query_hash.empty?
72
- query = []
73
- query_hash.each do |k, v|
74
- case v
75
- when Array
76
- # support array for query parameter, there is no standard. Either p[]=1&p[]=2, or p=1&p=2
77
- suffix = array_params?(v) ? v.shift : ''
78
- v.each do |e|
79
- query.push(["#{k}#{suffix}", e])
82
+ return uri if query.nil? || query.respond_to?(:empty?) && query.empty?
83
+ Log.log.debug{Log.dump('query', query)}
84
+ query_array = []
85
+ case query
86
+ when Hash
87
+ query.each do |k, v|
88
+ case v
89
+ when Array
90
+ # support array for query parameter, there is no standard. Either p[]=1&p[]=2, or p=1&p=2
91
+ suffix = array_params?(v) ? v.shift : ''
92
+ v.each do |e|
93
+ query_array.push(["#{k}#{suffix}", e])
94
+ end
95
+ else
96
+ query_array.push([k, v])
80
97
  end
81
- else
82
- query.push([k, v])
83
98
  end
99
+ when Array
100
+ Aspera.assert(query.all?{|i| i.is_a?(Array) && i.length.eql?(2)}) {'Query must be array of arrays or 2 elements'}
101
+ query_array = query
102
+ else
103
+ raise "Query must be Hash or Array, not #{query.class}"
84
104
  end
85
105
  # [] is allowed in url parameters
86
- uri.query = URI.encode_www_form(query).gsub('%5B%5D=', '[]=')
106
+ uri.query = URI.encode_www_form(query_array).gsub('%5B%5D=', '[]=')
87
107
  return uri
88
108
  end
89
109
 
90
- # decode query string as hash
110
+ # Decode query string as Hash
91
111
  # Does not support arrays in query string, no standard, e.g. PHP's way is p[]=1&p[]=2
92
- # @param query [String] query string
112
+ # @param query [String] query string as in URI.query
93
113
  # @return [Hash] decoded query
94
- def decode_query(query)
114
+ def query_to_h(query)
95
115
  URI.decode_www_form(query).each_with_object({}) do |pair, h|
96
116
  key = pair.first
97
117
  raise "Array not supported in query string: #{key}" if key.include?('[]') || h.key?(key)
@@ -108,7 +128,7 @@ module Aspera
108
128
  http_session = Net::HTTP.new(uri.host, uri.port)
109
129
  http_session.use_ssl = uri.scheme.eql?('https')
110
130
  # set http options in callback, such as timeout and cert. verification
111
- @@global[:session_cb]&.call(http_session)
131
+ RestParameters.instance.session_cb&.call(http_session)
112
132
  # manually start session for keep alive (if supported by server, else, session is closed every time)
113
133
  http_session.start
114
134
  return http_session
@@ -142,19 +162,6 @@ module Aspera
142
162
  return result
143
163
  end
144
164
 
145
- # set global parameters
146
- def set_parameters(**options)
147
- options.each do |key, value|
148
- Aspera.assert(@@global.key?(key)){"Unknown Rest option #{key}"}
149
- @@global[key] = value
150
- end
151
- end
152
-
153
- # @return [String] HTTP agent name
154
- def user_agent
155
- return @@global[:user_agent]
156
- end
157
-
158
165
  def parse_header(header)
159
166
  type, *params = header.split(/;\s*/)
160
167
  parameters = params.map do |param|
@@ -179,16 +186,17 @@ module Aspera
179
186
 
180
187
  public
181
188
 
182
- attr_reader :auth_params
183
189
  attr_reader :base_url
190
+ attr_reader :auth_params
184
191
 
192
+ # @return creation parameters
185
193
  def params
186
194
  return {
187
- base_url: @base_url,
188
- auth: @auth_params,
189
- not_auth_codes: @not_auth_codes,
190
- redirect_max: @redirect_max,
191
- headers: @headers
195
+ base_url: @base_url, # String
196
+ auth: @auth_params, # Hash
197
+ not_auth_codes: @not_auth_codes, # Array
198
+ redirect_max: @redirect_max, # Integer
199
+ headers: @headers # Hash
192
200
  }
193
201
  end
194
202
 
@@ -226,9 +234,10 @@ module Aspera
226
234
  # OAuth object (created on demand)
227
235
  @oauth = nil
228
236
  @redirect_max = redirect_max
237
+ Aspera.assert_type(@redirect_max, Integer)
229
238
  @headers = headers.nil? ? {} : headers
230
239
  Aspera.assert_type(@headers, Hash)
231
- @headers['User-Agent'] ||= @@global[:user_agent]
240
+ @headers['User-Agent'] ||= RestParameters.instance.user_agent
232
241
  end
233
242
 
234
243
  # @return the OAuth object (create, or cached if already created)
@@ -263,6 +272,8 @@ module Aspera
263
272
  )
264
273
  subpath = subpath.to_s if subpath.is_a?(Symbol)
265
274
  subpath = '' if subpath.nil?
275
+ Log.log.debug{"#{operation} [#{subpath}]".red.bold.bg_green}
276
+ Log.log.debug{Log.dump(:body, body)}
266
277
  Aspera.assert_type(subpath, String)
267
278
  if headers.nil?
268
279
  headers = @headers.clone
@@ -272,7 +283,6 @@ module Aspera
272
283
  headers.merge!(h)
273
284
  end
274
285
  Aspera.assert_type(headers, Hash)
275
- Log.log.debug{"#{operation} [#{subpath}]".red.bold.bg_green}
276
286
  case @auth_params[:type]
277
287
  when :none
278
288
  # no auth
@@ -322,11 +332,13 @@ module Aspera
322
332
  end
323
333
  # :type = :basic
324
334
  req.basic_auth(@auth_params[:username], @auth_params[:password]) if @auth_params[:type].eql?(:basic)
325
- Log.log.debug{Log.dump(:req_body, req.body)}
335
+ Log.log.trace1{Log.dump(:req_body, req.body)}
326
336
  # we try the call, and will retry only if oauth, as we can, first with refresh, and then re-auth if refresh is bad
327
337
  oauth_tries ||= 2
338
+ timeout_tries ||= 5
339
+ general_tries ||= 1 + RestParameters.instance.retry_on_error
328
340
  # initialize with number of initial retries allowed, nil gives zero
329
- tries_remain_redirect = @redirect_max.to_i if tries_remain_redirect.nil?
341
+ tries_remain_redirect = @redirect_max if tries_remain_redirect.nil?
330
342
  Log.log.debug("send request (retries=#{tries_remain_redirect})")
331
343
  result_mime = nil
332
344
  file_saved = false
@@ -350,38 +362,44 @@ module Aspera
350
362
  end
351
363
  end
352
364
  # download with temp filename
353
- target_file_tmp = "#{target_file}#{@@global[:download_partial_suffix]}"
365
+ target_file_tmp = "#{target_file}#{RestParameters.instance.download_partial_suffix}"
354
366
  Log.log.debug{"saving to: #{target_file}"}
355
367
  written_size = 0
356
- @@global[:progress_bar]&.event(session_id: 1, type: :session_start)
357
- @@global[:progress_bar]&.event(session_id: 1, type: :session_size, info: total_size)
368
+ session_id = SecureRandom.uuid.freeze
369
+ RestParameters.instance.progress_bar&.event(:session_start, session_id: session_id)
370
+ RestParameters.instance.progress_bar&.event(:session_size, session_id: session_id, info: total_size)
358
371
  File.open(target_file_tmp, 'wb') do |file|
359
372
  result[:http].read_body do |fragment|
360
373
  file.write(fragment)
361
374
  written_size += fragment.length
362
- @@global[:progress_bar]&.event(session_id: 1, type: :transfer, info: written_size)
375
+ RestParameters.instance.progress_bar&.event(:transfer, session_id: session_id, info: written_size)
363
376
  end
364
377
  end
365
- @@global[:progress_bar]&.event(session_id: 1, type: :end)
378
+ RestParameters.instance.progress_bar&.event(:end, session_id: session_id)
366
379
  # rename at the end
367
380
  File.rename(target_file_tmp, target_file)
368
381
  file_saved = true
369
382
  end
370
383
  end
384
+ Log.log.debug{"result: code=#{result[:http].code} mime=#{result_mime}"}
371
385
  # sometimes there is a UTF8 char (e.g. (c) ), TODO : related to mime type encoding ?
372
386
  # result[:http].body.force_encoding('UTF-8') if result[:http].body.is_a?(String)
373
387
  # Log.log.debug{"result: body=#{result[:http].body}"}
374
- result[:data] = case result_mime
388
+ case result_mime
375
389
  when *JSON_DECODE
376
- JSON.parse(result[:http].body) rescue result[:http].body
390
+ result[:data] = JSON.parse(result[:http].body) rescue result[:http].body
391
+ Log.log.debug{Log.dump('result_data', result[:data])}
377
392
  else # when 'text/plain'
378
- result[:http].body
393
+ result[:data] = result[:http].body
379
394
  end
380
- Log.log.debug{"result: code=#{result[:http].code} mime=#{result_mime}"}
381
- Log.log.debug{Log.dump('data', result[:data])}
382
395
  RestErrorAnalyzer.instance.raise_on_error(req, result)
383
- File.write(save_to_file, result[:http].body) unless file_saved || save_to_file.nil?
396
+ File.write(save_to_file, result[:http].body, binmode: true) unless file_saved || save_to_file.nil?
384
397
  rescue RestCallError => e
398
+ do_retry = false
399
+ # AoC have some timeout , like Connect to platform.bss.asperasoft.com:443 ...
400
+ do_retry = true if e.response.body.include?('failed: connect timed out') && (timeout_tries -= 1).positive?
401
+ # possibility to retry anything if it fails
402
+ do_retry = true if (general_tries -= 1).positive?
385
403
  # not authorized: oauth token expired
386
404
  if @not_auth_codes.include?(result[:http].code.to_s) && @auth_params[:type].eql?(:oauth2)
387
405
  begin
@@ -394,7 +412,11 @@ module Aspera
394
412
  req['Authorization'] = oauth.token(refresh: true)
395
413
  end
396
414
  Log.log.debug{"using new token=#{headers['Authorization']}"}
397
- retry if (oauth_tries -= 1).nonzero?
415
+ do_retry = true if (oauth_tries -= 1).positive?
416
+ end
417
+ if do_retry
418
+ sleep(RestParameters.instance.retry_sleep) unless RestParameters.instance.retry_sleep.nil?
419
+ retry
398
420
  end
399
421
  # redirect ? (any code beginning with 3)
400
422
  if e.response.is_a?(Net::HTTPRedirection) && tries_remain_redirect.positive?
@@ -420,27 +442,28 @@ module Aspera
420
442
  end
421
443
 
422
444
  #
423
- # CRUD methods here
445
+ # CRUD simplified methods here
446
+ # If specific elements are needed, then use the full `call` method
424
447
  #
425
448
 
426
449
  def create(subpath, params)
427
- return call(operation: 'POST', subpath: subpath, headers: {'Accept' => 'application/json'}, body: params, body_type: :json)
450
+ return call(operation: 'POST', subpath: subpath, headers: {'Accept' => 'application/json'}, body: params, body_type: :json)[:data]
428
451
  end
429
452
 
430
453
  def read(subpath, query=nil)
431
- return call(operation: 'GET', subpath: subpath, headers: {'Accept' => 'application/json'}, query: query)
454
+ return call(operation: 'GET', subpath: subpath, headers: {'Accept' => 'application/json'}, query: query)[:data]
432
455
  end
433
456
 
434
457
  def update(subpath, params)
435
- return call(operation: 'PUT', subpath: subpath, headers: {'Accept' => 'application/json'}, body: params, body_type: :json)
458
+ return call(operation: 'PUT', subpath: subpath, headers: {'Accept' => 'application/json'}, body: params, body_type: :json)[:data]
436
459
  end
437
460
 
438
461
  def delete(subpath, params=nil)
439
- return call(operation: 'DELETE', subpath: subpath, headers: {'Accept' => 'application/json'}, query: params)
462
+ return call(operation: 'DELETE', subpath: subpath, headers: {'Accept' => 'application/json'}, query: params)[:data]
440
463
  end
441
464
 
442
465
  def cancel(subpath)
443
- return call(operation: 'CANCEL', subpath: subpath, headers: {'Accept' => 'application/json'})
466
+ return call(operation: 'CANCEL', subpath: subpath, headers: {'Accept' => 'application/json'})[:data]
444
467
  end
445
468
 
446
469
  # Query entity by general search (read with parameter `q`)
@@ -449,9 +472,10 @@ module Aspera
449
472
  # @param search_name name of searched entity
450
473
  # @param query additional search query parameters
451
474
  # @returns [Hash] A single entity matching the search, or an exception if not found or multiple found
452
- def lookup_by_name(subpath, search_name, query={})
475
+ def lookup_by_name(subpath, search_name, query: nil)
476
+ query = {} if query.nil?
453
477
  # returns entities matching the query (it matches against several fields in case insensitive way)
454
- matching_items = read(subpath, query.merge({'q' => search_name}))[:data]
478
+ matching_items = read(subpath, query.merge({'q' => search_name}))
455
479
  # API style: {totalcount:, ...} cspell: disable-line
456
480
  matching_items = matching_items[subpath] if matching_items.is_a?(Hash)
457
481
  Aspera.assert_type(matching_items, Array)
@@ -13,16 +13,16 @@ module Aspera
13
13
  # @return nil if not a faux: scheme, else a FauxFile instance
14
14
  def create(name)
15
15
  return nil unless name.start_with?(PREFIX)
16
- url_parts = name[PREFIX.length..-1].split('?')
17
- raise 'Format: #{PREFIX}<file path>?<size>' unless url_parts.length.eql?(2)
18
- raise "Format: <integer>[#{SUFFIX.join(',')}]" unless (m = url_parts[1].downcase.match(/^(\d+)([#{SUFFIX.join('')}])$/))
16
+ name_params = name[PREFIX.length..-1].split('?', 2)
17
+ raise 'Format: #{PREFIX}<file path>?<size>' unless name_params.length.eql?(2)
18
+ raise "Format: <integer>[#{SUFFIX.join(',')}]" unless (m = name_params[1].downcase.match(/^(\d+)([#{SUFFIX.join('')}])$/))
19
19
  size = m[1].to_i
20
20
  suffix = m[2]
21
21
  SUFFIX.each do |s|
22
22
  size *= 1024
23
23
  break if s.eql?(suffix)
24
24
  end
25
- return FauxFile.new(url_parts[0], size)
25
+ return FauxFile.new(name_params[0], size)
26
26
  end
27
27
  end
28
28
  attr_reader :path, :size
@@ -29,10 +29,21 @@ module Aspera
29
29
  private_constant :SUPPORTED_AGENTS, :FILE_LIST_OPTIONS
30
30
 
31
31
  class << self
32
+ # temp file list files are created here
33
+ def file_list_folder=(value)
34
+ @file_list_folder = value
35
+ return if @file_list_folder.nil?
36
+
37
+ FileUtils.mkdir_p(@file_list_folder)
38
+ TempFileManager.instance.cleanup_expired(@file_list_folder)
39
+ end
40
+
32
41
  # Temp folder for file lists, must contain only file lists
33
42
  # because of garbage collection takes any file there
34
- # this could be refined, as , for instance, on macos, temp folder is already user specific
35
- @file_list_folder = TempFileManager.instance.new_file_path_global('asession_filelists') # cspell:disable-line
43
+ # this could be refined, as, for example, on macos, temp folder is already user specific
44
+ def file_list_folder
45
+ @file_list_folder ||= TempFileManager.instance.new_file_path_global('asession_filelists')
46
+ end
36
47
 
37
48
  # @param formatter [Cli::Formatter] formatter to use
38
49
  # @return a table suitable to display in manual
@@ -67,9 +78,7 @@ module Aspera
67
78
  else
68
79
  param[:d].eql?(tick_yes) ? '' : 'n/a'
69
80
  end
70
- if options.key?(:enum)
71
- param[:description] += "\nAllowed values: #{options[:enum].join(', ')}"
72
- end
81
+ param[:description] += "\nAllowed values: #{options[:enum].join(', ')}" if options.key?(:enum)
73
82
  # replace "solidus" HTML entity with its text value
74
83
  param[:description] = param[:description].gsub('&sol;', '\\')
75
84
  result.push(param)
@@ -91,17 +100,6 @@ module Aspera
91
100
  def ascp_args_file_list?(ascp_args)
92
101
  ascp_args&.any?{|i|FILE_LIST_OPTIONS.include?(i)}
93
102
  end
94
-
95
- # temp file list files are created here
96
- def file_list_folder=(value)
97
- @file_list_folder = value
98
- return if @file_list_folder.nil?
99
- FileUtils.mkdir_p(@file_list_folder)
100
- TempFileManager.instance.cleanup_expired(@file_list_folder)
101
- end
102
-
103
- # static methods
104
- attr_reader :file_list_folder
105
103
  end
106
104
 
107
105
  # @param options [Hash] key: :wss: bool, :ascp_args: array of strings
@@ -10,34 +10,30 @@ module Aspera
10
10
  class Spec
11
11
  # default transfer username for access key based transfers
12
12
  ACCESS_KEY_TRANSFER_USER = 'xfer'
13
+ # default ports for SSH and UDP
13
14
  SSH_PORT = 33_001
14
15
  UDP_PORT = 33_001
16
+ # base transfer spec for access keys
15
17
  AK_TSPEC_BASE = {
16
18
  'remote_user' => ACCESS_KEY_TRANSFER_USER,
17
19
  'ssh_port' => SSH_PORT,
18
20
  'fasp_port' => UDP_PORT
19
21
  }.freeze
20
- # fields for transport
21
- TRANSPORT_FIELDS = %w[remote_host remote_user ssh_port fasp_port wss_enabled wss_port].freeze
22
+ # fields for WSS
23
+ WSS_FIELDS = %w[wss_enabled wss_port].freeze
24
+ # all fields for transport
25
+ TRANSPORT_FIELDS = %w[remote_host remote_user ssh_port fasp_port].concat(WSS_FIELDS).freeze
22
26
  # reserved tag for Aspera
23
27
  TAG_RESERVED = 'aspera'
24
28
  class << self
25
29
  # translate upload/download to send/receive
26
30
  def transfer_type_to_direction(transfer_type)
27
- case transfer_type.to_sym
28
- when :upload then DIRECTION_SEND
29
- when :download then DIRECTION_RECEIVE
30
- else Aspera.error_unexpected_value(transfer_type.to_sym)
31
- end
31
+ XFER_TYPE_TO_DIR.fetch(transfer_type)
32
32
  end
33
33
 
34
34
  # translate send/receive to upload/download
35
35
  def direction_to_transfer_type(direction)
36
- case direction
37
- when DIRECTION_SEND then :upload
38
- when DIRECTION_RECEIVE then :download
39
- else Aspera.error_unexpected_value(direction)
40
- end
36
+ XFER_DIR_TO_TYPE.fetch(direction)
41
37
  end
42
38
  end
43
39
  DESCRIPTION = CommandLineBuilder.normalize_description(YAML.load_file("#{__FILE__[0..-3]}yaml"))
@@ -49,6 +45,10 @@ module Aspera
49
45
  const_set("#{name.to_s.upcase}_#{enum.upcase.gsub(/[^A-Z0-9]/, '_')}", enum.freeze)
50
46
  end
51
47
  end
48
+ # DIRECTION_* are read from yaml
49
+ XFER_TYPE_TO_DIR = {upload: DIRECTION_SEND, download: DIRECTION_RECEIVE}.freeze
50
+ XFER_DIR_TO_TYPE = XFER_TYPE_TO_DIR.invert.freeze
51
+ private_constant :XFER_TYPE_TO_DIR, :XFER_DIR_TO_TYPE
52
52
  end
53
53
  end
54
54
  end
@@ -266,11 +266,7 @@ module Aspera
266
266
  else
267
267
  raise 'At least one of `local` or `sessions` must be present in async parameters'
268
268
  end
269
- Environment.secure_spawn(env: {}, exec: ASYNC_ADMIN_EXECUTABLE, args: arguments, log_only: true)
270
- stdout, stderr, status = Open3.capture3(*[ASYNC_ADMIN_EXECUTABLE].concat(arguments))
271
- Log.log.debug{"status=#{status}, stderr=#{stderr}"}
272
- Log.log.trace1{"stdout=#{stdout}"}
273
- raise "Sync failed: #{status.exitstatus} : #{stderr}" unless status.success?
269
+ stdout = Environment.secure_capture(exec: ASYNC_ADMIN_EXECUTABLE, args: arguments)
274
270
  return parse_status(stdout)
275
271
  end
276
272
  end
@@ -26,7 +26,7 @@ module Aspera
26
26
  # faspex 4 does not encode trailing base64 padding, fix that to be able to decode properly
27
27
  fixed_query = @fasp_uri.query.gsub(/(=+)$/){|trail_equals|'%3D' * trail_equals.length}
28
28
 
29
- Rest.decode_query(fixed_query).each do |name, value|
29
+ Rest.query_to_h(fixed_query).each do |name, value|
30
30
  case name
31
31
  when 'cookie' then result_ts['cookie'] = value
32
32
  when 'token' then result_ts['token'] = value
@@ -12,7 +12,7 @@ module Aspera
12
12
  uri = URI.parse(uri_to_read)
13
13
  case uri.scheme
14
14
  when 'http', 'https'
15
- return Rest.new(base_url: uri_to_read, redirect_max: 5).call(operation: 'GET', subpath: '', headers: {'Accept' => 'text/plain'})[:data]
15
+ return Rest.new(base_url: uri_to_read, redirect_max: 5).call(operation: 'GET', headers: {'Accept' => '*/*'})[:data]
16
16
  when 'file', NilClass
17
17
  local_file_path = uri.path
18
18
  raise 'URL shall have a path, check syntax' if local_file_path.nil?