aspera-cli 4.4.0 → 4.5.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1042 -787
  3. data/bin/ascli +1 -1
  4. data/bin/asession +3 -5
  5. data/docs/Makefile +4 -7
  6. data/docs/README.erb.md +988 -740
  7. data/examples/faspex4.rb +4 -6
  8. data/examples/transfer.rb +2 -2
  9. data/lib/aspera/aoc.rb +139 -118
  10. data/lib/aspera/cli/listener/progress_multi.rb +5 -5
  11. data/lib/aspera/cli/main.rb +64 -34
  12. data/lib/aspera/cli/manager.rb +19 -20
  13. data/lib/aspera/cli/plugin.rb +9 -1
  14. data/lib/aspera/cli/plugins/aoc.rb +156 -143
  15. data/lib/aspera/cli/plugins/ats.rb +11 -10
  16. data/lib/aspera/cli/plugins/bss.rb +2 -2
  17. data/lib/aspera/cli/plugins/config.rb +236 -112
  18. data/lib/aspera/cli/plugins/faspex.rb +29 -7
  19. data/lib/aspera/cli/plugins/faspex5.rb +21 -8
  20. data/lib/aspera/cli/plugins/node.rb +21 -9
  21. data/lib/aspera/cli/plugins/orchestrator.rb +5 -3
  22. data/lib/aspera/cli/plugins/preview.rb +2 -2
  23. data/lib/aspera/cli/plugins/server.rb +3 -3
  24. data/lib/aspera/cli/plugins/shares.rb +17 -0
  25. data/lib/aspera/cli/transfer_agent.rb +47 -85
  26. data/lib/aspera/cli/version.rb +1 -1
  27. data/lib/aspera/environment.rb +4 -4
  28. data/lib/aspera/fasp/{manager.rb → agent_base.rb} +7 -6
  29. data/lib/aspera/fasp/{connect.rb → agent_connect.rb} +46 -39
  30. data/lib/aspera/fasp/{local.rb → agent_direct.rb} +14 -17
  31. data/lib/aspera/fasp/{http_gw.rb → agent_httpgw.rb} +4 -4
  32. data/lib/aspera/fasp/{node.rb → agent_node.rb} +25 -8
  33. data/lib/aspera/fasp/agent_trsdk.rb +106 -0
  34. data/lib/aspera/fasp/default.rb +17 -0
  35. data/lib/aspera/fasp/installation.rb +64 -48
  36. data/lib/aspera/fasp/parameters.rb +7 -3
  37. data/lib/aspera/faspex_gw.rb +6 -6
  38. data/lib/aspera/keychain/encrypted_hash.rb +120 -0
  39. data/lib/aspera/keychain/macos_security.rb +94 -0
  40. data/lib/aspera/log.rb +45 -32
  41. data/lib/aspera/node.rb +3 -6
  42. data/lib/aspera/rest.rb +65 -49
  43. metadata +68 -27
  44. data/lib/aspera/api_detector.rb +0 -60
  45. data/lib/aspera/secrets.rb +0 -20
data/examples/faspex4.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
  # find Faspex API here: https://developer.ibm.com/apis/catalog/?search=faspex
3
3
  # this example makes use of class Aspera::Rest for REST calls, alternatively class RestClient of gem rest-client could be used
4
- # this example makes use of class Aspera::Fasp::Local for transfers, alternatively the official "Transfer SDK" could be used
4
+ # this example makes use of class Aspera::Fasp::AgentDirect for transfers, alternatively the official "Transfer SDK" could be used
5
5
  # Aspera SDK can be downloaded with: `ascli conf ascp install` , it installs in $HOME/.aspera/ascli/sdk
6
6
  require 'aspera/rest'
7
7
  require 'aspera/log'
8
- require 'aspera/fasp/local'
8
+ require 'aspera/fasp/agent_direct'
9
9
 
10
10
  tmpdir=ENV['tmp']||Dir.tmpdir || '.'
11
11
 
@@ -59,10 +59,8 @@ pkg_created=api_v3.create('send',package_create_params)[:data]
59
59
  transfer_spec=pkg_created['xfer_sessions'].first
60
60
  # set paths of files to send
61
61
  transfer_spec['paths']=[{'source'=>file_to_send}]
62
- # get the local agent (i.e. ascp)
63
- transfer_client=Aspera::Fasp::Local.new
64
- # disable ascp output on stdout (optional)
65
- transfer_client.quiet=true
62
+ # get local agent (ascp), disable ascp output on stdout to not mix with JSON events
63
+ transfer_client=Aspera::Fasp::AgentDirect.new({quiet: true})
66
64
  # start transfer (asynchronous)
67
65
  job_id=transfer_client.start_transfer(transfer_spec)
68
66
  # wait for all transfer completion (for the example)
data/examples/transfer.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  # Example: transfer a file using one of the provided transfer agents
3
3
  # location of ascp can be specified with env var "ascp"
4
4
  # temp folder can be specified with env var "tmp"
5
- require 'aspera/fasp/local'
5
+ require 'aspera/fasp/agent_direct'
6
6
  require 'aspera/fasp/listener'
7
7
  require 'aspera/fasp/installation'
8
8
  require 'aspera/log'
@@ -39,7 +39,7 @@ Aspera::Fasp::Installation.instance.ascp_path=ENV['ascp'] if ENV.has_key?('ascp'
39
39
  #
40
40
 
41
41
  # get FASP Manager singleton based on above ascp location
42
- fasp_manager=Aspera::Fasp::Local.new
42
+ fasp_manager=Aspera::Fasp::AgentDirect.new
43
43
 
44
44
  # Note that it would also be possible to start transfers using other agents
45
45
  #require 'aspera/fasp/connect'
data/lib/aspera/aoc.rb CHANGED
@@ -2,7 +2,7 @@ require 'aspera/log'
2
2
  require 'aspera/rest'
3
3
  require 'aspera/hash_ext'
4
4
  require 'aspera/data_repository'
5
- require 'aspera/node'
5
+ require 'aspera/fasp/default'
6
6
  require 'base64'
7
7
 
8
8
  module Aspera
@@ -18,19 +18,20 @@ module Aspera
18
18
  # to avoid infinite loop in pub link redirection
19
19
  MAX_REDIRECT=10
20
20
  CLIENT_APPS=['aspera.global-cli-client','aspera.drive']
21
+ # index offset in data repository of client app
21
22
  DATA_REPO_INDEX_START = 4
23
+ # cookie prefix so that console can decode identity
24
+ COOKIE_PREFIX='aspera.aoc'
22
25
 
23
26
  # path in URL of public links
24
- PATHS_PUBLIC_LINK=['/packages/public/receive','/packages/public/send','/files/public']
27
+ PUBLIC_LINK_PATHS=['/packages/public/receive','/packages/public/send','/files/public']
25
28
  JWT_AUDIENCE='https://api.asperafiles.com/api/v1/oauth2/token'
26
29
  OAUTH_API_SUBPATH='api/v1/oauth2'
27
- DEFAULT_TSPEC_INFO={
28
- 'remote_user' => Node::ACCESS_KEY_TRANSFER_USER,
29
- 'ssh_port' => Node::SSH_PORT_DEFAULT,
30
- 'fasp_port' => Node::UDP_PORT_DEFAULT
31
- }
30
+ # minimum fields for user info if retrieval fails
31
+ USER_INFO_FIELDS_MIN=['name','email','id','default_workspace_id','organization_id']
32
32
 
33
- private_constant :PRODUCT_NAME,:PROD_DOMAIN,:MAX_REDIRECT,:CLIENT_APPS,:PATHS_PUBLIC_LINK,:JWT_AUDIENCE,:OAUTH_API_SUBPATH,:DEFAULT_TSPEC_INFO
33
+ private_constant :PRODUCT_NAME,:PROD_DOMAIN,:MAX_REDIRECT,:CLIENT_APPS,:PUBLIC_LINK_PATHS,:JWT_AUDIENCE,
34
+ :OAUTH_API_SUBPATH,:COOKIE_PREFIX,:USER_INFO_FIELDS_MIN
34
35
 
35
36
  public
36
37
  # various API scopes supported
@@ -45,84 +46,119 @@ module Aspera
45
46
  FILES_APP='files'
46
47
  PACKAGES_APP='packages'
47
48
 
48
- def self.get_client_info(client_name=CLIENT_APPS.first)
49
- client_index=CLIENT_APPS.index(client_name)
50
- raise "no such pre-defined client: #{client_name}" if client_index.nil?
49
+ # class static methods
50
+ class << self
51
51
  # strings /Applications/Aspera\ Drive.app/Contents/MacOS/AsperaDrive|grep -E '.{100}==$'|base64 --decode
52
- return client_name,Base64.urlsafe_encode64(DataRepository.instance.get_bin(DATA_REPO_INDEX_START+client_index))
53
- end
52
+ def get_client_info(client_name=CLIENT_APPS.first)
53
+ client_index=CLIENT_APPS.index(client_name)
54
+ raise "no such pre-defined client: #{client_name}" if client_index.nil?
55
+ return client_name,Base64.urlsafe_encode64(DataRepository.instance.get_bin(DATA_REPO_INDEX_START+client_index))
56
+ end
54
57
 
55
- # @param url of AoC instance
56
- # @return organization id in url and AoC domain: ibmaspera.com, asperafiles.com or qa.asperafiles.com, etc...
57
- def self.parse_url(aoc_org_url)
58
- uri=URI.parse(aoc_org_url.gsub(/\/+$/,''))
59
- instance_fqdn=uri.host
60
- Log.log.debug("instance_fqdn=#{instance_fqdn}")
61
- raise "No host found in URL.Please check URL format: https://myorg.#{PROD_DOMAIN}" if instance_fqdn.nil?
62
- organization,instance_domain=instance_fqdn.split('.',2)
63
- Log.log.debug("instance_domain=#{instance_domain}")
64
- Log.log.debug("organization=#{organization}")
65
- raise "expecting a public FQDN for #{PRODUCT_NAME}" if instance_domain.nil?
66
- return organization,instance_domain
67
- end
58
+ # @param url of AoC instance
59
+ # @return organization id in url and AoC domain: ibmaspera.com, asperafiles.com or qa.asperafiles.com, etc...
60
+ def parse_url(aoc_org_url)
61
+ uri=URI.parse(aoc_org_url.gsub(/\/+$/,''))
62
+ instance_fqdn=uri.host
63
+ Log.log.debug("instance_fqdn=#{instance_fqdn}")
64
+ raise "No host found in URL.Please check URL format: https://myorg.#{PROD_DOMAIN}" if instance_fqdn.nil?
65
+ organization,instance_domain=instance_fqdn.split('.',2)
66
+ Log.log.debug("instance_domain=#{instance_domain}")
67
+ Log.log.debug("organization=#{organization}")
68
+ raise "expecting a public FQDN for #{PRODUCT_NAME}" if instance_domain.nil?
69
+ return organization,instance_domain
70
+ end
68
71
 
69
- # base API url depends on domain, which could be "qa.xxx"
70
- def self.api_base_url(api_domain=PROD_DOMAIN)
71
- return "https://api.#{api_domain}"
72
- end
72
+ # base API url depends on domain, which could be "qa.xxx"
73
+ def api_base_url(api_domain=PROD_DOMAIN)
74
+ return "https://api.#{api_domain}"
75
+ end
73
76
 
74
- def self.metering_api(entitlement_id,customer_id,api_domain=PROD_DOMAIN)
75
- return Rest.new({
76
- :base_url => "#{api_base_url(api_domain)}/metering/v1",
77
- :headers => {'X-Aspera-Entitlement-Authorization' => Rest.basic_creds(entitlement_id,customer_id)}
78
- })
79
- end
77
+ def metering_api(entitlement_id,customer_id,api_domain=PROD_DOMAIN)
78
+ return Rest.new({
79
+ :base_url => "#{api_base_url(api_domain)}/metering/v1",
80
+ :headers => {'X-Aspera-Entitlement-Authorization' => Rest.basic_creds(entitlement_id,customer_id)}
81
+ })
82
+ end
80
83
 
81
- # node API scopes
82
- def self.node_scope(access_key,scope)
83
- return 'node.'+access_key+':'+scope
84
- end
84
+ # node API scopes
85
+ def node_scope(access_key,scope)
86
+ return 'node.'+access_key+':'+scope
87
+ end
85
88
 
86
- def self.set_use_default_ports(val)
87
- @@use_standard_ports=val
88
- end
89
+ def set_use_default_ports(val)
90
+ @@use_standard_ports=val
91
+ end
89
92
 
90
- # check option "link"
91
- # if present try to get token value (resolve redirection if short links used)
92
- # then set options url/token/auth
93
- def self.resolve_pub_link(rest_opts,public_link_url)
94
- return if public_link_url.nil?
95
- # set to token if available after redirection
96
- url_param_token_pair=nil
97
- redirect_count=0
98
- loop do
99
- uri=URI.parse(public_link_url)
100
- if PATHS_PUBLIC_LINK.include?(uri.path)
101
- url_param_token_pair=URI::decode_www_form(uri.query).select{|e|e.first.eql?('token')}.first
102
- if url_param_token_pair.nil?
103
- raise ArgumentError,"link option must be URL with 'token' parameter"
93
+ # check option "link"
94
+ # if present try to get token value (resolve redirection if short links used)
95
+ # then set options url/token/auth
96
+ def resolve_pub_link(rest_opts,public_link_url)
97
+ return if public_link_url.nil?
98
+ # set to token if available after redirection
99
+ url_param_token_pair=nil
100
+ redirect_count=0
101
+ loop do
102
+ uri=URI.parse(public_link_url)
103
+ if PUBLIC_LINK_PATHS.include?(uri.path)
104
+ url_param_token_pair=URI::decode_www_form(uri.query).select{|e|e.first.eql?('token')}.first
105
+ if url_param_token_pair.nil?
106
+ raise ArgumentError,"link option must be URL with 'token' parameter"
107
+ end
108
+ # ok we get it !
109
+ rest_opts[:org_url]='https://'+uri.host
110
+ rest_opts[:auth][:grant]=:url_token
111
+ rest_opts[:auth][:url_token]=url_param_token_pair.last
112
+ return
104
113
  end
105
- # ok we get it !
106
- rest_opts[:org_url]='https://'+uri.host
107
- rest_opts[:auth][:grant]=:url_token
108
- rest_opts[:auth][:url_token]=url_param_token_pair.last
109
- return
110
- end
111
- Log.log.debug("no expected format: #{public_link_url}")
112
- raise "exceeded max redirection: #{MAX_REDIRECT}" if redirect_count > MAX_REDIRECT
113
- r = Net::HTTP.get_response(uri)
114
- if r.code.start_with?("3")
115
- public_link_url = r['location']
116
- raise "no location in redirection" if public_link_url.nil?
117
- Log.log.debug("redirect to: #{public_link_url}")
118
- else
119
- # not a redirection
120
- raise ArgumentError,'link option must be redirect or have token parameter'
114
+ Log.log.debug("no expected format: #{public_link_url}")
115
+ raise "exceeded max redirection: #{MAX_REDIRECT}" if redirect_count > MAX_REDIRECT
116
+ r = Net::HTTP.get_response(uri)
117
+ if r.code.start_with?("3")
118
+ public_link_url = r['location']
119
+ raise "no location in redirection" if public_link_url.nil?
120
+ Log.log.debug("redirect to: #{public_link_url}")
121
+ else
122
+ # not a redirection
123
+ raise ArgumentError,'link option must be redirect or have token parameter'
124
+ end
125
+ end # loop
126
+
127
+ raise RuntimeError,'too many redirections'
128
+ end
129
+
130
+ # additional transfer spec (tags) for package information
131
+ def package_tags(package_info,operation)
132
+ return {'tags'=>{'aspera'=>{'files'=>{
133
+ 'package_id' => package_info['id'],
134
+ 'package_name' => package_info['name'],
135
+ 'package_operation' => operation
136
+ }}}}
137
+ end
138
+
139
+ # add details to show in analytics
140
+ def analytics_ts(app,direction,ws_id,ws_name)
141
+ # translate transfer to operation
142
+ operation=case direction
143
+ when 'send'; 'upload'
144
+ when 'receive'; 'download'
145
+ else raise "ERROR: unexpected value: #{direction}"
121
146
  end
122
- end # loop
123
147
 
124
- raise RuntimeError,'too many redirections'
125
- end
148
+ return {
149
+ 'tags' => {
150
+ 'aspera' => {
151
+ 'usage_id' => "aspera.files.workspace.#{ws_id}", # activity tracking
152
+ 'files' => {
153
+ 'files_transfer_action' => "#{operation}_#{app.gsub(/s$/,'')}",
154
+ 'workspace_name' => ws_name, # activity tracking
155
+ 'workspace_id' => ws_id,
156
+ }
157
+ }
158
+ }
159
+ }
160
+ end
161
+ end # static methods
126
162
 
127
163
  # @param :link,:url,:auth,:client_id,:client_secret,:scope,:redirect_uri,:private_key,:username,:subpath,:password (for pub link)
128
164
  def initialize(opt)
@@ -130,6 +166,7 @@ module Aspera
130
166
  # key: access key
131
167
  # value: associated secret
132
168
  @key_chain=nil
169
+ @user_info=nil
133
170
 
134
171
  # init rest params
135
172
  aoc_rest_p={:auth=>{:type =>:oauth2}}
@@ -197,50 +234,28 @@ module Aspera
197
234
 
198
235
  def key_chain=(keychain)
199
236
  raise "keychain already set" unless @key_chain.nil?
237
+ raise "keychain must have get_secret" unless keychain.respond_to?(:get_secret)
200
238
  @key_chain=keychain
201
239
  nil
202
240
  end
203
241
 
204
- # additional transfer spec (tags) for package information
205
- def self.package_tags(package_info,operation)
206
- return {'tags'=>{'aspera'=>{'files'=>{
207
- 'package_id' => package_info['id'],
208
- 'package_name' => package_info['name'],
209
- 'package_operation' => operation
210
- }}}}
211
- end
212
-
213
- # add details to show in analytics
214
- def self.analytics_ts(app,direction,ws_id,ws_name)
215
- # translate transfer to operation
216
- operation=case direction
217
- when 'send'; 'upload'
218
- when 'receive'; 'download'
219
- else raise "ERROR: unexpected value: #{direction}"
242
+ # cached user information
243
+ def user_info
244
+ if @user_info.nil?
245
+ # get our user's default information
246
+ @user_info=self.read('self')[:data] rescue nil
247
+ @user_info=USER_INFO_FIELDS_MIN.inject({}){|m,f|m[f]=nil;m} if @user_info.nil?
248
+ USER_INFO_FIELDS_MIN.each{|f|@user_info[f]='unknown' if @user_info[f].nil?}
220
249
  end
221
-
222
- return {
223
- 'tags' => {
224
- 'aspera' => {
225
- 'usage_id' => "aspera.files.workspace.#{ws_id}", # activity tracking
226
- 'files' => {
227
- 'files_transfer_action' => "#{operation}_#{app.gsub(/s$/,'')}",
228
- 'workspace_name' => ws_name, # activity tracking
229
- 'workspace_id' => ws_id,
230
- }
231
- }
232
- }
233
- }
250
+ return @user_info
234
251
  end
235
252
 
236
253
  # build ts addon for IBM Aspera Console (cookie)
237
- def self.console_ts(app,user_name,user_email)
238
- elements=[app,user_name,user_email].map{|e|Base64.strict_encode64(e)}
239
- elements.unshift('aspera.aoc')
240
- #Log.dump('elem1'.bg_red,elements[1])
241
- return {
242
- 'cookie'=>elements.join(':')
243
- }
254
+ def console_ts(app)
255
+ # we are sure that fields are not nil
256
+ elements=[app,user_info['name'],user_info['email']].map{|e|Base64.strict_encode64(e)}
257
+ elements.unshift(COOKIE_PREFIX)
258
+ return {'cookie'=>elements.join(':')}
244
259
  end
245
260
 
246
261
  # build "transfer info", 2 elements array with:
@@ -248,12 +263,12 @@ module Aspera
248
263
  # - source and token regeneration method
249
264
  def tr_spec(app,direction,node_file,ts_add)
250
265
  # prepare the rest end point is used to generate the bearer token
251
- token_generation_method=lambda {|do_refresh|self.oauth_token(scope: self.class.node_scope(node_file[:node_info]['access_key'],SCOPE_NODE_USER), refresh: do_refresh)}
266
+ token_generation_lambda=lambda {|do_refresh|self.oauth_token(scope: self.class.node_scope(node_file[:node_info]['access_key'],SCOPE_NODE_USER), refresh: do_refresh)}
252
267
  # prepare transfer specification
253
268
  # note xfer_id and xfer_retry are set by the transfer agent itself
254
269
  transfer_spec={
255
270
  'direction' => direction,
256
- 'token' => token_generation_method.call(false), # first time, use cache
271
+ 'token' => token_generation_lambda.call(false), # first time, use cache
257
272
  'tags' => {
258
273
  'aspera' => {
259
274
  'app' => app,
@@ -270,8 +285,14 @@ module Aspera
270
285
  }
271
286
  # add remote host info
272
287
  if @@use_standard_ports
273
- transfer_spec.merge!(DEFAULT_TSPEC_INFO)
288
+ # get default TCP/UDP ports and transfer user
289
+ transfer_spec.merge!(Fasp::Default::AK_TSPEC_BASE)
290
+ # by default: same address as node API
274
291
  transfer_spec['remote_host']=node_file[:node_info]['host']
292
+ # 30 it's necessarily https scheme: webui does not allow anything else
293
+ if node_file[:node_info]['transfer_url'].is_a?(String) and !node_file[:node_info]['transfer_url'].empty?
294
+ transfer_spec['remote_host']=URI.parse(node_file[:node_info]['transfer_url']).host
295
+ end
275
296
  else
276
297
  # retrieve values from API
277
298
  std_t_spec=get_node_api(node_file[:node_info],scope: SCOPE_NODE_USER).create('files/download_setup',{:transfer_requests => [ { :transfer_request => {:paths => [ {"source"=>'/'} ] } } ] } )[:data]['transfer_specs'].first['transfer_spec']
@@ -282,7 +303,7 @@ module Aspera
282
303
  # additional information for transfer agent
283
304
  source_and_token_generator={
284
305
  :src => :node_gen4,
285
- :regenerate_token => token_generation_method
306
+ :regenerate_token => token_generation_lambda
286
307
  }
287
308
  return transfer_spec,source_and_token_generator
288
309
  end
@@ -292,10 +313,10 @@ module Aspera
292
313
  # no scope: requires secret
293
314
  # if secret provided beforehand: use it
294
315
  def get_node_api(node_info,options={})
295
- raise "INTERNAL ERROR: method parameters: options must ne hash" unless options.is_a?(Hash)
316
+ raise "INTERNAL ERROR: method parameters: options must be Hash" unless options.is_a?(Hash)
296
317
  options.keys.each {|k| raise "INTERNAL ERROR: not valid option: #{k}" unless [:scope,:use_secret].include?(k)}
297
318
  # get optional secret unless :use_secret is false (default is true)
298
- ak_secret=@key_chain.get_secret(node_info['access_key'],false) if !options.has_key?(:use_secret) or options[:use_secret]
319
+ ak_secret=@key_chain.get_secret(url: node_info['url'], username: node_info['access_key'], mandatory: false) if !@key_chain.nil? and ( !options.has_key?(:use_secret) or options[:use_secret] )
299
320
  if ak_secret.nil? and !options.has_key?(:scope)
300
321
  raise "There must be at least one of: 'secret' or 'scope' for access key #{node_info['access_key']}"
301
322
  end
@@ -1,5 +1,5 @@
1
1
  require 'aspera/fasp/listener'
2
- require 'aspera/fasp/manager'
2
+ require 'aspera/fasp/agent_base'
3
3
  require 'ruby-progressbar'
4
4
 
5
5
  module Aspera
@@ -43,13 +43,13 @@ module Aspera
43
43
  :title => '',
44
44
  :total => nil)
45
45
  end
46
- if !data.has_key?(Fasp::Manager::LISTENER_SESSION_ID_S)
47
- Log.log.error("Internal error: no #{Fasp::Manager::LISTENER_SESSION_ID_S} in event: #{data}")
46
+ if !data.has_key?(Fasp::AgentBase::LISTENER_SESSION_ID_S)
47
+ Log.log.error("Internal error: no #{Fasp::AgentBase::LISTENER_SESSION_ID_S} in event: #{data}")
48
48
  return
49
49
  end
50
50
  newtitle=@sessions.length < 2 ? '' : "multi=#{@sessions.length}"
51
51
  @progress_bar.title=newtitle unless @progress_bar.title.eql?(newtitle)
52
- session=@sessions[data[Fasp::Manager::LISTENER_SESSION_ID_S]]||={
52
+ session=@sessions[data[Fasp::AgentBase::LISTENER_SESSION_ID_S]]||={
53
53
  cumulative: 0,
54
54
  job_size: 0,
55
55
  current: 0
@@ -78,7 +78,7 @@ module Aspera
78
78
  # stop event when one file is completed
79
79
  session[:cumulative]=session[:cumulative]+data['size'].to_i
80
80
  when 'DONE' # end of session
81
- @sessions.delete(data[Fasp::Manager::LISTENER_SESSION_ID_S])
81
+ @sessions.delete(data[Fasp::AgentBase::LISTENER_SESSION_ID_S])
82
82
  update_progress
83
83
  update_total
84
84
  else