aspera-cli 4.27.3 → 4.27.5
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 +118 -0
- data/CONTRIBUTING.md +5 -2
- data/bin/ascli +1 -0
- data/docs/README.md +224 -42
- data/lib/aspera/agent/base.rb +7 -2
- data/lib/aspera/agent/connect.rb +0 -4
- data/lib/aspera/agent/desktop.rb +0 -4
- data/lib/aspera/agent/direct.rb +49 -21
- data/lib/aspera/agent/node.rb +6 -5
- data/lib/aspera/agent/transferd.rb +2 -2
- data/lib/aspera/api/faspex.rb +2 -0
- data/lib/aspera/api/httpgw.rb +1 -2
- data/lib/aspera/api/node.rb +3 -3
- data/lib/aspera/ascp/installation.rb +1 -1
- data/lib/aspera/cli/async_transfer_store.rb +10 -9
- data/lib/aspera/cli/bootstrapper.rb +3 -1
- data/lib/aspera/cli/command_registry.rb +69 -7
- data/lib/aspera/cli/command_spec.rb +1 -1
- data/lib/aspera/cli/extended_value.rb +4 -3
- data/lib/aspera/cli/formatter.rb +10 -8
- data/lib/aspera/cli/http.rb +8 -20
- data/lib/aspera/cli/option_types.rb +3 -1
- data/lib/aspera/cli/option_value.rb +16 -19
- data/lib/aspera/cli/options.schema.yaml +86 -10
- data/lib/aspera/cli/parser.rb +30 -18
- data/lib/aspera/cli/plugins/aoc.rb +133 -156
- data/lib/aspera/cli/plugins/ats.rb +1 -7
- data/lib/aspera/cli/plugins/base.rb +40 -34
- data/lib/aspera/cli/plugins/config.rb +24 -11
- data/lib/aspera/cli/plugins/console.rb +1 -1
- data/lib/aspera/cli/plugins/faspex5.rb +30 -11
- data/lib/aspera/cli/plugins/faspio.rb +1 -1
- data/lib/aspera/cli/plugins/node.rb +26 -19
- data/lib/aspera/cli/plugins/orchestrator.rb +73 -44
- data/lib/aspera/cli/plugins/preview.rb +21 -19
- data/lib/aspera/cli/plugins/server.rb +3 -4
- data/lib/aspera/cli/plugins/shares.rb +21 -24
- data/lib/aspera/cli/preset_actions.rb +28 -18
- data/lib/aspera/cli/preset_manager.rb +34 -19
- data/lib/aspera/cli/prompt.rb +2 -1
- data/lib/aspera/cli/result.rb +33 -22
- data/lib/aspera/cli/runner.rb +1 -5
- data/lib/aspera/cli/sync_actions.rb +17 -16
- data/lib/aspera/cli/transfer_actions.rb +14 -3
- data/lib/aspera/cli/transfer_agent.rb +6 -4
- data/lib/aspera/cli/transfer_progress.rb +290 -55
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/cli/wizard.rb +1 -1
- data/lib/aspera/coverage.rb +0 -1
- data/lib/aspera/environment.rb +29 -5
- data/lib/aspera/keychain/encrypted_hash.rb +1 -1
- data/lib/aspera/keychain/factory.rb +2 -1
- data/lib/aspera/log.rb +25 -2
- data/lib/aspera/node_emulator.rb +759 -0
- data/lib/aspera/oauth/base.rb +2 -1
- data/lib/aspera/oauth/factory.rb +6 -3
- data/lib/aspera/oauth/json_credentials.rb +34 -0
- data/lib/aspera/oauth/jwt.rb +3 -4
- data/lib/aspera/oauth.rb +1 -0
- data/lib/aspera/persistency_folder.rb +1 -3
- data/lib/aspera/preview/generator.rb +4 -1
- data/lib/aspera/preview/options.schema.yaml +119 -0
- data/lib/aspera/rest/aspera_errors.rb +12 -0
- data/lib/aspera/rest/client.rb +28 -19
- data/lib/aspera/rest/list.rb +14 -8
- data/lib/aspera/rest/parameters.rb +2 -2
- data/lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml +0 -20
- data/lib/aspera/schema/IBM Aspera Orchestrator API-v1.yaml +1784 -0
- data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +1230 -137
- data/lib/aspera/schema/IBM_Aspera_Shares.yaml +14 -13
- data/lib/aspera/schema/reader.rb +12 -18
- data/lib/aspera/schema/registry.rb +6 -1
- data.tar.gz.sig +0 -0
- metadata +5 -3
- metadata.gz.sig +0 -0
- data/lib/aspera/node_simulator.rb +0 -345
- data/lib/aspera/preview/options.rb +0 -45
|
@@ -2930,21 +2930,25 @@ components:
|
|
|
2930
2930
|
name:
|
|
2931
2931
|
type: string
|
|
2932
2932
|
minLength: 1
|
|
2933
|
-
description:
|
|
2934
|
-
type: string
|
|
2935
2933
|
node_id:
|
|
2936
2934
|
type: integer
|
|
2937
|
-
|
|
2935
|
+
directory:
|
|
2938
2936
|
type: string
|
|
2937
|
+
description: Path of share folder on node
|
|
2938
|
+
create_directory:
|
|
2939
|
+
type: boolean
|
|
2940
|
+
description: Create the share folder on node
|
|
2939
2941
|
ShareUpdate:
|
|
2940
2942
|
type: object
|
|
2941
2943
|
properties:
|
|
2942
2944
|
name:
|
|
2943
2945
|
type: string
|
|
2944
|
-
|
|
2945
|
-
type:
|
|
2946
|
-
|
|
2946
|
+
node_id:
|
|
2947
|
+
type: integer
|
|
2948
|
+
description: Admin only
|
|
2949
|
+
directory:
|
|
2947
2950
|
type: string
|
|
2951
|
+
description: Path of share folder on node (admin only)
|
|
2948
2952
|
# Node Schemas
|
|
2949
2953
|
Node:
|
|
2950
2954
|
type: object
|
|
@@ -3206,9 +3210,10 @@ components:
|
|
|
3206
3210
|
name:
|
|
3207
3211
|
type: string
|
|
3208
3212
|
example: engineers
|
|
3209
|
-
|
|
3210
|
-
type:
|
|
3211
|
-
|
|
3213
|
+
group_id:
|
|
3214
|
+
type: integer
|
|
3215
|
+
format: int32
|
|
3216
|
+
description: Identifier in groups from all sources
|
|
3212
3217
|
created_at:
|
|
3213
3218
|
type: string
|
|
3214
3219
|
format: date-time
|
|
@@ -3224,16 +3229,12 @@ components:
|
|
|
3224
3229
|
name:
|
|
3225
3230
|
type: string
|
|
3226
3231
|
example: engineers
|
|
3227
|
-
description:
|
|
3228
|
-
type: string
|
|
3229
3232
|
LocalGroupUpdate:
|
|
3230
3233
|
type: object
|
|
3231
3234
|
properties:
|
|
3232
3235
|
name:
|
|
3233
3236
|
type: string
|
|
3234
3237
|
example: engineers
|
|
3235
|
-
description:
|
|
3236
|
-
type: string
|
|
3237
3238
|
LdapConfig:
|
|
3238
3239
|
type: object
|
|
3239
3240
|
properties:
|
data/lib/aspera/schema/reader.rb
CHANGED
|
@@ -116,15 +116,12 @@ module Aspera
|
|
|
116
116
|
# Yield current property to block
|
|
117
117
|
yield(property_schema, name, property_full_name)
|
|
118
118
|
|
|
119
|
-
# Recursively process nested structures
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if
|
|
125
|
-
array_item_schema = property_schema.dig('items')
|
|
126
|
-
array_item_schema.each_property("#{property_full_name}[].", on_variant: on_variant, &block) if array_item_schema.current['properties']
|
|
127
|
-
end
|
|
119
|
+
# Recursively process nested structures (`type` is a list for a nullable value, e.g. `[array, 'null']`)
|
|
120
|
+
types = Array(node['type'])
|
|
121
|
+
property_schema.each_property("#{property_full_name}.", on_variant: on_variant, &block) if types.include?('object') && node['properties']
|
|
122
|
+
if types.include?('array') && node['items']
|
|
123
|
+
array_item_schema = property_schema.dig('items')
|
|
124
|
+
array_item_schema.each_property("#{property_full_name}[].", on_variant: on_variant, &block) if array_item_schema.current['properties']
|
|
128
125
|
end
|
|
129
126
|
# allOf without explicit type: object — recurse to merge all branches
|
|
130
127
|
property_schema.each_property("#{property_full_name}.", on_variant: on_variant, &block) if node['allOf']
|
|
@@ -180,15 +177,12 @@ module Aspera
|
|
|
180
177
|
row['default'] = node['default'] if node.key?('default')
|
|
181
178
|
row['enum'] = node['enum'] if node.key?('enum')
|
|
182
179
|
rows << row
|
|
183
|
-
# Recurse into nested object or array-of-objects
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if
|
|
189
|
-
item_reader = prop_reader.dig('items')
|
|
190
|
-
collect_rows(rows, item_reader, "#{full_name}[].") if item_reader.current['properties']
|
|
191
|
-
end
|
|
180
|
+
# Recurse into nested object or array-of-objects (`type` is a list for a nullable value)
|
|
181
|
+
types = Array(node['type'])
|
|
182
|
+
collect_rows(rows, prop_reader, "#{full_name}.") if types.include?('object') && node['properties']
|
|
183
|
+
if types.include?('array') && node['items']
|
|
184
|
+
item_reader = prop_reader.dig('items')
|
|
185
|
+
collect_rows(rows, item_reader, "#{full_name}[].") if item_reader.current['properties']
|
|
192
186
|
end
|
|
193
187
|
collect_rows(rows, prop_reader, "#{full_name}.") if node['allOf']
|
|
194
188
|
end
|
|
@@ -58,6 +58,7 @@ module Aspera
|
|
|
58
58
|
args: 'aspera/sync/args.schema.yaml',
|
|
59
59
|
conf: 'aspera/sync/conf.schema.yaml',
|
|
60
60
|
opts: 'aspera/cli/options.schema.yaml',
|
|
61
|
+
preview: 'aspera/preview/options.schema.yaml',
|
|
61
62
|
aoc: 'aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml',
|
|
62
63
|
automation: 'aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml',
|
|
63
64
|
faspex: 'aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml',
|
|
@@ -65,27 +66,31 @@ module Aspera
|
|
|
65
66
|
console: 'aspera/schema/IBM Aspera Console-enhanced.yaml',
|
|
66
67
|
node: 'aspera/schema/IBM Aspera Node API-4.4.6.yaml',
|
|
67
68
|
shares: 'aspera/schema/IBM_Aspera_Shares.yaml',
|
|
69
|
+
orchestrator: 'aspera/schema/IBM Aspera Orchestrator API-v1.yaml',
|
|
68
70
|
async_tables: 'aspera/schema/async_tables.yaml'
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
# Schemas owned by ascli: values are validated against them (vendor API schemas are validated by the API)
|
|
72
|
-
OWNED = %i[spec args conf opts async_tables].freeze
|
|
74
|
+
OWNED = %i[spec args conf opts preview async_tables].freeze
|
|
73
75
|
|
|
74
76
|
OPTIONS = 'opts'
|
|
75
77
|
TRANSFER_SPEC = 'spec'
|
|
76
78
|
SYNC_CONF = 'conf'
|
|
77
79
|
SYNC_ARGS = 'args'
|
|
80
|
+
PREVIEW_OPTIONS = 'preview'
|
|
78
81
|
AOC = 'aoc'
|
|
79
82
|
AUTOMATION = 'automation'
|
|
80
83
|
FASPEX = 'faspex'
|
|
81
84
|
FASPIO = 'faspio'
|
|
82
85
|
CONSOLE = 'console'
|
|
83
86
|
NODE = 'node'
|
|
87
|
+
ORCHESTRATOR = 'orchestrator'
|
|
84
88
|
SHARES = 'shares+/api/v1'
|
|
85
89
|
ASYNC_TABLES = 'async_tables'
|
|
86
90
|
LOG_OPTIONS = "#{OPTIONS}:components.schemas.LogOptions"
|
|
87
91
|
DIRECT_AGENT_OPTIONS = "#{OPTIONS}:components.schemas.DirectAgentOptions"
|
|
88
92
|
NODE_AGENT_OPTIONS = "#{OPTIONS}:components.schemas.NodeAgentOptions"
|
|
93
|
+
NODE_EMULATOR_OPTIONS = "#{OPTIONS}:components.schemas.NodeEmulatorOptions"
|
|
89
94
|
HTTPGW_AGENT_OPTIONS = "#{OPTIONS}:components.schemas.HttpgwAgentOptions"
|
|
90
95
|
TRANSFERD_AGENT_OPTIONS = "#{OPTIONS}:components.schemas.TransferdAgentOptions"
|
|
91
96
|
TRANSFER_AGENT_OPTIONS = "#{OPTIONS}:components.schemas.TransferAgentOptions"
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aspera-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.27.
|
|
4
|
+
version: 4.27.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Laurent Martin
|
|
@@ -452,12 +452,13 @@ files:
|
|
|
452
452
|
- lib/aspera/markdown.rb
|
|
453
453
|
- lib/aspera/mime.rb
|
|
454
454
|
- lib/aspera/nagios.rb
|
|
455
|
-
- lib/aspera/
|
|
455
|
+
- lib/aspera/node_emulator.rb
|
|
456
456
|
- lib/aspera/oauth.rb
|
|
457
457
|
- lib/aspera/oauth/base.rb
|
|
458
458
|
- lib/aspera/oauth/boot.rb
|
|
459
459
|
- lib/aspera/oauth/factory.rb
|
|
460
460
|
- lib/aspera/oauth/generic.rb
|
|
461
|
+
- lib/aspera/oauth/json_credentials.rb
|
|
461
462
|
- lib/aspera/oauth/jwt.rb
|
|
462
463
|
- lib/aspera/oauth/url_json.rb
|
|
463
464
|
- lib/aspera/oauth/web.rb
|
|
@@ -466,7 +467,7 @@ files:
|
|
|
466
467
|
- lib/aspera/preview/file_types.rb
|
|
467
468
|
- lib/aspera/preview/generator.rb
|
|
468
469
|
- lib/aspera/preview/image_error.png
|
|
469
|
-
- lib/aspera/preview/options.
|
|
470
|
+
- lib/aspera/preview/options.schema.yaml
|
|
470
471
|
- lib/aspera/preview/terminal.rb
|
|
471
472
|
- lib/aspera/preview/utils.rb
|
|
472
473
|
- lib/aspera/preview/video_error.png
|
|
@@ -488,6 +489,7 @@ files:
|
|
|
488
489
|
- lib/aspera/schema/IBM Aspera Console-enhanced.yaml
|
|
489
490
|
- lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml
|
|
490
491
|
- lib/aspera/schema/IBM Aspera Node API-4.4.6.yaml
|
|
492
|
+
- lib/aspera/schema/IBM Aspera Orchestrator API-v1.yaml
|
|
491
493
|
- lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0.yaml
|
|
492
494
|
- lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml
|
|
493
495
|
- lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml
|
metadata.gz.sig
CHANGED
|
Binary file
|
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'aspera/assert'
|
|
4
|
-
require 'aspera/mime'
|
|
5
|
-
require 'aspera/ascp/installation'
|
|
6
|
-
require 'aspera/agent/direct'
|
|
7
|
-
require 'aspera/log'
|
|
8
|
-
require 'webrick'
|
|
9
|
-
require 'json'
|
|
10
|
-
|
|
11
|
-
module Aspera
|
|
12
|
-
class NodeSimulator
|
|
13
|
-
def initialize
|
|
14
|
-
@agent = Agent::Direct.new(management_cb: ->(event) { process_event(event) })
|
|
15
|
-
@sessions = {}
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def start(ts)
|
|
19
|
-
@agent.start_transfer(ts)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def all_sessions
|
|
23
|
-
@agent.sessions.map { |session| session[:job_id] }.uniq.each.map { |job_id| job_to_transfer(job_id) }
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
# status: ('waiting', 'partially_completed', 'unknown', 'waiting(read error)',] 'running', 'completed', 'failed'
|
|
27
|
-
def job_to_transfer(job_id)
|
|
28
|
-
jobs = @agent.sessions_by_job(job_id)
|
|
29
|
-
ts = nil
|
|
30
|
-
sessions = jobs.map do |j|
|
|
31
|
-
ts ||= j[:ts]
|
|
32
|
-
{
|
|
33
|
-
id: j[:id],
|
|
34
|
-
client_node_id: '',
|
|
35
|
-
server_node_id: '2bbdcc39-f789-4d47-8163-6767fc14f421',
|
|
36
|
-
client_ip_address: '192.168.0.100',
|
|
37
|
-
server_ip_address: '5.10.114.4',
|
|
38
|
-
status: 'running',
|
|
39
|
-
retry_timeout: 3600,
|
|
40
|
-
retry_count: 0,
|
|
41
|
-
start_time_usec: 1701094040000000,
|
|
42
|
-
end_time_usec: nil,
|
|
43
|
-
elapsed_usec: 405312,
|
|
44
|
-
bytes_transferred: 26,
|
|
45
|
-
bytes_written: 26,
|
|
46
|
-
bytes_lost: 0,
|
|
47
|
-
files_completed: 1,
|
|
48
|
-
directories_completed: 0,
|
|
49
|
-
target_rate_kbps: 500000,
|
|
50
|
-
min_rate_kbps: 0,
|
|
51
|
-
calc_rate_kbps: 9900,
|
|
52
|
-
network_delay_usec: 40000,
|
|
53
|
-
avg_rate_kbps: 0.51,
|
|
54
|
-
error_code: 0,
|
|
55
|
-
error_desc: '',
|
|
56
|
-
source_statistics: {
|
|
57
|
-
args_scan_attempted: 1,
|
|
58
|
-
args_scan_completed: 1,
|
|
59
|
-
paths_scan_attempted: 1,
|
|
60
|
-
paths_scan_failed: 0,
|
|
61
|
-
paths_scan_skipped: 0,
|
|
62
|
-
paths_scan_excluded: 0,
|
|
63
|
-
dirs_scan_completed: 0,
|
|
64
|
-
files_scan_completed: 1,
|
|
65
|
-
dirs_xfer_attempted: 0,
|
|
66
|
-
dirs_xfer_fail: 0,
|
|
67
|
-
files_xfer_attempted: 1,
|
|
68
|
-
files_xfer_fail: 0,
|
|
69
|
-
files_xfer_noxfer: 0
|
|
70
|
-
},
|
|
71
|
-
precalc: {
|
|
72
|
-
enabled: true,
|
|
73
|
-
status: 'ready',
|
|
74
|
-
bytes_expected: 0,
|
|
75
|
-
directories_expected: 0,
|
|
76
|
-
files_expected: 0,
|
|
77
|
-
files_excluded: 0,
|
|
78
|
-
files_special: 0,
|
|
79
|
-
files_failed: 1
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
end
|
|
83
|
-
ts ||= {}
|
|
84
|
-
result = {
|
|
85
|
-
id: job_id,
|
|
86
|
-
status: 'running',
|
|
87
|
-
start_spec: ts,
|
|
88
|
-
sessions: sessions,
|
|
89
|
-
bytes_transferred: 26,
|
|
90
|
-
bytes_written: 26,
|
|
91
|
-
bytes_lost: 0,
|
|
92
|
-
avg_rate_kbps: 0.51,
|
|
93
|
-
files_completed: 1,
|
|
94
|
-
files_skipped: 0,
|
|
95
|
-
directories_completed: 0,
|
|
96
|
-
start_time_usec: 1701094040000000,
|
|
97
|
-
end_time_usec: 1701094040405312,
|
|
98
|
-
elapsed_usec: 405312,
|
|
99
|
-
error_code: 0,
|
|
100
|
-
error_desc: '',
|
|
101
|
-
precalc: {
|
|
102
|
-
status: 'ready',
|
|
103
|
-
bytes_expected: 0,
|
|
104
|
-
files_expected: 0,
|
|
105
|
-
directories_expected: 0,
|
|
106
|
-
files_special: 0,
|
|
107
|
-
files_failed: 1
|
|
108
|
-
},
|
|
109
|
-
files: [{
|
|
110
|
-
id: 'd1b5c112-82b75425-860745fc-93851671-64541bdd',
|
|
111
|
-
path: '/workspaces/45071/packages/bYA_ilq73g.asp-package/contents/data_file.bin',
|
|
112
|
-
start_time_usec: 1701094040000000,
|
|
113
|
-
elapsed_usec: 105616,
|
|
114
|
-
end_time_usec: 1701094040001355,
|
|
115
|
-
status: 'completed',
|
|
116
|
-
error_code: 0,
|
|
117
|
-
error_desc: '',
|
|
118
|
-
size: 26,
|
|
119
|
-
type: 'file',
|
|
120
|
-
checksum_type: 'none',
|
|
121
|
-
checksum: nil,
|
|
122
|
-
start_byte: 0,
|
|
123
|
-
bytes_written: 26,
|
|
124
|
-
session_id: 'bafc72b8-366c-4501-8095-47208183d6b8'
|
|
125
|
-
}]
|
|
126
|
-
}
|
|
127
|
-
Log.dump(:job, result, level: :trace2)
|
|
128
|
-
return result
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
# Process event from management port
|
|
132
|
-
def process_event(event)
|
|
133
|
-
# Code duplicated on purpose, as implementation goes, blocks will be replaced
|
|
134
|
-
case event['Type']
|
|
135
|
-
when 'NOP' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
136
|
-
# rubocop:disable Lint/DuplicateBranch
|
|
137
|
-
when 'START' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
138
|
-
when 'QUERY' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
139
|
-
when 'QUERYRSP' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
140
|
-
when 'STATS' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
141
|
-
when 'STOP' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
142
|
-
when 'ERROR' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
143
|
-
when 'CANCEL' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
144
|
-
when 'DONE' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
145
|
-
when 'RATE' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
146
|
-
when 'FILEERROR' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
147
|
-
when 'SESSION' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
148
|
-
when 'NOTIFICATION' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
149
|
-
when 'INIT' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
150
|
-
when 'VLINK' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
151
|
-
when 'PUT' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
152
|
-
when 'WRITE' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
153
|
-
when 'CLOSE' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
154
|
-
when 'SKIP' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
155
|
-
when 'ARGSTOP' then Aspera.Log.debug { "event not managed: #{event['Type']}" }
|
|
156
|
-
# rubocop:enable Lint/DuplicateBranch
|
|
157
|
-
else Aspera.error_unreachable_line
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
# this class answers the Faspex /send API and creates a package on Aspera on Cloud
|
|
163
|
-
# a new instance is created for each request
|
|
164
|
-
class NodeSimulatorServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
165
|
-
PATH_TRANSFERS = '/ops/transfers'
|
|
166
|
-
PATH_ONE_TRANSFER = %r{/ops/transfers/(.+)$}
|
|
167
|
-
PATH_BROWSE = '/files/browse'
|
|
168
|
-
# @param credentials [Hash]
|
|
169
|
-
# @param simulator [NodeSimulator]
|
|
170
|
-
def initialize(server, credentials, simulator)
|
|
171
|
-
super(server)
|
|
172
|
-
@credentials = credentials
|
|
173
|
-
@simulator = simulator
|
|
174
|
-
# Resolve once at startup; default to current working directory
|
|
175
|
-
@browse_root = File.realpath(credentials[:browse_root] || Dir.pwd)
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
require 'json'
|
|
179
|
-
require 'time'
|
|
180
|
-
|
|
181
|
-
def folder_to_structure(folder_path)
|
|
182
|
-
# Resolve and confine to browse_root (prevents path traversal via client-supplied path)
|
|
183
|
-
resolved = File.realpath(folder_path)
|
|
184
|
-
Aspera.assert(resolved.start_with?("#{@browse_root}/") || resolved.eql?(@browse_root)) { 'Browse path traversal attempt detected' }
|
|
185
|
-
Aspera.assert(Dir.exist?(resolved)) { "Path does not exist or is not a directory: #{resolved}" }
|
|
186
|
-
folder_path = resolved
|
|
187
|
-
|
|
188
|
-
# Build self structure
|
|
189
|
-
folder_stat = File.stat(folder_path)
|
|
190
|
-
structure = {
|
|
191
|
-
'self' => {
|
|
192
|
-
'path' => folder_path,
|
|
193
|
-
'basename' => File.basename(folder_path),
|
|
194
|
-
'type' => 'directory',
|
|
195
|
-
'size' => folder_stat.size,
|
|
196
|
-
'mtime' => folder_stat.mtime.utc.iso8601,
|
|
197
|
-
'permissions' => [
|
|
198
|
-
{'name' => 'view'},
|
|
199
|
-
{'name' => 'edit'},
|
|
200
|
-
{'name' => 'delete'}
|
|
201
|
-
]
|
|
202
|
-
},
|
|
203
|
-
'items' => []
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
# Iterate over folder contents
|
|
207
|
-
Dir.foreach(folder_path) do |entry|
|
|
208
|
-
next if entry == '.' || entry == '..' # Skip current and parent directory
|
|
209
|
-
|
|
210
|
-
item_path = File.join(folder_path, entry)
|
|
211
|
-
item_type = File.ftype(item_path) rescue 'unknown' # Get the type of file
|
|
212
|
-
item_stat = File.lstat(item_path) # Use lstat to handle symbolic links correctly
|
|
213
|
-
|
|
214
|
-
item = {
|
|
215
|
-
'path' => item_path,
|
|
216
|
-
'basename' => entry,
|
|
217
|
-
'type' => item_type,
|
|
218
|
-
'size' => item_stat.size,
|
|
219
|
-
'mtime' => item_stat.mtime.utc.iso8601,
|
|
220
|
-
'permissions' => [
|
|
221
|
-
{'name' => 'view'},
|
|
222
|
-
{'name' => 'edit'},
|
|
223
|
-
{'name' => 'delete'}
|
|
224
|
-
]
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
# Add additional details for specific types
|
|
228
|
-
case item_type
|
|
229
|
-
when 'file'
|
|
230
|
-
item['partial_file'] = false
|
|
231
|
-
when 'link'
|
|
232
|
-
item['target'] = File.readlink(item_path) rescue nil # Add the target of the symlink
|
|
233
|
-
when 'unknown'
|
|
234
|
-
item['note'] = 'File type could not be determined'
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
structure['items'] << item
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
structure
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
def do_POST(request, response)
|
|
244
|
-
case request.path
|
|
245
|
-
when PATH_TRANSFERS
|
|
246
|
-
job_id = @simulator.start(JSON.parse(request.body))
|
|
247
|
-
sleep(0.5)
|
|
248
|
-
set_json_response(request, response, @simulator.job_to_transfer(job_id))
|
|
249
|
-
when PATH_BROWSE
|
|
250
|
-
req = JSON.parse(request.body)
|
|
251
|
-
# req['count']
|
|
252
|
-
set_json_response(request, response, folder_to_structure(req['path'] || @browse_root))
|
|
253
|
-
else
|
|
254
|
-
set_json_response(request, response, [{error: 'Bad request'}], code: 400)
|
|
255
|
-
end
|
|
256
|
-
end
|
|
257
|
-
|
|
258
|
-
def do_GET(request, response)
|
|
259
|
-
case request.path
|
|
260
|
-
when '/info'
|
|
261
|
-
info = Ascp::Installation.instance.ascp_info
|
|
262
|
-
set_json_response(request, response, {
|
|
263
|
-
application: 'node',
|
|
264
|
-
current_time: Time.now.utc.iso8601(0),
|
|
265
|
-
version: info['sdk_ascp_version'].gsub(/ .*$/, ''),
|
|
266
|
-
license_expiration_date: info['expiration_date'],
|
|
267
|
-
license_max_rate: info['maximum_bandwidth'],
|
|
268
|
-
os: %x(uname -srv).chomp,
|
|
269
|
-
aej_status: 'disconnected',
|
|
270
|
-
async_reporting: 'no',
|
|
271
|
-
transfer_activity_reporting: 'no',
|
|
272
|
-
transfer_user: 'xfer',
|
|
273
|
-
docroot: 'file:////data/aoc/eudemo-sedemo',
|
|
274
|
-
node_id: '2bbdcc39-f789-4d47-8163-6767fc14f421',
|
|
275
|
-
cluster_id: '6dae2844-d1a9-47a5-916d-9b3eac3ea466',
|
|
276
|
-
acls: ['impersonation'],
|
|
277
|
-
access_key_configuration_capabilities: {
|
|
278
|
-
transfer: %w[
|
|
279
|
-
cipher
|
|
280
|
-
policy
|
|
281
|
-
target_rate_cap_kbps
|
|
282
|
-
target_rate_kbps
|
|
283
|
-
preserve_timestamps
|
|
284
|
-
content_protection_secret
|
|
285
|
-
aggressiveness
|
|
286
|
-
token_encryption_key
|
|
287
|
-
byok_enabled
|
|
288
|
-
bandwidth_flow_network_rc_module
|
|
289
|
-
file_checksum_type
|
|
290
|
-
],
|
|
291
|
-
server: %w[
|
|
292
|
-
activity_event_logging
|
|
293
|
-
activity_file_event_logging
|
|
294
|
-
recursive_counts
|
|
295
|
-
aej_logging
|
|
296
|
-
wss_enabled
|
|
297
|
-
activity_transfer_ignore_skipped_files
|
|
298
|
-
activity_files_max
|
|
299
|
-
access_key_credentials_encryption_type
|
|
300
|
-
discovery
|
|
301
|
-
auto_delete
|
|
302
|
-
allow
|
|
303
|
-
deny
|
|
304
|
-
]
|
|
305
|
-
},
|
|
306
|
-
capabilities: [
|
|
307
|
-
{name: 'sync', value: true},
|
|
308
|
-
{name: 'watchfolder', value: true},
|
|
309
|
-
{name: 'symbolic_links', value: true},
|
|
310
|
-
{name: 'move_file', value: true},
|
|
311
|
-
{name: 'move_directory', value: true},
|
|
312
|
-
{name: 'filelock', value: false},
|
|
313
|
-
{name: 'ssh_fingerprint', value: false},
|
|
314
|
-
{name: 'aej_version', value: '1.0'},
|
|
315
|
-
{name: 'page', value: true},
|
|
316
|
-
{name: 'file_id_version', value: '2.0'},
|
|
317
|
-
{name: 'auto_delete', value: false}
|
|
318
|
-
],
|
|
319
|
-
settings: [
|
|
320
|
-
{name: 'content_protection_required', value: false},
|
|
321
|
-
{name: 'content_protection_strong_pass_required', value: false},
|
|
322
|
-
{name: 'filelock_restriction', value: 'none'},
|
|
323
|
-
{name: 'ssh_fingerprint', value: nil},
|
|
324
|
-
{name: 'wss_enabled', value: false},
|
|
325
|
-
{name: 'wss_port', value: 443}
|
|
326
|
-
]
|
|
327
|
-
})
|
|
328
|
-
when PATH_TRANSFERS
|
|
329
|
-
set_json_response(request, response, @simulator.all_sessions)
|
|
330
|
-
when PATH_ONE_TRANSFER
|
|
331
|
-
job_id = request.path.match(PATH_ONE_TRANSFER)[1]
|
|
332
|
-
set_json_response(request, response, @simulator.job_to_transfer(job_id))
|
|
333
|
-
else
|
|
334
|
-
set_json_response(request, response, [{error: 'Unknown request'}], code: 400)
|
|
335
|
-
end
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
def set_json_response(request, response, json, code: 200)
|
|
339
|
-
response.status = code
|
|
340
|
-
response['Content-Type'] = Mime::JSON
|
|
341
|
-
response.body = json.to_json
|
|
342
|
-
Log.log.trace1 { Log.obj_dump("response for #{request.request_method} #{request.path}", json) }
|
|
343
|
-
end
|
|
344
|
-
end
|
|
345
|
-
end
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# cspell:ignore reencode conv transframes pauseframes
|
|
4
|
-
|
|
5
|
-
module Aspera
|
|
6
|
-
module Preview
|
|
7
|
-
# generator options. Used as parameter to preview generator object.
|
|
8
|
-
# also settable by command line.
|
|
9
|
-
class Options
|
|
10
|
-
# types of generation for video files
|
|
11
|
-
VIDEO_CONVERSION_METHODS = %i[reencode blend clips].freeze
|
|
12
|
-
VIDEO_THUMBNAIL_METHODS = %i[fixed animated].freeze
|
|
13
|
-
# @type [Array<Symbol>] methods for office document conversion
|
|
14
|
-
OFFICE_CONVERSION_METHODS = %i[soffice unoconv].freeze
|
|
15
|
-
# Options used in generator
|
|
16
|
-
# For scaling see: https://trac.ffmpeg.org/wiki/Scaling
|
|
17
|
-
# iw/ih : input width or height
|
|
18
|
-
# -x : keep aspect ratio, having value a multiple of x
|
|
19
|
-
DESCRIPTIONS = [
|
|
20
|
-
{name: :office_conversion, default: :soffice, description: 'office: method for office document conversion', values: OFFICE_CONVERSION_METHODS},
|
|
21
|
-
{name: :max_size, default: 1 << 24, description: 'maximum size (in bytes) of preview file'},
|
|
22
|
-
{name: :thumb_vid_scale, default: '-1:min(ih,100)', description: 'png: video: size (ffmpeg scale argument)'},
|
|
23
|
-
{name: :thumb_vid_fraction, default: 0.1, description: 'png: video: time percent position of snapshot'},
|
|
24
|
-
{name: :thumb_img_size, default: 800, description: 'png: non-video: height (and width)'},
|
|
25
|
-
{name: :thumb_text_font, default: 'Courier', description: 'png: plaintext: font for text rendering: `magick identify -list font`'},
|
|
26
|
-
{name: :video_conversion, default: :reencode, description: 'mp4: method for preview generation', values: VIDEO_CONVERSION_METHODS},
|
|
27
|
-
{name: :video_png_conv, default: :fixed, description: 'mp4: method for thumbnail generation', values: VIDEO_THUMBNAIL_METHODS},
|
|
28
|
-
{name: :video_scale, default: 'min(iw,360):-2', description: 'mp4: all: video scale (ffmpeg scale argument)'},
|
|
29
|
-
{name: :video_start_sec, default: 10, description: 'mp4: all: start offset (seconds) of video preview'},
|
|
30
|
-
{name: :video_codec, default: nil, description: 'mp4: reencode: video codec for ffmpeg (e.g. libx264, h264_videotoolbox, h264_nvenc), default: auto-detect'},
|
|
31
|
-
{name: :reencode_ffmpeg, default: {}, description: 'mp4: reencode: options to ffmpeg, keys: `in`, `out`'},
|
|
32
|
-
{name: :blend_keyframes, default: 30, description: 'mp4: blend: # key frames'},
|
|
33
|
-
{name: :blend_pauseframes, default: 3, description: 'mp4: blend: # pause frames'},
|
|
34
|
-
{name: :blend_transframes, default: 5, description: 'mp4: blend: # transition blend frames'},
|
|
35
|
-
{name: :blend_fps, default: 15, description: 'mp4: blend: frame per second'},
|
|
36
|
-
{name: :clips_count, default: 5, description: 'mp4: clips: number of clips'},
|
|
37
|
-
{name: :clips_length, default: 5, description: 'mp4: clips: length in seconds of each clips'}
|
|
38
|
-
].freeze
|
|
39
|
-
# add accessors
|
|
40
|
-
DESCRIPTIONS.each do |opt|
|
|
41
|
-
attr_accessor opt[:name]
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|