aspera-cli 4.15.0 → 4.17.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 (108) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +29 -3
  4. data/CHANGELOG.md +375 -280
  5. data/CONTRIBUTING.md +71 -18
  6. data/README.md +1978 -1656
  7. data/bin/ascli +13 -31
  8. data/bin/asession +32 -22
  9. data/examples/dascli +2 -2
  10. data/lib/aspera/agent/alpha.rb +117 -0
  11. data/lib/aspera/agent/base.rb +61 -0
  12. data/lib/aspera/{fasp/agent_connect.rb → agent/connect.rb} +13 -11
  13. data/lib/aspera/{fasp/agent_direct.rb → agent/direct.rb} +116 -116
  14. data/lib/aspera/{fasp/agent_httpgw.rb → agent/httpgw.rb} +21 -19
  15. data/lib/aspera/{fasp/agent_node.rb → agent/node.rb} +21 -33
  16. data/lib/aspera/agent/trsdk.rb +188 -0
  17. data/lib/aspera/api/aoc.rb +586 -0
  18. data/lib/aspera/api/ats.rb +46 -0
  19. data/lib/aspera/api/cos_node.rb +95 -0
  20. data/lib/aspera/api/node.rb +344 -0
  21. data/lib/aspera/ascmd.rb +47 -14
  22. data/lib/aspera/{fasp → ascp}/installation.rb +54 -15
  23. data/lib/aspera/{fasp → ascp}/management.rb +14 -14
  24. data/lib/aspera/{fasp → ascp}/products.rb +1 -1
  25. data/lib/aspera/assert.rb +45 -0
  26. data/lib/aspera/cli/basic_auth_plugin.rb +11 -10
  27. data/lib/aspera/cli/extended_value.rb +5 -5
  28. data/lib/aspera/cli/formatter.rb +27 -14
  29. data/lib/aspera/cli/hints.rb +7 -6
  30. data/lib/aspera/cli/main.rb +49 -29
  31. data/lib/aspera/cli/manager.rb +46 -36
  32. data/lib/aspera/cli/plugin.rb +34 -20
  33. data/lib/aspera/cli/plugin_factory.rb +61 -0
  34. data/lib/aspera/cli/plugins/alee.rb +7 -7
  35. data/lib/aspera/cli/plugins/aoc.rb +168 -132
  36. data/lib/aspera/cli/plugins/ats.rb +33 -33
  37. data/lib/aspera/cli/plugins/bss.rb +3 -4
  38. data/lib/aspera/cli/plugins/config.rb +250 -272
  39. data/lib/aspera/cli/plugins/console.rb +8 -6
  40. data/lib/aspera/cli/plugins/cos.rb +20 -19
  41. data/lib/aspera/cli/plugins/faspex.rb +71 -60
  42. data/lib/aspera/cli/plugins/faspex5.rb +212 -133
  43. data/lib/aspera/cli/plugins/node.rb +83 -75
  44. data/lib/aspera/cli/plugins/orchestrator.rb +36 -44
  45. data/lib/aspera/cli/plugins/preview.rb +33 -31
  46. data/lib/aspera/cli/plugins/server.rb +33 -32
  47. data/lib/aspera/cli/plugins/shares.rb +39 -33
  48. data/lib/aspera/cli/sync_actions.rb +9 -9
  49. data/lib/aspera/cli/transfer_agent.rb +45 -25
  50. data/lib/aspera/cli/transfer_progress.rb +2 -3
  51. data/lib/aspera/cli/version.rb +1 -1
  52. data/lib/aspera/colors.rb +5 -0
  53. data/lib/aspera/command_line_builder.rb +16 -14
  54. data/lib/aspera/coverage.rb +21 -0
  55. data/lib/aspera/data_repository.rb +33 -2
  56. data/lib/aspera/environment.rb +5 -4
  57. data/lib/aspera/faspex_gw.rb +13 -11
  58. data/lib/aspera/faspex_postproc.rb +6 -5
  59. data/lib/aspera/id_generator.rb +4 -2
  60. data/lib/aspera/json_rpc.rb +10 -8
  61. data/lib/aspera/keychain/encrypted_hash.rb +46 -11
  62. data/lib/aspera/keychain/macos_security.rb +29 -22
  63. data/lib/aspera/log.rb +5 -4
  64. data/lib/aspera/nagios.rb +7 -2
  65. data/lib/aspera/node_simulator.rb +213 -0
  66. data/lib/aspera/oauth/base.rb +143 -0
  67. data/lib/aspera/oauth/factory.rb +124 -0
  68. data/lib/aspera/oauth/generic.rb +34 -0
  69. data/lib/aspera/oauth/jwt.rb +51 -0
  70. data/lib/aspera/oauth/url_json.rb +31 -0
  71. data/lib/aspera/oauth/web.rb +50 -0
  72. data/lib/aspera/oauth.rb +5 -328
  73. data/lib/aspera/open_application.rb +7 -7
  74. data/lib/aspera/persistency_action_once.rb +13 -14
  75. data/lib/aspera/persistency_folder.rb +3 -2
  76. data/lib/aspera/preview/file_types.rb +53 -267
  77. data/lib/aspera/preview/generator.rb +7 -5
  78. data/lib/aspera/preview/terminal.rb +17 -7
  79. data/lib/aspera/preview/utils.rb +8 -7
  80. data/lib/aspera/proxy_auto_config.rb +6 -3
  81. data/lib/aspera/rest.rb +187 -140
  82. data/lib/aspera/rest_error_analyzer.rb +1 -0
  83. data/lib/aspera/rest_errors_aspera.rb +5 -3
  84. data/lib/aspera/resumer.rb +77 -0
  85. data/lib/aspera/secret_hider.rb +5 -2
  86. data/lib/aspera/ssh.rb +15 -8
  87. data/lib/aspera/temp_file_manager.rb +1 -1
  88. data/lib/aspera/{fasp → transfer}/error.rb +3 -3
  89. data/lib/aspera/{fasp → transfer}/error_info.rb +1 -1
  90. data/lib/aspera/{fasp → transfer}/faux_file.rb +1 -1
  91. data/lib/aspera/{fasp → transfer}/parameters.rb +95 -120
  92. data/lib/aspera/{fasp/transfer_spec.rb → transfer/spec.rb} +23 -19
  93. data/lib/aspera/{fasp/parameters.yaml → transfer/spec.yaml} +4 -99
  94. data/lib/aspera/transfer/sync.rb +273 -0
  95. data/lib/aspera/{fasp → transfer}/uri.rb +10 -9
  96. data/lib/aspera/web_server_simple.rb +12 -3
  97. data.tar.gz.sig +0 -0
  98. metadata +92 -68
  99. metadata.gz.sig +0 -0
  100. data/lib/aspera/aoc.rb +0 -606
  101. data/lib/aspera/ats_api.rb +0 -47
  102. data/lib/aspera/cos_node.rb +0 -93
  103. data/lib/aspera/fasp/agent_aspera.rb +0 -126
  104. data/lib/aspera/fasp/agent_base.rb +0 -48
  105. data/lib/aspera/fasp/agent_trsdk.rb +0 -146
  106. data/lib/aspera/fasp/resume_policy.rb +0 -77
  107. data/lib/aspera/node.rb +0 -338
  108. data/lib/aspera/sync.rb +0 -219
@@ -6,19 +6,19 @@ require 'aspera/nagios'
6
6
  module Aspera
7
7
  module Cli
8
8
  module Plugins
9
- class Console < Aspera::Cli::BasicAuthPlugin
9
+ class Console < Cli::BasicAuthPlugin
10
10
  STANDARD_PATH = '/aspera/console'
11
11
  class << self
12
12
  def detect(address_or_url)
13
13
  address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
14
14
  urls = [address_or_url]
15
15
  urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
16
-
16
+ error = nil
17
17
  urls.each do |base_url|
18
18
  next unless base_url.start_with?('https://')
19
19
  api = Rest.new(base_url: base_url, redirect_max: 2)
20
20
  test_endpoint = 'login'
21
- test_page = api.call({operation: 'GET', subpath: test_endpoint, url_params: {local: true}})
21
+ test_page = api.call(operation: 'GET', subpath: test_endpoint, url_params: {local: true})
22
22
  next unless test_page[:http].body.include?('Aspera Console')
23
23
  version = 'unknown'
24
24
  if (m = test_page[:http].body.match(/\(v([1-9]\..*)\)/))
@@ -30,8 +30,10 @@ module Aspera
30
30
  url: url[0..url.index(test_endpoint) - 2]
31
31
  }
32
32
  rescue StandardError => e
33
+ error = e
33
34
  Log.log.debug{"detect error: #{e}"}
34
35
  end
36
+ raise error if error
35
37
  return nil
36
38
  end
37
39
 
@@ -49,8 +51,8 @@ module Aspera
49
51
  end
50
52
  DEFAULT_FILTER_AGE_SECONDS = 3 * 3600
51
53
  private_constant :DEFAULT_FILTER_AGE_SECONDS
52
- def initialize(env)
53
- super(env)
54
+ def initialize(**env)
55
+ super
54
56
  time_now = Time.now
55
57
  options.declare(:filter_from, 'Only after date', values: :date, default: Manager.time_to_string(time_now - DEFAULT_FILTER_AGE_SECONDS))
56
58
  options.declare(:filter_to, 'Only before date', values: :date, default: Manager.time_to_string(time_now))
@@ -83,7 +85,7 @@ module Aspera
83
85
  when :submit
84
86
  smart_id = options.get_next_argument('smart_id')
85
87
  params = options.get_next_argument('transfer parameters')
86
- return {type: :object_list, data: api_console.create('smart_transfers/' + smart_id, params)[:data]}
88
+ return {type: :object_list, data: api_console.create("smart_transfers/#{smart_id}", params)[:data]}
87
89
  end
88
90
  when :current
89
91
  command = options.get_next_command([:list])
@@ -2,21 +2,22 @@
2
2
 
3
3
  require 'aspera/cli/plugin'
4
4
  require 'aspera/cli/plugins/node'
5
- require 'aspera/cos_node'
5
+ require 'aspera/api/cos_node'
6
+ require 'aspera/assert'
6
7
 
7
8
  module Aspera
8
9
  module Cli
9
10
  module Plugins
10
- class Cos < Aspera::Cli::Plugin
11
- def initialize(env)
12
- super(env)
11
+ class Cos < Cli::Plugin
12
+ def initialize(**env)
13
+ super
13
14
  options.declare(:bucket, 'Bucket name')
14
- options.declare(:endpoint, 'Storage endpoint url')
15
+ options.declare(:endpoint, 'Storage endpoint (URL)')
15
16
  options.declare(:apikey, 'Storage API key')
16
- options.declare(:crn, 'Resource instance id')
17
+ options.declare(:crn, 'Resource instance id (CRN)')
17
18
  options.declare(:service_credentials, 'IBM Cloud service credentials', types: Hash)
18
19
  options.declare(:region, 'Storage region')
19
- options.declare(:identity, "Authentication url (#{CosNode::IBM_CLOUD_TOKEN_URL})", default: CosNode::IBM_CLOUD_TOKEN_URL)
20
+ options.declare(:identity, "Authentication URL (#{Api::CosNode::IBM_CLOUD_TOKEN_URL})", default: Api::CosNode::IBM_CLOUD_TOKEN_URL)
20
21
  options.parse_options!
21
22
  end
22
23
 
@@ -26,23 +27,23 @@ module Aspera
26
27
  command = options.get_next_command(ACTIONS)
27
28
  case command
28
29
  when :node
29
- bucket_name = options.get_option(:bucket, mandatory: true)
30
30
  # get service credentials, Hash, e.g. @json:@file:...
31
31
  service_credentials = options.get_option(:service_credentials)
32
- storage_endpoint = options.get_option(:endpoint)
33
- raise Cli::BadArgument, 'one of: endpoint or service_credentials is required' if service_credentials.nil? && storage_endpoint.nil?
34
- raise Cli::BadArgument, 'endpoint and service_credentials are mutually exclusive' unless service_credentials.nil? || storage_endpoint.nil?
32
+ cos_node_params = {
33
+ auth_url: options.get_option(:identity, mandatory: true),
34
+ bucket: options.get_option(:bucket, mandatory: true),
35
+ endpoint: options.get_option(:endpoint)
36
+ }
35
37
  if service_credentials.nil?
36
- service_api_key = options.get_option(:apikey, mandatory: true)
37
- instance_id = options.get_option(:crn, mandatory: true)
38
+ Aspera.assert(!cos_node_params[:endpoint].nil?, exception_class: Cli::BadArgument){'endpoint required when service credentials not provided'}
39
+ cos_node_params[:api_key] = options.get_option(:apikey, mandatory: true)
40
+ cos_node_params[:instance_id] = options.get_option(:crn, mandatory: true)
38
41
  else
39
- params = CosNode.parameters_from_svc_credentials(service_credentials, options.get_option(:region, mandatory: true))
40
- storage_endpoint = params[:storage_endpoint]
41
- service_api_key = params[:service_api_key]
42
- instance_id = params[:instance_id]
42
+ Aspera.assert(cos_node_params[:endpoint].nil?, exception_class: Cli::BadArgument){'endpoint not allowed when service credentials provided'}
43
+ cos_node_params.merge!(Api::CosNode.parameters_from_svc_credentials(service_credentials, options.get_option(:region, mandatory: true)))
43
44
  end
44
- api_node = CosNode.new(bucket_name, storage_endpoint, instance_id, service_api_key, options.get_option(:identity, mandatory: true))
45
- node_plugin = Node.new(@agents, api: api_node)
45
+ api_node = Api::CosNode.new(**cos_node_params)
46
+ node_plugin = Node.new(**init_params, api: api_node)
46
47
  command = options.get_next_command(Node::COMMANDS_COS)
47
48
  return node_plugin.execute_action(command)
48
49
  end
@@ -6,12 +6,14 @@ require 'aspera/cli/plugins/node'
6
6
  require 'aspera/cli/plugins/config'
7
7
  require 'aspera/cli/extended_value'
8
8
  require 'aspera/cli/transfer_agent'
9
- require 'aspera/fasp/uri'
10
- require 'aspera/fasp/transfer_spec'
9
+ require 'aspera/transfer/uri'
10
+ require 'aspera/transfer/spec'
11
11
  require 'aspera/persistency_action_once'
12
12
  require 'aspera/open_application'
13
13
  require 'aspera/nagios'
14
14
  require 'aspera/id_generator'
15
+ require 'aspera/log'
16
+ require 'aspera/assert'
15
17
  require 'xmlsimple'
16
18
  require 'json'
17
19
  require 'cgi'
@@ -19,7 +21,7 @@ require 'cgi'
19
21
  module Aspera
20
22
  module Cli
21
23
  module Plugins
22
- class Faspex < Aspera::Cli::BasicAuthPlugin
24
+ class Faspex < Cli::BasicAuthPlugin
23
25
  # required hash key for source in config
24
26
  KEY_NODE = 'node' # value must be hash with url, username, password
25
27
  KEY_PATH = 'path' # value must be same sub-path as in Faspex's node
@@ -41,25 +43,32 @@ module Aspera
41
43
  address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
42
44
  urls = [address_or_url]
43
45
  urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
44
-
46
+ error = nil
45
47
  urls.each do |base_url|
46
48
  next unless base_url.start_with?('https://')
47
49
  api = Rest.new(base_url: base_url, redirect_max: 1)
48
50
  result = api.call(
49
51
  operation: 'POST',
50
- subpath: '',
51
- headers: {'Accept' => 'application/xrds+xml', 'Content-type' => 'text/plain'},
52
- text_body_params: '')
52
+ headers: {
53
+ 'Content-type' => 'text/plain',
54
+ 'Accept' => 'application/xrds+xml'
55
+ }
56
+ )
53
57
  # 4.x
54
58
  next unless result[:http].body.start_with?('<?xml')
55
59
  res_s = XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
56
60
  Log.log.debug{"version: #{result[:http]['X-IBM-Aspera']}"}
57
61
  version = res_s['XRD']['application']['version']
58
62
  # take redirect if any
59
- return {version: version, url: result[:http].uri.to_s}
63
+ return {
64
+ version: version,
65
+ url: result[:http].uri.to_s
66
+ }
60
67
  rescue StandardError => e
68
+ error = e
61
69
  Log.log.debug{"detect error: #{e}"}
62
70
  end
71
+ raise error if error
63
72
  return nil
64
73
  end
65
74
 
@@ -75,10 +84,10 @@ module Aspera
75
84
  }
76
85
  end
77
86
 
78
- # extract elements from anonymous faspex link
87
+ # extract elements from faspex public link
79
88
  def get_link_data(public_url)
80
89
  public_uri = URI.parse(public_url)
81
- raise Cli::BadArgument, 'Public link does not match Faspex format' unless (m = public_uri.path.match(%r{^(.*)/(external.*)$}))
90
+ Aspera.assert((m = public_uri.path.match(%r{^(.*)/(external.*)$})), exception_class: Cli::BadArgument){'Public link does not match Faspex format'}
82
91
  base = m[1]
83
92
  subpath = m[2]
84
93
  port_add = public_uri.port.eql?(public_uri.default_port) ? '' : ":#{public_uri.port}"
@@ -91,16 +100,13 @@ module Aspera
91
100
  return result
92
101
  end
93
102
 
94
- # get Fasp::Uri::SCHEME URI from entry in xml, and fix problems..
103
+ # get Transfer::Uri::SCHEME URI from entry in xml, and fix problems.
95
104
  def get_fasp_uri_from_entry(entry, raise_no_link: true)
96
105
  unless entry.key?('link')
97
106
  raise Cli::BadArgument, 'package has no link (deleted?)' if raise_no_link
98
107
  return nil
99
108
  end
100
109
  result = entry['link'].find{|e| e['rel'].eql?('package')}['href']
101
- # tags in the end of URL is not well % encoded... there are "=" that should be %3D
102
- # TODO: enter ticket to Faspex ?
103
- # ##XXif m=result.match(/(=+)$/);result.gsub!(/=+$/,"#{"%3D"*m[1].length}");end
104
110
  return result
105
111
  end
106
112
 
@@ -112,10 +118,10 @@ module Aspera
112
118
  end
113
119
  end
114
120
 
115
- def initialize(env)
121
+ def initialize(**env)
122
+ super
116
123
  @api_v3 = nil
117
124
  @api_v4 = nil
118
- super(env)
119
125
  options.declare(:link, 'Public link for specific operation')
120
126
  options.declare(:delivery_info, 'Package delivery information', types: Hash)
121
127
  options.declare(:remote_source, 'Remote source for package send (id or %name:)')
@@ -135,16 +141,16 @@ module Aspera
135
141
  def api_v4
136
142
  if @api_v4.nil?
137
143
  faspex_api_base = options.get_option(:url, mandatory: true)
138
- @api_v4 = Rest.new({
139
- base_url: faspex_api_base + '/api',
144
+ @api_v4 = Rest.new(
145
+ base_url: "#{faspex_api_base}/api",
140
146
  auth: {
141
147
  type: :oauth2,
142
- base_url: faspex_api_base + '/auth/oauth2',
143
- auth: {type: :basic, username: options.get_option(:username, mandatory: true), password: options.get_option(:password, mandatory: true)},
144
148
  grant_method: :generic,
145
- generic: {grant_type: 'password'},
146
- scope: 'admin'
147
- }})
149
+ base_url: "#{faspex_api_base}/auth/oauth2",
150
+ auth: {type: :basic, username: options.get_option(:username, mandatory: true), password: options.get_option(:password, mandatory: true)},
151
+ scope: 'admin',
152
+ grant_type: 'password'
153
+ })
148
154
  end
149
155
  return @api_v4
150
156
  end
@@ -162,9 +168,9 @@ module Aspera
162
168
  max_pages = nil
163
169
  result = []
164
170
  if !mailbox_query.nil?
165
- raise 'query: must be Hash or nil' unless mailbox_query.is_a?(Hash)
166
- raise "query: supported params: #{ATOM_EXT_PARAMS}" unless (mailbox_query.keys - ATOM_EXT_PARAMS).empty?
167
- raise 'query: startIndex and page are exclusive' if mailbox_query.key?('startIndex') && mailbox_query.key?('page')
171
+ Aspera.assert_type(mailbox_query, Hash){'query'}
172
+ Aspera.assert((mailbox_query.keys - ATOM_EXT_PARAMS).empty?){"query: supported params: #{ATOM_EXT_PARAMS}"}
173
+ Aspera.assert(!(mailbox_query.key?('startIndex') && mailbox_query.key?('page'))){'query: startIndex and page are exclusive'}
168
174
  max_items = mailbox_query[MAX_ITEMS]
169
175
  mailbox_query.delete(MAX_ITEMS)
170
176
  max_pages = mailbox_query[MAX_PAGES]
@@ -173,7 +179,7 @@ module Aspera
173
179
  loop do
174
180
  # get a batch of package information
175
181
  # order: first batch is latest packages, and then in a batch ids are increasing
176
- atom_xml = api_v3.call({operation: 'GET', subpath: "#{mailbox}.atom", headers: {'Accept' => 'application/xml'}, url_params: mailbox_query})[:http].body
182
+ atom_xml = api_v3.call(operation: 'GET', subpath: "#{mailbox}.atom", headers: {'Accept' => 'application/xml'}, url_params: mailbox_query)[:http].body
177
183
  box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => %w[entry field link to]})
178
184
  Log.log.debug{Log.dump(:box_data, box_data)}
179
185
  items = box_data.key?('entry') ? box_data['entry'] : []
@@ -233,15 +239,15 @@ module Aspera
233
239
  package_create_params[:passcode] = link_data[:query]['passcode']
234
240
  delivery_info[:transfer_type] = 'connect'
235
241
  delivery_info[:source_paths_list] = transfer.source_list.join("\r\n")
236
- api_public_link = Rest.new({base_url: link_data[:base_url]})
242
+ api_public_link = Rest.new(base_url: link_data[:base_url])
237
243
  # Hum, as this does not always work (only user, but not dropbox), we get the javascript and need hack
238
244
  # pkg_created=api_public_link.create(create_path,package_create_params)[:data]
239
245
  # so extract data from javascript
240
- package_creation_data = api_public_link.call({
246
+ package_creation_data = api_public_link.call(
241
247
  operation: 'POST',
242
248
  subpath: create_path,
243
249
  json_params: package_create_params,
244
- headers: {'Accept' => 'text/javascript'}})[:http].body
250
+ headers: {'Accept' => 'text/javascript'})[:http].body
245
251
  # get arguments of function call
246
252
  package_creation_data.delete!("\n") # one line
247
253
  package_creation_data.gsub!(/^[^"]+\("\{/, '{') # delete header
@@ -271,7 +277,7 @@ module Aspera
271
277
  end
272
278
  return nagios.result
273
279
  when :package
274
- command_pkg = options.get_next_command(%i[send recv list show])
280
+ command_pkg = options.get_next_command(%i[send receive list show], aliases: {recv: :receive})
275
281
  case command_pkg
276
282
  when :show
277
283
  delivery_id = instance_identifier
@@ -284,7 +290,7 @@ module Aspera
284
290
  }
285
291
  when :send
286
292
  delivery_info = options.get_option(:delivery_info, mandatory: true)
287
- raise Cli::BadArgument, 'delivery_info must be hash, refer to doc' unless delivery_info.is_a?(Hash)
293
+ Aspera.assert_type(delivery_info, Hash, exception_class: Cli::BadArgument){'delivery_info'}
288
294
  # actual parameter to faspex API
289
295
  package_create_params = {'delivery' => delivery_info}
290
296
  public_link_url = options.get_option(:link)
@@ -294,17 +300,17 @@ module Aspera
294
300
  first_source = delivery_info['sources'].first
295
301
  first_source['paths'].push(*transfer.source_list)
296
302
  source_id = instance_identifier(as_option: :remote_source) do |field, value|
297
- raise Cli::BadArgument, 'only name as selector, or give id' unless field.eql?('name')
298
- source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
303
+ Aspera.assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
304
+ source_list = api_v3.call(operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'})[:data]['items']
299
305
  self.class.get_source_id_by_name(value, source_list)
300
306
  end
301
307
  first_source['id'] = source_id.to_i unless source_id.nil?
302
- pkg_created = api_v3.call({
308
+ pkg_created = api_v3.call(
303
309
  operation: 'POST',
304
310
  subpath: 'send',
305
311
  json_params: package_create_params,
306
312
  headers: {'Accept' => 'application/json'}
307
- })[:data]
313
+ )[:data]
308
314
  if first_source.key?('id')
309
315
  # no transfer spec if remote source: handled by faspex
310
316
  return {data: [pkg_created['links']['status']], type: :value_list, name: 'link'}
@@ -318,7 +324,7 @@ module Aspera
318
324
  end
319
325
  # Log.log.debug{Log.dump('transfer_spec',transfer_spec)}
320
326
  return Main.result_transfer(transfer.start(transfer_spec))
321
- when :recv
327
+ when :receive
322
328
  link_url = options.get_option(:link)
323
329
  # list of faspex ID/URI to download
324
330
  pkg_id_uri = nil
@@ -328,7 +334,7 @@ module Aspera
328
334
  when nil # usual case: no link
329
335
  if options.get_option(:once_only, mandatory: true)
330
336
  skip_ids_persistency = PersistencyActionOnce.new(
331
- manager: @agents[:persistency],
337
+ manager: persistency,
332
338
  data: skip_ids_data,
333
339
  id: IdGenerator.from_list([
334
340
  'faspex_recv',
@@ -341,11 +347,16 @@ module Aspera
341
347
  delivery_id = instance_identifier
342
348
  raise 'empty id' if delivery_id.empty?
343
349
  recipient = options.get_option(:recipient)
344
- if ExtendedValue::ALL.eql?(delivery_id)
350
+ if delivery_id.eql?(ExtendedValue::ALL)
345
351
  pkg_id_uri = mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD], uri: self.class.get_fasp_uri_from_entry(i, raise_no_link: false)}}
352
+ elsif delivery_id.eql?(ExtendedValue::INIT)
353
+ Aspera.assert(skip_ids_persistency){'Only with option once_only'}
354
+ skip_ids_persistency.data.clear.concat(mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD]}})
355
+ skip_ids_persistency.save
356
+ return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
346
357
  elsif !recipient.nil? && recipient.start_with?('*')
347
358
  found_package_link = mailbox_filtered_entries(stop_at_id: delivery_id).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivery_id)}['link'].first['href']
348
- raise "Not Found. Dropbox and Workgroup packages can use the link option with #{Fasp::Uri::SCHEME}" if found_package_link.nil?
359
+ raise "Not Found. Dropbox and Workgroup packages can use the link option with #{Transfer::Uri::SCHEME}" if found_package_link.nil?
349
360
  pkg_id_uri = [{id: delivery_id, uri: found_package_link}]
350
361
  else
351
362
  # TODO: delivery id is the right one if package was receive by workgroup
@@ -354,11 +365,11 @@ module Aspera
354
365
  when :inbox, :archive then'received'
355
366
  when :sent then 'sent'
356
367
  end
357
- entry_xml = api_v3.call({operation: 'GET', subpath: "#{endpoint}/#{delivery_id}", headers: {'Accept' => 'application/xml'}})[:http].body
368
+ entry_xml = api_v3.call(operation: 'GET', subpath: "#{endpoint}/#{delivery_id}", headers: {'Accept' => 'application/xml'})[:http].body
358
369
  package_entry = XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
359
370
  pkg_id_uri = [{id: delivery_id, uri: self.class.get_fasp_uri_from_entry(package_entry)}]
360
371
  end
361
- when /^#{Fasp::Uri::SCHEME}:/o
372
+ when /^#{Transfer::Uri::SCHEME}:/o
362
373
  pkg_id_uri = [{id: 'package', uri: link_url}]
363
374
  else
364
375
  link_data = self.class.get_link_data(link_url)
@@ -366,7 +377,7 @@ module Aspera
366
377
  raise Cli::BadArgument, "Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
367
378
  end
368
379
  # NOTE: unauthenticated API (authorization is in url params)
369
- api_public_link = Rest.new({base_url: link_data[:base_url]})
380
+ api_public_link = Rest.new(base_url: link_data[:base_url])
370
381
  package_creation_data = api_public_link.call(
371
382
  operation: 'GET',
372
383
  subpath: link_data[:subpath],
@@ -393,19 +404,19 @@ module Aspera
393
404
  # skip package with no link: empty or content deleted
394
405
  statuses = [:success]
395
406
  else
396
- transfer_spec = Fasp::Uri.new(id_uri[:uri]).transfer_spec
397
- # NOTE: only external users have token in Fasp::Uri::SCHEME link !
407
+ transfer_spec = Transfer::Uri.new(id_uri[:uri]).transfer_spec
408
+ # NOTE: only external users have token in Transfer::Uri::SCHEME link !
398
409
  if !transfer_spec.key?('token')
399
410
  sanitized = id_uri[:uri].gsub('&', '&amp;')
400
411
  xml_payload =
401
412
  %Q(<?xml version="1.0" encoding="UTF-8"?><url-list xmlns="http://schemas.asperasoft.com/xml/url-list"><url href="#{sanitized}"/></url-list>)
402
- transfer_spec['token'] = api_v3.call({
413
+ transfer_spec['token'] = api_v3.call(
403
414
  operation: 'POST',
404
415
  subpath: 'issue-token?direction=down',
405
416
  headers: {'Accept' => 'text/plain', 'Content-Type' => 'application/vnd.aspera.url-list+xml'},
406
- text_body_params: xml_payload})[:http].body
417
+ text_body_params: xml_payload)[:http].body
407
418
  end
408
- transfer_spec['direction'] = Fasp::TransferSpec::DIRECTION_RECEIVE
419
+ transfer_spec['direction'] = Transfer::Spec::DIRECTION_RECEIVE
409
420
  statuses = transfer.start(transfer_spec)
410
421
  end
411
422
  result_transfer.push({'package' => id_uri[:id], Main::STATUS_FIELD => statuses})
@@ -417,23 +428,23 @@ module Aspera
417
428
  end
418
429
  when :source
419
430
  command_source = options.get_next_command(%i[list info node])
420
- source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
431
+ source_list = api_v3.call(operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'})[:data]['items']
421
432
  case command_source
422
433
  when :list
423
434
  return {type: :object_list, data: source_list}
424
435
  else # :info :node
425
436
  source_id = instance_identifier do |field, value|
426
- raise Cli::BadArgument, 'only name as selector, or give id' unless field.eql?('name')
437
+ Aspera.assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
427
438
  self.class.get_source_id_by_name(value, source_list)
428
439
  end.to_i
429
440
  source_name = source_list.find{|i|i['id'].eql?(source_id)}['name']
430
441
  source_hash = options.get_option(:storage, mandatory: true)
431
442
  # check value of option
432
- raise Cli::Error, 'storage option must be a Hash' unless source_hash.is_a?(Hash)
443
+ Aspera.assert_type(source_hash, Hash, exception_class: Cli::Error){'storage option'}
433
444
  source_hash.each do |name, storage|
434
- raise Cli::Error, "storage '#{name}' must be a Hash" unless storage.is_a?(Hash)
445
+ Aspera.assert_type(storage, Hash, exception_class: Cli::Error){"storage '#{name}'"}
435
446
  [KEY_NODE, KEY_PATH].each do |key|
436
- raise Cli::Error, "storage '#{name}' must have a '#{key}'" unless storage.key?(key)
447
+ Aspera.assert(storage.key?(key), exception_class: Cli::Error){"storage '#{name}' must have a '#{key}'"}
437
448
  end
438
449
  end
439
450
  if !source_hash.key?(source_name)
@@ -446,26 +457,26 @@ module Aspera
446
457
  return {data: source_info, type: :single_object}
447
458
  when :node
448
459
  node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE])
449
- raise Cli::Error, "bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
450
460
  Log.log.debug{"node=#{node_config}"}
451
- api_node = Rest.new({
461
+ Aspera.assert_type(node_config, Hash, exception_class: Cli::Error){source_info[KEY_NODE]}
462
+ api_node = Rest.new(
452
463
  base_url: node_config['url'],
453
464
  auth: {
454
465
  type: :basic,
455
466
  username: node_config['username'],
456
- password: node_config['password']}})
467
+ password: node_config['password']})
457
468
  command = options.get_next_command(Node::COMMANDS_FASPEX)
458
- return Node.new(@agents, api: api_node).execute_action(command, source_info[KEY_PATH])
469
+ return Node.new(**init_params, api: api_node).execute_action(command, source_info[KEY_PATH])
459
470
  end
460
471
  end
461
472
  when :me
462
- my_info = api_v3.call({operation: 'GET', subpath: 'me', headers: {'Accept' => 'application/json'}})[:data]
473
+ my_info = api_v3.call(operation: 'GET', subpath: 'me', headers: {'Accept' => 'application/json'})[:data]
463
474
  return {data: my_info, type: :single_object}
464
475
  when :dropbox
465
476
  command_pkg = options.get_next_command([:list])
466
477
  case command_pkg
467
478
  when :list
468
- dropbox_list = api_v3.call({operation: 'GET', subpath: 'dropboxes', headers: {'Accept' => 'application/json'}})[:data]
479
+ dropbox_list = api_v3.call(operation: 'GET', subpath: 'dropboxes', headers: {'Accept' => 'application/json'})[:data]
469
480
  return {type: :object_list, data: dropbox_list['items'], fields: %w[name id description can_read can_write]}
470
481
  end
471
482
  when :v4
@@ -512,7 +523,7 @@ module Aspera
512
523
  end
513
524
  return {type: :object_list, data: users}
514
525
  when :login_methods
515
- login_meths = api_v3.call({operation: 'GET', subpath: 'login/new', headers: {'Accept' => 'application/xrds+xml'}})[:http].body
526
+ login_meths = api_v3.call(operation: 'GET', subpath: 'login/new', headers: {'Accept' => 'application/xrds+xml'})[:http].body
516
527
  login_methods = XmlSimple.xml_in(login_meths, {'ForceArray' => false})
517
528
  return {type: :object_list, data: login_methods['XRD']['Service']}
518
529
  end # command