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,5 +1,7 @@
1
- #!/bin/echo this is a ruby class:
1
+ # frozen_string_literal: true
2
+
2
3
  require 'aspera/fasp/agent_base'
4
+ require 'aspera/fasp/transfer_spec'
3
5
  require 'aspera/log'
4
6
  require 'aspera/rest'
5
7
  require 'websocket-client-simple'
@@ -14,9 +16,9 @@ module Aspera
14
16
  # start a transfer using Aspera HTTP Gateway, using web socket session
15
17
  class AgentHttpgw < AgentBase
16
18
  # message returned by HTTP GW in case of success
17
- OK_MESSAGE='end upload'
19
+ OK_MESSAGE = 'end upload'
18
20
  # refresh rate for progress
19
- UPLOAD_REFRESH_SEC=0.5
21
+ UPLOAD_REFRESH_SEC = 0.5
20
22
  private_constant :OK_MESSAGE,:UPLOAD_REFRESH_SEC
21
23
  # send message on http gw web socket
22
24
  def ws_send(ws,type,data)
@@ -25,63 +27,64 @@ module Aspera
25
27
 
26
28
  def upload(transfer_spec)
27
29
  # total size of all files
28
- total_size=0
30
+ total_size = 0
29
31
  # we need to keep track of actual file path because transfer spec is modified to be sent in web socket
30
- source_paths=[]
32
+ source_paths = []
31
33
  # get source root or nil
32
- source_root = (transfer_spec.has_key?('source_root') and !transfer_spec['source_root'].empty?) ? transfer_spec['source_root'] : nil
34
+ source_root = transfer_spec.has_key?('source_root') && !transfer_spec['source_root'].empty? ? transfer_spec['source_root'] : nil
33
35
  # source root is ignored by GW, used only here
34
36
  transfer_spec.delete('source_root')
35
37
  # compute total size of files to upload (for progress)
36
38
  # modify transfer spec to be suitable for GW
37
39
  transfer_spec['paths'].each do |item|
38
40
  # save actual file location to be able read contents later
39
- full_src_filepath=item['source']
41
+ full_src_filepath = item['source']
40
42
  # add source root if needed
41
- full_src_filepath=File.join(source_root,full_src_filepath) unless source_root.nil?
43
+ full_src_filepath = File.join(source_root,full_src_filepath) unless source_root.nil?
42
44
  # GW expects a simple file name in 'source' but if user wants to change the name, we take it
43
- item['source']=File.basename(item['destination'].nil? ? item['source'] : item['destination'])
44
- item['file_size']=File.size(full_src_filepath)
45
- total_size+=item['file_size']
45
+ item['source'] = File.basename(item['destination'].nil? ? item['source'] : item['destination'])
46
+ item['file_size'] = File.size(full_src_filepath)
47
+ total_size += item['file_size']
46
48
  # save so that we can actually read the file later
47
49
  source_paths.push(full_src_filepath)
48
50
  end
49
51
 
50
- session_id=SecureRandom.uuid
51
- ws=::WebSocket::Client::Simple::Client.new
52
+ session_id = SecureRandom.uuid
53
+ ws = ::WebSocket::Client::Simple::Client.new
52
54
  # error message if any in callback
53
- error=nil
55
+ error = nil
54
56
  # number of files totally sent
55
- received=0
57
+ received = 0
56
58
  # setup callbacks on websocket
57
- ws.on :message do |msg|
59
+ ws.on(:message) do |msg|
58
60
  Log.log.info("ws: message: #{msg.data}")
59
- message=msg.data
61
+ message = msg.data
60
62
  if message.eql?(OK_MESSAGE)
61
- received+=1
63
+ received += 1
62
64
  else
63
65
  message.chomp!
64
- if message[0].eql?('"') and message[-1].eql?('"')
65
- error=JSON.parse(Base64.strict_decode64(message.chomp[1..-2]))['message']
66
- else
67
- error="expecting quotes in [#{message}]"
68
- end
66
+ error =
67
+ if message.start_with?('"') && message.end_with?('"')
68
+ JSON.parse(Base64.strict_decode64(message.chomp[1..-2]))['message']
69
+ else
70
+ "expecting quotes in [#{message}]"
71
+ end
69
72
  end
70
73
  end
71
- ws.on :error do |e|
72
- error=e
74
+ ws.on(:error) do |e|
75
+ error = e
73
76
  end
74
- ws.on :open do
75
- Log.log.info("ws: open")
77
+ ws.on(:open) do
78
+ Log.log.info('ws: open')
76
79
  end
77
- ws.on :close do
78
- Log.log.info("ws: close")
80
+ ws.on(:close) do
81
+ Log.log.info('ws: close')
79
82
  end
80
83
  # open web socket to end point
81
84
  ws.connect("#{@gw_api.params[:base_url]}/upload")
82
85
  # async wait ready
83
- while !ws.open? and error.nil? do
84
- Log.log.info("ws: wait")
86
+ while !ws.open? && error.nil?
87
+ Log.log.info('ws: wait')
85
88
  sleep(0.2)
86
89
  end
87
90
  # notify progress bar
@@ -90,93 +93,94 @@ module Aspera
90
93
  Log.dump(:ws_spec,transfer_spec)
91
94
  ws_send(ws,:transfer_spec,transfer_spec)
92
95
  # current file index
93
- file_index=0
96
+ file_index = 0
94
97
  # aggregate size sent
95
- sent_bytes=0
98
+ sent_bytes = 0
96
99
  # last progress event
97
- lastevent=nil
100
+ lastevent = nil
98
101
  transfer_spec['paths'].each do |item|
99
102
  # TODO: get mime type?
100
- file_mime_type=''
101
- file_size=item['file_size']
102
- file_name=File.basename(item[item['destination'].nil? ? 'source' : 'destination'])
103
+ file_mime_type = ''
104
+ file_size = item['file_size']
105
+ file_name = File.basename(item[item['destination'].nil? ? 'source' : 'destination'])
103
106
  # compute total number of slices
104
- numslices=1+(file_size-1)/@upload_chunksize
107
+ numslices = 1 + ((file_size - 1) / @upload_chunksize)
105
108
  File.open(source_paths[file_index]) do |file|
106
109
  # current slice index
107
- slicenum=0
108
- while !file.eof? do
109
- data=file.read(@upload_chunksize)
110
- slice_data={
111
- name: file_name,
112
- type: file_mime_type,
113
- size: file_size,
114
- data: Base64.strict_encode64(data),
115
- slice: slicenum,
110
+ slicenum = 0
111
+ while !file.eof?
112
+ data = file.read(@upload_chunksize)
113
+ slice_data = {
114
+ name: file_name,
115
+ type: file_mime_type,
116
+ size: file_size,
117
+ data: Base64.strict_encode64(data),
118
+ slice: slicenum,
116
119
  total_slices: numslices,
117
- fileIndex: file_index
120
+ fileIndex: file_index
118
121
  }
119
122
  # log without data
120
- Log.dump(:slide_data,slice_data.keys.inject({}){|m,i|m[i]=i.eql?(:data)?'base64 data':slice_data[i];m}) if slicenum.eql?(0)
123
+ Log.dump(:slide_data,slice_data.keys.each_with_object({}){|i,m|m[i] = i.eql?(:data) ? 'base64 data' : slice_data[i];}) if slicenum.eql?(0)
121
124
  ws_send(ws,:slice_upload, slice_data)
122
- sent_bytes+=data.length
123
- currenttime=Time.now
124
- if lastevent.nil? or (currenttime-lastevent)>UPLOAD_REFRESH_SEC
125
+ sent_bytes += data.length
126
+ currenttime = Time.now
127
+ if lastevent.nil? || ((currenttime - lastevent) > UPLOAD_REFRESH_SEC)
125
128
  notify_progress(session_id,sent_bytes)
126
- lastevent=currenttime
129
+ lastevent = currenttime
127
130
  end
128
- slicenum+=1
131
+ slicenum += 1
129
132
  raise error unless error.nil?
130
133
  end
131
134
  end
132
- file_index+=1
135
+ file_index += 1
133
136
  end
134
137
  ws.close
135
138
  notify_end(session_id)
136
139
  end
137
140
 
138
141
  def download(transfer_spec)
139
- transfer_spec['zip_required']||=false
140
- transfer_spec['source_root']||='/'
142
+ transfer_spec['zip_required'] ||= false
143
+ transfer_spec['source_root'] ||= '/'
141
144
  # is normally provided by application, like package name
142
145
  if !transfer_spec.has_key?('download_name')
143
146
  # by default it is the name of first file
144
- dname=File.basename(transfer_spec['paths'].first['source'])
147
+ dname = File.basename(transfer_spec['paths'].first['source'])
145
148
  # we remove extension
146
- dname=dname.gsub(/\.@gw_api.*$/,'')
149
+ dname = dname.gsub(/\.@gw_api.*$/,'')
147
150
  # ands add indication of number of files if there is more than one
148
151
  if transfer_spec['paths'].length > 1
149
- dname=dname+" #{transfer_spec['paths'].length} Files"
152
+ dname += " #{transfer_spec['paths'].length} Files"
150
153
  end
151
- transfer_spec['download_name']=dname
152
- end
153
- creation=@gw_api.create('download',{'transfer_spec'=>transfer_spec})[:data]
154
- transfer_uuid=creation['url'].split('/').last
155
- if transfer_spec['zip_required'] or transfer_spec['paths'].length > 1
156
- # it is a zip file if zip is required or there is more than 1 file
157
- file_dest=transfer_spec['download_name']+'.zip'
158
- else
159
- # it is a plain file if we don't require zip and there is only one file
160
- file_dest=File.basename(transfer_spec['paths'].first['source'])
154
+ transfer_spec['download_name'] = dname
161
155
  end
162
- file_dest=File.join(transfer_spec['destination_root'],file_dest)
163
- @gw_api.call({:operation=>'GET',:subpath=>"download/#{transfer_uuid}",:save_to_file=>file_dest})
156
+ creation = @gw_api.create('download',{'transfer_spec' => transfer_spec})[:data]
157
+ transfer_uuid = creation['url'].split('/').last
158
+ file_dest =
159
+ if transfer_spec['zip_required'] || transfer_spec['paths'].length > 1
160
+ # it is a zip file if zip is required or there is more than 1 file
161
+ transfer_spec['download_name'] + '.zip'
162
+ else
163
+ # it is a plain file if we don't require zip and there is only one file
164
+ File.basename(transfer_spec['paths'].first['source'])
165
+ end
166
+ file_dest = File.join(transfer_spec['destination_root'],file_dest)
167
+ @gw_api.call({operation: 'GET',subpath: "download/#{transfer_uuid}",save_to_file: file_dest})
164
168
  end
165
169
 
166
170
  # start FASP transfer based on transfer spec (hash table)
167
171
  # note that it is asynchronous
168
172
  # HTTP download only supports file list
169
173
  def start_transfer(transfer_spec,options={})
170
- raise "GW URL must be set" unless !@gw_api.nil?
171
- raise "option: must be hash (or nil)" unless options.is_a?(Hash)
172
- raise "paths: must be Array" unless transfer_spec['paths'].is_a?(Array)
173
- raise "only token based transfer is supported in GW" unless transfer_spec['token'].is_a?(String)
174
+ raise 'GW URL must be set' if @gw_api.nil?
175
+ raise 'option: must be hash (or nil)' unless options.is_a?(Hash)
176
+ raise 'paths: must be Array' unless transfer_spec['paths'].is_a?(Array)
177
+ raise 'only token based transfer is supported in GW' unless transfer_spec['token'].is_a?(String)
174
178
  Log.dump(:user_spec,transfer_spec)
175
- transfer_spec['authentication']||='token'
179
+ transfer_spec['authentication'] ||= 'token'
176
180
  case transfer_spec['direction']
177
- when 'send'
181
+ when Fasp::TransferSpec::DIRECTION_SEND
178
182
  upload(transfer_spec)
179
- when 'receive'
183
+ when Fasp::TransferSpec::DIRECTION_RECEIVE
180
184
  download(transfer_spec)
181
185
  else
182
186
  raise "unexpected direction: [#{transfer_spec['direction']}]"
@@ -190,25 +194,22 @@ module Aspera
190
194
  end
191
195
 
192
196
  # terminates monitor thread
193
- def shutdown
194
- end
197
+ def shutdown; end
195
198
 
196
- def url=(api_url)
197
- end
199
+ def url=(api_url); end
198
200
 
199
201
  private
200
202
 
201
203
  def initialize(params)
202
- raise "params must be Hash" unless params.is_a?(Hash)
203
- params=params.symbolize_keys
204
- raise "must have only one param: url" unless params.keys.eql?([:url])
204
+ raise 'params must be Hash' unless params.is_a?(Hash)
205
+ params = params.symbolize_keys
206
+ raise 'must have only one param: url' unless params.keys.eql?([:url])
205
207
  super()
206
- @gw_api=Rest.new({:base_url => params[:url]})
208
+ @gw_api = Rest.new({base_url: params[:url]})
207
209
  api_info = @gw_api.read('info')[:data]
208
- Log.log.info("#{api_info}")
209
- @upload_chunksize=128000 # TODO: configurable ?
210
+ Log.log.info(api_info.to_s)
211
+ @upload_chunksize = 128_000 # TODO: configurable ?
210
212
  end
211
-
212
213
  end # AgentHttpgw
213
214
  end
214
215
  end
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/fasp/agent_base'
4
+ require 'aspera/fasp/transfer_spec'
2
5
  require 'aspera/log'
3
6
  require 'tty-spinner'
4
7
 
@@ -10,28 +13,28 @@ module Aspera
10
13
  # option include: root_id if the node is an access key
11
14
  attr_writer :options
12
15
  def initialize(options)
13
- raise "node specification must be Hash" unless options.is_a?(Hash)
14
- [:url,:username,:password].each { |k| raise "missing parameter [#{k}] in node specification: #{options}" unless options.has_key?(k) }
16
+ raise 'node specification must be Hash' unless options.is_a?(Hash)
17
+ %i[url username password].each { |k| raise "missing parameter [#{k}] in node specification: #{options}" unless options.has_key?(k) }
15
18
  super()
16
19
  # root id is required for access key
17
- @root_id=options[:root_id]
18
- rest_params={ base_url: options[:url]}
19
- if options[:password].match(/^Bearer /)
20
- rest_params[:headers]={
21
- 'X-Aspera-AccessKey'=>options[:username],
22
- 'Authorization' =>options[:password]
20
+ @root_id = options[:root_id]
21
+ rest_params = { base_url: options[:url]}
22
+ if /^Bearer /.match?(options[:password])
23
+ rest_params[:headers] = {
24
+ 'X-Aspera-AccessKey' => options[:username],
25
+ 'Authorization' => options[:password]
23
26
  }
24
- raise "root_id is required for access key" if @root_id.nil?
27
+ raise 'root_id is required for access key' if @root_id.nil?
25
28
  else
26
- rest_params[:auth]={
29
+ rest_params[:auth] = {
27
30
  type: :basic,
28
31
  username: options[:username],
29
32
  password: options[:password]
30
33
  }
31
34
  end
32
- @node_api=Rest.new(rest_params)
35
+ @node_api = Rest.new(rest_params)
33
36
  # TODO: currently only supports one transfer. This is bad shortcut. but ok for CLI.
34
- @transfer_id=nil
37
+ @transfer_id = nil
35
38
  end
36
39
 
37
40
  # used internally to ensure node api is set before using.
@@ -44,61 +47,61 @@ module Aspera
44
47
 
45
48
  # use this to set the node_api end point before using the class.
46
49
  def node_api=(new_value)
47
- if !@node_api.nil? and !new_value.nil?
50
+ if !@node_api.nil? && !new_value.nil?
48
51
  Log.log.warn('overriding existing node api value')
49
52
  end
50
- @node_api=new_value
53
+ @node_api = new_value
51
54
  end
52
55
 
53
56
  # generic method
54
- def start_transfer(transfer_spec,options=nil)
57
+ def start_transfer(transfer_spec,_options=nil)
55
58
  # add root id if access key
56
- if ! @root_id.nil?
59
+ if !@root_id.nil?
57
60
  case transfer_spec['direction']
58
- when 'send';transfer_spec['source_root_id']=@root_id
59
- when 'receive';transfer_spec['destination_root_id']=@root_id
61
+ when Fasp::TransferSpec::DIRECTION_SEND then transfer_spec['source_root_id'] = @root_id
62
+ when Fasp::TransferSpec::DIRECTION_RECEIVE then transfer_spec['destination_root_id'] = @root_id
60
63
  else raise "unexpected direction in ts: #{transfer_spec['direction']}"
61
64
  end
62
65
  end
63
66
  # manage special additional parameter
64
- if transfer_spec.has_key?('EX_ssh_key_paths') and transfer_spec['EX_ssh_key_paths'].is_a?(Array) and !transfer_spec['EX_ssh_key_paths'].empty?
67
+ if transfer_spec.has_key?('EX_ssh_key_paths') && transfer_spec['EX_ssh_key_paths'].is_a?(Array) && !transfer_spec['EX_ssh_key_paths'].empty?
65
68
  # not standard, so place standard field
66
69
  if transfer_spec.has_key?('ssh_private_key')
67
70
  Log.log.warn('Both ssh_private_key and EX_ssh_key_paths are present, using ssh_private_key')
68
71
  else
69
72
  Log.log.warn('EX_ssh_key_paths has multiple keys, using first one only') unless transfer_spec['EX_ssh_key_paths'].length.eql?(1)
70
- transfer_spec['ssh_private_key']=File.read(transfer_spec['EX_ssh_key_paths'].first)
73
+ transfer_spec['ssh_private_key'] = File.read(transfer_spec['EX_ssh_key_paths'].first)
71
74
  transfer_spec.delete('EX_ssh_key_paths')
72
75
  end
73
76
  end
74
- if transfer_spec['tags'].is_a?(Hash) and transfer_spec['tags']['aspera'].is_a?(Hash)
75
- transfer_spec['tags']['aspera']['xfer_retry']||=150
77
+ if transfer_spec['tags'].is_a?(Hash) && transfer_spec['tags']['aspera'].is_a?(Hash)
78
+ transfer_spec['tags']['aspera']['xfer_retry'] ||= 150
76
79
  end
77
80
  # optimisation in case of sending to the same node
78
81
  if transfer_spec['remote_host'].eql?(URI.parse(node_api_.params[:base_url]).host)
79
- transfer_spec['remote_host']='localhost'
82
+ transfer_spec['remote_host'] = 'localhost'
80
83
  end
81
- resp=node_api_.create('ops/transfers',transfer_spec)[:data]
82
- @transfer_id=resp['id']
84
+ resp = node_api_.create('ops/transfers',transfer_spec)[:data]
85
+ @transfer_id = resp['id']
83
86
  Log.log.debug("tr_id=#{@transfer_id}")
84
87
  return @transfer_id
85
88
  end
86
89
 
87
90
  # generic method
88
91
  def wait_for_transfers_completion
89
- started=false
90
- spinner=nil
92
+ started = false
93
+ spinner = nil
91
94
  # lets emulate management events to display progress bar
92
95
  loop do
93
96
  # status is empty sometimes with status 200...
94
- trdata=node_api_.read("ops/transfers/#{@transfer_id}")[:data] || {"status"=>"unknown"} rescue {"status"=>"waiting(read error)"}
97
+ trdata = node_api_.read("ops/transfers/#{@transfer_id}")[:data] || {'status' => 'unknown'} rescue {'status' => 'waiting(read error)'}
95
98
  case trdata['status']
96
99
  when 'completed'
97
100
  notify_end(@transfer_id)
98
101
  break
99
102
  when 'waiting','partially_completed','unknown','waiting(read error)'
100
103
  if spinner.nil?
101
- spinner = TTY::Spinner.new("[:spinner] :title", format: :classic)
104
+ spinner = TTY::Spinner.new('[:spinner] :title', format: :classic)
102
105
  spinner.start
103
106
  end
104
107
  spinner.update(title: trdata['status'])
@@ -106,18 +109,18 @@ module Aspera
106
109
  #puts trdata
107
110
  when 'running'
108
111
  #puts "running: sessions:#{trdata["sessions"].length}, #{trdata["sessions"].map{|i| i['bytes_transferred']}.join(',')}"
109
- if !started and trdata['precalc'].is_a?(Hash) and
112
+ if !started && trdata['precalc'].is_a?(Hash) &&
110
113
  trdata['precalc']['status'].eql?('ready')
111
114
  notify_begin(@transfer_id,trdata['precalc']['bytes_expected'])
112
- started=true
115
+ started = true
113
116
  else
114
117
  notify_progress(@transfer_id,trdata['bytes_transferred'])
115
118
  end
116
119
  else
117
120
  Log.log.warn("trdata -> #{trdata}")
118
- raise Fasp::Error.new("#{trdata['status']}: #{trdata['error_desc']}")
121
+ raise Fasp::Error, "#{trdata['status']}: #{trdata['error_desc']}"
119
122
  end
120
- sleep 1
123
+ sleep(1)
121
124
  end
122
125
  #TODO get status of sessions
123
126
  return []
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/fasp/agent_base'
2
4
  require 'aspera/fasp/installation'
3
5
  require 'json'
@@ -7,23 +9,18 @@ module Aspera
7
9
  class AgentTrsdk < AgentBase
8
10
  DEFAULT_OPTIONS = {
9
11
  address: '127.0.0.1',
10
- port: 55002,
11
- }
12
+ port: 55_002
13
+ }.freeze
12
14
  private_constant :DEFAULT_OPTIONS
13
15
 
14
16
  # options come from transfer_info
15
17
  def initialize(user_opts)
16
- raise "expecting Hash (or nil), but have #{user_opts.class}" unless user_opts.nil? or user_opts.is_a?(Hash)
18
+ raise "expecting Hash (or nil), but have #{user_opts.class}" unless user_opts.nil? || user_opts.is_a?(Hash)
17
19
  # set default options and override if specified
18
- options=DEFAULT_OPTIONS.clone
19
- if !user_opts.nil?
20
- user_opts.each do |k,v|
21
- if DEFAULT_OPTIONS.has_key?(k)
22
- options[k]=v
23
- else
24
- raise "Unknown local agent parameter: #{k}, expect one of #{DEFAULT_OPTIONS.keys.map{|i|i.to_s}.join(",")}"
25
- end
26
- end
20
+ options = DEFAULT_OPTIONS.dup
21
+ user_opts&.each do |k,v|
22
+ raise "Unknown local agent parameter: #{k}, expect one of #{DEFAULT_OPTIONS.keys.map(&:to_s).join(',')}" unless DEFAULT_OPTIONS.has_key?(k)
23
+ options[k] = v
27
24
  end
28
25
  Log.log.debug("options= #{options}")
29
26
  super()
@@ -34,39 +31,39 @@ module Aspera
34
31
  begin
35
32
  get_info_response = @transfer_client.get_info(Transfersdk::InstanceInfoRequest.new)
36
33
  Log.log.debug("daemon info: #{get_info_response}")
37
- rescue GRPC::Unavailable => e
38
- Log.log.warn("no daemon present, starting daemon...")
34
+ rescue GRPC::Unavailable
35
+ Log.log.warn('no daemon present, starting daemon...')
39
36
  # location of daemon binary
40
- bin_folder=File.realpath(File.join(Installation.instance.sdk_ruby_folder,'..'))
37
+ bin_folder = File.realpath(File.join(Installation.instance.sdk_ruby_folder,'..'))
41
38
  # config file and logs are created in same folder
42
39
  conf_file = File.join(bin_folder,'sdk.conf')
43
40
  log_base = File.join(bin_folder,'transferd')
44
41
  # create a config file for daemon
45
42
  config = {
46
- address: options[:address],
47
- port: options[:port],
43
+ address: options[:address],
44
+ port: options[:port],
48
45
  fasp_runtime: {
49
- use_embedded: false,
50
- user_defined: {
51
- bin: bin_folder,
52
- etc: bin_folder,
53
- }
46
+ use_embedded: false,
47
+ user_defined: {
48
+ bin: bin_folder,
49
+ etc: bin_folder
50
+ }
54
51
  }
55
52
  }
56
53
  File.write(conf_file,config.to_json)
57
- trd_pid = Process.spawn(Installation.instance.path(:transferd),'--config' , conf_file, out: "#{log_base}.out", err: "#{log_base}.err")
54
+ trd_pid = Process.spawn(Installation.instance.path(:transferd),'--config', conf_file, out: "#{log_base}.out", err: "#{log_base}.err")
58
55
  Process.detach(trd_pid)
59
56
  sleep(2.0)
60
57
  retry
61
58
  end
62
59
  end
63
60
 
64
- def start_transfer(transfer_spec,options=nil)
61
+ def start_transfer(transfer_spec,_options=nil)
65
62
  # create a transfer request
66
63
  transfer_request = Transfersdk::TransferRequest.new(
67
- transferType: Transfersdk::TransferType::FILE_REGULAR, # transfer type (file/stream)
68
- config: Transfersdk::TransferConfig.new, # transfer configuration
69
- transferSpec: transfer_spec.to_json) # transfer definition
64
+ transferType: Transfersdk::TransferType::FILE_REGULAR, # transfer type (file/stream)
65
+ config: Transfersdk::TransferConfig.new, # transfer configuration
66
+ transferSpec: transfer_spec.to_json) # transfer definition
70
67
  # send start transfer request to the transfer manager daemon
71
68
  start_transfer_response = @transfer_client.start_transfer(transfer_request)
72
69
  Log.log.debug("start transfer response #{start_transfer_response}")
@@ -75,22 +72,22 @@ module Aspera
75
72
  end
76
73
 
77
74
  def wait_for_transfers_completion
78
- started=false
75
+ started = false
79
76
  # monitor transfer status
80
77
  @transfer_client.monitor_transfers(Transfersdk::RegistrationRequest.new(transferId: [@transfer_id])) do |response|
81
78
  Log.dump(:response, response.to_h)
82
79
  #Log.log.debug("#{response.sessionInfo.preTransferBytes} #{response.transferInfo.bytesTransferred}")
83
80
  case response.status
84
81
  when :RUNNING
85
- if !started and !response.sessionInfo.preTransferBytes.eql?(0)
82
+ if !started && !response.sessionInfo.preTransferBytes.eql?(0)
86
83
  notify_begin(@transfer_id,response.sessionInfo.preTransferBytes)
87
- started=true
84
+ started = true
88
85
  elsif started
89
86
  notify_progress(@transfer_id,response.transferInfo.bytesTransferred)
90
87
  end
91
88
  when :FAILED, :COMPLETED, :CANCELED
92
89
  notify_end(@transfer_id)
93
- raise Fasp::Error.new(JSON.parse(response.message)['Description']) unless :COMPLETED.eql?(response.status)
90
+ raise Fasp::Error, JSON.parse(response.message)['Description'] unless :COMPLETED.eql?(response.status)
94
91
  break
95
92
  when :QUEUED,:UNKNOWN_STATUS,:PAUSED,:ORPHANED
96
93
  # ignore
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'aspera/fasp/error_info'
2
4
 
3
5
  module Aspera
@@ -11,7 +13,7 @@ module Aspera
11
13
  end
12
14
 
13
15
  def info
14
- r=Fasp::ERROR_INFO[@err_code] || {r: false , c: 'UNKNOWN', m: 'unknown', a: 'unknown'}
16
+ r = Fasp::ERROR_INFO[@err_code] || {r: false, c: 'UNKNOWN', m: 'unknown', a: 'unknown'}
15
17
  return r.merge({i: @err_code})
16
18
  end
17
19