aspera-cli 4.9.0 → 4.11.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 (95) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +20 -0
  4. data/CHANGELOG.md +509 -0
  5. data/CONTRIBUTING.md +118 -0
  6. data/README.md +1241 -916
  7. data/bin/ascli +4 -4
  8. data/bin/asession +11 -11
  9. data/docs/test_env.conf +32 -21
  10. data/examples/aoc.rb +4 -4
  11. data/examples/dascli +16 -9
  12. data/examples/faspex4.rb +8 -8
  13. data/examples/node.rb +12 -12
  14. data/examples/server.rb +10 -10
  15. data/lib/aspera/aoc.rb +273 -266
  16. data/lib/aspera/ascmd.rb +56 -54
  17. data/lib/aspera/ats_api.rb +4 -4
  18. data/lib/aspera/cli/basic_auth_plugin.rb +15 -12
  19. data/lib/aspera/cli/extended_value.rb +5 -5
  20. data/lib/aspera/cli/formater.rb +64 -64
  21. data/lib/aspera/cli/info.rb +2 -2
  22. data/lib/aspera/cli/listener/line_dump.rb +1 -1
  23. data/lib/aspera/cli/listener/logger.rb +1 -1
  24. data/lib/aspera/cli/listener/progress.rb +5 -6
  25. data/lib/aspera/cli/listener/progress_multi.rb +14 -19
  26. data/lib/aspera/cli/main.rb +66 -67
  27. data/lib/aspera/cli/manager.rb +112 -110
  28. data/lib/aspera/cli/plugin.rb +57 -36
  29. data/lib/aspera/cli/plugins/alee.rb +4 -4
  30. data/lib/aspera/cli/plugins/aoc.rb +309 -670
  31. data/lib/aspera/cli/plugins/ats.rb +44 -46
  32. data/lib/aspera/cli/plugins/bss.rb +10 -10
  33. data/lib/aspera/cli/plugins/config.rb +497 -378
  34. data/lib/aspera/cli/plugins/console.rb +12 -12
  35. data/lib/aspera/cli/plugins/cos.rb +18 -20
  36. data/lib/aspera/cli/plugins/faspex.rb +112 -114
  37. data/lib/aspera/cli/plugins/faspex5.rb +71 -46
  38. data/lib/aspera/cli/plugins/node.rb +379 -283
  39. data/lib/aspera/cli/plugins/orchestrator.rb +46 -46
  40. data/lib/aspera/cli/plugins/preview.rb +122 -114
  41. data/lib/aspera/cli/plugins/server.rb +137 -83
  42. data/lib/aspera/cli/plugins/shares.rb +30 -29
  43. data/lib/aspera/cli/plugins/sync.rb +13 -33
  44. data/lib/aspera/cli/transfer_agent.rb +60 -59
  45. data/lib/aspera/cli/version.rb +1 -1
  46. data/lib/aspera/colors.rb +3 -3
  47. data/lib/aspera/command_line_builder.rb +27 -27
  48. data/lib/aspera/cos_node.rb +22 -20
  49. data/lib/aspera/data_repository.rb +1 -1
  50. data/lib/aspera/environment.rb +35 -15
  51. data/lib/aspera/fasp/agent_base.rb +15 -15
  52. data/lib/aspera/fasp/agent_connect.rb +23 -21
  53. data/lib/aspera/fasp/agent_direct.rb +66 -64
  54. data/lib/aspera/fasp/agent_httpgw.rb +141 -78
  55. data/lib/aspera/fasp/agent_node.rb +23 -21
  56. data/lib/aspera/fasp/agent_trsdk.rb +20 -20
  57. data/lib/aspera/fasp/error.rb +3 -2
  58. data/lib/aspera/fasp/error_info.rb +11 -8
  59. data/lib/aspera/fasp/installation.rb +79 -79
  60. data/lib/aspera/fasp/listener.rb +1 -1
  61. data/lib/aspera/fasp/parameters.rb +86 -71
  62. data/lib/aspera/fasp/parameters.yaml +7 -4
  63. data/lib/aspera/fasp/resume_policy.rb +8 -8
  64. data/lib/aspera/fasp/transfer_spec.rb +35 -2
  65. data/lib/aspera/fasp/uri.rb +7 -7
  66. data/lib/aspera/faspex_gw.rb +7 -5
  67. data/lib/aspera/hash_ext.rb +3 -3
  68. data/lib/aspera/id_generator.rb +5 -5
  69. data/lib/aspera/keychain/encrypted_hash.rb +38 -105
  70. data/lib/aspera/keychain/macos_security.rb +128 -57
  71. data/lib/aspera/log.rb +7 -7
  72. data/lib/aspera/nagios.rb +19 -18
  73. data/lib/aspera/node.rb +209 -35
  74. data/lib/aspera/oauth.rb +37 -36
  75. data/lib/aspera/open_application.rb +19 -11
  76. data/lib/aspera/persistency_action_once.rb +4 -4
  77. data/lib/aspera/persistency_folder.rb +16 -15
  78. data/lib/aspera/preview/file_types.rb +8 -8
  79. data/lib/aspera/preview/generator.rb +67 -67
  80. data/lib/aspera/preview/utils.rb +27 -27
  81. data/lib/aspera/proxy_auto_config.js +41 -41
  82. data/lib/aspera/proxy_auto_config.rb +21 -14
  83. data/lib/aspera/rest.rb +72 -67
  84. data/lib/aspera/rest_call_error.rb +2 -1
  85. data/lib/aspera/rest_error_analyzer.rb +18 -17
  86. data/lib/aspera/rest_errors_aspera.rb +16 -16
  87. data/lib/aspera/secret_hider.rb +15 -13
  88. data/lib/aspera/ssh.rb +11 -10
  89. data/lib/aspera/sync.rb +158 -44
  90. data/lib/aspera/temp_file_manager.rb +2 -2
  91. data/lib/aspera/uri_reader.rb +4 -4
  92. data/lib/aspera/web_auth.rb +14 -13
  93. data.tar.gz.sig +0 -0
  94. metadata +11 -36
  95. metadata.gz.sig +0 -0
@@ -18,23 +18,21 @@ require 'cgi'
18
18
  module Aspera
19
19
  module Cli
20
20
  module Plugins
21
- class Faspex < BasicAuthPlugin
21
+ class Faspex < Aspera::Cli::BasicAuthPlugin
22
22
  # required hash key for source in config
23
23
  KEY_NODE = 'node' # value must be hash with url, username, password
24
24
  KEY_PATH = 'path' # value must be same sub-path as in Faspex's node
25
- VAL_ALL = 'ALL'
26
25
  # added field in result that identifies the package
27
26
  PACKAGE_MATCH_FIELD = 'package_id'
28
27
  # list of supported atoms
29
28
  ATOM_MAILBOXES = %i[inbox archive sent].freeze
30
29
  # allowed parameters for inbox.atom
31
30
  ATOM_PARAMS = %w[page count startIndex].freeze
32
- # with special parameters (from Plugin class) : max and pmax
33
- ATOM_EXT_PARAMS = ATOM_PARAMS + [MAX_ITEMS, MAX_PAGES]
31
+ # with special parameters (from Plugin class) : max and pmax (from Plugin)
32
+ ATOM_EXT_PARAMS = [MAX_ITEMS, MAX_PAGES].concat(ATOM_PARAMS).freeze
34
33
  # sub path in url for public link delivery
35
34
  PUB_LINK_EXTERNAL_MATCH = 'external_deliveries/'
36
- private_constant :KEY_NODE,:KEY_PATH,:VAL_ALL,:PACKAGE_MATCH_FIELD,:ATOM_MAILBOXES,:ATOM_PARAMS,
37
- :ATOM_EXT_PARAMS,:PUB_LINK_EXTERNAL_MATCH
35
+ private_constant(*%i[KEY_NODE KEY_PATH PACKAGE_MATCH_FIELD ATOM_MAILBOXES ATOM_PARAMS ATOM_EXT_PARAMS PUB_LINK_EXTERNAL_MATCH])
38
36
 
39
37
  class << self
40
38
  def detect(base_url)
@@ -56,45 +54,45 @@ module Aspera
56
54
  # extract elements from anonymous faspex link
57
55
  def get_link_data(publink)
58
56
  publink_uri = URI.parse(publink)
59
- raise CliBadArgument, 'public link does not match Faspex format' unless (m = publink_uri.path.match(/^(.*)\/(external.*)$/))
57
+ raise CliBadArgument, 'Public link does not match Faspex format' unless (m = publink_uri.path.match(%r{^(.*)/(external.*)$}))
60
58
  base = m[1]
61
59
  subpath = m[2]
62
60
  port_add = publink_uri.port.eql?(publink_uri.default_port) ? '' : ":#{publink_uri.port}"
63
61
  result = {
64
62
  base_url: "#{publink_uri.scheme}://#{publink_uri.host}#{port_add}#{base}",
65
63
  subpath: subpath,
66
- query: URI.decode_www_form(publink_uri.query).each_with_object({}){|v,h|h[v.first] = v.last;}
64
+ query: URI.decode_www_form(publink_uri.query).each_with_object({}){|v, h|h[v.first] = v.last; }
67
65
  }
68
- Log.dump('publink',result)
66
+ Log.dump('publink', result)
69
67
  return result
70
68
  end
71
69
 
72
70
  # get faspe: URI from entry in xml, and fix problems..
73
71
  def get_fasp_uri_from_entry(entry, raise_no_link: true)
74
- unless entry.has_key?('link')
72
+ unless entry.key?('link')
75
73
  raise CliBadArgument, 'package has no link (deleted?)' if raise_no_link
76
74
  return nil
77
75
  end
78
76
  result = entry['link'].find{|e| e['rel'].eql?('package')}['href']
79
77
  # tags in the end of URL is not well % encoded... there are "=" that should be %3D
80
78
  # TODO: enter ticket to Faspex ?
81
- ###XXif m=result.match(/(=+)$/);result.gsub!(/=+$/,"#{"%3D"*m[1].length}");end
79
+ # ##XXif m=result.match(/(=+)$/);result.gsub!(/=+$/,"#{"%3D"*m[1].length}");end
82
80
  return result
83
81
  end
84
82
 
85
83
  def textify_package_list(table_data)
86
84
  return table_data.map do |e|
87
- e.keys.each {|k| e[k] = e[k].first if e[k].is_a?(Array) && (e[k].length == 1)}
88
- e['items'] = e.has_key?('link') ? e['link'].length : 0
85
+ e.each_key {|k| e[k] = e[k].first if e[k].is_a?(Array) && (e[k].length == 1)}
86
+ e['items'] = e.key?('link') ? e['link'].length : 0
89
87
  e
90
88
  end
91
89
  end
92
90
 
93
91
  # field_sym : :id or :name
94
- def get_source_id(source_list,source_name)
92
+ def get_source_id(source_list, source_name)
95
93
  source_ids = source_list.select { |i| i['name'].eql?(source_name) }
96
94
  if source_ids.empty?
97
- raise CliError,%Q(No such Faspex source "#{source_name}" in [#{source_list.map{|i| %Q("#{i['name']}")}.join(', ')}])
95
+ raise CliError, %Q(No such Faspex source "#{source_name}" in [#{source_list.map{|i| %Q("#{i['name']}")}.join(', ')}])
98
96
  end
99
97
  return source_ids.first['id']
100
98
  end
@@ -104,13 +102,13 @@ module Aspera
104
102
  @api_v3 = nil
105
103
  @api_v4 = nil
106
104
  super(env)
107
- options.add_opt_simple(:link,'public link for specific operation')
108
- options.add_opt_simple(:delivery_info,'package delivery information (extended value)')
109
- options.add_opt_simple(:source_name,'create package from remote source (by name)')
110
- options.add_opt_simple(:storage,'Faspex local storage definition')
111
- options.add_opt_simple(:recipient,'use if recipient is a dropbox (with *)')
112
- options.add_opt_list(:box,ATOM_MAILBOXES,'package box')
113
- options.set_option(:box,:inbox)
105
+ options.add_opt_simple(:link, 'public link for specific operation')
106
+ options.add_opt_simple(:delivery_info, 'package delivery information (extended value)')
107
+ options.add_opt_simple(:source_name, 'create package from remote source (by name)')
108
+ options.add_opt_simple(:storage, 'Faspex local storage definition')
109
+ options.add_opt_simple(:recipient, 'use if recipient is a dropbox (with *)')
110
+ options.add_opt_list(:box, ATOM_MAILBOXES, 'package box')
111
+ options.set_option(:box, :inbox)
114
112
  options.parse_options!
115
113
  end
116
114
 
@@ -123,13 +121,13 @@ module Aspera
123
121
 
124
122
  def api_v4
125
123
  if @api_v4.nil?
126
- faspex_api_base = options.get_option(:url,is_type: :mandatory)
124
+ faspex_api_base = options.get_option(:url, is_type: :mandatory)
127
125
  @api_v4 = Rest.new({
128
126
  base_url: faspex_api_base + '/api',
129
127
  auth: {
130
128
  type: :oauth2,
131
129
  base_url: faspex_api_base + '/auth/oauth2',
132
- auth: {type: :basic, username: options.get_option(:username,is_type: :mandatory), password: options.get_option(:password,is_type: :mandatory)},
130
+ auth: {type: :basic, username: options.get_option(:username, is_type: :mandatory), password: options.get_option(:password, is_type: :mandatory)},
133
131
  crtype: :generic,
134
132
  generic: {grant_type: 'password'},
135
133
  scope: 'admin'
@@ -140,11 +138,11 @@ module Aspera
140
138
 
141
139
  # query supports : {"startIndex":10,"count":1,"page":109,"max":2,"pmax":1}
142
140
  def mailbox_filtered_entries(stop_at_id: nil)
143
- recipient_names = [options.get_option(:recipient) || options.get_option(:username,is_type: :mandatory)]
141
+ recipient_names = [options.get_option(:recipient) || options.get_option(:username, is_type: :mandatory)]
144
142
  # some workgroup messages have no star in recipient name
145
143
  recipient_names.push(recipient_names.first[1..-1]) if recipient_names.first.start_with?('*')
146
144
  # mailbox is in ATOM_MAILBOXES
147
- mailbox = options.get_option(:box,is_type: :mandatory)
145
+ mailbox = options.get_option(:box, is_type: :mandatory)
148
146
  # parameters
149
147
  mailbox_query = options.get_option(:query)
150
148
  max_items = nil
@@ -153,7 +151,7 @@ module Aspera
153
151
  if !mailbox_query.nil?
154
152
  raise 'query: must be Hash or nil' unless mailbox_query.is_a?(Hash)
155
153
  raise "query: supported params: #{ATOM_EXT_PARAMS}" unless (mailbox_query.keys - ATOM_EXT_PARAMS).empty?
156
- raise 'query: startIndex and page are exclusive' if mailbox_query.has_key?('startIndex') && mailbox_query.has_key?('page')
154
+ raise 'query: startIndex and page are exclusive' if mailbox_query.key?('startIndex') && mailbox_query.key?('page')
157
155
  max_items = mailbox_query[MAX_ITEMS]
158
156
  mailbox_query.delete(MAX_ITEMS)
159
157
  max_pages = mailbox_query[MAX_PAGES]
@@ -162,11 +160,11 @@ module Aspera
162
160
  loop do
163
161
  # get a batch of package information
164
162
  # order: first batch is latest packages, and then in a batch ids are increasing
165
- atom_xml = api_v3.call({operation: 'GET',subpath: "#{mailbox}.atom",headers: {'Accept' => 'application/xml'},url_params: mailbox_query})[:http].body
163
+ atom_xml = api_v3.call({operation: 'GET', subpath: "#{mailbox}.atom", headers: {'Accept' => 'application/xml'}, url_params: mailbox_query})[:http].body
166
164
  box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => true})
167
- Log.dump(:box_data,box_data)
168
- items = box_data.has_key?('entry') ? box_data['entry'] : []
169
- Log.log.debug("new items: #{items.count}")
165
+ Log.dump(:box_data, box_data)
166
+ items = box_data.key?('entry') ? box_data['entry'] : []
167
+ Log.log.debug{"new items: #{items.count}"}
170
168
  # it is the end if page is empty
171
169
  break if items.empty?
172
170
  stop_condition = false
@@ -174,7 +172,7 @@ module Aspera
174
172
  items.reverse_each do |package|
175
173
  package[PACKAGE_MATCH_FIELD] =
176
174
  case mailbox
177
- when :inbox,:archive
175
+ when :inbox, :archive
178
176
  recipient = package['to'].find{|i|recipient_names.include?(i['name'].first)}
179
177
  recipient.nil? ? nil : recipient['recipient_delivery_id'].first
180
178
  else # :sent
@@ -186,33 +184,33 @@ module Aspera
186
184
  result.push(package) unless package[PACKAGE_MATCH_FIELD].nil?
187
185
  end
188
186
  break if stop_condition
189
- #result.push({PACKAGE_MATCH_FIELD=>'======'})
190
- Log.log.debug("total items: #{result.count}")
187
+ # result.push({PACKAGE_MATCH_FIELD=>'======'})
188
+ Log.log.debug{"total items: #{result.count}"}
191
189
  # reach the limit ?
192
190
  if !max_items.nil? && (result.count >= max_items)
193
- result = result.slice(0,max_items) if result.count > max_items
191
+ result = result.slice(0, max_items) if result.count > max_items
194
192
  break
195
193
  end
196
194
  link = box_data['link'].find{|i|i['rel'].eql?('next')}
197
- Log.log.debug("link: #{link}")
195
+ Log.log.debug{"link: #{link}"}
198
196
  # no next link
199
197
  break if link.nil?
200
198
  # replace parameters with the ones from next link
201
199
  params = CGI.parse(URI.parse(link['href']).query)
202
- mailbox_query = params.keys.each_with_object({}){|i,m|;m[i] = params[i].first;}
203
- Log.log.debug("query: #{mailbox_query}")
200
+ mailbox_query = params.keys.each_with_object({}){|i, m|; m[i] = params[i].first; }
201
+ Log.log.debug{"query: #{mailbox_query}"}
204
202
  break if !max_pages.nil? && (mailbox_query['page'].to_i > max_pages)
205
203
  end
206
204
  return result
207
205
  end
208
206
 
209
207
  # retrieve transfer spec from pub link for send package
210
- def send_publink_to_ts(public_link_url,package_create_params)
208
+ def send_publink_to_ts(public_link_url, package_create_params)
211
209
  delivery_info = package_create_params['delivery']
212
210
  # pub link user
213
211
  link_data = self.class.get_link_data(public_link_url)
214
- if !['external/submissions/new','external/dropbox_submissions/new'].include?(link_data[:subpath])
215
- raise CliBadArgument,"pub link is #{link_data[:subpath]}, expecting external/submissions/new"
212
+ if !['external/submissions/new', 'external/dropbox_submissions/new'].include?(link_data[:subpath])
213
+ raise CliBadArgument, "pub link is #{link_data[:subpath]}, expecting external/submissions/new"
216
214
  end
217
215
  create_path = link_data[:subpath].split('/')[0..-2].join('/')
218
216
  package_create_params[:passcode] = link_data[:query]['passcode']
@@ -220,7 +218,7 @@ module Aspera
220
218
  delivery_info[:source_paths_list] = transfer.ts_source_paths.map{|i|i['source']}.join("\r\n")
221
219
  api_public_link = Rest.new({base_url: link_data[:base_url]})
222
220
  # Hum, as this does not always work (only user, but not dropbox), we get the javascript and need hack
223
- #pkg_created=api_public_link.create(create_path,package_create_params)[:data]
221
+ # pkg_created=api_public_link.create(create_path,package_create_params)[:data]
224
222
  # so extract data from javascript
225
223
  pkgdatares = api_public_link.call({
226
224
  operation: 'POST',
@@ -229,14 +227,14 @@ module Aspera
229
227
  headers: {'Accept' => 'text/javascript'}})[:http].body
230
228
  # get args of function call
231
229
  pkgdatares.delete!("\n") # one line
232
- pkgdatares.gsub!(/^[^"]+\("\{/,'{') # delete header
233
- pkgdatares.gsub!(/"\);[^"]+$/,'"') # delete trailer
234
- pkgdatares.gsub!(/\}", *"/,'},"') # between two args
235
- pkgdatares.gsub!('\\"','"') # remove protecting quote
230
+ pkgdatares.gsub!(/^[^"]+\("\{/, '{') # delete header
231
+ pkgdatares.gsub!(/"\);[^"]+$/, '"') # delete trailer
232
+ pkgdatares.gsub!(/\}", *"/, '},"') # between two args
233
+ pkgdatares.gsub!('\\"', '"') # remove protecting quote
236
234
  begin
237
235
  pkgdatares = JSON.parse("[#{pkgdatares}]")
238
236
  rescue JSON::ParserError # => e
239
- raise 'Link not valid'
237
+ raise 'Unexpected response: missing metadata ?'
240
238
  end
241
239
  return pkgdatares.first
242
240
  end
@@ -250,9 +248,9 @@ module Aspera
250
248
  nagios = Nagios.new
251
249
  begin
252
250
  api_v3.read('me')
253
- nagios.add_ok('faspex api','accessible')
251
+ nagios.add_ok('faspex api', 'accessible')
254
252
  rescue StandardError => e
255
- nagios.add_critical('faspex api',e.to_s)
253
+ nagios.add_critical('faspex api', e.to_s)
256
254
  end
257
255
  return nagios.result
258
256
  when :package
@@ -262,12 +260,12 @@ module Aspera
262
260
  return {
263
261
  type: :object_list,
264
262
  data: mailbox_filtered_entries,
265
- fields: [PACKAGE_MATCH_FIELD,'title','items'],
263
+ fields: [PACKAGE_MATCH_FIELD, 'title', 'items'],
266
264
  textify: lambda {|table_data|Faspex.textify_package_list(table_data)}
267
265
  }
268
266
  when :send
269
- delivery_info = options.get_option(:delivery_info,is_type: :mandatory)
270
- raise CliBadArgument,'delivery_info must be hash, refer to doc' unless delivery_info.is_a?(Hash)
267
+ delivery_info = options.get_option(:delivery_info, is_type: :mandatory)
268
+ raise CliBadArgument, 'delivery_info must be hash, refer to doc' unless delivery_info.is_a?(Hash)
271
269
  # actual parameter to faspex API
272
270
  package_create_params = {'delivery' => delivery_info}
273
271
  public_link_url = options.get_option(:link)
@@ -278,8 +276,8 @@ module Aspera
278
276
  first_source['paths'].push(*transfer.ts_source_paths.map{|i|i['source']})
279
277
  source_name = options.get_option(:source_name)
280
278
  if !source_name.nil?
281
- source_list = api_v3.call({operation: 'GET',subpath: 'source_shares',headers: {'Accept' => 'application/json'}})[:data]['items']
282
- source_id = self.class.get_source_id(source_list,source_name)
279
+ source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
280
+ source_id = self.class.get_source_id(source_list, source_name)
283
281
  first_source['id'] = source_id
284
282
  end
285
283
  pkg_created = api_v3.call({
@@ -290,17 +288,17 @@ module Aspera
290
288
  })[:data]
291
289
  if !source_name.nil?
292
290
  # no transfer spec if remote source
293
- return {data: [pkg_created['links']['status']],type: :value_list,name: 'link'}
291
+ return {data: [pkg_created['links']['status']], type: :value_list, name: 'link'}
294
292
  end
295
- raise CliBadArgument,'expecting one session exactly' if pkg_created['xfer_sessions'].length != 1
293
+ raise CliBadArgument, 'expecting one session exactly' if pkg_created['xfer_sessions'].length != 1
296
294
  transfer_spec = pkg_created['xfer_sessions'].first
297
295
  # use source from cmd line, this one only contains destination (already in dest root)
298
296
  transfer_spec.delete('paths')
299
297
  else # publink
300
- transfer_spec = send_publink_to_ts(public_link_url,package_create_params)
298
+ transfer_spec = send_publink_to_ts(public_link_url, package_create_params)
301
299
  end
302
- #Log.dump('transfer_spec',transfer_spec)
303
- return Main.result_transfer(transfer.start(transfer_spec,{src: :node_gen3}))
300
+ # Log.dump('transfer_spec',transfer_spec)
301
+ return Main.result_transfer(transfer.start(transfer_spec))
304
302
  when :recv
305
303
  link_url = options.get_option(:link)
306
304
  # list of faspex ID/URI to download
@@ -309,46 +307,46 @@ module Aspera
309
307
  skip_ids_persistency = nil
310
308
  case link_url
311
309
  when nil # usual case: no link
312
- if options.get_option(:once_only,is_type: :mandatory)
310
+ if options.get_option(:once_only, is_type: :mandatory)
313
311
  skip_ids_persistency = PersistencyActionOnce.new(
314
312
  manager: @agents[:persistency],
315
313
  data: skip_ids_data,
316
314
  id: IdGenerator.from_list([
317
315
  'faspex_recv',
318
- options.get_option(:url,is_type: :mandatory),
319
- options.get_option(:username,is_type: :mandatory),
320
- options.get_option(:box,is_type: :mandatory).to_s
316
+ options.get_option(:url, is_type: :mandatory),
317
+ options.get_option(:username, is_type: :mandatory),
318
+ options.get_option(:box, is_type: :mandatory).to_s
321
319
  ]))
322
320
  end
323
321
  # get command line parameters
324
322
  delivid = instance_identifier
325
323
  raise 'empty id' if delivid.empty?
326
324
  recipient = options.get_option(:recipient)
327
- if delivid.eql?(VAL_ALL)
328
- 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)}}
325
+ if VAL_ALL.eql?(delivid)
326
+ 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)}}
329
327
  elsif !recipient.nil? && recipient.start_with?('*')
330
328
  found_package_link = mailbox_filtered_entries(stop_at_id: delivid).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivid)}['link'].first['href']
331
329
  raise 'Not Found. Dropbox and Workgroup packages can use the link option with faspe:' if found_package_link.nil?
332
- pkg_id_uri = [{id: delivid,uri: found_package_link}]
330
+ pkg_id_uri = [{id: delivid, uri: found_package_link}]
333
331
  else
334
332
  # TODO: delivery id is the right one if package was receive by workgroup
335
333
  endpoint =
336
- case options.get_option(:box,is_type: :mandatory)
337
- when :inbox,:archive then'received'
334
+ case options.get_option(:box, is_type: :mandatory)
335
+ when :inbox, :archive then'received'
338
336
  when :sent then 'sent'
339
337
  end
340
- entry_xml = api_v3.call({operation: 'GET',subpath: "#{endpoint}/#{delivid}",headers: {'Accept' => 'application/xml'}})[:http].body
338
+ entry_xml = api_v3.call({operation: 'GET', subpath: "#{endpoint}/#{delivid}", headers: {'Accept' => 'application/xml'}})[:http].body
341
339
  package_entry = XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
342
- pkg_id_uri = [{id: delivid,uri: self.class.get_fasp_uri_from_entry(package_entry)}]
340
+ pkg_id_uri = [{id: delivid, uri: self.class.get_fasp_uri_from_entry(package_entry)}]
343
341
  end
344
342
  when /^faspe:/
345
- pkg_id_uri = [{id: 'package',uri: link_url}]
343
+ pkg_id_uri = [{id: 'package', uri: link_url}]
346
344
  else
347
345
  link_data = self.class.get_link_data(link_url)
348
346
  if !link_data[:subpath].start_with?(PUB_LINK_EXTERNAL_MATCH)
349
- raise CliBadArgument,"Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
347
+ raise CliBadArgument, "Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
350
348
  end
351
- # Note: unauthenticated API (authorization is in url params)
349
+ # NOTE: unauthenticated API (authorization is in url params)
352
350
  api_public_link = Rest.new({base_url: link_data[:base_url]})
353
351
  pkgdatares = api_public_link.call(
354
352
  operation: 'GET',
@@ -357,18 +355,18 @@ module Aspera
357
355
  headers: {'Accept' => 'application/xml'})
358
356
  if !pkgdatares[:http].body.start_with?('<?xml ')
359
357
  OpenApplication.instance.uri(link_url)
360
- raise CliError, 'no such package'
358
+ raise CliError, 'Unexpected response: package not found ?'
361
359
  end
362
360
  package_entry = XmlSimple.xml_in(pkgdatares[:http].body, {'ForceArray' => false})
363
- Log.dump(:package_entry,package_entry)
361
+ Log.dump(:package_entry, package_entry)
364
362
  transfer_uri = self.class.get_fasp_uri_from_entry(package_entry)
365
- pkg_id_uri = [{id: package_entry['id'],uri: transfer_uri}]
363
+ pkg_id_uri = [{id: package_entry['id'], uri: transfer_uri}]
366
364
  end # public link
367
365
  # prune packages already downloaded
368
366
  # TODO : remove ids from skip not present in inbox to avoid growing too big
369
367
  # skip_ids_data.select!{|id|pkg_id_uri.select{|p|p[:id].eql?(id)}}
370
368
  pkg_id_uri.reject!{|i|skip_ids_data.include?(i[:id])}
371
- Log.dump(:pkg_id_uri,pkg_id_uri)
369
+ Log.dump(:pkg_id_uri, pkg_id_uri)
372
370
  return Main.result_status('no new package') if pkg_id_uri.empty?
373
371
  result_transfer = []
374
372
  pkg_id_uri.each do |id_uri|
@@ -378,20 +376,20 @@ module Aspera
378
376
  else
379
377
  transfer_spec = Fasp::Uri.new(id_uri[:uri]).transfer_spec
380
378
  # NOTE: only external users have token in faspe: link !
381
- if !transfer_spec.has_key?('token')
382
- sanitized = id_uri[:uri].gsub('&','&amp;')
379
+ if !transfer_spec.key?('token')
380
+ sanitized = id_uri[:uri].gsub('&', '&amp;')
383
381
  xmlpayload =
384
382
  %Q(<?xml version="1.0" encoding="UTF-8"?><url-list xmlns="http://schemas.asperasoft.com/xml/url-list"><url href="#{sanitized}"/></url-list>)
385
383
  transfer_spec['token'] = api_v3.call({
386
384
  operation: 'POST',
387
385
  subpath: 'issue-token?direction=down',
388
- headers: {'Accept' => 'text/plain','Content-Type' => 'application/vnd.aspera.url-list+xml'},
386
+ headers: {'Accept' => 'text/plain', 'Content-Type' => 'application/vnd.aspera.url-list+xml'},
389
387
  text_body_params: xmlpayload})[:http].body
390
388
  end
391
389
  transfer_spec['direction'] = Fasp::TransferSpec::DIRECTION_RECEIVE
392
- statuses = transfer.start(transfer_spec,{src: :node_gen3})
390
+ statuses = transfer.start(transfer_spec)
393
391
  end
394
- result_transfer.push({'package' => id_uri[:id],Main::STATUS_FIELD => statuses})
392
+ result_transfer.push({'package' => id_uri[:id], Main::STATUS_FIELD => statuses})
395
393
  # skip only if all sessions completed
396
394
  skip_ids_data.push(id_uri[:id]) if TransferAgent.session_status(statuses).eql?(:success)
397
395
  end
@@ -400,87 +398,87 @@ module Aspera
400
398
  end
401
399
  when :source
402
400
  command_source = options.get_next_command(%i[list id name])
403
- source_list = api_v3.call({operation: 'GET',subpath: 'source_shares',headers: {'Accept' => 'application/json'}})[:data]['items']
401
+ source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
404
402
  case command_source
405
403
  when :list
406
- return {type: :object_list,data: source_list}
404
+ return {type: :object_list, data: source_list}
407
405
  else # :id or :name
408
406
  source_match_val = options.get_next_argument('source id or name')
409
407
  source_ids = source_list.select { |i| i[command_source.to_s].to_s.eql?(source_match_val) }
410
408
  if source_ids.empty?
411
- raise CliError,"No such Faspex source #{command_source}: #{source_match_val} in [#{source_list.map{|i| i[command_source.to_s]}.join(', ')}]"
409
+ raise CliError, "No such Faspex source #{command_source}: #{source_match_val} in [#{source_list.map{|i| i[command_source.to_s]}.join(', ')}]"
412
410
  end
413
411
  # get id and name
414
412
  source_name = source_ids.first['name']
415
- #source_id=source_ids.first['id']
416
- source_hash = options.get_option(:storage,is_type: :mandatory)
413
+ # source_id=source_ids.first['id']
414
+ source_hash = options.get_option(:storage, is_type: :mandatory)
417
415
  # check value of option
418
- raise CliError,'storage option must be a Hash' unless source_hash.is_a?(Hash)
419
- source_hash.each do |name,storage|
420
- raise CliError,"storage '#{name}' must be a Hash" unless storage.is_a?(Hash)
421
- [KEY_NODE,KEY_PATH].each do |key|
422
- raise CliError,"storage '#{name}' must have a '#{key}'" unless storage.has_key?(key)
416
+ raise CliError, 'storage option must be a Hash' unless source_hash.is_a?(Hash)
417
+ source_hash.each do |name, storage|
418
+ raise CliError, "storage '#{name}' must be a Hash" unless storage.is_a?(Hash)
419
+ [KEY_NODE, KEY_PATH].each do |key|
420
+ raise CliError, "storage '#{name}' must have a '#{key}'" unless storage.key?(key)
423
421
  end
424
422
  end
425
- if !source_hash.has_key?(source_name)
426
- raise CliError,"No such storage in config file: \"#{source_name}\" in [#{source_hash.keys.join(', ')}]"
423
+ if !source_hash.key?(source_name)
424
+ raise CliError, "No such storage in config file: \"#{source_name}\" in [#{source_hash.keys.join(', ')}]"
427
425
  end
428
426
  source_info = source_hash[source_name]
429
- Log.log.debug("source_info: #{source_info}")
427
+ Log.log.debug{"source_info: #{source_info}"}
430
428
  command_node = options.get_next_command(%i[info node])
431
429
  case command_node
432
430
  when :info
433
- return {data: source_info,type: :single_object}
431
+ return {data: source_info, type: :single_object}
434
432
  when :node
435
433
  node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE])
436
- raise CliError,"bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
437
- Log.log.debug("node=#{node_config}")
434
+ raise CliError, "bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
435
+ Log.log.debug{"node=#{node_config}"}
438
436
  api_node = Rest.new({
439
437
  base_url: node_config['url'],
440
438
  auth: {
441
439
  type: :basic,
442
440
  username: node_config['username'],
443
441
  password: node_config['password']}})
444
- command = options.get_next_command(Node::COMMON_ACTIONS)
445
- return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action(command,source_info[KEY_PATH])
442
+ command = options.get_next_command(Node::COMMANDS_FASPEX)
443
+ return Node.new(@agents.merge(skip_basic_auth_options: true, node_api: api_node)).execute_action(command, source_info[KEY_PATH])
446
444
  end
447
445
  end
448
446
  when :me
449
- my_info = api_v3.call({operation: 'GET',subpath: 'me',headers: {'Accept' => 'application/json'}})[:data]
447
+ my_info = api_v3.call({operation: 'GET', subpath: 'me', headers: {'Accept' => 'application/json'}})[:data]
450
448
  return {data: my_info, type: :single_object}
451
449
  when :dropbox
452
450
  command_pkg = options.get_next_command([:list])
453
451
  case command_pkg
454
452
  when :list
455
- dropbox_list = api_v3.call({operation: 'GET',subpath: 'dropboxes',headers: {'Accept' => 'application/json'}})[:data]
453
+ dropbox_list = api_v3.call({operation: 'GET', subpath: 'dropboxes', headers: {'Accept' => 'application/json'}})[:data]
456
454
  return {type: :object_list, data: dropbox_list['items'], fields: %w[name id description can_read can_write]}
457
455
  end
458
456
  when :v4
459
457
  command = options.get_next_command(%i[package dropbox dmembership workgroup wmembership user metadata_profile])
460
458
  case command
461
459
  when :dropbox
462
- return entity_action(api_v4,'admin/dropboxes',display_fields: %w[id e_wg_name e_wg_desc created_at])
460
+ return entity_action(api_v4, 'admin/dropboxes', display_fields: %w[id e_wg_name e_wg_desc created_at])
463
461
  when :dmembership
464
- return entity_action(api_v4,'dropbox_memberships')
462
+ return entity_action(api_v4, 'dropbox_memberships')
465
463
  when :workgroup
466
- return entity_action(api_v4,'admin/workgroups',display_fields: %w[id e_wg_name e_wg_desc created_at])
464
+ return entity_action(api_v4, 'admin/workgroups', display_fields: %w[id e_wg_name e_wg_desc created_at])
467
465
  when :wmembership
468
- return entity_action(api_v4,'workgroup_memberships')
466
+ return entity_action(api_v4, 'workgroup_memberships')
469
467
  when :user
470
- return entity_action(api_v4,'users',display_fields: %w[id name first_name last_name])
468
+ return entity_action(api_v4, 'users', display_fields: %w[id name first_name last_name])
471
469
  when :metadata_profile
472
- return entity_action(api_v4,'metadata_profiles')
470
+ return entity_action(api_v4, 'metadata_profiles')
473
471
  when :package
474
472
  pkg_box_type = options.get_next_command([:users])
475
473
  pkg_box_id = instance_identifier
476
- return entity_action(api_v4,"#{pkg_box_type}/#{pkg_box_id}/packages")
474
+ return entity_action(api_v4, "#{pkg_box_type}/#{pkg_box_id}/packages")
477
475
  end
478
476
  when :address_book
479
477
  result = api_v3.call(
480
478
  operation: 'GET',
481
479
  subpath: 'address-book',
482
480
  headers: {'Accept' => 'application/json'},
483
- url_params: {'format' => 'json','count' => 100_000}
481
+ url_params: {'format' => 'json', 'count' => 100_000}
484
482
  )[:data]
485
483
  self.format.display_status("users: #{result['itemsPerPage']}/#{result['totalResults']}, start:#{result['startIndex']}")
486
484
  users = result['entry']
@@ -491,15 +489,15 @@ module Aspera
491
489
  u['email'] = email['value'] unless email.nil?
492
490
  end
493
491
  if u['email'].nil?
494
- Log.log.warn("Skip user without email: #{u}")
492
+ Log.log.warn{"Skip user without email: #{u}"}
495
493
  next
496
494
  end
497
- u['first_name'],u['last_name'] = u['displayName'].split(' ',2)
495
+ u['first_name'], u['last_name'] = u['displayName'].split(' ', 2)
498
496
  u['x'] = true
499
497
  end
500
- return {type: :object_list,data: users}
498
+ return {type: :object_list, data: users}
501
499
  when :login_methods
502
- login_meths = api_v3.call({operation: 'GET',subpath: 'login/new',headers: {'Accept' => 'application/xrds+xml'}})[:http].body
500
+ login_meths = api_v3.call({operation: 'GET', subpath: 'login/new', headers: {'Accept' => 'application/xrds+xml'}})[:http].body
503
501
  login_methods = XmlSimple.xml_in(login_meths, {'ForceArray' => false})
504
502
  return {type: :object_list, data: login_methods['XRD']['Service']}
505
503
  end # command