aspera-cli 4.27.0 → 4.27.1

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 (140) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +29 -0
  4. data/CONTRIBUTING.md +1 -7
  5. data/TODO.md +50 -0
  6. data/docs/README.md +708 -488
  7. data/lib/aspera/agent/base.rb +10 -2
  8. data/lib/aspera/agent/connect.rb +7 -7
  9. data/lib/aspera/agent/desktop.rb +3 -3
  10. data/lib/aspera/agent/direct.rb +48 -19
  11. data/lib/aspera/agent/factory.rb +3 -3
  12. data/lib/aspera/agent/httpgw.rb +55 -14
  13. data/lib/aspera/agent/node.rb +2 -2
  14. data/lib/aspera/agent/transferd.rb +12 -12
  15. data/lib/aspera/api/aoc.rb +28 -28
  16. data/lib/aspera/api/cos_node.rb +10 -9
  17. data/lib/aspera/api/faspex.rb +2 -2
  18. data/lib/aspera/api/httpgw.rb +20 -20
  19. data/lib/aspera/api/node.rb +31 -53
  20. data/lib/aspera/ascmd.rb +13 -13
  21. data/lib/aspera/ascp/installation.rb +43 -36
  22. data/lib/aspera/ascp/management.rb +6 -6
  23. data/lib/aspera/assert.rb +12 -13
  24. data/lib/aspera/cli/ascp_actions.rb +7 -7
  25. data/lib/aspera/cli/async_transfer_store.rb +49 -5
  26. data/lib/aspera/cli/bootstrapper.rb +9 -9
  27. data/lib/aspera/cli/command_registry.rb +1 -1
  28. data/lib/aspera/cli/command_spec.rb +6 -3
  29. data/lib/aspera/cli/context.rb +3 -3
  30. data/lib/aspera/cli/extended_value.rb +26 -26
  31. data/lib/aspera/cli/formatter.rb +76 -54
  32. data/lib/aspera/cli/gem_checker.rb +1 -1
  33. data/lib/aspera/cli/hints.rb +2 -2
  34. data/lib/aspera/cli/http.rb +22 -29
  35. data/lib/aspera/cli/mailer.rb +7 -7
  36. data/lib/aspera/cli/mcp_tool.rb +31 -4
  37. data/lib/aspera/cli/option_declarator.rb +77 -0
  38. data/lib/aspera/cli/options.schema.yaml +273 -3
  39. data/lib/aspera/cli/parser.rb +539 -280
  40. data/lib/aspera/cli/plugins/alee.rb +1 -1
  41. data/lib/aspera/cli/plugins/aoc.rb +297 -313
  42. data/lib/aspera/cli/plugins/ats.rb +25 -21
  43. data/lib/aspera/cli/plugins/base.rb +357 -186
  44. data/lib/aspera/cli/plugins/basic_auth.rb +0 -12
  45. data/lib/aspera/cli/plugins/config.rb +76 -73
  46. data/lib/aspera/cli/plugins/console.rb +8 -8
  47. data/lib/aspera/cli/plugins/cos.rb +4 -3
  48. data/lib/aspera/cli/plugins/factory.rb +2 -2
  49. data/lib/aspera/cli/plugins/faspex5.rb +259 -248
  50. data/lib/aspera/cli/plugins/faspio.rb +7 -2
  51. data/lib/aspera/cli/plugins/httpgw.rb +1 -1
  52. data/lib/aspera/cli/plugins/mcp.rb +11 -11
  53. data/lib/aspera/cli/plugins/node.rb +227 -283
  54. data/lib/aspera/cli/plugins/orchestrator.rb +23 -23
  55. data/lib/aspera/cli/plugins/preview.rb +61 -64
  56. data/lib/aspera/cli/plugins/server.rb +36 -31
  57. data/lib/aspera/cli/plugins/shares.rb +174 -135
  58. data/lib/aspera/cli/preset_actions.rb +39 -19
  59. data/lib/aspera/cli/preset_manager.rb +74 -32
  60. data/lib/aspera/cli/result.rb +18 -16
  61. data/lib/aspera/cli/runner.rb +75 -39
  62. data/lib/aspera/cli/secret_finder.rb +1 -1
  63. data/lib/aspera/cli/sync_actions.rb +36 -35
  64. data/lib/aspera/cli/terminal_formatter.rb +2 -2
  65. data/lib/aspera/cli/transfer_actions.rb +17 -10
  66. data/lib/aspera/cli/transfer_agent.rb +44 -44
  67. data/lib/aspera/cli/transfer_progress.rb +7 -7
  68. data/lib/aspera/cli/vault_manager.rb +34 -12
  69. data/lib/aspera/cli/version.rb +1 -1
  70. data/lib/aspera/cli/wizard.rb +17 -20
  71. data/lib/aspera/colors.rb +3 -3
  72. data/lib/aspera/command_line_builder.rb +16 -16
  73. data/lib/aspera/command_line_converter.rb +1 -1
  74. data/lib/aspera/coverage.rb +1 -2
  75. data/lib/aspera/data_repository.rb +1 -1
  76. data/lib/aspera/dot_container.rb +8 -8
  77. data/lib/aspera/environment.rb +12 -12
  78. data/lib/aspera/faspex_gw.rb +4 -4
  79. data/lib/aspera/faspex_postproc.rb +14 -9
  80. data/lib/aspera/graphql.rb +4 -2
  81. data/lib/aspera/hash_ext.rb +2 -2
  82. data/lib/aspera/json_rpc/client.rb +1 -1
  83. data/lib/aspera/keychain/base.rb +10 -3
  84. data/lib/aspera/keychain/encrypted_hash.rb +92 -17
  85. data/lib/aspera/keychain/factory.rb +17 -5
  86. data/lib/aspera/keychain/hashicorp_vault.rb +1 -1
  87. data/lib/aspera/keychain/macos_security.rb +23 -25
  88. data/lib/aspera/keychain/one_password_api.rb +86 -0
  89. data/lib/aspera/keychain/one_password_base.rb +34 -0
  90. data/lib/aspera/keychain/one_password_cli.rb +98 -0
  91. data/lib/aspera/link_header.rb +2 -2
  92. data/lib/aspera/log.rb +13 -13
  93. data/lib/aspera/markdown.rb +5 -5
  94. data/lib/aspera/nagios.rb +8 -8
  95. data/lib/aspera/node_simulator.rb +33 -27
  96. data/lib/aspera/oauth/base.rb +4 -5
  97. data/lib/aspera/oauth/boot.rb +3 -3
  98. data/lib/aspera/oauth/factory.rb +5 -5
  99. data/lib/aspera/oauth/jwt.rb +5 -7
  100. data/lib/aspera/oauth/web.rb +4 -4
  101. data/lib/aspera/persistency_action_once.rb +4 -4
  102. data/lib/aspera/persistency_folder.rb +8 -8
  103. data/lib/aspera/preview/file_types.rb +4 -4
  104. data/lib/aspera/preview/generator.rb +49 -46
  105. data/lib/aspera/preview/options.rb +3 -2
  106. data/lib/aspera/preview/terminal.rb +5 -5
  107. data/lib/aspera/preview/utils.rb +65 -18
  108. data/lib/aspera/products/connect.rb +2 -2
  109. data/lib/aspera/products/desktop.rb +1 -1
  110. data/lib/aspera/products/other.rb +2 -2
  111. data/lib/aspera/products/transferd.rb +3 -3
  112. data/lib/aspera/proxy_auto_config.rb +10 -10
  113. data/lib/aspera/rest.rb +149 -115
  114. data/lib/aspera/rest_error_analyzer.rb +3 -3
  115. data/lib/aspera/rest_list.rb +10 -9
  116. data/lib/aspera/schema/IBM Aspera Node API-4.4.6.yaml +6232 -0
  117. data/lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0.yaml +249 -0
  118. data/lib/aspera/schema/IBM_Aspera_Shares.yaml +4653 -0
  119. data/lib/aspera/schema/documentation.rb +17 -11
  120. data/lib/aspera/schema/reader.rb +78 -4
  121. data/lib/aspera/schema/registry.rb +26 -7
  122. data/lib/aspera/secret_hider.rb +5 -5
  123. data/lib/aspera/ssh.rb +64 -31
  124. data/lib/aspera/ssl.rb +3 -3
  125. data/lib/aspera/sync/database.rb +2 -2
  126. data/lib/aspera/sync/operations.rb +13 -13
  127. data/lib/aspera/temp_file_manager.rb +24 -4
  128. data/lib/aspera/transfer/faux_file.rb +2 -2
  129. data/lib/aspera/transfer/parameters.rb +15 -15
  130. data/lib/aspera/transfer/resumer.rb +9 -9
  131. data/lib/aspera/transfer/spec.rb +1 -1
  132. data/lib/aspera/uri_reader.rb +52 -15
  133. data/lib/aspera/web_auth.rb +6 -5
  134. data/lib/aspera/web_server_simple.rb +9 -9
  135. data/lib/aspera/yaml.rb +4 -4
  136. data.tar.gz.sig +0 -0
  137. metadata +10 -4
  138. metadata.gz.sig +0 -0
  139. data/lib/aspera/cli/plugins/faspex.rb +0 -576
  140. data/lib/aspera/transfer/uri.rb +0 -56
@@ -65,7 +65,7 @@ module Aspera
65
65
  MAX_AOC_URL_REDIRECT = 10
66
66
  CLIENT_ID_PREFIX = 'aspera.'
67
67
  # Well-known AoC global client apps
68
- GLOBAL_CLIENT_APPS = DataRepository::ELEMENTS.select{ |i| i.to_s.start_with?(CLIENT_ID_PREFIX)}.freeze
68
+ GLOBAL_CLIENT_APPS = DataRepository::ELEMENTS.select { |i| i.to_s.start_with?(CLIENT_ID_PREFIX) }.freeze
69
69
  # cookie prefix so that console can decode identity
70
70
  COOKIE_PREFIX_CONSOLE_AOC = 'aspera.aoc'
71
71
  # path in URL of public links (warning if not in list)
@@ -123,9 +123,9 @@ module Aspera
123
123
  # split host of URL into organization and domain
124
124
  def split_org_domain(uri)
125
125
  Aspera.assert_type(uri, URI)
126
- Aspera.assert(!uri.host.nil?){"No host found in URL. Please check URL format: https://myorg.#{SAAS_DOMAIN_PROD}"}
126
+ Aspera.assert(!uri.host.nil?) { "No host found in URL. Please check URL format: https://myorg.#{SAAS_DOMAIN_PROD}" }
127
127
  parts = uri.host.split('.', 2)
128
- Aspera.assert(parts.length == 2){"expecting a public FQDN for #{PRODUCT_NAME}"}
128
+ Aspera.assert(parts.length == 2) { "expecting a public FQDN for #{PRODUCT_NAME}" }
129
129
  parts[0] = nil if parts[0].eql?('api')
130
130
  return %i{organization domain}.zip(parts).to_h
131
131
  end
@@ -146,14 +146,14 @@ module Aspera
146
146
  if (m = final_uri.path.match(%r{/oauth2/([^/]+)/login$}))
147
147
  org_domain[:organization] = m[1] if org_domain[:organization].nil?
148
148
  else
149
- Log.log.debug{"path=#{final_uri.path} does not end with /login"}
149
+ Log.log.debug { "path=#{final_uri.path} does not end with /login" }
150
150
  end
151
151
  Aspera.assert(!final_uri.query.nil?, 'AoC shall redirect to login page with a query', type: Error)
152
152
  query = Rest.query_to_h(final_uri.query)
153
153
  Log.dump(:query, query, level: :trace1)
154
154
  # is that a public link ?
155
155
  if query.key?('token')
156
- Log.log.warn{"Unknown pub link path: #{final_uri.path}"} unless PUBLIC_LINK_PATHS.include?(final_uri.path)
156
+ Log.log.warn { "Unknown pub link path: #{final_uri.path}" } unless PUBLIC_LINK_PATHS.include?(final_uri.path)
157
157
  # ok we get it !
158
158
  return {
159
159
  instance_domain: org_domain[:domain],
@@ -198,7 +198,7 @@ module Aspera
198
198
  # @option return [Array<Hash>] :items The list of items
199
199
  # @option return [Integer] :total The total number of items
200
200
  def call_paging(query: {})
201
- Aspera.assert_type(query, Hash){'query'}
201
+ Aspera.assert_type(query, Hash) { 'query' }
202
202
  Aspera.assert(block_given?, 'block required for call_paging')
203
203
  # set default large page if user does not specify own parameters. AoC Caps to 1000 anyway
204
204
  query['per_page'] = 1000 unless query.key?('per_page')
@@ -257,10 +257,10 @@ module Aspera
257
257
  when 'download' then %w[list preview read]
258
258
  when 'upload' then %w[mkdir write]
259
259
  when Array
260
- Aspera.assert_array_all(levels, String){'access_levels'}
261
- levels.each{ |level| Aspera.assert_values(level, Node::ACCESS_LEVELS){'access_level'}}
260
+ Aspera.assert_array_all(levels, String) { 'access_levels' }
261
+ levels.each { |level| Aspera.assert_values(level, Node::ACCESS_LEVELS) { 'access_level' } }
262
262
  levels
263
- else Aspera.error_unexpected_value(levels){"access_levels must be a list of #{Node::ACCESS_LEVELS.join(', ')} or one of edit, preview, download, upload"}
263
+ else Aspera.error_unexpected_value(levels) { "access_levels must be a list of #{Node::ACCESS_LEVELS.join(', ')} or one of edit, preview, download, upload" }
264
264
  end
265
265
  end
266
266
  end
@@ -352,7 +352,7 @@ module Aspera
352
352
  when :none
353
353
  auth_params.clear
354
354
  auth_params[:type] = :none
355
- else Aspera.error_unexpected_value(auth_params[:grant_method]){'auth, use one of: web, jwt, boot'}
355
+ else Aspera.error_unexpected_value(auth_params[:grant_method]) { 'auth, use one of: web, jwt, boot' }
356
356
  end
357
357
  super(**base_args)
358
358
  end
@@ -369,7 +369,7 @@ module Aspera
369
369
 
370
370
  # @param expected [Array<String>] Link types
371
371
  def assert_public_link_types(expected)
372
- Aspera.assert_values(public_link['purpose'], expected){'public link type'}
372
+ Aspera.assert_values(public_link['purpose'], expected) { 'public link type' }
373
373
  end
374
374
 
375
375
  def additional_persistence_ids
@@ -396,10 +396,10 @@ module Aspera
396
396
  read('self')
397
397
  rescue Aspera::RestCallError => e
398
398
  raise if exception || e.message.include?('invalid_grant')
399
- Log.log.debug{"Ignoring error: (#{e.class}) #{e}"}
399
+ Log.log.debug { "Ignoring error: (#{e.class}) #{e}" }
400
400
  {}
401
401
  end
402
- USER_INFO_FIELDS_MIN.each{ |f| @cache_user_info[f] = nil if @cache_user_info[f].nil?}
402
+ USER_INFO_FIELDS_MIN.each { |f| @cache_user_info[f] = nil if @cache_user_info[f].nil? }
403
403
  return @cache_user_info
404
404
  end
405
405
 
@@ -488,7 +488,7 @@ module Aspera
488
488
  ak_secret = @secret_finder&.lookup(url: node_info['url'], username: node_info['access_key'])
489
489
  # If secret is available, or no scope, use basic auth
490
490
  if scope.nil? || ak_secret
491
- Aspera.assert(ak_secret, type: Error){"Secret not found for access key #{node_info['access_key']}@#{node_info['url']}"}
491
+ Aspera.assert(ak_secret, type: Error) { "Secret not found for access key #{node_info['access_key']}@#{node_info['url']}" }
492
492
  node_params[:auth] = {
493
493
  type: :basic,
494
494
  username: node_info['access_key'],
@@ -519,21 +519,21 @@ module Aspera
519
519
  Log.log.debug('no metadata in shared inbox')
520
520
  return
521
521
  end
522
- Aspera.assert(pkg_data.key?('metadata')){"package requires metadata: #{meta_schema}"}
522
+ Aspera.assert(pkg_data.key?('metadata')) { "package requires metadata: #{meta_schema}" }
523
523
  pkg_meta = pkg_data['metadata']
524
- Aspera.assert_type(pkg_meta, Array){'metadata'}
524
+ Aspera.assert_type(pkg_meta, Array) { 'metadata' }
525
525
  Log.dump(:metadata, pkg_meta)
526
526
  pkg_meta.each do |field|
527
- Aspera.assert_type(field, Hash){'metadata field'}
527
+ Aspera.assert_type(field, Hash) { 'metadata field' }
528
528
  Aspera.assert(field.key?('name'), 'metadata field must have name')
529
529
  Aspera.assert(field.key?('values'), 'metadata field must have values')
530
- Aspera.assert_type(field['values'], Array){'metadata field values'}
531
- Aspera.assert(meta_schema.any?{ |i| i['name'].eql?(field['name'])}){"unknown metadata field: #{field['name']}"}
530
+ Aspera.assert_type(field['values'], Array) { 'metadata field values' }
531
+ Aspera.assert(meta_schema.any? { |i| i['name'].eql?(field['name']) }) { "unknown metadata field: #{field['name']}" }
532
532
  end
533
533
  meta_schema.each do |field|
534
- provided = pkg_meta.select{ |i| i['name'].eql?(field['name'])}
535
- Aspera.assert(provided.count <= 1, type: Error){"only one field with name #{field['name']} allowed"}
536
- Aspera.assert(!provided.empty?, type: Error){"missing mandatory field: #{field['name']}"} if field['required']
534
+ provided = pkg_meta.select { |i| i['name'].eql?(field['name']) }
535
+ Aspera.assert(provided.count <= 1, type: Error) { "only one field with name #{field['name']} allowed" }
536
+ Aspera.assert(!provided.empty?, type: Error) { "missing mandatory field: #{field['name']}" } if field['required']
537
537
  end
538
538
  end
539
539
 
@@ -546,16 +546,16 @@ module Aspera
546
546
  # @return [nil] `package_data` is modified in place
547
547
  def resolve_package_recipients(package_data, rcpt_lst_field, new_user_option)
548
548
  return unless package_data.key?(rcpt_lst_field)
549
- Aspera.assert_type(package_data[rcpt_lst_field], Array){rcpt_lst_field}
549
+ Aspera.assert_type(package_data[rcpt_lst_field], Array) { rcpt_lst_field }
550
550
  new_user_option = {'package_contact' => true} if new_user_option.nil?
551
- Aspera.assert_type(new_user_option, Hash){'new_user_option'}
551
+ Aspera.assert_type(new_user_option, Hash) { 'new_user_option' }
552
552
  ws_id = package_data['workspace_id']
553
553
  # list with resolved elements
554
554
  resolved_list = []
555
555
  package_data[rcpt_lst_field].each do |short_recipient_info|
556
556
  case short_recipient_info
557
557
  when Hash # native API information, check keys
558
- Aspera.assert(short_recipient_info.keys.sort.eql?(%w[id type])){"#{rcpt_lst_field} element shall have fields: id and type"}
558
+ Aspera.assert(short_recipient_info.keys.sort.eql?(%w[id type])) { "#{rcpt_lst_field} element shall have fields: id and type" }
559
559
  when String # CLI helper: need to resolve provided name to type/id
560
560
  # email: user, else dropbox
561
561
  entity_type = short_recipient_info.include?('@') ? 'contacts' : 'dropboxes'
@@ -563,7 +563,7 @@ module Aspera
563
563
  full_recipient_info = lookup_with_q(entity_type, value: short_recipient_info, query: {'workspace_id' => ws_id})
564
564
  rescue EntityNotFound
565
565
  # dropboxes cannot be created on the fly
566
- Aspera.assert_values(entity_type, %w[contacts], type: Error){"No such shared inbox in workspace #{ws_id}"}
566
+ Aspera.assert_values(entity_type, %w[contacts], type: Error) { "No such shared inbox in workspace #{ws_id}" }
567
567
  # unknown user: create it as external user
568
568
  full_recipient_info = create('contacts', {
569
569
  'current_workspace_id' => ws_id,
@@ -575,7 +575,7 @@ module Aspera
575
575
  else
576
576
  {'id' => full_recipient_info['source_id'], 'type' => full_recipient_info['source_type']}
577
577
  end
578
- else Aspera.error_unexpected_value(short_recipient_info.class.name){"#{rcpt_lst_field} item must be a String (email, shared inbox) or Hash (id,type)"}
578
+ else Aspera.error_unexpected_value(short_recipient_info.class.name) { "#{rcpt_lst_field} item must be a String (email, shared inbox) or Hash (id,type)" }
579
579
  end
580
580
  # add original or resolved recipient info
581
581
  resolved_list.push(short_recipient_info)
@@ -669,7 +669,7 @@ module Aspera
669
669
  # Console cookie
670
670
  ################
671
671
  # we are sure that fields are not nil
672
- cookie_elements = [app_info.app, current_user_info['name'] || 'public link', current_user_info['email'] || 'none'].map{ |e| Base64.strict_encode64(e)}
672
+ cookie_elements = [app_info.app, current_user_info['name'] || 'public link', current_user_info['email'] || 'none'].map { |e| Base64.strict_encode64(e) }
673
673
  cookie_elements.unshift(COOKIE_PREFIX_CONSOLE_AOC)
674
674
  transfer_spec['cookie'] = cookie_elements.join(':')
675
675
  # Application tags
@@ -12,19 +12,20 @@ module Aspera
12
12
  IBM_CLOUD_TOKEN_URL = 'https://iam.cloud.ibm.com/identity'
13
13
  TOKEN_FIELD = 'delegated_refresh_token'
14
14
  FASP_INFO_KEYS = %w[ATSEndpoint AccessKey].freeze
15
+ SERVICE_CREDS_PARAMS = %w[apikey resource_instance_id endpoints]
15
16
  class << self
16
17
  def parameters_from_svc_credentials(service_credentials, bucket_region)
17
18
  # check necessary contents
18
- Aspera.assert_type(service_credentials, Hash){'service_credentials'}
19
+ Aspera.assert_type(service_credentials, Hash) { 'service_credentials' }
19
20
  Log.dump(:service_credentials, service_credentials)
20
- %w[apikey resource_instance_id endpoints].each do |field|
21
- Aspera.assert(service_credentials.key?(field)){"service_credentials must have a field: #{field}"}
21
+ SERVICE_CREDS_PARAMS.each do |field|
22
+ Aspera.assert(service_credentials.key?(field)) { "service_credentials must have a field: #{field}" }
22
23
  end
23
24
  # read endpoints from service provided in service credentials
24
25
  endpoints = Aspera::Rest.new(base_url: service_credentials['endpoints']).read('')
25
26
  Log.dump(:endpoints, endpoints)
26
27
  endpoint = endpoints.dig('service-endpoints', 'regional', bucket_region, 'public', bucket_region)
27
- Aspera.assert(!endpoint.nil?){"no such region: #{bucket_region}"}
28
+ Aspera.assert(!endpoint.nil?) { "no such region: #{bucket_region}" }
28
29
  return {
29
30
  instance_id: service_credentials['resource_instance_id'],
30
31
  api_key: service_credentials['apikey'],
@@ -34,8 +35,8 @@ module Aspera
34
35
  end
35
36
 
36
37
  def initialize(instance_id:, api_key:, endpoint:, bucket:, auth_url: IBM_CLOUD_TOKEN_URL)
37
- Aspera.assert_type(instance_id, String){'resource instance id (crn)'}
38
- Aspera.assert_type(endpoint, String){'endpoint'}
38
+ Aspera.assert_type(instance_id, String) { 'resource instance id (crn)' }
39
+ Aspera.assert_type(endpoint, String) { 'endpoint' }
39
40
  endpoint = "https://#{endpoint}" unless endpoint.start_with?('http')
40
41
  @auth_url = auth_url
41
42
  @api_key = api_key
@@ -61,10 +62,10 @@ module Aspera
61
62
  ret: :resp
62
63
  ).body
63
64
  ats_info = XmlSimple.xml_in(xml_result_text, {'ForceArray' => false})
64
- Log.dump(:ats_info, ats_info)
65
- Aspera.assert_hash_all(ats_info, String, nil){'ats_info'}
65
+ Log.dump(:ats_info, ats_info.reject { |k, _| k == 'AccessKey' })
66
+ Aspera.assert_hash_all(ats_info, String, nil) { 'ats_info' }
66
67
  Aspera.assert((FASP_INFO_KEYS - ats_info.keys).empty?, 'ats_info missing required keys')
67
- Aspera.assert_hash_all(ats_info['AccessKey'], String, String){'ats_info'}
68
+ Aspera.assert_hash_all(ats_info['AccessKey'], String, String) { 'ats_info' }
68
69
  @storage_credentials = {
69
70
  'type' => 'token',
70
71
  'token' => {TOKEN_FIELD => nil}
@@ -170,7 +170,7 @@ module Aspera
170
170
  Log.dump(:final_url, final_url, level: :trace1)
171
171
  # Get context from query
172
172
  encoded_context = Rest.query_to_h(URI.parse(final_url).query)['context']
173
- Aspera.assert(!encoded_context.nil?, type: ParameterError){'Bad faspex5 public link, missing context in query'}
173
+ Aspera.assert(!encoded_context.nil?, type: ParameterError) { 'Bad faspex5 public link, missing context in query' }
174
174
  # public link information (contains passcode and allowed usage)
175
175
  @pub_link_context = JSON.parse(Base64.decode64(encoded_context))
176
176
  Log.dump(:pub_link_context, @pub_link_context, level: :trace1)
@@ -238,7 +238,7 @@ module Aspera
238
238
  headers: {typ: 'JWT'}
239
239
  }
240
240
  }
241
- else Aspera.error_unexpected_value(auth, type: ParameterError){'auth'}
241
+ else Aspera.error_unexpected_value(auth, type: ParameterError) { 'auth' }
242
242
  end
243
243
  )
244
244
  end
@@ -60,7 +60,7 @@ module Aspera
60
60
 
61
61
  # send data on http gw web socket
62
62
  def ws_send(ws_type:, data:)
63
- Log.log.trace1{"#{LOG_WS_SEND}sending: #{ws_type} (#{data&.length || 0} bytes)"}
63
+ Log.log.trace1 { "#{LOG_WS_SEND}sending: #{ws_type} (#{data&.length || 0} bytes)" }
64
64
  @shared_info[:count][:sent_general] += 1 if ws_type.eql?(:binary)
65
65
  frame_generator = ::WebSocket::Frame::Outgoing::Client.new(data: data, type: ws_type, version: @ws_handshake.version)
66
66
  @ws_io.write(frame_generator.to_s)
@@ -72,12 +72,12 @@ module Aspera
72
72
  @shared_info[:read_exception].nil? &&
73
73
  (((@shared_info[:count][:sent_general] - @shared_info[:count][:received_general]) > 1) ||
74
74
  ((@shared_info[:count][:received_v2_delimiter] - @shared_info[:count][:sent_v2_delimiter]) > 1))
75
- Log.log.trace1{"#{LOG_WS_SEND}#{'timeout'.blue}: #{@shared_info[:count]}"} if !@shared_info[:cond_var].wait(@shared_info[:mutex], 2.0)
75
+ Log.log.trace1 { "#{LOG_WS_SEND}#{'timeout'.blue}: #{@shared_info[:count]}" } if !@shared_info[:cond_var].wait(@shared_info[:mutex], 2.0)
76
76
  end
77
77
  end
78
78
  end
79
79
  raise @shared_info[:read_exception] unless @shared_info[:read_exception].nil?
80
- Log.log.trace2{"#{LOG_WS_SEND}counts: #{@shared_info[:count]}"}
80
+ Log.log.trace2 { "#{LOG_WS_SEND}counts: #{@shared_info[:count]}" }
81
81
  end
82
82
 
83
83
  # Check header ourself and give precise error message, as websocket will only throw error without details
@@ -91,7 +91,7 @@ module Aspera
91
91
 
92
92
  # message processing for read thread
93
93
  def process_received_message(message)
94
- Log.log.debug{"#{LOG_WS_RECV}message: [#{message}] (#{message.class})"}
94
+ Log.log.debug { "#{LOG_WS_RECV}message: [#{message}] (#{message.class})" }
95
95
  if message.eql?(MSG_RECV_DATA_RECEIVED_SIGNAL)
96
96
  @shared_info[:mutex].synchronize do
97
97
  @shared_info[:count][:received_general] += 1
@@ -119,21 +119,21 @@ module Aspera
119
119
 
120
120
  # main function of read thread
121
121
  def process_read_thread
122
- Log.log.debug{"#{LOG_WS_RECV}read thread started"}
122
+ Log.log.debug { "#{LOG_WS_RECV}read thread started" }
123
123
  frame_parser = ::WebSocket::Frame::Incoming::Client.new(version: @ws_handshake.version)
124
124
  until @ws_io.eof?
125
125
  begin
126
126
  # ready byte by byte until frame is ready
127
127
  # blocking read
128
128
  byte = @ws_io.read(1)
129
- Log.log.trace2{"#{LOG_WS_RECV}read: #{byte} (#{byte.class}) eof=#{@ws_io.eof?}"}
129
+ Log.log.trace2 { "#{LOG_WS_RECV}read: #{byte} (#{byte.class}) eof=#{@ws_io.eof?}" }
130
130
  frame_parser << byte
131
131
  frame_ok = frame_parser.next
132
132
  next if frame_ok.nil?
133
133
  process_received_message(frame_ok.data.to_s)
134
- Log.log.trace2{"#{LOG_WS_RECV}counts: #{@shared_info[:count]}"}
134
+ Log.log.trace2 { "#{LOG_WS_RECV}counts: #{@shared_info[:count]}" }
135
135
  rescue => e
136
- Log.log.debug{"#{LOG_WS_RECV}Exception: #{e}"}
136
+ Log.log.debug { "#{LOG_WS_RECV}Exception: #{e}" }
137
137
  @shared_info[:mutex].synchronize do
138
138
  @shared_info[:read_exception] = e
139
139
  @shared_info[:cond_var].signal
@@ -144,7 +144,7 @@ module Aspera
144
144
  Log.log.debug do
145
145
  "#{LOG_WS_RECV}exception: #{@shared_info[:read_exception]},cls=#{@shared_info[:read_exception].class})"
146
146
  end unless @shared_info[:read_exception].nil?
147
- Log.log.debug{"#{LOG_WS_RECV}read thread stopped (ws eof=#{@ws_io.eof?})"}
147
+ Log.log.debug { "#{LOG_WS_RECV}read thread stopped (ws eof=#{@ws_io.eof?})" }
148
148
  end
149
149
 
150
150
  def upload(transfer_spec)
@@ -170,7 +170,7 @@ module Aspera
170
170
  # Get whole HTTP response header, Check and process
171
171
  # no need to check `finished?` or result of `<<` (true), as we give the whole header at once
172
172
  @ws_handshake << validated_ws_response_header(@ws_io.readuntil("\r\n\r\n"))
173
- Log.log.debug{"#{LOG_WS_SEND}handshake success"}
173
+ Log.log.debug { "#{LOG_WS_SEND}handshake success" }
174
174
  # data shared between main thread and read thread
175
175
  @shared_info = {
176
176
  read_exception: nil, # error message if any in callback
@@ -184,7 +184,7 @@ module Aspera
184
184
  cond_var: ConditionVariable.new
185
185
  }
186
186
  # start read thread after handshake
187
- @ws_read_thread = Thread.new{process_read_thread}
187
+ @ws_read_thread = Thread.new { process_read_thread }
188
188
  @notify_cb&.call(:session_start, session_id: session_id)
189
189
  @notify_cb&.call(:session_size, session_id: session_id, info: total_bytes_to_transfer)
190
190
  sleep(1)
@@ -224,7 +224,7 @@ module Aspera
224
224
  # send once, before data, at beginning
225
225
  ws_snd_json(MSG_SEND_SLICE_UPLOAD, slice_info) if slice_info[:slice].eql?(0)
226
226
  ws_send(ws_type: :binary, data: slice_bin_data)
227
- Log.log.trace1{"#{LOG_WS_SEND}buffer: file: #{file_index}, slice: #{slice_info[:slice]}/#{last_slice}"}
227
+ Log.log.trace1 { "#{LOG_WS_SEND}buffer: file: #{file_index}, slice: #{slice_info[:slice]}/#{last_slice}" }
228
228
  # send once, after data, at end
229
229
  ws_snd_json(MSG_SEND_SLICE_UPLOAD, slice_info) if slice_info[:slice].eql?(last_slice)
230
230
  end
@@ -232,7 +232,7 @@ module Aspera
232
232
  raise @shared_info[:read_exception] unless @shared_info[:read_exception].nil?
233
233
  raise e
234
234
  rescue Net::ReadTimeout => e
235
- Log.log.warn{'A timeout condition using HTTPGW may signal a permission problem on destination. Check ascp logs on httpgw.'}
235
+ Log.log.warn { 'A timeout condition using HTTPGW may signal a permission problem on destination. Check ascp logs on httpgw.' }
236
236
  raise e
237
237
  end
238
238
  session_sent_bytes += slice_bin_data.length
@@ -250,7 +250,7 @@ module Aspera
250
250
  ws_send(ws_type: :close, data: nil)
251
251
  Log.log.debug("Finished upload, waiting for end of #{THR_RECV} thread.")
252
252
  @ws_read_thread.join
253
- Log.log.debug{'Read thread joined'}
253
+ Log.log.debug { 'Read thread joined' }
254
254
  ensure
255
255
  # session no more used
256
256
  @ws_io = nil
@@ -284,7 +284,7 @@ module Aspera
284
284
  File.basename(default_file_name)
285
285
  end
286
286
  file_path = File.join(transfer_spec['destination_root'], file_name)
287
- call(operation: 'GET', subpath: "download/#{transfer_uuid}", save_to_file: file_path)
287
+ call(operation: 'GET', subpath: "download/#{transfer_uuid}", save_to: file_path)
288
288
  end
289
289
 
290
290
  def info
@@ -308,7 +308,7 @@ module Aspera
308
308
  Log.dump(:gw_url, url)
309
309
  # add scheme if missing
310
310
  url = "https://#{url}" unless url.match?(%r{^[a-z]{1,6}://})
311
- Aspera.assert(url.start_with?('https://'), type: Error){'GW URL shall be with scheme https'}
311
+ Aspera.assert(url.start_with?('https://'), type: Error) { 'GW URL shall be with scheme https' }
312
312
  # remove trailing slash and version (o=only once) if present
313
313
  # TODO: issue warning ?
314
314
  url = url.chomp('/').gsub(%r{/#{API_V1}$}o, '')
@@ -326,8 +326,8 @@ module Aspera
326
326
  # web socket endpoint: by default use v2 (newer gateways), without base64 encoding
327
327
  # is the latest supported? else revert to old api
328
328
  if !@upload_version.eql?(API_V1)
329
- if !@api_info['endpoints'].any?{ |i| i.include?(@upload_version)}
330
- Log.log.warn{"API version #{@upload_version} not supported, reverting to #{API_V1}"}
329
+ if !@api_info['endpoints'].any? { |i| i.include?(@upload_version) }
330
+ Log.log.warn { "API version #{@upload_version} not supported, reverting to #{API_V1}" }
331
331
  @upload_version = API_V1
332
332
  end
333
333
  end
@@ -386,7 +386,7 @@ module Aspera
386
386
  size: file_size
387
387
  })
388
388
  else
389
- Log.log.warn{"Ignoring non file/directory: #{entry_path}"}
389
+ Log.log.warn { "Ignoring non file/directory: #{entry_path}" }
390
390
  end
391
391
  end
392
392
  end
@@ -394,7 +394,7 @@ module Aspera
394
394
  raise "File not found: #{source_path}"
395
395
  end
396
396
  end
397
- transfer_spec['paths'] = files_to_send.map{ |i| {'source' => i[:name]}}
397
+ transfer_spec['paths'] = files_to_send.map { |i| {'source' => i[:name]} }
398
398
  files_to_send.push(total_bytes_to_transfer)
399
399
  return files_to_send
400
400
  end