aspera-cli 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -88,7 +88,7 @@ module Aspera
88
88
  raise StandardError,"expect: nil, String or Array"
89
89
  end
90
90
 
91
- SIMPLE_ACTIONS=[:nagios_check,:events, :space, :info, :license, :mkdir, :mklink, :mkfile, :rename, :delete, :search ]
91
+ SIMPLE_ACTIONS=[:health,:events, :space, :info, :license, :mkdir, :mklink, :mkfile, :rename, :delete, :search ]
92
92
 
93
93
  COMMON_ACTIONS=[:browse, :upload, :download, :api_details ].concat(SIMPLE_ACTIONS)
94
94
 
@@ -96,7 +96,7 @@ module Aspera
96
96
  # prefix_path is used to list remote sources in Faspex
97
97
  def execute_simple_common(command,prefix_path)
98
98
  case command
99
- when :nagios_check
99
+ when :health
100
100
  nagios=Nagios.new
101
101
  begin
102
102
  info=@api_node.read('info')[:data]
@@ -341,7 +341,7 @@ module Aspera
341
341
  raise "error"
342
342
  end
343
343
  when :access_key
344
- return self.entity_action(@api_node,'access_keys',['id','root_file_id','storage'],:id,'self')
344
+ return self.entity_action(@api_node,'access_keys',nil,:id,'self')
345
345
  when :service
346
346
  command=self.options.get_next_command([ :list, :create, :delete])
347
347
  if [:delete].include?(command)
@@ -56,9 +56,11 @@ module Aspera
56
56
  self.options.add_opt_simple(:case,'basename of output for for test')
57
57
  self.options.add_opt_simple(:scan_path,'subpath in folder id to start scan in (default=/)')
58
58
  self.options.add_opt_simple(:scan_id,'forder id in storage to start scan in, default is access key main folder id')
59
+ self.options.add_opt_boolean(:mimemagic,'use Mime type detection of gem mimemagic')
59
60
  self.options.add_opt_list(:overwrite,[:always,:never,:mtime],'when to overwrite result file')
60
61
  self.options.add_opt_list(:file_access,[:local,:remote],'how to read and write files in repository')
61
62
  self.options.set_option(:temp_folder,Dir.tmpdir)
63
+ self.options.set_option(:mimemagic,:false)
62
64
 
63
65
  # add other options for generator (and set default values)
64
66
  Aspera::Preview::Options::DESCRIPTIONS.each do |opt|
@@ -100,8 +102,6 @@ module Aspera
100
102
  return @preview_formats_to_generate.map{|i|i.to_s}.join(',')
101
103
  end
102
104
 
103
- ACTIONS=[:scan,:events,:trevents,:check,:test]
104
-
105
105
  # /files/id/files is normally cached in redis, but we can discard the cache
106
106
  # but /files/id is not cached
107
107
  def get_folder_entries(file_id,request_args=nil)
@@ -112,14 +112,23 @@ module Aspera
112
112
  end
113
113
 
114
114
  # old version based on folders
115
- def process_transfer_events(iteration_token)
115
+ def process_trevents(iteration_token)
116
116
  events_filter={
117
117
  'access_key'=>@access_key_self['id'],
118
118
  'type'=>'download.ended'
119
119
  }
120
120
  # optionally by iteration token
121
121
  events_filter['iteration_token']=iteration_token unless iteration_token.nil?
122
- events=@api_node.read('events',events_filter)[:data]
122
+ begin
123
+ events=@api_node.read('events',events_filter)[:data]
124
+ rescue RestCallError => e
125
+ if e.message.include?('Invalid iteration_token')
126
+ Log.log.warn("Retrying without iteration token: #{e}")
127
+ events_filter.delete('iteration_token')
128
+ retry
129
+ end
130
+ raise e
131
+ end
123
132
  return if events.empty?
124
133
  events.each do |event|
125
134
  next unless event['data']['direction'].eql?('receive')
@@ -137,7 +146,7 @@ module Aspera
137
146
  end
138
147
 
139
148
  # requests recent events on node api and process newly modified folders
140
- def process_file_events(iteration_token)
149
+ def process_events(iteration_token)
141
150
  # get new file creation by access key (TODO: what if file already existed?)
142
151
  events_filter={
143
152
  'access_key'=>@access_key_self['id'],
@@ -276,7 +285,7 @@ module Aspera
276
285
  end
277
286
  end
278
287
  # need generator for further checks
279
- gen_info[:generator]=Aspera::Preview::Generator.new(@gen_options,gen_info[:src],gen_info[:dst],@tmp_folder,entry['content_type'],false)
288
+ gen_info[:generator]=Aspera::Preview::Generator.new(@gen_options,gen_info[:src],gen_info[:dst],@tmp_folder,entry['content_type'])
280
289
  # get conversion_type (if known) and check if supported
281
290
  next false unless gen_info[:generator].supported?
282
291
  # shall we skip it ?
@@ -360,6 +369,8 @@ module Aspera
360
369
  end
361
370
  end
362
371
 
372
+ ACTIONS=[:scan,:events,:trevents,:check,:test]
373
+
363
374
  def execute_action
364
375
  command=self.options.get_next_command(ACTIONS)
365
376
  unless [:check,:test].include?(command)
@@ -402,6 +413,7 @@ module Aspera
402
413
  end
403
414
  end
404
415
  end
416
+ Aspera::Preview::FileTypes.instance.use_mimemagic = self.options.get_option(:mimemagic,:mandatory)
405
417
  case command
406
418
  when :scan
407
419
  scan_path=self.options.get_option(:scan_path,:optional)
@@ -417,30 +429,18 @@ module Aspera
417
429
  end
418
430
  scan_folder_files(folder_info,scan_path)
419
431
  return Main.result_status('scan finished')
420
- when :events
421
- iteration_data=[]
422
- iteration_persistency=nil
423
- if self.options.get_option(:once_only,:mandatory)
424
- iteration_persistency=PersistencyActionOnce.new(
425
- manager: @agents[:persistency],
426
- data: iteration_data,
427
- ids: ['preview_iteration_events',self.options.get_option(:url,:mandatory),self.options.get_option(:username,:mandatory)])
428
- end
429
- iteration_data[0]=process_file_events(iteration_data[0])
430
- iteration_persistency.save unless iteration_persistency.nil?
431
- return Main.result_status('events finished')
432
- when :trevents
432
+ when :events,:trevents
433
433
  iteration_data=[]
434
434
  iteration_persistency=nil
435
435
  if self.options.get_option(:once_only,:mandatory)
436
436
  iteration_persistency=PersistencyActionOnce.new(
437
437
  manager: @agents[:persistency],
438
438
  data: iteration_data,
439
- ids: ['preview_iteration_transfer',self.options.get_option(:url,:mandatory),self.options.get_option(:username,:mandatory)])
439
+ ids: ["preview_iteration_#{command}",self.options.get_option(:url,:mandatory),self.options.get_option(:username,:mandatory)])
440
440
  end
441
- iteration_data[0]=process_transfer_events(iteration_data[0])
441
+ iteration_data[0]=send("process_#{command}",iteration_data[0])
442
442
  iteration_persistency.save unless iteration_persistency.nil?
443
- return Main.result_status('trevents finished')
443
+ return Main.result_status("#{command} finished")
444
444
  when :check
445
445
  Aspera::Preview::Utils.check_tools(@skip_types)
446
446
  return Main.result_status('tools validated')
@@ -448,8 +448,9 @@ module Aspera
448
448
  format = self.options.get_next_argument('format',Aspera::Preview::Generator::PREVIEW_FORMATS)
449
449
  source = self.options.get_next_argument('source file')
450
450
  dest=preview_filename(format,self.options.get_option(:case,:optional))
451
- g=Aspera::Preview::Generator.new(@gen_options,source,dest,@tmp_folder)
452
- raise "format not supported: #{format}" unless g.supported?
451
+ g=Aspera::Preview::Generator.new(@gen_options,source,dest,@tmp_folder,nil)
452
+ raise "cannot find file type for #{source}" if g.conversion_type.nil?
453
+ raise "out format #{format} not supported" unless g.supported?
453
454
  g.generate
454
455
  return Main.result_status("generated: #{dest}")
455
456
  else
@@ -62,7 +62,7 @@ module Aspera
62
62
  end.select{|i|!i.nil?}
63
63
  end
64
64
 
65
- ACTIONS=[:nagios,:nodeadmin,:userdata,:configurator,:ctl,:download,:upload,:browse,:delete,:rename].concat(Aspera::AsCmd::OPERATIONS)
65
+ ACTIONS=[:health,:nodeadmin,:userdata,:configurator,:ctl,:download,:upload,:browse,:delete,:rename].concat(Aspera::AsCmd::OPERATIONS)
66
66
 
67
67
  def execute_action
68
68
  server_uri=URI.parse(self.options.get_option(:url,:mandatory))
@@ -93,12 +93,14 @@ module Aspera
93
93
  ssh_keys=[ssh_keys] if ssh_keys.is_a?(String)
94
94
  ssh_keys.map!{|p|File.expand_path(p)}
95
95
  Log.log.debug("ssh keys=#{ssh_keys}")
96
- ssh_options[:keys]=ssh_keys
97
- server_transfer_spec['EX_ssh_key_paths']=ssh_keys
98
- ssh_keys.each do |k|
99
- Log.log.warn("no such key file: #{k}") unless File.exist?(k)
96
+ if !ssh_keys.empty?
97
+ ssh_options[:keys]=ssh_keys
98
+ server_transfer_spec['EX_ssh_key_paths']=ssh_keys
99
+ ssh_keys.each do |k|
100
+ Log.log.warn("no such key file: #{k}") unless File.exist?(k)
101
+ end
102
+ cred_set=true
100
103
  end
101
- cred_set=true
102
104
  end
103
105
  raise 'either password or key must be provided' if !cred_set
104
106
  shell_executor=Ssh.new(server_transfer_spec['remote_host'],server_transfer_spec['remote_user'],ssh_options)
@@ -114,9 +116,9 @@ module Aspera
114
116
  command=:rm if command.eql?(:delete)
115
117
  command=:mv if command.eql?(:rename)
116
118
  case command
117
- when :nagios
119
+ when :health
118
120
  nagios=Nagios.new
119
- command_nagios=self.options.get_next_command([ :app_services, :transfer ])
121
+ command_nagios=self.options.get_next_command([ :app_services, :transfer, :asctlstatus ])
120
122
  case command_nagios
121
123
  when :app_services
122
124
  # will not work with aspshell, requires Linux/bash
@@ -145,6 +147,19 @@ module Aspera
145
147
  else
146
148
  nagios.add_critical('transfer',statuses.select{|i|!i.eql?(:success)}.first.to_s)
147
149
  end
150
+ when :asctlstatus
151
+ realcmd='asctl'
152
+ prefix=self.options.get_option(:cmd_prefix,:optional)
153
+ realcmd="#{prefix}#{realcmd} all:status" unless prefix.nil?
154
+ result=shell_executor.execute(realcmd.split(' '))
155
+ data=asctl_parse(result)
156
+ data.each do |i|
157
+ if i['state'].eql?('running')
158
+ nagios.add_ok(i['process'],i['state'])
159
+ else
160
+ nagios.add_critical(i['process'],i['state'])
161
+ end
162
+ end
148
163
  else raise "ERROR"
149
164
  end
150
165
  return nagios.result
@@ -22,7 +22,7 @@ module Aspera
22
22
  @opt_mgr=cli_objects[:options]
23
23
  @config=cli_objects[:config]
24
24
  # transfer spec overrides provided on command line
25
- @transfer_spec_cmdline={}
25
+ @transfer_spec_cmdline={"create_dir"=>true}
26
26
  # the currently selected transfer agent
27
27
  @agent=nil
28
28
  @progress_listener=Listener::ProgressMulti.new
@@ -1,5 +1,5 @@
1
1
  module Aspera
2
2
  module Cli
3
- VERSION = "4.0.0"
3
+ VERSION = "4.1.0"
4
4
  end
5
5
  end
@@ -12,7 +12,9 @@ module Aspera
12
12
  private_constant :MAX_CONNECT_START_RETRY,:SLEEP_SEC_BETWEEN_RETRY
13
13
  def initialize
14
14
  super
15
- @connect_app_id=SecureRandom.uuid
15
+ @connect_settings={
16
+ 'app_id' => SecureRandom.uuid
17
+ }
16
18
  # TODO: start here and create monitor
17
19
  end
18
20
 
@@ -32,46 +34,51 @@ module Aspera
32
34
  OpenApplication.uri_graphical('https://downloads.asperasoft.com/connect2/')
33
35
  raise StandardError,'Connect is not installed'
34
36
  end
35
- sleep SLEEP_SEC_BETWEEN_RETRY
37
+ sleep(SLEEP_SEC_BETWEEN_RETRY)
36
38
  retry
37
39
  end
38
40
  if transfer_spec['direction'] == 'send'
39
41
  Log.log.warn("Connect requires upload selection using GUI, ignoring #{transfer_spec['paths']}".red)
40
42
  transfer_spec.delete('paths')
41
- resdata=@connect_api.create('windows/select-open-file-dialog/',{'title'=>'Select Files','suggestedName'=>'','allowMultipleSelection'=>true,'allowedFileTypes'=>'','aspera_connect_settings'=>{'app_id'=>@connect_app_id}})[:data]
43
+ resdata=@connect_api.create('windows/select-open-file-dialog/',{'aspera_connect_settings'=>@connect_settings,'title'=>'Select Files','suggestedName'=>'','allowMultipleSelection'=>true,'allowedFileTypes'=>''})[:data]
42
44
  transfer_spec['paths']=resdata['dataTransfer']['files'].map { |i| {'source'=>i['name']}}
43
45
  end
44
46
  @request_id=SecureRandom.uuid
45
47
  # if there is a token, we ask connect client to use well known ssh private keys
46
48
  # instead of asking password
47
49
  transfer_spec['authentication']='token' if transfer_spec.has_key?('token')
50
+ connect_settings=
48
51
  connect_transfer_args={
49
- 'transfer_specs'=>[{
50
- 'transfer_spec'=>transfer_spec,
51
- 'aspera_connect_settings'=>{
52
- 'allow_dialogs'=>true,
53
- 'app_id'=>@connect_app_id,
54
- 'request_id'=>@request_id
55
- }}]}
52
+ 'aspera_connect_settings'=>@connect_settings.merge({
53
+ 'request_id' =>@request_id,
54
+ 'allow_dialogs' =>true,
55
+ }),
56
+ 'transfer_specs' =>[{
57
+ 'transfer_spec' =>transfer_spec,
58
+ }]}
56
59
  # asynchronous anyway
57
- @connect_api.create('transfers/start',connect_transfer_args)
60
+ res=@connect_api.create('transfers/start',connect_transfer_args)[:data]
61
+ @xfer_id=res['transfer_specs'].first['transfer_spec']['tags']['aspera']['xfer_id']
58
62
  end
59
63
 
60
64
  def wait_for_transfers_completion
61
- connect_activity_args={'aspera_connect_settings'=>{'app_id'=>@connect_app_id}}
65
+ connect_activity_args={'aspera_connect_settings'=>@connect_settings}
62
66
  started=false
63
67
  spinner=nil
64
68
  loop do
65
- result=@connect_api.create('transfers/activity',connect_activity_args)[:data]
66
- if result['transfers']
67
- trdata=result['transfers'].select{|i| i['aspera_connect_settings'] and i['aspera_connect_settings']['request_id'].eql?(@request_id)}.first
68
- raise 'problem with connect, please kill it' unless trdata
69
+ tr_info=@connect_api.create("transfers/info/#{@xfer_id}",connect_activity_args)[:data]
70
+ if tr_info['transfer_info'].is_a?(Hash)
71
+ trdata=tr_info['transfer_info']
72
+ if trdata.nil?
73
+ Log.log.warn("no session in Connect")
74
+ break
75
+ end
69
76
  # TODO: get session id
70
77
  case trdata['status']
71
78
  when 'completed'
72
- notify_listeners('emulated',{Manager::LISTENER_SESSION_ID_B=>@connect_app_id,'Type'=>'DONE'})
79
+ notify_end(@connect_settings['app_id'])
73
80
  break
74
- when 'initiating'
81
+ when 'initiating','queued'
75
82
  if spinner.nil?
76
83
  spinner = TTY::Spinner.new('[:spinner] :title', format: :classic)
77
84
  spinner.start
@@ -81,13 +88,13 @@ module Aspera
81
88
  when 'running'
82
89
  #puts "running: sessions:#{trdata['sessions'].length}, #{trdata['sessions'].map{|i| i['bytes_transferred']}.join(',')}"
83
90
  if !started and trdata['bytes_expected'] != 0
84
- notify_listeners('emulated',{Manager::LISTENER_SESSION_ID_B=>@connect_app_id,'Type'=>'NOTIFICATION','PreTransferBytes'=>trdata['bytes_expected']})
91
+ notify_begin(@connect_settings['app_id'],trdata['bytes_expected'])
85
92
  started=true
86
93
  else
87
- notify_listeners('emulated',{Manager::LISTENER_SESSION_ID_B=>@connect_app_id,'Type'=>'STATS','Bytescont'=>trdata['bytes_written']})
94
+ notify_progress(@connect_settings['app_id'],trdata['bytes_written'])
88
95
  end
89
96
  else
90
- raise Fasp::Error.new("#{trdata['status']}: #{trdata['error_desc']}")
97
+ raise Fasp::Error.new("unknown status: #{trdata['status']}: #{trdata['error_desc']}")
91
98
  end
92
99
  end
93
100
  sleep 1
@@ -2,12 +2,147 @@
2
2
  require 'aspera/fasp/manager'
3
3
  require 'aspera/log'
4
4
  require 'aspera/rest'
5
+ require 'websocket-client-simple'
6
+ require 'securerandom'
7
+ require 'openssl'
8
+ require 'base64'
9
+ require 'json'
10
+ require 'uri'
5
11
 
6
12
  # ref: https://api.ibm.com/explorer/catalog/aspera/product/ibm-aspera/api/http-gateway-api/doc/guides-toc
7
13
  module Aspera
8
14
  module Fasp
9
15
  # executes a local "ascp", connects mgt port, equivalent of "Fasp Manager"
10
16
  class HttpGW < Manager
17
+ # message returned by HTTP GW in case of success
18
+ OK_MESSAGE='end upload'
19
+ # refresh rate for progress
20
+ UPLOAD_REFRESH_SEC=0.5
21
+ private_constant :OK_MESSAGE,:UPLOAD_REFRESH_SEC
22
+ # send message on http gw web socket
23
+ def ws_send(ws,type,data)
24
+ ws.send(JSON.generate({type => data}))
25
+ end
26
+
27
+ def upload(transfer_spec)
28
+ # precalculate size
29
+ total_size=0
30
+ # currently, files are sent flat
31
+ source_path=[]
32
+ transfer_spec['paths'].each do |item|
33
+ filepath=item['source']
34
+ item['source']=item['destination']=File.basename(filepath)
35
+ total_size+=item['file_size']=File.size(filepath)
36
+ source_path.push(filepath)
37
+ end
38
+ session_id=SecureRandom.uuid
39
+ ws=::WebSocket::Client::Simple::Client.new
40
+ error=nil
41
+ received=0
42
+ ws.on :message do |msg|
43
+ Log.log.info("ws: message: #{msg.data}")
44
+ message=msg.data
45
+ if message.eql?(OK_MESSAGE)
46
+ received+=1
47
+ else
48
+ message.chomp!
49
+ if message[0].eql?('"') and message[-1].eql?('"')
50
+ error=JSON.parse(Base64.strict_decode64(message.chomp[1..-2]))['message']
51
+ else
52
+ error="expecting quotes in [#{message}]"
53
+ end
54
+ end
55
+ end
56
+ ws.on :error do |e|
57
+ error=e
58
+ end
59
+ ws.on :open do
60
+ Log.log.info("ws: open")
61
+ end
62
+ ws.on :close do
63
+ Log.log.info("ws: close")
64
+ end
65
+ # open web socket to end point
66
+ ws.connect("#{@gw_api.params[:base_url]}/upload")
67
+ while !ws.open? and error.nil? do
68
+ Log.log.info("ws: wait")
69
+ sleep(0.2)
70
+ end
71
+ notify_begin(session_id,total_size)
72
+ ws_send(ws,:transfer_spec,transfer_spec)
73
+ # current file index
74
+ filenum=0
75
+ # aggregate size sent
76
+ sent_bytes=0
77
+ # last progress event
78
+ lastevent=Time.now-1
79
+ transfer_spec['paths'].each do |item|
80
+ # TODO: on destination write same path?
81
+ destination_path=item['source']
82
+ # TODO: get mime type?
83
+ file_mime_type=''
84
+ total=item['file_size']
85
+ # compute total number of slices
86
+ numslices=1+(total-1)/@upload_chunksize
87
+ # current slice index
88
+ slicenum=0
89
+ File.open(source_path[filenum]) do |file|
90
+ while !file.eof? do
91
+ data=file.read(@upload_chunksize)
92
+ slice_data={
93
+ name: destination_path,
94
+ type: file_mime_type,
95
+ size: total,
96
+ data: Base64.strict_encode64(data),
97
+ slice: slicenum,
98
+ total_slices: numslices,
99
+ fileIndex: filenum
100
+ }
101
+ ws_send(ws,:slice_upload, slice_data)
102
+ sent_bytes+=data.length
103
+ currenttime=Time.now
104
+ if (currenttime-lastevent)>UPLOAD_REFRESH_SEC
105
+ notify_progress(session_id,sent_bytes)
106
+ lastevent=currenttime
107
+ end
108
+ slicenum+=1
109
+ raise error unless error.nil?
110
+ end
111
+ end
112
+ filenum+=1
113
+ end
114
+ ws.close
115
+ notify_end(session_id)
116
+ end
117
+
118
+ def download(transfer_spec)
119
+ transfer_spec['zip_required']||=false
120
+ transfer_spec['source_root']||='/'
121
+ # is normally provided by application, like package name
122
+ if !transfer_spec.has_key?('download_name')
123
+ # by default it is the name of first file
124
+ dname=File.basename(transfer_spec['paths'].first['source'])
125
+ # we remove extension
126
+ dname=dname.gsub(/\.@gw_api.*$/,'')
127
+ # ands add indication of number of files if there is more than one
128
+ if transfer_spec['paths'].length > 1
129
+ dname=dname+" #{transfer_spec['paths'].length} Files"
130
+ end
131
+ transfer_spec['download_name']=dname
132
+ end
133
+ creation=@gw_api.create('download',{'transfer_spec'=>transfer_spec})[:data]
134
+ transfer_uuid=creation['url'].split('/').last
135
+ if transfer_spec['zip_required'] or transfer_spec['paths'].length > 1
136
+ # it is a zip file if zip is required or there is more than 1 file
137
+ file_dest=transfer_spec['download_name']+'.zip'
138
+ else
139
+ # it is a plain file if we don't require zip and there is only one file
140
+ file_dest=File.basename(transfer_spec['paths'].first['source'])
141
+ end
142
+ file_dest=File.join(transfer_spec['destination_root'],file_dest)
143
+ @gw_api.call({:operation=>'GET',:subpath=>"download/#{transfer_uuid}",:save_to_file=>file_dest})
144
+ end
145
+
11
146
  # start FASP transfer based on transfer spec (hash table)
12
147
  # note that it is asynchronous
13
148
  # HTTP download only supports file list
@@ -15,37 +150,13 @@ module Aspera
15
150
  raise "GW URL must be set" unless !@gw_api.nil?
16
151
  raise "option: must be hash (or nil)" unless options.is_a?(Hash)
17
152
  raise "paths: must be Array" unless transfer_spec['paths'].is_a?(Array)
153
+ raise "on token based transfer is supported in GW" unless transfer_spec['token'].is_a?(String)
154
+ transfer_spec['authentication']||='token'
18
155
  case transfer_spec['direction']
19
156
  when 'send'
20
- # this is a websocket
21
- raise "error, not implemented"
157
+ upload(transfer_spec)
22
158
  when 'receive'
23
- transfer_spec['zip_required']||=false
24
- transfer_spec['authentication']||='token'
25
- transfer_spec['source_root']||='/'
26
- # is normally provided by application, like package name
27
- if !transfer_spec.has_key?('download_name')
28
- # by default it is the name of first file
29
- dname=File.basename(transfer_spec['paths'].first['source'])
30
- # we remove extension
31
- dname=dname.gsub(/\.@gw_api.*$/,'')
32
- # ands add indication of number of files if there is more than one
33
- if transfer_spec['paths'].length > 1
34
- dname=dname+" #{transfer_spec['paths'].length} Files"
35
- end
36
- transfer_spec['download_name']=dname
37
- end
38
- creation=@gw_api.create('download',{'transfer_spec'=>transfer_spec})[:data]
39
- transfer_uuid=creation['url'].split('/').last
40
- if transfer_spec['zip_required'] or transfer_spec['paths'].length > 1
41
- # it is a zip file if zip is required or there is more than 1 file
42
- file_dest=transfer_spec['download_name']+'.zip'
43
- else
44
- # it is a plain file if we don't require zip and there is only one file
45
- file_dest=File.basename(transfer_spec['paths'].first['source'])
46
- end
47
- file_dest=File.join(transfer_spec['destination_root'],file_dest)
48
- @gw_api.call({:operation=>'GET',:subpath=>"download/#{transfer_uuid}",:save_to_file=>file_dest})
159
+ download(transfer_spec)
49
160
  else
50
161
  raise "error"
51
162
  end
@@ -74,6 +185,7 @@ module Aspera
74
185
  @gw_api=Rest.new({:base_url => params[:url]})
75
186
  api_info = @gw_api.read('info')[:data]
76
187
  Log.log.info("#{api_info}")
188
+ @upload_chunksize=128000 # TODO: configurable ?
77
189
  end
78
190
 
79
191
  end # LocalHttp