aspera-cli 4.19.0 → 4.20.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +20 -0
- data/CONTRIBUTING.md +16 -4
- data/README.md +344 -164
- data/bin/asession +26 -19
- data/examples/build_exec +65 -76
- data/examples/build_exec_rubyc +40 -0
- data/examples/get_proto_file.rb +7 -0
- data/lib/aspera/agent/alpha.rb +8 -8
- data/lib/aspera/agent/base.rb +2 -18
- data/lib/aspera/agent/connect.rb +14 -13
- data/lib/aspera/agent/direct.rb +23 -24
- data/lib/aspera/agent/httpgw.rb +2 -3
- data/lib/aspera/agent/node.rb +10 -10
- data/lib/aspera/agent/trsdk.rb +17 -20
- data/lib/aspera/api/alee.rb +15 -0
- data/lib/aspera/api/aoc.rb +126 -97
- data/lib/aspera/api/ats.rb +1 -1
- data/lib/aspera/api/cos_node.rb +1 -1
- data/lib/aspera/api/httpgw.rb +15 -10
- data/lib/aspera/api/node.rb +33 -12
- data/lib/aspera/ascmd.rb +56 -48
- data/lib/aspera/ascp/installation.rb +99 -42
- data/lib/aspera/ascp/management.rb +3 -2
- data/lib/aspera/ascp/products.rb +12 -0
- data/lib/aspera/assert.rb +10 -5
- data/lib/aspera/cli/formatter.rb +27 -17
- data/lib/aspera/cli/hints.rb +2 -1
- data/lib/aspera/cli/info.rb +12 -10
- data/lib/aspera/cli/main.rb +16 -13
- data/lib/aspera/cli/manager.rb +5 -0
- data/lib/aspera/cli/plugin.rb +15 -29
- data/lib/aspera/cli/plugins/alee.rb +3 -3
- data/lib/aspera/cli/plugins/aoc.rb +222 -194
- data/lib/aspera/cli/plugins/ats.rb +16 -14
- data/lib/aspera/cli/plugins/config.rb +53 -45
- data/lib/aspera/cli/plugins/console.rb +3 -3
- data/lib/aspera/cli/plugins/faspex.rb +11 -21
- data/lib/aspera/cli/plugins/faspex5.rb +44 -42
- data/lib/aspera/cli/plugins/faspio.rb +2 -2
- data/lib/aspera/cli/plugins/httpgw.rb +1 -1
- data/lib/aspera/cli/plugins/node.rb +153 -95
- data/lib/aspera/cli/plugins/orchestrator.rb +14 -13
- data/lib/aspera/cli/plugins/preview.rb +8 -9
- data/lib/aspera/cli/plugins/server.rb +5 -9
- data/lib/aspera/cli/plugins/shares.rb +2 -2
- data/lib/aspera/cli/sync_actions.rb +2 -2
- data/lib/aspera/cli/transfer_agent.rb +12 -14
- data/lib/aspera/cli/transfer_progress.rb +35 -17
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/command_line_builder.rb +3 -4
- data/lib/aspera/coverage.rb +13 -1
- data/lib/aspera/environment.rb +34 -18
- data/lib/aspera/faspex_gw.rb +2 -2
- data/lib/aspera/json_rpc.rb +1 -1
- data/lib/aspera/keychain/macos_security.rb +7 -12
- data/lib/aspera/log.rb +3 -4
- data/lib/aspera/oauth/base.rb +39 -45
- data/lib/aspera/oauth/factory.rb +11 -4
- data/lib/aspera/oauth/generic.rb +4 -8
- data/lib/aspera/oauth/jwt.rb +3 -3
- data/lib/aspera/oauth/url_json.rb +1 -2
- data/lib/aspera/oauth/web.rb +5 -2
- data/lib/aspera/persistency_action_once.rb +16 -8
- data/lib/aspera/preview/utils.rb +5 -16
- data/lib/aspera/rest.rb +100 -76
- data/lib/aspera/transfer/faux_file.rb +4 -4
- data/lib/aspera/transfer/parameters.rb +14 -16
- data/lib/aspera/transfer/spec.rb +12 -12
- data/lib/aspera/transfer/sync.rb +1 -5
- data/lib/aspera/transfer/uri.rb +1 -1
- data/lib/aspera/uri_reader.rb +1 -1
- data/lib/aspera/web_auth.rb +166 -17
- data/lib/aspera/web_server_simple.rb +4 -3
- data/lib/transfer_pb.rb +84 -0
- data/lib/transfer_services_pb.rb +82 -0
- data.tar.gz.sig +0 -0
- metadata +24 -5
- metadata.gz.sig +0 -0
data/lib/aspera/agent/trsdk.rb
CHANGED
@@ -7,6 +7,7 @@ require 'aspera/log'
|
|
7
7
|
require 'aspera/assert'
|
8
8
|
require 'json'
|
9
9
|
require 'uri'
|
10
|
+
require 'transfer_services_pb'
|
10
11
|
|
11
12
|
module Aspera
|
12
13
|
module Agent
|
@@ -48,14 +49,12 @@ module Aspera
|
|
48
49
|
**base_options
|
49
50
|
)
|
50
51
|
super(**base_options)
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
$LOAD_PATH.unshift(Ascp::Installation.instance.sdk_ruby_folder)
|
55
|
-
require 'transfer_services_pb'
|
52
|
+
@keep = keep
|
53
|
+
is_local_auto_port = url.eql?(AUTO_LOCAL_TCP_PORT)
|
54
|
+
raise 'Cannot use options `keep` or `external` with port zero' if is_local_auto_port && (@keep || external)
|
56
55
|
# keep PID for optional shutdown
|
57
56
|
@daemon_pid = nil
|
58
|
-
daemon_endpoint =
|
57
|
+
daemon_endpoint = url
|
59
58
|
Log.log.debug{Log.dump(:daemon_endpoint, daemon_endpoint)}
|
60
59
|
# retry loop
|
61
60
|
begin
|
@@ -66,16 +65,14 @@ module Aspera
|
|
66
65
|
# Initiate actual connection
|
67
66
|
get_info_response = @transfer_client.get_info(Transfersdk::InstanceInfoRequest.new)
|
68
67
|
Log.log.debug{"Daemon info: #{get_info_response}"}
|
69
|
-
Log.log.warn{'Attached to existing daemon'} unless @daemon_pid ||
|
68
|
+
Log.log.warn{'Attached to existing daemon'} unless @daemon_pid || external || @keep
|
70
69
|
at_exit{shutdown}
|
71
70
|
rescue GRPC::Unavailable => e
|
72
71
|
# if transferd is external: do not start it, or other error
|
73
|
-
raise if
|
72
|
+
raise if external || !e.message.include?('failed to connect')
|
74
73
|
# we already tried to start a daemon, but it failed
|
75
74
|
Aspera.assert(@daemon_pid.nil?){"Daemon started with PID #{@daemon_pid}, but connection failed to #{daemon_endpoint}}"}
|
76
|
-
Log.log.warn('no daemon present, starting daemon...') if
|
77
|
-
# location of daemon binary
|
78
|
-
sdk_folder = File.realpath(File.join(Ascp::Installation.instance.sdk_ruby_folder, '..'))
|
75
|
+
Log.log.warn('no daemon present, starting daemon...') if external
|
79
76
|
# transferd only supports local ip and port
|
80
77
|
daemon_uri = URI.parse("ipv4://#{daemon_endpoint}")
|
81
78
|
Aspera.assert(daemon_uri.scheme.eql?('ipv4')){"Invalid scheme daemon URI #{daemon_endpoint}"}
|
@@ -86,8 +83,8 @@ module Aspera
|
|
86
83
|
fasp_runtime: {
|
87
84
|
use_embedded: false,
|
88
85
|
user_defined: {
|
89
|
-
bin: sdk_folder,
|
90
|
-
etc: sdk_folder
|
86
|
+
bin: Ascp::Installation.instance.sdk_folder,
|
87
|
+
etc: Ascp::Installation.instance.sdk_folder
|
91
88
|
}
|
92
89
|
}
|
93
90
|
}
|
@@ -143,24 +140,24 @@ module Aspera
|
|
143
140
|
case response.status
|
144
141
|
when :RUNNING
|
145
142
|
if !session_started
|
146
|
-
notify_progress(session_id: @transfer_id
|
143
|
+
notify_progress(:session_start, session_id: @transfer_id)
|
147
144
|
session_started = true
|
148
145
|
end
|
149
146
|
if bytes_expected.nil? &&
|
150
147
|
!response.sessionInfo.preTransferBytes.eql?(0)
|
151
148
|
bytes_expected = response.sessionInfo.preTransferBytes
|
152
|
-
notify_progress(
|
149
|
+
notify_progress(:session_size, session_id: @transfer_id, info: bytes_expected)
|
153
150
|
end
|
154
|
-
notify_progress(
|
151
|
+
notify_progress(:transfer, session_id: @transfer_id, info: response.transferInfo.bytesTransferred)
|
155
152
|
when :COMPLETED
|
156
|
-
notify_progress(
|
157
|
-
notify_progress(
|
153
|
+
notify_progress(:transfer, session_id: @transfer_id, info: bytes_expected) if bytes_expected
|
154
|
+
notify_progress(:end, session_id: @transfer_id)
|
158
155
|
break
|
159
156
|
when :FAILED, :CANCELED
|
160
|
-
notify_progress(
|
157
|
+
notify_progress(:end, session_id: @transfer_id)
|
161
158
|
raise Transfer::Error, JSON.parse(response.message)['Description']
|
162
159
|
when :QUEUED, :UNKNOWN_STATUS, :PAUSED, :ORPHANED
|
163
|
-
notify_progress(
|
160
|
+
notify_progress(:pre_start, session_id: nil, info: response.status.to_s.downcase)
|
164
161
|
else
|
165
162
|
Log.log.error{"unknown status#{response.status}"}
|
166
163
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'aspera/api/aoc.rb'
|
4
|
+
module Aspera
|
5
|
+
module Api
|
6
|
+
class Alee < Aspera::Rest
|
7
|
+
def initialize(entitlement_id, customer_id, api_domain: AoC::SAAS_DOMAIN_PROD, version: 'v1')
|
8
|
+
super(
|
9
|
+
base_url: "https://api.#{api_domain}/metering/#{version}",
|
10
|
+
headers: {'X-Aspera-Entitlement-Authorization' => Rest.basic_token(entitlement_id, customer_id)}
|
11
|
+
)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/aspera/api/aoc.rb
CHANGED
@@ -12,18 +12,9 @@ require 'cgi'
|
|
12
12
|
|
13
13
|
module Aspera
|
14
14
|
module Api
|
15
|
-
SAAS_DOMAIN_PROD = 'ibmaspera.com'
|
16
|
-
class Alee < Aspera::Rest
|
17
|
-
def initialize(entitlement_id, customer_id, api_domain: SAAS_DOMAIN_PROD, version: 'v1')
|
18
|
-
super(
|
19
|
-
base_url: "https://api.#{api_domain}/metering/#{version}",
|
20
|
-
headers: {'X-Aspera-Entitlement-Authorization' => Rest.basic_token(entitlement_id, customer_id)}
|
21
|
-
)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
15
|
class AoC < Aspera::Rest
|
26
16
|
PRODUCT_NAME = 'Aspera on Cloud'
|
17
|
+
# use default workspace if it is set, else none
|
27
18
|
DEFAULT_WORKSPACE = ''
|
28
19
|
# Production domain of AoC
|
29
20
|
SAAS_DOMAIN_PROD = 'ibmaspera.com' # cspell:disable-line
|
@@ -78,42 +69,50 @@ module Aspera
|
|
78
69
|
end
|
79
70
|
|
80
71
|
# split host of http://myorg.asperafiles.com in org and domain
|
81
|
-
def
|
72
|
+
def split_org_domain(uri)
|
82
73
|
raise "No host found in URL.Please check URL format: https://myorg.#{SAAS_DOMAIN_PROD}" if uri.host.nil?
|
83
74
|
parts = uri.host.split('.', 2)
|
84
75
|
Aspera.assert(parts.length == 2){"expecting a public FQDN for #{PRODUCT_NAME}"}
|
85
|
-
|
76
|
+
parts[0] = nil if parts[0].eql?('api')
|
77
|
+
return %i{organization domain}.zip(parts).to_h
|
86
78
|
end
|
87
79
|
|
88
80
|
# @param url [String] URL of AoC public link
|
89
81
|
# @return [Hash] information about public link, or nil if not a public link
|
90
82
|
def link_info(url)
|
91
|
-
final_uri = Rest.new(base_url: url, redirect_max: MAX_AOC_URL_REDIRECT).
|
92
|
-
|
93
|
-
|
83
|
+
final_uri = Rest.new(base_url: url, redirect_max: MAX_AOC_URL_REDIRECT).call(operation: 'GET')[:http].uri
|
84
|
+
Log.log.trace1{Log.dump(:final_uri, final_uri)}
|
85
|
+
org_domain = split_org_domain(final_uri)
|
86
|
+
if (m = final_uri.path.match(%r{/oauth2/([^/]+)/login$}))
|
87
|
+
org_domain[:organization] = m[1] if org_domain[:organization].nil?
|
88
|
+
else
|
89
|
+
Log.log.debug{"path=#{final_uri.path} does not end with /login"}
|
90
|
+
end
|
91
|
+
raise 'AoC shall redirect to login page with a query' if final_uri.query.nil?
|
92
|
+
query = Rest.query_to_h(final_uri.query)
|
93
|
+
Log.log.trace1{Log.dump(:query, query)}
|
94
94
|
# is that a public link ?
|
95
|
-
if
|
95
|
+
if query.key?('token')
|
96
96
|
Log.log.warn{"Unknown pub link path: #{final_uri.path}"} unless PUBLIC_LINK_PATHS.include?(final_uri.path)
|
97
97
|
# ok we get it !
|
98
98
|
return {
|
99
|
-
instance_domain:
|
99
|
+
instance_domain: org_domain[:domain],
|
100
100
|
url: "https://#{final_uri.host}",
|
101
|
-
token:
|
101
|
+
token: query['token']
|
102
102
|
}
|
103
103
|
end
|
104
|
-
|
105
|
-
if decoded_query['state']
|
104
|
+
if query['state']
|
106
105
|
# can be a private link
|
107
|
-
state_uri = URI.parse(
|
108
|
-
if state_uri.query &&
|
109
|
-
decoded_state = Rest.
|
106
|
+
state_uri = URI.parse(query['state'])
|
107
|
+
if state_uri.query && query['redirect_uri']
|
108
|
+
decoded_state = Rest.query_to_h(state_uri.query)
|
110
109
|
if decoded_state.key?('short_link_url')
|
111
110
|
if (m = state_uri.path.match(%r{/files/workspaces/([0-9]+)/all/([0-9]+):([0-9]+)}))
|
112
|
-
redirect_uri = URI.parse(
|
113
|
-
|
111
|
+
redirect_uri = URI.parse(query['redirect_uri'])
|
112
|
+
org_domain = split_org_domain(redirect_uri)
|
114
113
|
return {
|
115
|
-
instance_domain:
|
116
|
-
organization:
|
114
|
+
instance_domain: org_domain[:domain],
|
115
|
+
organization: org_domain[:organization],
|
117
116
|
url: "https://#{redirect_uri.host}",
|
118
117
|
private_link: {
|
119
118
|
workspace_id: m[1],
|
@@ -125,10 +124,10 @@ module Aspera
|
|
125
124
|
end
|
126
125
|
end
|
127
126
|
end
|
128
|
-
|
127
|
+
Log.log.debug{Log.dump(:org_domain, org_domain)}
|
129
128
|
return {
|
130
|
-
instance_domain:
|
131
|
-
organization:
|
129
|
+
instance_domain: org_domain[:domain],
|
130
|
+
organization: org_domain[:organization]
|
132
131
|
}
|
133
132
|
end
|
134
133
|
end
|
@@ -149,7 +148,8 @@ module Aspera
|
|
149
148
|
@workspace_name = workspace
|
150
149
|
@cache_user_info = nil
|
151
150
|
@cache_url_token_info = nil
|
152
|
-
@
|
151
|
+
@workspace_info = nil
|
152
|
+
@home_info = nil
|
153
153
|
auth_params = {
|
154
154
|
type: :oauth2,
|
155
155
|
client_id: client_id,
|
@@ -206,7 +206,7 @@ module Aspera
|
|
206
206
|
return nil unless auth_params[:grant_method].eql?(:url_json)
|
207
207
|
return @cache_url_token_info unless @cache_url_token_info.nil?
|
208
208
|
# TODO: can there be several in list ?
|
209
|
-
@cache_url_token_info = read('url_tokens')
|
209
|
+
@cache_url_token_info = read('url_tokens').first
|
210
210
|
return @cache_url_token_info
|
211
211
|
end
|
212
212
|
|
@@ -225,7 +225,7 @@ module Aspera
|
|
225
225
|
# get our user's default information
|
226
226
|
@cache_user_info =
|
227
227
|
begin
|
228
|
-
read('self')
|
228
|
+
read('self')
|
229
229
|
rescue StandardError => e
|
230
230
|
raise e if exception
|
231
231
|
Log.log.debug{"ignoring error: #{e}"}
|
@@ -235,11 +235,20 @@ module Aspera
|
|
235
235
|
return @cache_user_info
|
236
236
|
end
|
237
237
|
|
238
|
-
|
238
|
+
def workspace
|
239
|
+
raise 'internal error: AoC workspace context is not set' if @workspace_info.nil?
|
240
|
+
@workspace_info
|
241
|
+
end
|
242
|
+
|
243
|
+
def home
|
244
|
+
raise 'internal error: AoC home context is not set' if @home_info.nil?
|
245
|
+
@home_info
|
246
|
+
end
|
247
|
+
|
248
|
+
# Set the application context
|
249
|
+
# @param application [Symbol,NilClass] :files or :packages
|
239
250
|
# @return [Hash] current context information: workspace, and home node/file if app is "Files"
|
240
|
-
def context(application
|
241
|
-
return @context_cache unless @context_cache.nil?
|
242
|
-
Aspera.assert(!application.nil?){'application must be set once'}
|
251
|
+
def context=(application)
|
243
252
|
Aspera.assert_values(application, %i[files packages])
|
244
253
|
ws_id =
|
245
254
|
if !public_link.nil?
|
@@ -249,9 +258,10 @@ module Aspera
|
|
249
258
|
Log.log.debug('Using workspace of private link')
|
250
259
|
private_link[:workspace_id]
|
251
260
|
elsif @workspace_name.eql?(DEFAULT_WORKSPACE)
|
252
|
-
|
253
|
-
|
254
|
-
|
261
|
+
if !current_user_info['default_workspace_id'].nil?
|
262
|
+
Log.log.debug('Using default workspace'.green)
|
263
|
+
current_user_info['default_workspace_id']
|
264
|
+
end
|
255
265
|
elsif @workspace_name.nil?
|
256
266
|
nil
|
257
267
|
else
|
@@ -261,39 +271,49 @@ module Aspera
|
|
261
271
|
if ws_id.nil?
|
262
272
|
nil
|
263
273
|
else
|
264
|
-
read("workspaces/#{ws_id}")
|
274
|
+
read("workspaces/#{ws_id}")
|
265
275
|
end
|
266
|
-
@
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
276
|
+
@workspace_info =
|
277
|
+
if ws_info.nil?
|
278
|
+
{
|
279
|
+
id: nil,
|
280
|
+
name: 'Shared folders'
|
281
|
+
}
|
282
|
+
else
|
283
|
+
{
|
284
|
+
id: ws_info['id'],
|
285
|
+
name: ws_info['name']
|
286
|
+
}
|
287
|
+
end
|
288
|
+
Log.log.debug{Log.dump(:context, @workspace_info)}
|
289
|
+
return nil unless application.eql?(:files)
|
290
|
+
@home_info =
|
291
|
+
if !public_link.nil?
|
292
|
+
assert_public_link_types(['view_shared_file'])
|
293
|
+
{
|
294
|
+
node_id: public_link['data']['node_id'],
|
295
|
+
file_id: public_link['data']['file_id']
|
296
|
+
}
|
297
|
+
elsif !private_link.nil?
|
298
|
+
{
|
299
|
+
node_id: private_link[:node_id],
|
300
|
+
file_id: private_link[:file_id]
|
301
|
+
}
|
302
|
+
elsif ws_info
|
303
|
+
{
|
304
|
+
node_id: ws_info['home_node_id'],
|
305
|
+
file_id: ws_info['home_file_id']
|
306
|
+
}
|
307
|
+
else
|
308
|
+
# not part of any workspace, but has some folder shared
|
309
|
+
user_info = current_user_info(exception: true) rescue {'read_only_home_node_id' => nil, 'read_only_home_file_id' => nil}
|
310
|
+
{
|
311
|
+
node_id: user_info['read_only_home_node_id'],
|
312
|
+
file_id: user_info['read_only_home_file_id']
|
313
|
+
}
|
314
|
+
end
|
315
|
+
raise "Cannot get user's home node id, check your default workspace or specify one" if @home_info[:node_id].to_s.empty?
|
316
|
+
Log.log.debug{Log.dump(:context, @home_info)}
|
297
317
|
end
|
298
318
|
|
299
319
|
# @param node_id [String] identifier of node in AoC
|
@@ -304,9 +324,9 @@ module Aspera
|
|
304
324
|
# @returns [Node] a node API for access key
|
305
325
|
def node_api_from(node_id:, workspace_id: nil, workspace_name: nil, scope: Node::SCOPE_USER, package_info: nil)
|
306
326
|
Aspera.assert_type(node_id, String)
|
307
|
-
node_info = read("nodes/#{node_id}")
|
327
|
+
node_info = read("nodes/#{node_id}")
|
308
328
|
if workspace_name.nil? && !workspace_id.nil?
|
309
|
-
workspace_name = read("workspaces/#{workspace_id}")[
|
329
|
+
workspace_name = read("workspaces/#{workspace_id}")['name']
|
310
330
|
end
|
311
331
|
app_info = {
|
312
332
|
api: self, # for callback
|
@@ -346,7 +366,7 @@ module Aspera
|
|
346
366
|
pkg_data['recipients'].first.is_a?(Hash) &&
|
347
367
|
pkg_data['recipients'].first.key?('type') &&
|
348
368
|
pkg_data['recipients'].first['type'].eql?('dropbox')
|
349
|
-
meta_schema = read("dropboxes/#{pkg_data['recipients'].first['id']}")[
|
369
|
+
meta_schema = read("dropboxes/#{pkg_data['recipients'].first['id']}")['metadata_schema']
|
350
370
|
if meta_schema.nil? || meta_schema.empty?
|
351
371
|
Log.log.debug('no metadata in shared inbox')
|
352
372
|
return
|
@@ -390,7 +410,7 @@ module Aspera
|
|
390
410
|
# email: user, else dropbox
|
391
411
|
entity_type = short_recipient_info.include?('@') ? 'contacts' : 'dropboxes'
|
392
412
|
begin
|
393
|
-
full_recipient_info = lookup_by_name(entity_type, short_recipient_info, {'current_workspace_id' => ws_id})
|
413
|
+
full_recipient_info = lookup_by_name(entity_type, short_recipient_info, query: {'current_workspace_id' => ws_id})
|
394
414
|
rescue RuntimeError => e
|
395
415
|
raise e unless e.message.start_with?(ENTITY_NOT_FOUND)
|
396
416
|
# dropboxes cannot be created on the fly
|
@@ -399,7 +419,7 @@ module Aspera
|
|
399
419
|
full_recipient_info = create('contacts', {
|
400
420
|
'current_workspace_id' => ws_id,
|
401
421
|
'email' => short_recipient_info
|
402
|
-
}.merge(new_user_option))
|
422
|
+
}.merge(new_user_option))
|
403
423
|
end
|
404
424
|
short_recipient_info = if entity_type.eql?('dropboxes')
|
405
425
|
{'id' => full_recipient_info['id'], 'type' => 'dropbox'}
|
@@ -453,7 +473,7 @@ module Aspera
|
|
453
473
|
validate_metadata(package_data) if validate_meta
|
454
474
|
|
455
475
|
# create a new package container
|
456
|
-
created_package = create('packages', package_data)
|
476
|
+
created_package = create('packages', package_data)
|
457
477
|
|
458
478
|
package_node_api = node_api_from(
|
459
479
|
node_id: created_package['node_id'],
|
@@ -463,7 +483,7 @@ module Aspera
|
|
463
483
|
# tell AoC what to expect in package: 1 transfer (can also be done after transfer)
|
464
484
|
# TODO: if multi session was used we should probably tell
|
465
485
|
# also, currently no "multi-source" , i.e. only from client-side files, unless "node" agent is used
|
466
|
-
update("packages/#{created_package['id']}", {'sent' => true, 'transfers_expected' => 1})
|
486
|
+
update("packages/#{created_package['id']}", {'sent' => true, 'transfers_expected' => 1})
|
467
487
|
|
468
488
|
return {
|
469
489
|
spec: package_node_api.transfer_spec_gen4(created_package['contents_file_id'], Transfer::Spec::DIRECTION_SEND),
|
@@ -524,14 +544,14 @@ module Aspera
|
|
524
544
|
ID_AK_ADMIN = 'ASPERA_ACCESS_KEY_ADMIN'
|
525
545
|
# Callback from Plugins::Node
|
526
546
|
# add application specific tags to permissions creation
|
527
|
-
# @param
|
547
|
+
# @param perm_data [Hash] parameters for creating permissions
|
528
548
|
# @param app_info [Hash] application information
|
529
|
-
def permissions_set_create_params(
|
549
|
+
def permissions_set_create_params(perm_data:, app_info:)
|
530
550
|
# workspace shared folder:
|
531
551
|
# access_id = "#{ID_AK_ADMIN}_WS_#{app_info[:workspace_id]}"
|
532
|
-
|
552
|
+
defaults = {
|
533
553
|
# 'access_type' => 'user', # mandatory: user or group
|
534
|
-
# 'access_id' => access_id, # id of user or group
|
554
|
+
# 'access_id' => access_id, # id of user or group or special
|
535
555
|
'tags' => {
|
536
556
|
Transfer::Spec::TAG_RESERVED => {
|
537
557
|
'files' => {
|
@@ -543,6 +563,7 @@ module Aspera
|
|
543
563
|
'shared_by_name' => current_user_info['name'],
|
544
564
|
'shared_by_email' => current_user_info['email'],
|
545
565
|
# 'shared_with_name' => access_id,
|
566
|
+
# 'share_as' => new_name_for_folder,
|
546
567
|
'access_key' => app_info[:node_info]['access_key'],
|
547
568
|
'node' => app_info[:node_info]['name']
|
548
569
|
}
|
@@ -550,34 +571,42 @@ module Aspera
|
|
550
571
|
}
|
551
572
|
}
|
552
573
|
}
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
574
|
+
perm_data.deep_merge!(defaults)
|
575
|
+
tag_workspace = perm_data['tags'][Transfer::Spec::TAG_RESERVED]['files']['workspace']
|
576
|
+
case perm_data['with']
|
577
|
+
when NilClass
|
578
|
+
when ''
|
579
|
+
perm_data['access_type'] = 'user'
|
580
|
+
perm_data['access_id'] = "#{ID_AK_ADMIN}_WS_#{app_info[:workspace_id]}"
|
581
|
+
tag_workspace['shared_with_name'] = perm_data['access_id']
|
582
|
+
else
|
583
|
+
entity_info = lookup_by_name('contacts', perm_data['with'], query: {'current_workspace_id' => app_info[:workspace_id]})
|
584
|
+
perm_data['access_type'] = entity_info['source_type']
|
585
|
+
perm_data['access_id'] = entity_info['source_id']
|
586
|
+
tag_workspace['shared_with_name'] = entity_info['email']
|
587
|
+
end
|
588
|
+
perm_data.delete('with')
|
589
|
+
if perm_data.key?('as')
|
590
|
+
tag_workspace['share_as'] = perm_data['as']
|
591
|
+
perm_data.delete('as')
|
563
592
|
end
|
564
593
|
# optional
|
565
|
-
app_info[:opt_link_name] =
|
594
|
+
app_info[:opt_link_name] = perm_data.delete('link_name')
|
566
595
|
end
|
567
596
|
|
568
597
|
# Callback from Plugins::Node
|
569
598
|
# send shared folder event to AoC
|
570
|
-
# @param
|
599
|
+
# @param event_data [Hash] response from permission creation
|
571
600
|
# @param app_info [Hash] hash with app info
|
572
601
|
# @param types [Array] event types
|
573
|
-
def permissions_send_event(
|
602
|
+
def permissions_send_event(event_data:, app_info:, types: PERMISSIONS_CREATED)
|
574
603
|
Aspera.assert_type(types, Array)
|
575
604
|
Aspera.assert(!types.empty?)
|
576
605
|
event_creation = {
|
577
606
|
'types' => types,
|
578
607
|
'node_id' => app_info[:node_info]['id'],
|
579
608
|
'workspace_id' => app_info[:workspace_id],
|
580
|
-
'data' =>
|
609
|
+
'data' => event_data
|
581
610
|
}
|
582
611
|
# (optional). The name of the folder to be displayed to the destination user.
|
583
612
|
# Use it if its value is different from the "share_as" field.
|
data/lib/aspera/api/ats.rb
CHANGED
data/lib/aspera/api/cos_node.rb
CHANGED
@@ -19,7 +19,7 @@ module Aspera
|
|
19
19
|
Aspera.assert(service_credentials.key?(field)){"service_credentials must have a field: #{field}"}
|
20
20
|
end
|
21
21
|
# read endpoints from service provided in service credentials
|
22
|
-
endpoints = Aspera::Rest.new(base_url: service_credentials['endpoints']).read('')
|
22
|
+
endpoints = Aspera::Rest.new(base_url: service_credentials['endpoints']).read('')
|
23
23
|
Aspera::Log.dump('endpoints', endpoints)
|
24
24
|
endpoint = endpoints.dig('service-endpoints', 'regional', bucket_region, 'public', bucket_region)
|
25
25
|
raise "no such region: #{bucket_region}" if endpoint.nil?
|
data/lib/aspera/api/httpgw.rb
CHANGED
@@ -138,7 +138,7 @@ module Aspera
|
|
138
138
|
def upload(transfer_spec)
|
139
139
|
# identify this session uniquely
|
140
140
|
session_id = SecureRandom.uuid
|
141
|
-
@notify_cb&.call(
|
141
|
+
@notify_cb&.call(:pre_start, session_id: nil, info: 'starting')
|
142
142
|
# process files to send, modify `paths` in transfer_spec
|
143
143
|
files_to_send = process_upload_list(transfer_spec)
|
144
144
|
# total size of all files is last element
|
@@ -147,7 +147,7 @@ module Aspera
|
|
147
147
|
Log.log.trace1{Log.dump(:files_to_send, files_to_send)}
|
148
148
|
# TODO: check that this is available in endpoints: @api_info['endpoints']
|
149
149
|
upload_url = File.join(@gw_root_url, @upload_version, 'upload')
|
150
|
-
@notify_cb&.call(
|
150
|
+
@notify_cb&.call(:pre_start, session_id: nil, info: 'connecting wss')
|
151
151
|
# open web socket to end point (equivalent to Net::HTTP.start)
|
152
152
|
http_session = Rest.start_http_session(upload_url)
|
153
153
|
# get the underlying socket i/o
|
@@ -172,11 +172,11 @@ module Aspera
|
|
172
172
|
}
|
173
173
|
# start read thread after handshake
|
174
174
|
@ws_read_thread = Thread.new {process_read_thread}
|
175
|
-
@notify_cb&.call(
|
176
|
-
@notify_cb&.call(
|
175
|
+
@notify_cb&.call(:session_start, session_id: session_id)
|
176
|
+
@notify_cb&.call(:session_size, session_id: session_id, info: total_bytes_to_transfer)
|
177
177
|
sleep(1)
|
178
178
|
# notify progress bar
|
179
|
-
@notify_cb&.call(
|
179
|
+
@notify_cb&.call(:session_size, session_id: session_id, info: total_bytes_to_transfer)
|
180
180
|
# first step send transfer spec
|
181
181
|
ws_snd_json(MSG_SEND_TRANSFER_SPEC, transfer_spec)
|
182
182
|
# current file index
|
@@ -223,7 +223,7 @@ module Aspera
|
|
223
223
|
raise e
|
224
224
|
end
|
225
225
|
session_sent_bytes += slice_bin_data.length
|
226
|
-
@notify_cb&.call(
|
226
|
+
@notify_cb&.call(:transfer, session_id: session_id, info: session_sent_bytes)
|
227
227
|
slice_info[:slice] += 1
|
228
228
|
end
|
229
229
|
ensure
|
@@ -232,8 +232,8 @@ module Aspera
|
|
232
232
|
file_index += 1
|
233
233
|
end
|
234
234
|
# throttling may have skipped last one
|
235
|
-
@notify_cb&.call(
|
236
|
-
@notify_cb&.call(
|
235
|
+
@notify_cb&.call(:transfer, session_id: session_id, info: session_sent_bytes)
|
236
|
+
@notify_cb&.call(:end, session_id: session_id)
|
237
237
|
ws_send(ws_type: :close, data: nil)
|
238
238
|
Log.log.debug("Finished upload, waiting for end of #{THR_RECV} thread.")
|
239
239
|
@ws_read_thread.join
|
@@ -256,7 +256,7 @@ module Aspera
|
|
256
256
|
end
|
257
257
|
transfer_spec['download_name'] = download_name
|
258
258
|
end
|
259
|
-
creation = create('download', {'transfer_spec' => transfer_spec})
|
259
|
+
creation = create('download', {'transfer_spec' => transfer_spec})
|
260
260
|
transfer_uuid = creation['url'].split('/').last
|
261
261
|
file_name =
|
262
262
|
if transfer_spec['zip_required'] || transfer_spec['paths'].length > 1
|
@@ -274,6 +274,11 @@ module Aspera
|
|
274
274
|
return @api_info
|
275
275
|
end
|
276
276
|
|
277
|
+
# @return the base url of the gateway
|
278
|
+
def base_url
|
279
|
+
return @gw_root_url
|
280
|
+
end
|
281
|
+
|
277
282
|
# @param url [String] URL of the HTTP Gateway, without version
|
278
283
|
def initialize(
|
279
284
|
url:,
|
@@ -299,7 +304,7 @@ module Aspera
|
|
299
304
|
@synchronous = synchronous
|
300
305
|
@notify_cb = notify_cb
|
301
306
|
# get API info
|
302
|
-
@api_info = read('info')
|
307
|
+
@api_info = read('info').freeze
|
303
308
|
Log.log.debug{Log.dump(:api_info, @api_info)}
|
304
309
|
# web socket endpoint: by default use v2 (newer gateways), without base64 encoding
|
305
310
|
# is the latest supported? else revert to old api
|