aspera-cli 4.14.0 → 4.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/BUGS.md +29 -3
- data/CHANGELOG.md +300 -185
- data/CONTRIBUTING.md +74 -23
- data/README.md +2346 -1619
- data/bin/ascli +16 -25
- data/bin/asession +15 -15
- data/examples/dascli +2 -2
- data/examples/proxy.pac +1 -1
- data/lib/aspera/aoc.rb +216 -150
- data/lib/aspera/ascmd.rb +25 -18
- data/lib/aspera/assert.rb +45 -0
- data/lib/aspera/cli/basic_auth_plugin.rb +9 -6
- data/lib/aspera/cli/error.rb +17 -0
- data/lib/aspera/cli/extended_value.rb +51 -16
- data/lib/aspera/cli/formatter.rb +276 -174
- data/lib/aspera/cli/hints.rb +81 -0
- data/lib/aspera/cli/main.rb +114 -147
- data/lib/aspera/cli/manager.rb +181 -136
- data/lib/aspera/cli/plugin.rb +82 -64
- data/lib/aspera/cli/plugins/alee.rb +0 -1
- data/lib/aspera/cli/plugins/aoc.rb +327 -331
- data/lib/aspera/cli/plugins/ats.rb +12 -8
- data/lib/aspera/cli/plugins/bss.rb +2 -2
- data/lib/aspera/cli/plugins/config.rb +575 -439
- data/lib/aspera/cli/plugins/console.rb +40 -0
- data/lib/aspera/cli/plugins/cos.rb +4 -5
- data/lib/aspera/cli/plugins/faspex.rb +111 -92
- data/lib/aspera/cli/plugins/faspex5.rb +245 -182
- data/lib/aspera/cli/plugins/node.rb +239 -160
- data/lib/aspera/cli/plugins/orchestrator.rb +56 -19
- data/lib/aspera/cli/plugins/preview.rb +54 -38
- data/lib/aspera/cli/plugins/server.rb +63 -20
- data/lib/aspera/cli/plugins/shares.rb +64 -38
- data/lib/aspera/cli/sync_actions.rb +68 -0
- data/lib/aspera/cli/transfer_agent.rb +64 -67
- data/lib/aspera/cli/transfer_progress.rb +73 -0
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +3 -1
- data/lib/aspera/command_line_builder.rb +27 -22
- data/lib/aspera/cos_node.rb +6 -4
- data/lib/aspera/coverage.rb +22 -0
- data/lib/aspera/data_repository.rb +33 -2
- data/lib/aspera/environment.rb +21 -8
- data/lib/aspera/fasp/agent_alpha.rb +116 -0
- data/lib/aspera/fasp/agent_base.rb +40 -76
- data/lib/aspera/fasp/agent_connect.rb +21 -22
- data/lib/aspera/fasp/agent_direct.rb +169 -179
- data/lib/aspera/fasp/agent_httpgw.rb +200 -195
- data/lib/aspera/fasp/agent_node.rb +43 -35
- data/lib/aspera/fasp/agent_trsdk.rb +124 -41
- data/lib/aspera/fasp/error_info.rb +2 -2
- data/lib/aspera/fasp/faux_file.rb +52 -0
- data/lib/aspera/fasp/installation.rb +89 -191
- data/lib/aspera/fasp/management.rb +249 -0
- data/lib/aspera/fasp/parameters.rb +86 -47
- data/lib/aspera/fasp/parameters.yaml +75 -8
- data/lib/aspera/fasp/products.rb +162 -0
- data/lib/aspera/fasp/resume_policy.rb +7 -5
- data/lib/aspera/fasp/sync.rb +273 -0
- data/lib/aspera/fasp/transfer_spec.rb +10 -8
- data/lib/aspera/fasp/uri.rb +6 -6
- data/lib/aspera/faspex_gw.rb +11 -8
- data/lib/aspera/faspex_postproc.rb +8 -7
- data/lib/aspera/hash_ext.rb +2 -2
- data/lib/aspera/id_generator.rb +3 -1
- data/lib/aspera/json_rpc.rb +51 -0
- data/lib/aspera/keychain/encrypted_hash.rb +46 -11
- data/lib/aspera/keychain/macos_security.rb +15 -13
- data/lib/aspera/line_logger.rb +23 -0
- data/lib/aspera/log.rb +61 -19
- data/lib/aspera/nagios.rb +7 -2
- data/lib/aspera/node.rb +105 -21
- data/lib/aspera/node_simulator.rb +214 -0
- data/lib/aspera/oauth.rb +57 -36
- data/lib/aspera/open_application.rb +4 -4
- data/lib/aspera/persistency_action_once.rb +13 -14
- data/lib/aspera/persistency_folder.rb +5 -4
- data/lib/aspera/preview/file_types.rb +56 -268
- data/lib/aspera/preview/generator.rb +28 -39
- data/lib/aspera/preview/options.rb +2 -0
- data/lib/aspera/preview/terminal.rb +36 -16
- data/lib/aspera/preview/utils.rb +23 -29
- data/lib/aspera/proxy_auto_config.rb +6 -3
- data/lib/aspera/rest.rb +127 -80
- data/lib/aspera/rest_call_error.rb +1 -1
- data/lib/aspera/rest_error_analyzer.rb +16 -14
- data/lib/aspera/rest_errors_aspera.rb +39 -34
- data/lib/aspera/secret_hider.rb +18 -17
- data/lib/aspera/ssh.rb +10 -5
- data/lib/aspera/temp_file_manager.rb +11 -4
- data/lib/aspera/web_auth.rb +10 -7
- data/lib/aspera/web_server_simple.rb +11 -5
- data.tar.gz.sig +0 -0
- metadata +108 -39
- metadata.gz.sig +0 -0
- data/lib/aspera/cli/listener/line_dump.rb +0 -19
- data/lib/aspera/cli/listener/logger.rb +0 -22
- data/lib/aspera/cli/listener/progress.rb +0 -50
- data/lib/aspera/cli/listener/progress_multi.rb +0 -84
- data/lib/aspera/cli/plugins/sync.rb +0 -44
- data/lib/aspera/fasp/listener.rb +0 -13
- data/lib/aspera/sync.rb +0 -213
@@ -7,6 +7,46 @@ module Aspera
|
|
7
7
|
module Cli
|
8
8
|
module Plugins
|
9
9
|
class Console < Aspera::Cli::BasicAuthPlugin
|
10
|
+
STANDARD_PATH = '/aspera/console'
|
11
|
+
class << self
|
12
|
+
def detect(address_or_url)
|
13
|
+
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
14
|
+
urls = [address_or_url]
|
15
|
+
urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
|
16
|
+
|
17
|
+
urls.each do |base_url|
|
18
|
+
next unless base_url.start_with?('https://')
|
19
|
+
api = Rest.new(base_url: base_url, redirect_max: 2)
|
20
|
+
test_endpoint = 'login'
|
21
|
+
test_page = api.call({operation: 'GET', subpath: test_endpoint, url_params: {local: true}})
|
22
|
+
next unless test_page[:http].body.include?('Aspera Console')
|
23
|
+
version = 'unknown'
|
24
|
+
if (m = test_page[:http].body.match(/\(v([1-9]\..*)\)/))
|
25
|
+
version = m[1]
|
26
|
+
end
|
27
|
+
url = test_page[:http].uri.to_s
|
28
|
+
return {
|
29
|
+
version: version,
|
30
|
+
url: url[0..url.index(test_endpoint) - 2]
|
31
|
+
}
|
32
|
+
rescue StandardError => e
|
33
|
+
Log.log.debug{"detect error: #{e}"}
|
34
|
+
end
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def wizard(object:, private_key_path: nil, pub_key_pem: nil)
|
39
|
+
options = object.options
|
40
|
+
return {
|
41
|
+
preset_value: {
|
42
|
+
url: options.get_option(:url, mandatory: true),
|
43
|
+
username: options.get_option(:username, mandatory: true),
|
44
|
+
password: options.get_option(:password, mandatory: true)
|
45
|
+
},
|
46
|
+
test_args: 'transfer list'
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
10
50
|
DEFAULT_FILTER_AGE_SECONDS = 3 * 3600
|
11
51
|
private_constant :DEFAULT_FILTER_AGE_SECONDS
|
12
52
|
def initialize(env)
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'aspera/cli/plugin'
|
4
4
|
require 'aspera/cli/plugins/node'
|
5
5
|
require 'aspera/cos_node'
|
6
|
+
require 'aspera/assert'
|
6
7
|
|
7
8
|
module Aspera
|
8
9
|
module Cli
|
@@ -10,7 +11,6 @@ module Aspera
|
|
10
11
|
class Cos < Aspera::Cli::Plugin
|
11
12
|
def initialize(env)
|
12
13
|
super(env)
|
13
|
-
@service_creds = nil
|
14
14
|
options.declare(:bucket, 'Bucket name')
|
15
15
|
options.declare(:endpoint, 'Storage endpoint url')
|
16
16
|
options.declare(:apikey, 'Storage API key')
|
@@ -31,19 +31,18 @@ module Aspera
|
|
31
31
|
# get service credentials, Hash, e.g. @json:@file:...
|
32
32
|
service_credentials = options.get_option(:service_credentials)
|
33
33
|
storage_endpoint = options.get_option(:endpoint)
|
34
|
-
|
35
|
-
raise CliBadArgument, 'endpoint and service_credentials are mutually exclusive' unless service_credentials.nil? || storage_endpoint.nil?
|
34
|
+
assert(service_credentials.nil? ^ storage_endpoint.nil?, exception_class: Cli::BadArgument){'endpoint and service_credentials are mutually exclusive'}
|
36
35
|
if service_credentials.nil?
|
37
36
|
service_api_key = options.get_option(:apikey, mandatory: true)
|
38
37
|
instance_id = options.get_option(:crn, mandatory: true)
|
39
38
|
else
|
40
|
-
params = CosNode.
|
39
|
+
params = CosNode.parameters_from_svc_credentials(service_credentials, options.get_option(:region, mandatory: true))
|
41
40
|
storage_endpoint = params[:storage_endpoint]
|
42
41
|
service_api_key = params[:service_api_key]
|
43
42
|
instance_id = params[:instance_id]
|
44
43
|
end
|
45
44
|
api_node = CosNode.new(bucket_name, storage_endpoint, instance_id, service_api_key, options.get_option(:identity, mandatory: true))
|
46
|
-
node_plugin = Node.new(@agents
|
45
|
+
node_plugin = Node.new(@agents, api: api_node)
|
47
46
|
command = options.get_next_command(Node::COMMANDS_COS)
|
48
47
|
return node_plugin.execute_action(command)
|
49
48
|
end
|
@@ -1,16 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# cspell:ignore passcode xrds workgroups dmembership wmembership
|
3
4
|
require 'aspera/cli/basic_auth_plugin'
|
4
5
|
require 'aspera/cli/plugins/node'
|
5
6
|
require 'aspera/cli/plugins/config'
|
6
7
|
require 'aspera/cli/extended_value'
|
7
8
|
require 'aspera/cli/transfer_agent'
|
8
|
-
require 'aspera/persistency_action_once'
|
9
|
-
require 'aspera/open_application'
|
10
9
|
require 'aspera/fasp/uri'
|
11
10
|
require 'aspera/fasp/transfer_spec'
|
11
|
+
require 'aspera/persistency_action_once'
|
12
|
+
require 'aspera/open_application'
|
12
13
|
require 'aspera/nagios'
|
13
14
|
require 'aspera/id_generator'
|
15
|
+
require 'aspera/log'
|
16
|
+
require 'aspera/assert'
|
14
17
|
require 'xmlsimple'
|
15
18
|
require 'json'
|
16
19
|
require 'cgi'
|
@@ -32,69 +35,79 @@ module Aspera
|
|
32
35
|
ATOM_EXT_PARAMS = [MAX_ITEMS, MAX_PAGES].concat(ATOM_PARAMS).freeze
|
33
36
|
# sub path in url for public link delivery
|
34
37
|
PUB_LINK_EXTERNAL_MATCH = 'external_deliveries/'
|
38
|
+
STANDARD_PATH = '/aspera/faspex'
|
35
39
|
private_constant(*%i[KEY_NODE KEY_PATH PACKAGE_MATCH_FIELD ATOM_MAILBOXES ATOM_PARAMS ATOM_EXT_PARAMS PUB_LINK_EXTERNAL_MATCH])
|
36
40
|
|
37
41
|
class << self
|
38
|
-
def detect(
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
def detect(address_or_url)
|
43
|
+
address_or_url = "https://#{address_or_url}" unless address_or_url.match?(%r{^[a-z]{1,6}://})
|
44
|
+
urls = [address_or_url]
|
45
|
+
urls.push("#{address_or_url}#{STANDARD_PATH}") unless address_or_url.end_with?(STANDARD_PATH)
|
46
|
+
|
47
|
+
urls.each do |base_url|
|
48
|
+
next unless base_url.start_with?('https://')
|
49
|
+
api = Rest.new(base_url: base_url, redirect_max: 1)
|
50
|
+
result = api.call(
|
51
|
+
operation: 'POST',
|
52
|
+
subpath: '',
|
53
|
+
headers: {'Accept' => 'application/xrds+xml', 'Content-type' => 'text/plain'},
|
54
|
+
text_body_params: '')
|
55
|
+
# 4.x
|
56
|
+
next unless result[:http].body.start_with?('<?xml')
|
47
57
|
res_s = XmlSimple.xml_in(result[:http].body, {'ForceArray' => false})
|
58
|
+
Log.log.debug{"version: #{result[:http]['X-IBM-Aspera']}"}
|
48
59
|
version = res_s['XRD']['application']['version']
|
49
|
-
|
60
|
+
# take redirect if any
|
61
|
+
return {version: version, url: result[:http].uri.to_s}
|
62
|
+
rescue StandardError => e
|
63
|
+
Log.log.debug{"detect error: #{e}"}
|
50
64
|
end
|
51
65
|
return nil
|
52
66
|
end
|
53
67
|
|
54
|
-
|
68
|
+
def wizard(object:, private_key_path: nil, pub_key_pem: nil)
|
69
|
+
options = object.options
|
70
|
+
return {
|
71
|
+
preset_value: {
|
72
|
+
url: options.get_option(:url, mandatory: true),
|
73
|
+
username: options.get_option(:username, mandatory: true),
|
74
|
+
password: options.get_option(:password, mandatory: true)
|
75
|
+
},
|
76
|
+
test_args: 'me'
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
# extract elements from faspex public link
|
55
81
|
def get_link_data(public_url)
|
56
82
|
public_uri = URI.parse(public_url)
|
57
|
-
|
83
|
+
assert((m = public_uri.path.match(%r{^(.*)/(external.*)$})), exception_class: Cli::BadArgument){'Public link does not match Faspex format'}
|
58
84
|
base = m[1]
|
59
85
|
subpath = m[2]
|
60
86
|
port_add = public_uri.port.eql?(public_uri.default_port) ? '' : ":#{public_uri.port}"
|
61
87
|
result = {
|
62
88
|
base_url: "#{public_uri.scheme}://#{public_uri.host}#{port_add}#{base}",
|
63
89
|
subpath: subpath,
|
64
|
-
query:
|
90
|
+
query: Rest.decode_query(public_uri.query)
|
65
91
|
}
|
66
|
-
Log.dump('link data', result)
|
92
|
+
Log.log.debug{Log.dump('link data', result)}
|
67
93
|
return result
|
68
94
|
end
|
69
95
|
|
70
|
-
# get
|
96
|
+
# get Fasp::Uri::SCHEME URI from entry in xml, and fix problems.
|
71
97
|
def get_fasp_uri_from_entry(entry, raise_no_link: true)
|
72
98
|
unless entry.key?('link')
|
73
|
-
raise
|
99
|
+
raise Cli::BadArgument, 'package has no link (deleted?)' if raise_no_link
|
74
100
|
return nil
|
75
101
|
end
|
76
102
|
result = entry['link'].find{|e| e['rel'].eql?('package')}['href']
|
77
|
-
# tags in the end of URL is not well % encoded... there are "=" that should be %3D
|
78
|
-
# TODO: enter ticket to Faspex ?
|
79
|
-
# ##XXif m=result.match(/(=+)$/);result.gsub!(/=+$/,"#{"%3D"*m[1].length}");end
|
80
103
|
return result
|
81
104
|
end
|
82
105
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# field_sym : :id or :name
|
92
|
-
def get_source_id(source_list, source_name)
|
93
|
-
source_ids = source_list.select { |i| i['name'].eql?(source_name) }
|
94
|
-
if source_ids.empty?
|
95
|
-
raise CliError, %Q(No such Faspex source "#{source_name}" in [#{source_list.map{|i| %Q("#{i['name']}")}.join(', ')}])
|
96
|
-
end
|
97
|
-
return source_ids.first['id']
|
106
|
+
# @return [Integer] identifier of source
|
107
|
+
def get_source_id_by_name(source_name, source_list)
|
108
|
+
match_source = source_list.find { |i| i['name'].eql?(source_name) }
|
109
|
+
return match_source['id'] unless match_source.nil?
|
110
|
+
raise Cli::Error, %Q(No such Faspex source: "#{source_name}" in [#{source_list.map{|i| %Q("#{i['name']}")}.join(', ')}])
|
98
111
|
end
|
99
112
|
end
|
100
113
|
|
@@ -104,8 +117,8 @@ module Aspera
|
|
104
117
|
super(env)
|
105
118
|
options.declare(:link, 'Public link for specific operation')
|
106
119
|
options.declare(:delivery_info, 'Package delivery information', types: Hash)
|
107
|
-
options.declare(:
|
108
|
-
options.declare(:storage, 'Faspex local storage definition')
|
120
|
+
options.declare(:remote_source, 'Remote source for package send (id or %name:)')
|
121
|
+
options.declare(:storage, 'Faspex local storage definition (for browsing source)')
|
109
122
|
options.declare(:recipient, 'Use if recipient is a dropbox (with *)')
|
110
123
|
options.declare(:box, 'Package box', values: ATOM_MAILBOXES, default: :inbox)
|
111
124
|
options.parse_options!
|
@@ -148,9 +161,9 @@ module Aspera
|
|
148
161
|
max_pages = nil
|
149
162
|
result = []
|
150
163
|
if !mailbox_query.nil?
|
151
|
-
|
152
|
-
|
153
|
-
|
164
|
+
assert_type(mailbox_query, Hash){'query'}
|
165
|
+
assert((mailbox_query.keys - ATOM_EXT_PARAMS).empty?){"query: supported params: #{ATOM_EXT_PARAMS}"}
|
166
|
+
assert(!(mailbox_query.key?('startIndex') && mailbox_query.key?('page'))){'query: startIndex and page are exclusive'}
|
154
167
|
max_items = mailbox_query[MAX_ITEMS]
|
155
168
|
mailbox_query.delete(MAX_ITEMS)
|
156
169
|
max_pages = mailbox_query[MAX_PAGES]
|
@@ -160,8 +173,8 @@ module Aspera
|
|
160
173
|
# get a batch of package information
|
161
174
|
# order: first batch is latest packages, and then in a batch ids are increasing
|
162
175
|
atom_xml = api_v3.call({operation: 'GET', subpath: "#{mailbox}.atom", headers: {'Accept' => 'application/xml'}, url_params: mailbox_query})[:http].body
|
163
|
-
box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' =>
|
164
|
-
Log.dump(:box_data, box_data)
|
176
|
+
box_data = XmlSimple.xml_in(atom_xml, {'ForceArray' => %w[entry field link to]})
|
177
|
+
Log.log.debug{Log.dump(:box_data, box_data)}
|
165
178
|
items = box_data.key?('entry') ? box_data['entry'] : []
|
166
179
|
Log.log.debug{"new items: #{items.count}"}
|
167
180
|
# it is the end if page is empty
|
@@ -173,11 +186,14 @@ module Aspera
|
|
173
186
|
package[PACKAGE_MATCH_FIELD] =
|
174
187
|
case mailbox
|
175
188
|
when :inbox, :archive
|
176
|
-
recipient = package['to'].find{|i|recipient_names.include?(i['name']
|
177
|
-
recipient.nil? ? nil : recipient['recipient_delivery_id']
|
189
|
+
recipient = package['to'].find{|i|recipient_names.include?(i['name'])}
|
190
|
+
recipient.nil? ? nil : recipient['recipient_delivery_id']
|
178
191
|
else # :sent
|
179
|
-
package['delivery_id']
|
192
|
+
package['delivery_id']
|
180
193
|
end
|
194
|
+
# add special key
|
195
|
+
package['items'] = package['link'].is_a?(Array) ? package['link'].length : 0
|
196
|
+
package['metadata'] = package['metadata']['field'].each_with_object({}){|i, m| m[i['name']] = i['content'] }
|
181
197
|
# if we look for a specific package
|
182
198
|
stop_condition = true if !stop_at_id.nil? && stop_at_id.eql?(package[PACKAGE_MATCH_FIELD])
|
183
199
|
# keep only those for the specified recipient
|
@@ -197,7 +213,7 @@ module Aspera
|
|
197
213
|
break if link.nil?
|
198
214
|
# replace parameters with the ones from next link
|
199
215
|
params = CGI.parse(URI.parse(link['href']).query)
|
200
|
-
mailbox_query = params.keys.each_with_object({}){|i, m
|
216
|
+
mailbox_query = params.keys.each_with_object({}){|i, m| m[i] = params[i].first }
|
201
217
|
Log.log.debug{"query: #{mailbox_query}"}
|
202
218
|
break if !max_pages.nil? && (mailbox_query['page'].to_i > max_pages)
|
203
219
|
end
|
@@ -210,7 +226,7 @@ module Aspera
|
|
210
226
|
# pub link user
|
211
227
|
link_data = self.class.get_link_data(public_link_url)
|
212
228
|
if !['external/submissions/new', 'external/dropbox_submissions/new'].include?(link_data[:subpath])
|
213
|
-
raise
|
229
|
+
raise Cli::BadArgument, "pub link is #{link_data[:subpath]}, expecting external/submissions/new"
|
214
230
|
end
|
215
231
|
create_path = link_data[:subpath].split('/')[0..-2].join('/')
|
216
232
|
package_create_params[:passcode] = link_data[:query]['passcode']
|
@@ -225,11 +241,11 @@ module Aspera
|
|
225
241
|
subpath: create_path,
|
226
242
|
json_params: package_create_params,
|
227
243
|
headers: {'Accept' => 'text/javascript'}})[:http].body
|
228
|
-
# get
|
244
|
+
# get arguments of function call
|
229
245
|
package_creation_data.delete!("\n") # one line
|
230
246
|
package_creation_data.gsub!(/^[^"]+\("\{/, '{') # delete header
|
231
247
|
package_creation_data.gsub!(/"\);[^"]+$/, '"') # delete trailer
|
232
|
-
package_creation_data.gsub!(/\}", *"/, '},"') # between two
|
248
|
+
package_creation_data.gsub!(/\}", *"/, '},"') # between two arguments
|
233
249
|
package_creation_data.gsub!('\\"', '"') # remove protecting quote
|
234
250
|
begin
|
235
251
|
package_creation_data = JSON.parse("[#{package_creation_data}]")
|
@@ -254,18 +270,20 @@ module Aspera
|
|
254
270
|
end
|
255
271
|
return nagios.result
|
256
272
|
when :package
|
257
|
-
command_pkg = options.get_next_command(%i[send
|
273
|
+
command_pkg = options.get_next_command(%i[send receive list show], aliases: {recv: :receive})
|
258
274
|
case command_pkg
|
275
|
+
when :show
|
276
|
+
delivery_id = instance_identifier
|
277
|
+
return {type: :single_object, data: mailbox_filtered_entries(stop_at_id: delivery_id).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivery_id)} }
|
259
278
|
when :list
|
260
279
|
return {
|
261
|
-
type:
|
262
|
-
data:
|
263
|
-
fields:
|
264
|
-
textify: lambda {|table_data|Faspex.textify_package_list(table_data)}
|
280
|
+
type: :object_list,
|
281
|
+
data: mailbox_filtered_entries,
|
282
|
+
fields: [PACKAGE_MATCH_FIELD, 'title', 'items']
|
265
283
|
}
|
266
284
|
when :send
|
267
285
|
delivery_info = options.get_option(:delivery_info, mandatory: true)
|
268
|
-
|
286
|
+
assert_type(delivery_info, Hash, exception_class: Cli::BadArgument){'delivery_info'}
|
269
287
|
# actual parameter to faspex API
|
270
288
|
package_create_params = {'delivery' => delivery_info}
|
271
289
|
public_link_url = options.get_option(:link)
|
@@ -274,32 +292,32 @@ module Aspera
|
|
274
292
|
delivery_info['sources'] ||= [{'paths' => []}]
|
275
293
|
first_source = delivery_info['sources'].first
|
276
294
|
first_source['paths'].push(*transfer.source_list)
|
277
|
-
|
278
|
-
|
295
|
+
source_id = instance_identifier(as_option: :remote_source) do |field, value|
|
296
|
+
assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
|
279
297
|
source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
|
280
|
-
|
281
|
-
first_source['id'] = source_id
|
298
|
+
self.class.get_source_id_by_name(value, source_list)
|
282
299
|
end
|
300
|
+
first_source['id'] = source_id.to_i unless source_id.nil?
|
283
301
|
pkg_created = api_v3.call({
|
284
302
|
operation: 'POST',
|
285
303
|
subpath: 'send',
|
286
304
|
json_params: package_create_params,
|
287
305
|
headers: {'Accept' => 'application/json'}
|
288
306
|
})[:data]
|
289
|
-
if
|
290
|
-
# no transfer spec if remote source
|
307
|
+
if first_source.key?('id')
|
308
|
+
# no transfer spec if remote source: handled by faspex
|
291
309
|
return {data: [pkg_created['links']['status']], type: :value_list, name: 'link'}
|
292
310
|
end
|
293
|
-
raise
|
311
|
+
raise Cli::BadArgument, 'expecting one session exactly' if pkg_created['xfer_sessions'].length != 1
|
294
312
|
transfer_spec = pkg_created['xfer_sessions'].first
|
295
313
|
# use source from cmd line, this one only contains destination (already in dest root)
|
296
314
|
transfer_spec.delete('paths')
|
297
315
|
else # public link
|
298
316
|
transfer_spec = send_public_link_to_ts(public_link_url, package_create_params)
|
299
317
|
end
|
300
|
-
# Log.dump('transfer_spec',transfer_spec)
|
318
|
+
# Log.log.debug{Log.dump('transfer_spec',transfer_spec)}
|
301
319
|
return Main.result_transfer(transfer.start(transfer_spec))
|
302
|
-
when :
|
320
|
+
when :receive
|
303
321
|
link_url = options.get_option(:link)
|
304
322
|
# list of faspex ID/URI to download
|
305
323
|
pkg_id_uri = nil
|
@@ -322,11 +340,16 @@ module Aspera
|
|
322
340
|
delivery_id = instance_identifier
|
323
341
|
raise 'empty id' if delivery_id.empty?
|
324
342
|
recipient = options.get_option(:recipient)
|
325
|
-
if
|
343
|
+
if delivery_id.eql?(ExtendedValue::ALL)
|
326
344
|
pkg_id_uri = mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD], uri: self.class.get_fasp_uri_from_entry(i, raise_no_link: false)}}
|
345
|
+
elsif delivery_id.eql?(ExtendedValue::INIT)
|
346
|
+
assert(skip_ids_persistency){'Only with option once_only'}
|
347
|
+
skip_ids_persistency.data.clear.concat(mailbox_filtered_entries.map{|i|{id: i[PACKAGE_MATCH_FIELD]}})
|
348
|
+
skip_ids_persistency.save
|
349
|
+
return Main.result_status("Initialized skip for #{skip_ids_persistency.data.count} package(s)")
|
327
350
|
elsif !recipient.nil? && recipient.start_with?('*')
|
328
351
|
found_package_link = mailbox_filtered_entries(stop_at_id: delivery_id).find{|p|p[PACKAGE_MATCH_FIELD].eql?(delivery_id)}['link'].first['href']
|
329
|
-
raise
|
352
|
+
raise "Not Found. Dropbox and Workgroup packages can use the link option with #{Fasp::Uri::SCHEME}" if found_package_link.nil?
|
330
353
|
pkg_id_uri = [{id: delivery_id, uri: found_package_link}]
|
331
354
|
else
|
332
355
|
# TODO: delivery id is the right one if package was receive by workgroup
|
@@ -339,12 +362,12 @@ module Aspera
|
|
339
362
|
package_entry = XmlSimple.xml_in(entry_xml, {'ForceArray' => true})
|
340
363
|
pkg_id_uri = [{id: delivery_id, uri: self.class.get_fasp_uri_from_entry(package_entry)}]
|
341
364
|
end
|
342
|
-
when
|
365
|
+
when /^#{Fasp::Uri::SCHEME}:/o
|
343
366
|
pkg_id_uri = [{id: 'package', uri: link_url}]
|
344
367
|
else
|
345
368
|
link_data = self.class.get_link_data(link_url)
|
346
369
|
if !link_data[:subpath].start_with?(PUB_LINK_EXTERNAL_MATCH)
|
347
|
-
raise
|
370
|
+
raise Cli::BadArgument, "Pub link is #{link_data[:subpath]}. Expecting #{PUB_LINK_EXTERNAL_MATCH}"
|
348
371
|
end
|
349
372
|
# NOTE: unauthenticated API (authorization is in url params)
|
350
373
|
api_public_link = Rest.new({base_url: link_data[:base_url]})
|
@@ -355,10 +378,10 @@ module Aspera
|
|
355
378
|
headers: {'Accept' => 'application/xml'})
|
356
379
|
if !package_creation_data[:http].body.start_with?('<?xml ')
|
357
380
|
OpenApplication.instance.uri(link_url)
|
358
|
-
raise
|
381
|
+
raise Cli::Error, 'Unexpected response: package not found ?'
|
359
382
|
end
|
360
383
|
package_entry = XmlSimple.xml_in(package_creation_data[:http].body, {'ForceArray' => false})
|
361
|
-
Log.dump(:package_entry, package_entry)
|
384
|
+
Log.log.debug{Log.dump(:package_entry, package_entry)}
|
362
385
|
transfer_uri = self.class.get_fasp_uri_from_entry(package_entry)
|
363
386
|
pkg_id_uri = [{id: package_entry['id'], uri: transfer_uri}]
|
364
387
|
end # public link
|
@@ -366,7 +389,7 @@ module Aspera
|
|
366
389
|
# TODO : remove ids from skip not present in inbox to avoid growing too big
|
367
390
|
# skip_ids_data.select!{|id|pkg_id_uri.select{|p|p[:id].eql?(id)}}
|
368
391
|
pkg_id_uri.reject!{|i|skip_ids_data.include?(i[:id])}
|
369
|
-
Log.dump(:pkg_id_uri, pkg_id_uri)
|
392
|
+
Log.log.debug{Log.dump(:pkg_id_uri, pkg_id_uri)}
|
370
393
|
return Main.result_status('no new package') if pkg_id_uri.empty?
|
371
394
|
result_transfer = []
|
372
395
|
pkg_id_uri.each do |id_uri|
|
@@ -375,7 +398,7 @@ module Aspera
|
|
375
398
|
statuses = [:success]
|
376
399
|
else
|
377
400
|
transfer_spec = Fasp::Uri.new(id_uri[:uri]).transfer_spec
|
378
|
-
# NOTE: only external users have token in
|
401
|
+
# NOTE: only external users have token in Fasp::Uri::SCHEME link !
|
379
402
|
if !transfer_spec.key?('token')
|
380
403
|
sanitized = id_uri[:uri].gsub('&', '&')
|
381
404
|
xml_payload =
|
@@ -397,42 +420,38 @@ module Aspera
|
|
397
420
|
return Main.result_transfer_multiple(result_transfer)
|
398
421
|
end
|
399
422
|
when :source
|
400
|
-
command_source = options.get_next_command(%i[list
|
423
|
+
command_source = options.get_next_command(%i[list info node])
|
401
424
|
source_list = api_v3.call({operation: 'GET', subpath: 'source_shares', headers: {'Accept' => 'application/json'}})[:data]['items']
|
402
425
|
case command_source
|
403
426
|
when :list
|
404
427
|
return {type: :object_list, data: source_list}
|
405
|
-
else # :
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
# get id and name
|
412
|
-
source_name = source_ids.first['name']
|
413
|
-
# source_id=source_ids.first['id']
|
428
|
+
else # :info :node
|
429
|
+
source_id = instance_identifier do |field, value|
|
430
|
+
assert(field.eql?('name'), exception_class: Cli::BadArgument){'only name as selector, or give id'}
|
431
|
+
self.class.get_source_id_by_name(value, source_list)
|
432
|
+
end.to_i
|
433
|
+
source_name = source_list.find{|i|i['id'].eql?(source_id)}['name']
|
414
434
|
source_hash = options.get_option(:storage, mandatory: true)
|
415
435
|
# check value of option
|
416
|
-
|
436
|
+
assert_type(source_hash, Hash, exception_class: Cli::Error){'storage option'}
|
417
437
|
source_hash.each do |name, storage|
|
418
|
-
|
438
|
+
assert_type(storage, Hash, exception_class: Cli::Error){"storage '#{name}'"}
|
419
439
|
[KEY_NODE, KEY_PATH].each do |key|
|
420
|
-
|
440
|
+
assert(storage.key?(key), exception_class: Cli::Error){"storage '#{name}' must have a '#{key}'"}
|
421
441
|
end
|
422
442
|
end
|
423
443
|
if !source_hash.key?(source_name)
|
424
|
-
raise
|
444
|
+
raise Cli::Error, "No such storage in config file: \"#{source_name}\" in [#{source_hash.keys.join(', ')}]"
|
425
445
|
end
|
426
446
|
source_info = source_hash[source_name]
|
427
|
-
Log.log.debug{
|
428
|
-
|
429
|
-
case command_node
|
447
|
+
Log.log.debug{Log.dump(:source_info, source_info)}
|
448
|
+
case command_source
|
430
449
|
when :info
|
431
450
|
return {data: source_info, type: :single_object}
|
432
451
|
when :node
|
433
452
|
node_config = ExtendedValue.instance.evaluate(source_info[KEY_NODE])
|
434
|
-
raise CliError, "bad type for: \"#{source_info[KEY_NODE]}\"" unless node_config.is_a?(Hash)
|
435
453
|
Log.log.debug{"node=#{node_config}"}
|
454
|
+
assert_type(node_config, Hash, exception_class: Cli::Error){source_info[KEY_NODE]}
|
436
455
|
api_node = Rest.new({
|
437
456
|
base_url: node_config['url'],
|
438
457
|
auth: {
|
@@ -440,7 +459,7 @@ module Aspera
|
|
440
459
|
username: node_config['username'],
|
441
460
|
password: node_config['password']}})
|
442
461
|
command = options.get_next_command(Node::COMMANDS_FASPEX)
|
443
|
-
return Node.new(@agents
|
462
|
+
return Node.new(@agents, api: api_node).execute_action(command, source_info[KEY_PATH])
|
444
463
|
end
|
445
464
|
end
|
446
465
|
when :me
|