aspera-cli 4.5.0 → 4.8.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 (104) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -0
  3. data/README.md +1894 -1574
  4. data/bin/ascli +21 -1
  5. data/bin/asession +38 -34
  6. data/docs/test_env.conf +14 -3
  7. data/examples/aoc.rb +17 -15
  8. data/examples/dascli +26 -0
  9. data/examples/faspex4.rb +42 -35
  10. data/examples/proxy.pac +1 -1
  11. data/examples/transfer.rb +38 -37
  12. data/lib/aspera/aoc.rb +245 -205
  13. data/lib/aspera/ascmd.rb +111 -90
  14. data/lib/aspera/ats_api.rb +16 -14
  15. data/lib/aspera/cli/basic_auth_plugin.rb +19 -18
  16. data/lib/aspera/cli/extended_value.rb +50 -39
  17. data/lib/aspera/cli/formater.rb +161 -135
  18. data/lib/aspera/cli/info.rb +18 -0
  19. data/lib/aspera/cli/listener/line_dump.rb +4 -2
  20. data/lib/aspera/cli/listener/logger.rb +3 -1
  21. data/lib/aspera/cli/listener/progress.rb +20 -21
  22. data/lib/aspera/cli/listener/progress_multi.rb +29 -31
  23. data/lib/aspera/cli/main.rb +194 -183
  24. data/lib/aspera/cli/manager.rb +213 -206
  25. data/lib/aspera/cli/plugin.rb +71 -49
  26. data/lib/aspera/cli/plugins/alee.rb +8 -7
  27. data/lib/aspera/cli/plugins/aoc.rb +675 -558
  28. data/lib/aspera/cli/plugins/ats.rb +116 -109
  29. data/lib/aspera/cli/plugins/bss.rb +35 -34
  30. data/lib/aspera/cli/plugins/config.rb +722 -542
  31. data/lib/aspera/cli/plugins/console.rb +28 -22
  32. data/lib/aspera/cli/plugins/cos.rb +28 -37
  33. data/lib/aspera/cli/plugins/faspex.rb +281 -227
  34. data/lib/aspera/cli/plugins/faspex5.rb +129 -84
  35. data/lib/aspera/cli/plugins/node.rb +426 -232
  36. data/lib/aspera/cli/plugins/orchestrator.rb +106 -98
  37. data/lib/aspera/cli/plugins/preview.rb +196 -191
  38. data/lib/aspera/cli/plugins/server.rb +131 -126
  39. data/lib/aspera/cli/plugins/shares.rb +49 -36
  40. data/lib/aspera/cli/plugins/sync.rb +27 -28
  41. data/lib/aspera/cli/transfer_agent.rb +84 -79
  42. data/lib/aspera/cli/version.rb +3 -1
  43. data/lib/aspera/colors.rb +37 -28
  44. data/lib/aspera/command_line_builder.rb +84 -63
  45. data/lib/aspera/cos_node.rb +68 -34
  46. data/lib/aspera/data_repository.rb +4 -2
  47. data/lib/aspera/environment.rb +61 -46
  48. data/lib/aspera/fasp/agent_base.rb +36 -31
  49. data/lib/aspera/fasp/agent_connect.rb +44 -37
  50. data/lib/aspera/fasp/agent_direct.rb +101 -104
  51. data/lib/aspera/fasp/agent_httpgw.rb +91 -90
  52. data/lib/aspera/fasp/agent_node.rb +36 -33
  53. data/lib/aspera/fasp/agent_trsdk.rb +28 -31
  54. data/lib/aspera/fasp/error.rb +3 -1
  55. data/lib/aspera/fasp/error_info.rb +81 -54
  56. data/lib/aspera/fasp/installation.rb +171 -151
  57. data/lib/aspera/fasp/listener.rb +2 -0
  58. data/lib/aspera/fasp/parameters.rb +105 -111
  59. data/lib/aspera/fasp/parameters.yaml +305 -249
  60. data/lib/aspera/fasp/resume_policy.rb +20 -20
  61. data/lib/aspera/fasp/transfer_spec.rb +27 -0
  62. data/lib/aspera/fasp/uri.rb +31 -29
  63. data/lib/aspera/faspex_gw.rb +95 -118
  64. data/lib/aspera/hash_ext.rb +12 -13
  65. data/lib/aspera/id_generator.rb +11 -9
  66. data/lib/aspera/keychain/encrypted_hash.rb +73 -57
  67. data/lib/aspera/keychain/macos_security.rb +27 -29
  68. data/lib/aspera/log.rb +40 -39
  69. data/lib/aspera/nagios.rb +24 -22
  70. data/lib/aspera/node.rb +38 -30
  71. data/lib/aspera/oauth.rb +217 -248
  72. data/lib/aspera/open_application.rb +9 -7
  73. data/lib/aspera/persistency_action_once.rb +15 -14
  74. data/lib/aspera/persistency_folder.rb +15 -18
  75. data/lib/aspera/preview/file_types.rb +266 -270
  76. data/lib/aspera/preview/generator.rb +94 -92
  77. data/lib/aspera/preview/image_error.png +0 -0
  78. data/lib/aspera/preview/options.rb +20 -17
  79. data/lib/aspera/preview/utils.rb +99 -102
  80. data/lib/aspera/preview/video_error.png +0 -0
  81. data/lib/aspera/{proxy_auto_config.erb.js → proxy_auto_config.js} +23 -31
  82. data/lib/aspera/proxy_auto_config.rb +114 -21
  83. data/lib/aspera/rest.rb +144 -142
  84. data/lib/aspera/rest_call_error.rb +3 -2
  85. data/lib/aspera/rest_error_analyzer.rb +31 -31
  86. data/lib/aspera/rest_errors_aspera.rb +18 -16
  87. data/lib/aspera/secret_hider.rb +68 -0
  88. data/lib/aspera/ssh.rb +20 -16
  89. data/lib/aspera/sync.rb +57 -54
  90. data/lib/aspera/temp_file_manager.rb +20 -14
  91. data/lib/aspera/timer_limiter.rb +10 -8
  92. data/lib/aspera/uri_reader.rb +14 -15
  93. data/lib/aspera/web_auth.rb +85 -80
  94. data.tar.gz.sig +0 -0
  95. metadata +169 -40
  96. metadata.gz.sig +2 -0
  97. data/bin/dascli +0 -13
  98. data/docs/Makefile +0 -63
  99. data/docs/README.erb.md +0 -4221
  100. data/docs/README.md +0 -13
  101. data/docs/diagrams.txt +0 -49
  102. data/docs/doc_tools.rb +0 -58
  103. data/lib/aspera/cli/plugins/shares2.rb +0 -114
  104. data/lib/aspera/fasp/default.rb +0 -17
@@ -1,56 +1,90 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/log'
2
4
  require 'aspera/rest'
3
5
  require 'xmlsimple'
4
6
 
5
7
  module Aspera
6
8
  class CosNode < Rest
9
+ class << self
10
+ def parameters_from_svc_creds(service_credentials,bucket_region)
11
+ # check necessary contents
12
+ raise 'service_credentials must be a Hash' unless service_credentials.is_a?(Hash)
13
+ %w[apikey resource_instance_id endpoints].each do |field|
14
+ raise "service_credentials must have a field: #{field}" unless service_credentials.has_key?(field)
15
+ end
16
+ Aspera::Log.dump('service_credentials',service_credentials)
17
+ # read endpoints from service provided in service credentials
18
+ endpoints = Aspera::Rest.new({base_url: service_credentials['endpoints']}).read('')[:data]
19
+ Aspera::Log.dump('endpoints',endpoints)
20
+ storage_endpoint = endpoints.dig('service-endpoints','regional',bucket_region,'public',bucket_region)
21
+ raise "no such region: #{bucket_region}" if storage_endpoint.nil?
22
+ return {
23
+ instance_id: service_credentials['resource_instance_id'],
24
+ service_api_key: service_credentials['apikey'],
25
+ storage_endpoint: "https://#{storage_endpoint}"
26
+ }
27
+ end
28
+ end
29
+ IBM_CLOUD_TOKEN_URL = 'https://iam.cloud.ibm.com/identity'
30
+ TOKEN_FIELD = 'delegated_refresh_token'
7
31
  attr_reader :add_ts
8
- IBM_CLOUD_TOKEN_URL='https://iam.cloud.ibm.com/identity'
9
- TOKEN_FIELD='delegated_refresh_token'
10
32
  def initialize(bucket_name,storage_endpoint,instance_id,api_key,auth_url=IBM_CLOUD_TOKEN_URL)
11
- @auth_url=auth_url
12
- @api_key=api_key
13
- s3_api=Aspera::Rest.new({
14
- :base_url => storage_endpoint,
15
- :not_auth_codes => ['401','403'], # error codes when not authorized
16
- :headers => {'ibm-service-instance-id' => instance_id},
17
- :auth => {
18
- :type => :oauth2,
19
- :base_url => @auth_url,
20
- :grant => :ibm_apikey,
21
- :api_key => @api_key
22
- }})
33
+ @auth_url = auth_url
34
+ @api_key = api_key
35
+ s3_api = Aspera::Rest.new({
36
+ base_url: storage_endpoint,
37
+ not_auth_codes: %w[401 403], # error codes when not authorized
38
+ headers: {'ibm-service-instance-id' => instance_id},
39
+ auth: {
40
+ type: :oauth2,
41
+ base_url: @auth_url,
42
+ crtype: :generic,
43
+ generic: {
44
+ grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
45
+ response_type: 'cloud_iam',
46
+ apikey: @api_key
47
+ }}})
23
48
  # read FASP connection information for bucket
24
- xml_result_text=s3_api.call({:operation=>'GET',:subpath=>bucket_name,:headers=>{'Accept'=>'application/xml'},:url_params=>{'faspConnectionInfo'=>nil}})[:http].body
25
- ats_info=XmlSimple.xml_in(xml_result_text, {'ForceArray' => false})
49
+ xml_result_text = s3_api.call(
50
+ operation: 'GET',
51
+ subpath: bucket_name,
52
+ headers: {'Accept' => 'application/xml'},
53
+ url_params: {'faspConnectionInfo' => nil}
54
+ )[:http].body
55
+ ats_info = XmlSimple.xml_in(xml_result_text, {'ForceArray' => false})
26
56
  Aspera::Log.dump('ats_info',ats_info)
27
57
  super({
28
- :base_url => ats_info['ATSEndpoint'],
29
- :auth => {
30
- :type => :basic,
31
- :username => ats_info['AccessKey']['Id'],
32
- :password => ats_info['AccessKey']['Secret']}})
58
+ base_url: ats_info['ATSEndpoint'],
59
+ auth: {
60
+ type: :basic,
61
+ username: ats_info['AccessKey']['Id'],
62
+ password: ats_info['AccessKey']['Secret']}})
33
63
  # prepare transfer spec addition
34
- @add_ts={'tags'=>{'aspera'=>{'node'=>{'storage_credentials'=>{
64
+ @add_ts = {'tags' => {'aspera' => {'node' => {'storage_credentials' => {
35
65
  'type' => 'token',
36
- 'token' => {TOKEN_FIELD=>nil}
37
- }}}}}
66
+ 'token' => {TOKEN_FIELD => nil}
67
+ }}}}}
38
68
  generate_token
39
69
  end
40
70
 
41
71
  # potentially call this if delegated token is expired
42
72
  def generate_token
43
73
  # OAuth API to get delegated token
44
- delegated_oauth=Oauth.new({
45
- :type => :oauth2,
46
- :base_url => @auth_url,
47
- :grant => :delegated_refresh,
48
- :api_key => @api_key,
49
- :token_field=> TOKEN_FIELD
50
- })
51
- # get delagated token to be placed in rest call header and in transfer tags
52
- @add_ts['tags']['aspera']['node']['storage_credentials']['token'][TOKEN_FIELD]=delegated_oauth.get_authorization().gsub(/^Bearer /,'')
53
- @params[:headers]={'X-Aspera-Storage-Credentials'=>JSON.generate(@add_ts['tags']['aspera']['node']['storage_credentials'])}
74
+ delegated_oauth = Oauth.new({
75
+ type: :oauth2,
76
+ base_url: @auth_url,
77
+ token_field: TOKEN_FIELD,
78
+ crtype: :generic,
79
+ generic: {
80
+ grant_type: 'urn:ibm:params:oauth:grant-type:apikey',
81
+ response_type: 'delegated_refresh_token',
82
+ apikey: @api_key,
83
+ receiver_client_ids: 'aspera_ats'
84
+ }})
85
+ # get delegated token to be placed in rest call header and in transfer tags
86
+ @add_ts['tags']['aspera']['node']['storage_credentials']['token'][TOKEN_FIELD] = delegated_oauth.get_authorization.gsub(/^Bearer /,'')
87
+ @params[:headers] = {'X-Aspera-Storage-Credentials' => JSON.generate(@add_ts['tags']['aspera']['node']['storage_credentials'])}
54
88
  end
55
89
  end
56
90
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/log'
2
4
  require 'singleton'
3
5
 
@@ -6,8 +8,8 @@ module Aspera
6
8
  class DataRepository
7
9
  include Singleton
8
10
  # get binary value from data repository
9
- def get_bin(id)
10
- File.read(File.join(File.expand_path(File.dirname(__FILE__)),'data',id.to_s),mode: 'rb')
11
+ def data(id)
12
+ File.read(File.join(__dir__,'data',id.to_s),mode: 'rb')
11
13
  end
12
14
  end
13
15
  end
@@ -1,65 +1,80 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/log'
2
4
  require 'rbconfig'
3
5
 
4
6
  module Aspera
5
- # detect OS, architecture, and OS specific stuff
7
+ # detect OS, architecture, and specific stuff
6
8
  class Environment
7
9
  OS_WINDOWS = :windows
8
10
  OS_X = :osx
9
11
  OS_LINUX = :linux
10
12
  OS_AIX = :aix
11
- OS_LIST=[OS_WINDOWS,OS_X,OS_LINUX,OS_AIX]
13
+ OS_LIST = [OS_WINDOWS,OS_X,OS_LINUX,OS_AIX].freeze
14
+ CPU_X86_64 = :x86_64
15
+ CPU_PPC64 = :ppc64
16
+ CPU_PPC64LE = :ppc64le
17
+ CPU_S390 = :s390
18
+ CPU_LIST = [CPU_X86_64,CPU_PPC64,CPU_PPC64LE,CPU_S390].freeze
12
19
 
13
- def self.os
14
- case RbConfig::CONFIG['host_os']
15
- when /mswin/,/msys/,/mingw/,/cygwin/,/bccwin/,/wince/,/emc/
16
- return OS_WINDOWS
17
- when /darwin/,/mac os/
18
- return OS_X
19
- when /linux/
20
- return OS_LINUX
21
- when /aix/
22
- return OS_AIX
23
- else
24
- raise "Unknown OS: #{RbConfig::CONFIG['host_os']}"
20
+ class << self
21
+ def ruby_version
22
+ return RbConfig::CONFIG['RUBY_PROGRAM_VERSION']
25
23
  end
26
- end
27
- CPU_X86_64=:x86_64
28
- CPU_PPC64=:ppc64
29
- CPU_PPC64LE=:ppc64le
30
- CPU_S390=:s390
31
- CPU_LIST=[CPU_X86_64,CPU_PPC64,CPU_PPC64LE,CPU_S390]
32
24
 
33
- def self.cpu
34
- case RbConfig::CONFIG['host_cpu']
35
- when /x86_64/,/x64/
36
- return CPU_X86_64
37
- when /powerpc/
38
- return CPU_PPC64LE if os.eql?(OS_LINUX)
39
- return CPU_PPC64
40
- when /s390/
41
- return CPU_S390
42
- else # other
43
- raise "Unknown CPU: #{RbConfig::CONFIG['host_cpu']}"
25
+ def os
26
+ case RbConfig::CONFIG['host_os']
27
+ when /mswin/,/msys/,/mingw/,/cygwin/,/bccwin/,/wince/,/emc/
28
+ return OS_WINDOWS
29
+ when /darwin/,/mac os/
30
+ return OS_X
31
+ when /linux/
32
+ return OS_LINUX
33
+ when /aix/
34
+ return OS_AIX
35
+ else
36
+ raise "Unknown OS: #{RbConfig::CONFIG['host_os']}"
37
+ end
44
38
  end
45
- end
46
39
 
47
- def self.architecture
48
- return "#{os}-#{cpu}"
49
- end
40
+ def cpu
41
+ case RbConfig::CONFIG['host_cpu']
42
+ when /x86_64/,/x64/
43
+ return CPU_X86_64
44
+ when /powerpc/,/ppc64/
45
+ return CPU_PPC64LE if os.eql?(OS_LINUX)
46
+ return CPU_PPC64
47
+ when /s390/
48
+ return CPU_S390
49
+ else # other
50
+ raise "Unknown CPU: #{RbConfig::CONFIG['host_cpu']}"
51
+ end
52
+ end
50
53
 
51
- def self.exe_extension
52
- return '.exe' if os.eql?(OS_WINDOWS)
53
- return ''
54
- end
54
+ def architecture
55
+ return "#{os}-#{cpu}"
56
+ end
55
57
 
56
- # on Windows, the env var %USERPROFILE% provides the path to user's home more reliably than %HOMEDRIVE%%HOMEPATH%
57
- def self.fix_home
58
- if os.eql?(OS_WINDOWS)
59
- if ENV.has_key?('USERPROFILE') and Dir.exist?(ENV['USERPROFILE'])
60
- ENV['HOME']=ENV['USERPROFILE']
61
- Log.log.debug("Windows: set home to USERPROFILE: #{ENV['HOME']}")
62
- end
58
+ def exe_extension
59
+ return '.exe' if os.eql?(OS_WINDOWS)
60
+ return ''
61
+ end
62
+
63
+ # on Windows, the env var %USERPROFILE% provides the path to user's home more reliably than %HOMEDRIVE%%HOMEPATH%
64
+ # so, tell Ruby the right way
65
+ def fix_home
66
+ return unless os.eql?(OS_WINDOWS) && ENV.has_key?('USERPROFILE') && Dir.exist?(ENV['USERPROFILE'])
67
+ ENV['HOME'] = ENV['USERPROFILE']
68
+ Log.log.debug("Windows: set home to USERPROFILE: #{ENV['HOME']}")
69
+ end
70
+
71
+ def empty_binding
72
+ return Kernel.binding
73
+ end
74
+
75
+ # secure execution of Ruby code
76
+ def secure_eval(code)
77
+ Kernel.send('lave'.reverse,code,empty_binding, __FILE__, __LINE__)
63
78
  end
64
79
  end
65
80
  end
@@ -1,69 +1,75 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aspera
2
4
  module Fasp
3
5
  # Base class for FASP transfer agents
4
6
  # sub classes shall implement start_transfer and shutdown
5
7
  class AgentBase
8
+ # fields description for JSON generation
9
+ INTEGER_FIELDS = %w[Bytescont FaspFileArgIndex StartByte Rate MinRate Port Priority RateCap MinRateCap TCPPort CreatePolicy TimePolicy
10
+ DatagramSize XoptFlags VLinkVersion PeerVLinkVersion DSPipelineDepth PeerDSPipelineDepth ReadBlockSize WriteBlockSize
11
+ ClusterNumNodes ClusterNodeId Size Written Loss FileBytes PreTransferBytes TransferBytes PMTU Elapsedusec ArgScansAttempted
12
+ ArgScansCompleted PathScansAttempted FileScansCompleted TransfersAttempted TransfersPassed Delay].freeze
13
+ BOOLEAN_FIELDS = %w[Encryption Remote RateLock MinRateLock PolicyLock FilesEncrypt FilesDecrypt VLinkLocalEnabled VLinkRemoteEnabled
14
+ MoveRange Keepalive TestLogin UseProxy Precalc RTTAutocorrect].freeze
15
+ EXPECTED_METHODS = %i[text struct enhanced].freeze
16
+ private_constant :INTEGER_FIELDS,:BOOLEAN_FIELDS,:EXPECTED_METHODS
6
17
 
7
18
  private
8
19
 
9
- # fields description for JSON generation
10
- IntegerFields=['Bytescont','FaspFileArgIndex','StartByte','Rate','MinRate','Port','Priority','RateCap','MinRateCap','TCPPort','CreatePolicy','TimePolicy','DatagramSize','XoptFlags','VLinkVersion','PeerVLinkVersion','DSPipelineDepth','PeerDSPipelineDepth','ReadBlockSize','WriteBlockSize','ClusterNumNodes','ClusterNodeId','Size','Written','Loss','FileBytes','PreTransferBytes','TransferBytes','PMTU','Elapsedusec','ArgScansAttempted','ArgScansCompleted','PathScansAttempted','FileScansCompleted','TransfersAttempted','TransfersPassed','Delay']
11
- BooleanFields=['Encryption','Remote','RateLock','MinRateLock','PolicyLock','FilesEncrypt','FilesDecrypt','VLinkLocalEnabled','VLinkRemoteEnabled','MoveRange','Keepalive','TestLogin','UseProxy','Precalc','RTTAutocorrect']
12
- ExpectedMethod=[:text,:struct,:enhanced]
13
-
14
20
  # translates legacy event into enhanced (JSON) event
15
21
  def enhanced_event_format(event)
16
- return event.keys.inject({}) do |h,e|
22
+ return event.keys.each_with_object({}) do |e,h|
17
23
  # capital_to_snake_case
18
- new_name=e.
19
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
20
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
21
- gsub(/([a-z\d])(usec)$/,'\1_\2').
22
- downcase
23
- value=event[e]
24
- value=value.to_i if IntegerFields.include?(e)
25
- value=value.eql?('Yes') ? true : false if BooleanFields.include?(e)
26
- h[new_name]=value
27
- h
24
+ new_name = e.
25
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
26
+ gsub(/([a-z\d])(usec)$/,'\1_\2').
27
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
28
+ downcase
29
+ value = event[e]
30
+ value = value.to_i if INTEGER_FIELDS.include?(e)
31
+ value = value.eql?('Yes') if BOOLEAN_FIELDS.include?(e)
32
+ h[new_name] = value
28
33
  end
29
34
  end
30
35
 
31
36
  def initialize
32
- @listeners=[]
37
+ @listeners = []
33
38
  end
34
39
 
35
40
  def notify_listeners(current_event_text,current_event_data)
36
- Log.log.debug("send event to listeners")
37
- enhanced_event=nil
41
+ Log.log.debug('send event to listeners')
42
+ enhanced_event = nil
38
43
  @listeners.each do |listener|
39
- listener.send(:event_text,current_event_text) if listener.respond_to?(:event_text)
40
- listener.send(:event_struct,current_event_data) if listener.respond_to?(:event_struct)
44
+ listener.event_text(current_event_text) if listener.respond_to?(:event_text)
45
+ listener.event_struct(current_event_data) if listener.respond_to?(:event_struct)
41
46
  if listener.respond_to?(:event_enhanced)
42
- enhanced_event=enhanced_event_format(current_event_data) if enhanced_event.nil?
43
- listener.send(:event_enhanced,enhanced_event)
47
+ enhanced_event = enhanced_event_format(current_event_data) if enhanced_event.nil?
48
+ listener.event_enhanced(enhanced_event)
44
49
  end
45
50
  end
46
51
  end # notify_listeners
47
52
 
48
53
  def notify_begin(id,size)
49
- notify_listeners('emulated',{LISTENER_SESSION_ID_B=>id,'Type'=>'NOTIFICATION','PreTransferBytes'=>size})
54
+ notify_listeners('emulated',{LISTENER_SESSION_ID_B => id,'Type' => 'NOTIFICATION','PreTransferBytes' => size})
50
55
  end
51
56
 
52
57
  def notify_progress(id,size)
53
- notify_listeners('emulated',{LISTENER_SESSION_ID_B=>id,'Type'=>'STATS','Bytescont'=>size})
58
+ notify_listeners('emulated',{LISTENER_SESSION_ID_B => id,'Type' => 'STATS','Bytescont' => size})
54
59
  end
55
60
 
56
61
  def notify_end(id)
57
- notify_listeners('emulated',{LISTENER_SESSION_ID_B=>id,'Type'=>'DONE'})
62
+ notify_listeners('emulated',{LISTENER_SESSION_ID_B => id,'Type' => 'DONE'})
58
63
  end
59
64
 
60
65
  public
61
- LISTENER_SESSION_ID_B='ListenerSessionId'
62
- LISTENER_SESSION_ID_S='listener_session_id'
66
+
67
+ LISTENER_SESSION_ID_B = 'ListenerSessionId'
68
+ LISTENER_SESSION_ID_S = 'listener_session_id'
63
69
 
64
70
  # listener receives events
65
71
  def add_listener(listener)
66
- raise "expect one of #{ExpectedMethod}" if ExpectedMethod.inject(0){|m,e|m+=listener.respond_to?("event_#{e}")?1:0;m}.eql?(0)
72
+ raise "expect one of #{EXPECTED_METHODS}" if EXPECTED_METHODS.inject(0){|m,e|m += listener.respond_to?("event_#{e}") ? 1 : 0;m}.eql?(0)
67
73
  @listeners.push(listener)
68
74
  self
69
75
  end
@@ -72,14 +78,13 @@ module Aspera
72
78
  # it must be a list of :success or exception
73
79
  def self.validate_status_list(statuses)
74
80
  raise "internal error: bad statuses type: #{statuses.class}" unless statuses.is_a?(Array)
75
- raise "internal error: bad statuses content: #{statuses}" unless statuses.select{|i|!i.eql?(:success) and !i.is_a?(StandardError)}.empty?
81
+ raise "internal error: bad statuses content: #{statuses}" unless statuses.select{|i|!i.eql?(:success) && !i.is_a?(StandardError)}.empty?
76
82
  end
77
83
 
78
84
  # the following methods must be implemented by subclass:
79
85
  # start_transfer(transfer_spec,options) : start and wait for completion
80
86
  # wait_for_transfers_completion : wait for termination of all transfers, @return list of : :success or error message
81
87
  # optional: shutdown
82
-
83
88
  end
84
89
  end
85
90
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/fasp/agent_base'
2
4
  require 'aspera/rest'
3
5
  require 'aspera/open_application'
@@ -7,26 +9,26 @@ require 'tty-spinner'
7
9
  module Aspera
8
10
  module Fasp
9
11
  class AgentConnect < AgentBase
10
- MAX_CONNECT_START_RETRY=3
11
- SLEEP_SEC_BETWEEN_RETRY=2
12
+ MAX_CONNECT_START_RETRY = 3
13
+ SLEEP_SEC_BETWEEN_RETRY = 2
12
14
  private_constant :MAX_CONNECT_START_RETRY,:SLEEP_SEC_BETWEEN_RETRY
13
- def initialize(options)
15
+ def initialize(_options)
14
16
  super()
15
- @connect_settings={
17
+ @connect_settings = {
16
18
  'app_id' => SecureRandom.uuid
17
19
  }
18
20
  raise 'Using connect requires a graphical environment' if !OpenApplication.default_gui_mode.eql?(:graphical)
19
- trynumber=0
21
+ trynumber = 0
20
22
  begin
21
- connect_url=Installation.instance.connect_uri
23
+ connect_url = Installation.instance.connect_uri
22
24
  Log.log.debug("found: #{connect_url}")
23
- @connect_api=Rest.new({base_url: "#{connect_url}/v5/connect",headers: {'Origin'=>Rest.user_agent}}) # could use v6 also now
24
- cinfo=@connect_api.read('info/version')[:data]
25
+ @connect_api = Rest.new({base_url: "#{connect_url}/v5/connect",headers: {'Origin' => Rest.user_agent}}) # could use v6 also now
26
+ cinfo = @connect_api.read('info/version')[:data]
25
27
  Log.dump(:connect_version,cinfo)
26
- rescue => e # Errno::ECONNREFUSED
28
+ rescue StandardError => e # Errno::ECONNREFUSED
27
29
  raise StandardError,"Unable to start connect after #{trynumber} try" if trynumber >= MAX_CONNECT_START_RETRY
28
30
  Log.log.warn("connect is not started. Retry ##{trynumber}, err=#{e}")
29
- trynumber+=1
31
+ trynumber += 1
30
32
  if !OpenApplication.uri_graphical('fasp://initialize')
31
33
  OpenApplication.uri_graphical('https://downloads.asperasoft.com/connect2/')
32
34
  raise StandardError,'Connect is not installed'
@@ -36,41 +38,46 @@ module Aspera
36
38
  end
37
39
  end
38
40
 
39
- def start_transfer(transfer_spec,options=nil)
41
+ def start_transfer(transfer_spec,_options=nil)
40
42
  if transfer_spec['direction'] == 'send'
41
43
  Log.log.warn("Connect requires upload selection using GUI, ignoring #{transfer_spec['paths']}".red)
42
44
  transfer_spec.delete('paths')
43
- resdata=@connect_api.create('windows/select-open-file-dialog/',{'aspera_connect_settings'=>@connect_settings,'title'=>'Select Files','suggestedName'=>'','allowMultipleSelection'=>true,'allowedFileTypes'=>''})[:data]
44
- transfer_spec['paths']=resdata['dataTransfer']['files'].map { |i| {'source'=>i['name']}}
45
+ resdata = @connect_api.create('windows/select-open-file-dialog/',{
46
+ 'aspera_connect_settings' => @connect_settings,
47
+ 'title' => 'Select Files',
48
+ 'suggestedName' => '',
49
+ 'allowMultipleSelection' => true,
50
+ 'allowedFileTypes' => ''})[:data]
51
+ transfer_spec['paths'] = resdata['dataTransfer']['files'].map { |i| {'source' => i['name']}}
45
52
  end
46
- @request_id=SecureRandom.uuid
53
+ @request_id = SecureRandom.uuid
47
54
  # if there is a token, we ask connect client to use well known ssh private keys
48
55
  # instead of asking password
49
- transfer_spec['authentication']='token' if transfer_spec.has_key?('token')
50
- connect_transfer_args={
51
- 'aspera_connect_settings'=>@connect_settings.merge({
52
- 'request_id' =>@request_id,
53
- 'allow_dialogs' =>true,
56
+ transfer_spec['authentication'] = 'token' if transfer_spec.has_key?('token')
57
+ connect_transfer_args = {
58
+ 'aspera_connect_settings' => @connect_settings.merge({
59
+ 'request_id' => @request_id,
60
+ 'allow_dialogs' => true
54
61
  }),
55
- 'transfer_specs' =>[{
56
- 'transfer_spec' =>transfer_spec,
62
+ 'transfer_specs' => [{
63
+ 'transfer_spec' => transfer_spec
57
64
  }]}
58
65
  # asynchronous anyway
59
- res=@connect_api.create('transfers/start',connect_transfer_args)[:data]
60
- @xfer_id=res['transfer_specs'].first['transfer_spec']['tags']['aspera']['xfer_id']
66
+ res = @connect_api.create('transfers/start',connect_transfer_args)[:data]
67
+ @xfer_id = res['transfer_specs'].first['transfer_spec']['tags']['aspera']['xfer_id']
61
68
  end
62
69
 
63
70
  def wait_for_transfers_completion
64
- connect_activity_args={'aspera_connect_settings'=>@connect_settings}
65
- started=false
66
- spinner=nil
71
+ connect_activity_args = {'aspera_connect_settings' => @connect_settings}
72
+ started = false
73
+ spinner = nil
67
74
  begin
68
75
  loop do
69
- tr_info=@connect_api.create("transfers/info/#{@xfer_id}",connect_activity_args)[:data]
76
+ tr_info = @connect_api.create("transfers/info/#{@xfer_id}",connect_activity_args)[:data]
70
77
  if tr_info['transfer_info'].is_a?(Hash)
71
- trdata=tr_info['transfer_info']
78
+ trdata = tr_info['transfer_info']
72
79
  if trdata.nil?
73
- Log.log.warn("no session in Connect")
80
+ Log.log.warn('no session in Connect')
74
81
  break
75
82
  end
76
83
  # TODO: get session id
@@ -87,23 +94,23 @@ module Aspera
87
94
  spinner.spin
88
95
  when 'running'
89
96
  #puts "running: sessions:#{trdata['sessions'].length}, #{trdata['sessions'].map{|i| i['bytes_transferred']}.join(',')}"
90
- if !started and trdata['bytes_expected'] != 0
91
- spinner.success unless spinner.nil?
97
+ if !started && (trdata['bytes_expected'] != 0)
98
+ spinner&.success
92
99
  notify_begin(@connect_settings['app_id'],trdata['bytes_expected'])
93
- started=true
100
+ started = true
94
101
  else
95
102
  notify_progress(@connect_settings['app_id'],trdata['bytes_written'])
96
103
  end
97
104
  when 'failed'
98
- spinner.error unless spinner.nil?
99
- raise Fasp::Error.new(trdata['error_desc'])
105
+ spinner&.error
106
+ raise Fasp::Error, trdata['error_desc']
100
107
  else
101
- raise Fasp::Error.new("unknown status: #{trdata['status']}: #{trdata['error_desc']}")
108
+ raise Fasp::Error, "unknown status: #{trdata['status']}: #{trdata['error_desc']}"
102
109
  end
103
110
  end
104
- sleep 1
111
+ sleep(1)
105
112
  end
106
- rescue => e
113
+ rescue StandardError => e
107
114
  return [e]
108
115
  end
109
116
  return [:success]