aspera-cli 4.25.1 → 4.25.3
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 +456 -405
- data/CONTRIBUTING.md +22 -18
- data/README.md +33 -9741
- data/bin/asession +111 -88
- data/lib/aspera/agent/connect.rb +1 -1
- data/lib/aspera/agent/desktop.rb +1 -1
- data/lib/aspera/agent/direct.rb +19 -18
- data/lib/aspera/agent/node.rb +1 -1
- data/lib/aspera/api/aoc.rb +44 -20
- data/lib/aspera/api/faspex.rb +25 -6
- data/lib/aspera/api/node.rb +20 -16
- data/lib/aspera/ascp/installation.rb +32 -51
- data/lib/aspera/assert.rb +2 -2
- data/lib/aspera/cli/extended_value.rb +1 -0
- data/lib/aspera/cli/formatter.rb +0 -4
- data/lib/aspera/cli/hints.rb +18 -4
- data/lib/aspera/cli/main.rb +3 -6
- data/lib/aspera/cli/manager.rb +46 -30
- data/lib/aspera/cli/plugins/aoc.rb +155 -131
- data/lib/aspera/cli/plugins/base.rb +15 -18
- data/lib/aspera/cli/plugins/config.rb +50 -87
- data/lib/aspera/cli/plugins/factory.rb +2 -2
- data/lib/aspera/cli/plugins/faspex.rb +4 -4
- data/lib/aspera/cli/plugins/faspex5.rb +74 -76
- data/lib/aspera/cli/plugins/node.rb +3 -5
- data/lib/aspera/cli/plugins/oauth.rb +26 -25
- data/lib/aspera/cli/plugins/preview.rb +9 -14
- data/lib/aspera/cli/plugins/shares.rb +15 -7
- data/lib/aspera/cli/transfer_agent.rb +2 -2
- data/lib/aspera/cli/version.rb +1 -1
- data/lib/aspera/colors.rb +7 -0
- data/lib/aspera/environment.rb +30 -16
- data/lib/aspera/faspex_gw.rb +6 -6
- data/lib/aspera/faspex_postproc.rb +20 -14
- data/lib/aspera/hash_ext.rb +8 -0
- data/lib/aspera/log.rb +15 -15
- data/lib/aspera/markdown.rb +22 -0
- data/lib/aspera/node_simulator.rb +1 -1
- data/lib/aspera/oauth/base.rb +2 -2
- data/lib/aspera/oauth/url_json.rb +2 -2
- data/lib/aspera/oauth/web.rb +1 -1
- data/lib/aspera/preview/generator.rb +9 -9
- data/lib/aspera/rest.rb +44 -37
- data/lib/aspera/rest_call_error.rb +16 -8
- data/lib/aspera/rest_error_analyzer.rb +38 -36
- data/lib/aspera/rest_errors_aspera.rb +19 -18
- data/lib/aspera/transfer/resumer.rb +2 -2
- data/lib/aspera/yaml.rb +49 -0
- data.tar.gz.sig +0 -0
- metadata +17 -3
- metadata.gz.sig +0 -0
- data/release_notes.md +0 -8
|
@@ -90,8 +90,8 @@ module Aspera
|
|
|
90
90
|
Aspera::Preview::Options::DESCRIPTIONS.each do |opt|
|
|
91
91
|
values = if opt.key?(:values)
|
|
92
92
|
opt[:values]
|
|
93
|
-
elsif
|
|
94
|
-
|
|
93
|
+
elsif BoolValue.symbol?(opt[:default])
|
|
94
|
+
BoolValue::TYPES
|
|
95
95
|
end
|
|
96
96
|
options.declare(opt[:name], opt[:description].capitalize, allowed: values, handler: {o: @gen_options, m: opt[:name]}, default: opt[:default])
|
|
97
97
|
end
|
|
@@ -106,17 +106,12 @@ module Aspera
|
|
|
106
106
|
Log.log.debug{"tmpdir: #{@tmp_folder}"}
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
-
# /files/id/files is normally cached in
|
|
109
|
+
# /files/id/files is normally cached in Redis, but we can discard the cache
|
|
110
110
|
# but /files/id is not cached
|
|
111
111
|
def get_folder_entries(file_id, request_args = nil)
|
|
112
|
-
headers = {'Accept' =>
|
|
112
|
+
headers = {'Accept' => Mime::JSON}
|
|
113
113
|
headers['X-Aspera-Cache-Control'] = 'no-cache' if @option_folder_reset_cache.eql?(:header)
|
|
114
|
-
return @api_node.
|
|
115
|
-
operation: 'GET',
|
|
116
|
-
subpath: "files/#{file_id}/files",
|
|
117
|
-
headers: headers,
|
|
118
|
-
query: request_args
|
|
119
|
-
)
|
|
114
|
+
return @api_node.read("files/#{file_id}/files", request_args, headers: headers)
|
|
120
115
|
end
|
|
121
116
|
|
|
122
117
|
# old version based on folders
|
|
@@ -153,7 +148,7 @@ module Aspera
|
|
|
153
148
|
end
|
|
154
149
|
# log/persist periodically or last one
|
|
155
150
|
next unless @periodic.trigger? || event.equal?(events.last)
|
|
156
|
-
Log.log.
|
|
151
|
+
Log.log.debug{"Processed event #{event['id']}"}
|
|
157
152
|
# save checkpoint to avoid losing processing in case of error
|
|
158
153
|
if !iteration_persistency.nil?
|
|
159
154
|
iteration_persistency.data[0] = event['id'].to_s
|
|
@@ -186,7 +181,7 @@ module Aspera
|
|
|
186
181
|
end
|
|
187
182
|
# log/persist periodically or last one
|
|
188
183
|
next unless @periodic.trigger? || event.equal?(events.last)
|
|
189
|
-
Log.log.
|
|
184
|
+
Log.log.debug{"Processing event #{event['id']}"}
|
|
190
185
|
# save checkpoint to avoid losing processing in case of error
|
|
191
186
|
if !iteration_persistency.nil?
|
|
192
187
|
iteration_persistency.data[0] = event['id'].to_s
|
|
@@ -303,7 +298,7 @@ module Aspera
|
|
|
303
298
|
# download original file to temp folder
|
|
304
299
|
do_transfer(Transfer::Spec::DIRECTION_RECEIVE, entry['parent_file_id'], entry['name'], @tmp_folder)
|
|
305
300
|
end
|
|
306
|
-
Log.log.
|
|
301
|
+
Log.log.debug{"source: #{entry['id']}: #{entry['path']}"}
|
|
307
302
|
gen_infos.each do |gen_info|
|
|
308
303
|
gen_info[:generator].generate rescue nil
|
|
309
304
|
end
|
|
@@ -335,7 +330,7 @@ module Aspera
|
|
|
335
330
|
entry = entries_to_process.shift
|
|
336
331
|
# process this entry only if it is within the top_path
|
|
337
332
|
entry_path_with_slash = entry['path']
|
|
338
|
-
Log.log.
|
|
333
|
+
Log.log.debug{"processing entry #{entry_path_with_slash}"} if @periodic.trigger?
|
|
339
334
|
entry_path_with_slash = "#{entry_path_with_slash}/" unless entry_path_with_slash.end_with?('/')
|
|
340
335
|
if !top_path.nil? && !top_path.start_with?(entry_path_with_slash) && !entry_path_with_slash.start_with?(top_path)
|
|
341
336
|
Log.log.debug{"#{entry['path']} folder (skip start)".bg_red}
|
|
@@ -17,20 +17,21 @@ module Aspera
|
|
|
17
17
|
# @return [Hash] with version, ping, api
|
|
18
18
|
def health_check(url)
|
|
19
19
|
result = {}
|
|
20
|
+
# Get version from main page
|
|
20
21
|
result[:version] =
|
|
21
22
|
begin
|
|
22
23
|
version = nil
|
|
23
24
|
login_page = Rest
|
|
24
25
|
.new(base_url: url, redirect_max: 2)
|
|
25
26
|
.read('', headers: {'Accept'=>'text/html'})
|
|
27
|
+
raise 'not Shares' unless login_page.include?('aspera-Shares')
|
|
26
28
|
if (m = login_page.match(/\(v([0-9a-f\.]+)\)/))
|
|
27
29
|
version = m[1]
|
|
28
30
|
if (m = login_page.match(/Patch level ([0-9]+)/))
|
|
29
|
-
version = "#{
|
|
31
|
+
version = "#{version} #{m[0]}"
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
|
-
|
|
33
|
-
version
|
|
34
|
+
version.nil? ? 'no version' : version
|
|
34
35
|
rescue => e
|
|
35
36
|
e
|
|
36
37
|
end
|
|
@@ -45,10 +46,15 @@ module Aspera
|
|
|
45
46
|
end
|
|
46
47
|
result[:api] =
|
|
47
48
|
begin
|
|
48
|
-
resp = Rest
|
|
49
|
+
data, resp = Rest
|
|
50
|
+
.new(base_url: "#{url}/#{NODE_API_PATH}", redirect_max: 1)
|
|
51
|
+
.read('info', exception: false, ret: :both)
|
|
49
52
|
# shall fail: shares requires auth, but we check error message
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
if resp.code.to_s.eql?('401') && data&.dig('error', 'user_message')&.include?('authentication failed')
|
|
54
|
+
'available'
|
|
55
|
+
else
|
|
56
|
+
raise "not found (#{resp.code})"
|
|
57
|
+
end
|
|
52
58
|
rescue => e
|
|
53
59
|
e
|
|
54
60
|
end
|
|
@@ -88,7 +94,7 @@ module Aspera
|
|
|
88
94
|
SAML_IMPORT_MANDATORY = %w[id name_id].freeze
|
|
89
95
|
SAML_IMPORT_ALLOWED = %w[email given_name surname].concat(SAML_IMPORT_MANDATORY).freeze
|
|
90
96
|
|
|
91
|
-
ACTIONS = %i[health files admin].freeze
|
|
97
|
+
ACTIONS = %i[health info files admin].freeze
|
|
92
98
|
# common to users and groups
|
|
93
99
|
USR_GRP_SETTINGS = %i[transfer_settings app_authorizations share_permissions].freeze
|
|
94
100
|
|
|
@@ -111,6 +117,8 @@ module Aspera
|
|
|
111
117
|
nagios.add_critical('API', health[:api].to_s)
|
|
112
118
|
end
|
|
113
119
|
Main.result_object_list(nagios.status_list)
|
|
120
|
+
when :info
|
|
121
|
+
return Main.result_single_object(basic_auth_api(NODE_API_PATH).read('info', headers: {'Content-Type'=>'application/json'}))
|
|
114
122
|
when :files
|
|
115
123
|
api_shares_node = basic_auth_api(NODE_API_PATH)
|
|
116
124
|
repo_command = options.get_next_command(Node::COMMANDS_SHARES)
|
|
@@ -33,8 +33,8 @@ module Aspera
|
|
|
33
33
|
:DEFAULT_TRANSFER_NOTIFY_TEMPLATE
|
|
34
34
|
|
|
35
35
|
class << self
|
|
36
|
-
# @return :success
|
|
37
|
-
#
|
|
36
|
+
# @return [:success] if all sessions statuses returned by "start" are success
|
|
37
|
+
# @return [Exception] if one sessions statuses returned by "start" is failed
|
|
38
38
|
def session_status(statuses)
|
|
39
39
|
error_statuses = statuses.reject{ |i| i.eql?(:success)}
|
|
40
40
|
return :success if error_statuses.empty?
|
data/lib/aspera/cli/version.rb
CHANGED
data/lib/aspera/colors.rb
CHANGED
|
@@ -58,6 +58,13 @@ class String
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
# Applies the provided list of string decoration (colors).
|
|
62
|
+
# @param colors [Array<Symbol>] List of decorations.
|
|
63
|
+
# @return [String] Enhanced String.
|
|
64
|
+
def apply(*colors)
|
|
65
|
+
colors.reduce(self){ |s, c| s.public_send(c)}
|
|
66
|
+
end
|
|
67
|
+
|
|
61
68
|
# Transform capitalized to snake case
|
|
62
69
|
def capital_to_snake
|
|
63
70
|
return gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
data/lib/aspera/environment.rb
CHANGED
|
@@ -58,8 +58,8 @@ module Aspera
|
|
|
58
58
|
# @param code [String] Ruby code to execute
|
|
59
59
|
# @param file [String] File name for error reporting
|
|
60
60
|
# @param line [Integer] Line number for error reporting
|
|
61
|
-
def secure_eval(code, file, line)
|
|
62
|
-
Kernel.send('lave'.reverse, code, empty_binding, file, line)
|
|
61
|
+
def secure_eval(code, file, line, user_binding = nil)
|
|
62
|
+
Kernel.send('lave'.reverse, code, user_binding || empty_binding, file, line)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
# Build argv for Process.spawn / Kernel.system (no shell)
|
|
@@ -74,26 +74,40 @@ module Aspera
|
|
|
74
74
|
argv
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
#
|
|
88
|
-
#
|
|
77
|
+
# like `Shellwords.shellescape`, but does not escape `=`
|
|
78
|
+
def shell_escape_pretty(str)
|
|
79
|
+
# Safe unquoted characters + '=' explicitly allowed
|
|
80
|
+
return str if str.match?(%r{\A[A-Za-z0-9_.,:/@+=-]+\z})
|
|
81
|
+
# return str if Shellwords.shellescape(str) == str
|
|
82
|
+
|
|
83
|
+
# Otherwise use single quotes
|
|
84
|
+
"'#{str.gsub("'", %q('\'\''))}'"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Execute a process securely without shell.
|
|
88
|
+
#
|
|
89
|
+
# Execution `mode` can be:
|
|
90
|
+
# - :execute -> Kernel.system, return nil
|
|
91
|
+
# - :background -> Process.spawn, return pid
|
|
92
|
+
# - :capture -> Open3.capture3, return stdout
|
|
93
|
+
#
|
|
94
|
+
# @param cmd [Array<String>] Executable and arguments (mapped "to_s")
|
|
95
|
+
# @param mode [:execute,:background,:capture] Execution mode
|
|
96
|
+
# @param kwargs [Hash] Additional arguments to underlying method
|
|
97
|
+
# @option kwargs [Hash] :env Environment variables
|
|
98
|
+
# @option kwargs [Boolean] :exception for :capture mode, raise error if process fails
|
|
99
|
+
# @option kwargs [Boolean] :close_others for :background mode
|
|
100
|
+
# @return [nil] for :execute mode
|
|
101
|
+
# @return [Integer] pid for :background mode
|
|
102
|
+
# @return [String] stdout for :capture mode
|
|
89
103
|
def secure_execute(*cmd, mode: :execute, **kwargs)
|
|
90
104
|
cmd = cmd.map(&:to_s)
|
|
91
105
|
Aspera.assert(cmd.size.positive?, type: ArgumentError){'executable must be present'}
|
|
92
106
|
Aspera.assert_values(mode, PROCESS_MODES, type: ArgumentError){'mode'}
|
|
93
107
|
Log.log.debug do
|
|
94
108
|
parts = [mode.to_s, 'command:']
|
|
95
|
-
kwargs[:env]&.each{ |k, v| parts << "#{k}=#{
|
|
96
|
-
cmd.each{ |a| parts <<
|
|
109
|
+
kwargs[:env]&.each{ |k, v| parts << "#{k}=#{shell_escape_pretty(v.to_s)}"}
|
|
110
|
+
cmd.each{ |a| parts << shell_escape_pretty(a)}
|
|
97
111
|
parts.join(' ')
|
|
98
112
|
end
|
|
99
113
|
case mode
|
data/lib/aspera/faspex_gw.rb
CHANGED
|
@@ -52,9 +52,9 @@ module Aspera
|
|
|
52
52
|
operation: 'POST',
|
|
53
53
|
subpath: "packages/#{package['id']}/transfer_spec/upload",
|
|
54
54
|
query: {transfer_type: Api::Faspex::TRANSFER_CONNECT},
|
|
55
|
-
content_type:
|
|
55
|
+
content_type: Mime::JSON,
|
|
56
56
|
body: {paths: [{'destination'=>'/'}]},
|
|
57
|
-
headers: {'Accept' =>
|
|
57
|
+
headers: {'Accept' => Mime::JSON}
|
|
58
58
|
)
|
|
59
59
|
transfer_spec.delete('authentication')
|
|
60
60
|
# but we place it in a Faspex package creation response
|
|
@@ -80,20 +80,20 @@ module Aspera
|
|
|
80
80
|
faspex4_send_to_faspex5(faspex_pkg_parameters)
|
|
81
81
|
else Aspera.error_unexpected_value(@app_api.class.name)
|
|
82
82
|
end
|
|
83
|
-
Log.log.
|
|
83
|
+
Log.log.debug{"faspex_package_create_result=#{faspex_package_create_result}"}
|
|
84
84
|
response.status = 200
|
|
85
|
-
response.content_type =
|
|
85
|
+
response.content_type = Mime::JSON
|
|
86
86
|
response.body = JSON.generate(faspex_package_create_result)
|
|
87
87
|
rescue => e
|
|
88
88
|
response.status = 500
|
|
89
|
-
response['Content-Type'] =
|
|
89
|
+
response['Content-Type'] = Mime::JSON
|
|
90
90
|
response.body = {error: e.message, stacktrace: e.backtrace}.to_json
|
|
91
91
|
Log.log.error(e.message)
|
|
92
92
|
Log.log.debug{e.backtrace.join("\n")}
|
|
93
93
|
end
|
|
94
94
|
else
|
|
95
95
|
response.status = 400
|
|
96
|
-
response['Content-Type'] =
|
|
96
|
+
response['Content-Type'] = Mime::JSON
|
|
97
97
|
response.body = {error: 'Unsupported endpoint'}.to_json
|
|
98
98
|
end
|
|
99
99
|
end
|
|
@@ -27,17 +27,18 @@ module Aspera
|
|
|
27
27
|
# :reek:UncommunicativeMethodName
|
|
28
28
|
def do_POST(request, response)
|
|
29
29
|
Log.log.debug{"request=#{request.path}"}
|
|
30
|
+
Log.log.debug{"query=#{request.query}"}
|
|
30
31
|
begin
|
|
31
|
-
#
|
|
32
|
+
# Only accept requests on the root
|
|
32
33
|
if !request.path.start_with?(@parameters[:root])
|
|
33
34
|
response.status = 400
|
|
34
|
-
response['Content-Type'] =
|
|
35
|
+
response['Content-Type'] = Mime::JSON
|
|
35
36
|
response.body = {status: 'error', message: 'Request outside domain'}.to_json
|
|
36
37
|
return
|
|
37
38
|
end
|
|
38
39
|
if request.body.nil?
|
|
39
40
|
response.status = 400
|
|
40
|
-
response['Content-Type'] =
|
|
41
|
+
response['Content-Type'] = Mime::JSON
|
|
41
42
|
response.body = {status: 'error', message: 'Empty request'}.to_json
|
|
42
43
|
return
|
|
43
44
|
end
|
|
@@ -48,18 +49,23 @@ module Aspera
|
|
|
48
49
|
Log.log.debug{"script=#{script_path}"}
|
|
49
50
|
webhook_parameters = JSON.parse(request.body)
|
|
50
51
|
Log.dump(:webhook_parameters, webhook_parameters)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
post_proc_pid =
|
|
52
|
+
if request.query.key?('lambda')
|
|
53
|
+
# Code can throw exception, source code must return a lambda
|
|
54
|
+
Environment.secure_eval(File.read(script_path), __FILE__, __LINE__).call(webhook_parameters)
|
|
55
|
+
else
|
|
56
|
+
# env expects only strings
|
|
57
|
+
environment = webhook_parameters.each_with_object({}){ |(k, v), h| h[k] = v.to_s}
|
|
58
|
+
post_proc_pid = Environment.secure_execute(script_path, mode: :background, env: environment)
|
|
59
|
+
Timeout.timeout(@parameters[:timeout_seconds]) do
|
|
60
|
+
# "wait" for process to avoid zombie
|
|
61
|
+
Process.wait(post_proc_pid)
|
|
62
|
+
post_proc_pid = nil
|
|
63
|
+
end
|
|
64
|
+
process_status = $CHILD_STATUS
|
|
65
|
+
raise "script #{script_path} failed with code #{process_status.exitstatus}" if !process_status.success? && @parameters[:fail_on_error]
|
|
58
66
|
end
|
|
59
|
-
process_status = $CHILD_STATUS
|
|
60
|
-
raise "script #{script_path} failed with code #{process_status.exitstatus}" if !process_status.success? && @parameters[:fail_on_error]
|
|
61
67
|
response.status = 200
|
|
62
|
-
response.content_type =
|
|
68
|
+
response.content_type = Mime::JSON
|
|
63
69
|
response.body = JSON.generate({status: 'success', script: script_path, exit_code: process_status.exitstatus})
|
|
64
70
|
Log.log.debug{'Script executed successfully'}
|
|
65
71
|
rescue => e
|
|
@@ -70,7 +76,7 @@ module Aspera
|
|
|
70
76
|
Log.log.error("Killed process: #{post_proc_pid}")
|
|
71
77
|
end
|
|
72
78
|
response.status = 500
|
|
73
|
-
response['Content-Type'] =
|
|
79
|
+
response['Content-Type'] = Mime::JSON
|
|
74
80
|
response.body = {status: 'error', script: script_path, message: e.message}.to_json
|
|
75
81
|
end
|
|
76
82
|
end
|
data/lib/aspera/hash_ext.rb
CHANGED
|
@@ -26,6 +26,10 @@ unless Hash.method_defined?(:symbolize_keys)
|
|
|
26
26
|
def symbolize_keys
|
|
27
27
|
return transform_keys(&:to_sym)
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
def symbolize_keys!
|
|
31
|
+
return transform_keys!(&:to_sym)
|
|
32
|
+
end
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
|
|
@@ -35,5 +39,9 @@ unless Hash.method_defined?(:stringify_keys)
|
|
|
35
39
|
def stringify_keys
|
|
36
40
|
return transform_keys(&:to_s)
|
|
37
41
|
end
|
|
42
|
+
|
|
43
|
+
def stringify_keys!
|
|
44
|
+
return transform_keys!(&:to_s)
|
|
45
|
+
end
|
|
38
46
|
end
|
|
39
47
|
end
|
data/lib/aspera/log.rb
CHANGED
|
@@ -65,11 +65,8 @@ module Aspera
|
|
|
65
65
|
|
|
66
66
|
# Class methods
|
|
67
67
|
class << self
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
# @param colors [Array(Symbol)] List of decorations
|
|
71
|
-
def apply_colors(value, colors)
|
|
72
|
-
colors.inject(value){ |s, c| s.send(c)}
|
|
68
|
+
def short_levl(level)
|
|
69
|
+
"#{level[0, 3]}#{level[-1]}"
|
|
73
70
|
end
|
|
74
71
|
|
|
75
72
|
# Get the logger object of singleton
|
|
@@ -154,8 +151,8 @@ module Aspera
|
|
|
154
151
|
|
|
155
152
|
def formatter=(formatter)
|
|
156
153
|
if formatter.is_a?(String)
|
|
157
|
-
raise Error, "Unknown formatter #{formatter}, use one of: #{FORMATTERS.
|
|
158
|
-
formatter =
|
|
154
|
+
raise Error, "Unknown formatter #{formatter}, use one of: #{FORMATTERS.join(', ')}" unless FORMATTER_LAMBDAS.key?(formatter.to_sym)
|
|
155
|
+
formatter = FORMATTER_LAMBDAS[formatter.to_sym]
|
|
159
156
|
elsif !formatter.respond_to?(:call) && !formatter.is_a?(Logger::Formatter)
|
|
160
157
|
raise Error, 'Formatter must be a String, a Logger::Formatter or a Proc'
|
|
161
158
|
end
|
|
@@ -174,11 +171,10 @@ module Aspera
|
|
|
174
171
|
Logger::SEVERITY_LABEL[@logger.level].downcase
|
|
175
172
|
end
|
|
176
173
|
|
|
177
|
-
# Change underlying logger, but keep log level
|
|
174
|
+
# Change underlying logger, but keep log level (default: INFO)
|
|
178
175
|
def logger_type=(new_log_type)
|
|
179
|
-
|
|
180
|
-
current_severity_integer = ENV
|
|
181
|
-
current_severity_integer = Logger::Severity::WARN if current_severity_integer.nil?
|
|
176
|
+
# [Integer]
|
|
177
|
+
current_severity_integer = @logger&.level || ENV['AS_LOG_LEVEL']&.to_i || Logger::Severity::INFO
|
|
182
178
|
case new_log_type
|
|
183
179
|
when :stderr
|
|
184
180
|
@logger = Logger.new($stderr, progname: @program_name, formatter: DEFAULT_FORMATTER)
|
|
@@ -227,18 +223,22 @@ module Aspera
|
|
|
227
223
|
UNKNOWN: %i{blink}
|
|
228
224
|
}.freeze
|
|
229
225
|
|
|
230
|
-
# Short levels with color
|
|
231
|
-
LVL_COLOR = LVL_DECO.
|
|
226
|
+
# Short (4-letters) levels with color
|
|
227
|
+
LVL_COLOR = LVL_DECO.to_h do |k, v|
|
|
228
|
+
[k, short_levl(k).apply(*v)]
|
|
229
|
+
end.freeze
|
|
232
230
|
|
|
233
231
|
DEFAULT_FORMATTER = ->(s, _d, _p, m){"#{LVL_COLOR[s]} #{m}\n"}
|
|
234
232
|
|
|
235
233
|
# pre-defined formatters
|
|
236
|
-
|
|
234
|
+
FORMATTER_LAMBDAS = {
|
|
237
235
|
standard: Logger::Formatter.new,
|
|
238
236
|
default: DEFAULT_FORMATTER,
|
|
239
237
|
caller: ->(s, _d, _p, m){"#{LVL_COLOR[s]} #{Log.caller_method}\n#{m}\n"}
|
|
240
238
|
}.freeze
|
|
241
239
|
|
|
242
|
-
|
|
240
|
+
FORMATTERS = FORMATTER_LAMBDAS.keys
|
|
241
|
+
|
|
242
|
+
private_constant :LVL_DECO, :DEFAULT_FORMATTER, :FORMATTER_LAMBDAS
|
|
243
243
|
end
|
|
244
244
|
end
|
data/lib/aspera/markdown.rb
CHANGED
|
@@ -26,6 +26,28 @@ module Aspera
|
|
|
26
26
|
def list(items)
|
|
27
27
|
items.map{ |i| "- #{i}"}.join("\n")
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
def heading(title, level: 1)
|
|
31
|
+
"#{'#' * level} #{title}\n\n"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# type: NOTE CAUTION WARNING IMPORTANT TIP INFO
|
|
35
|
+
def admonition(lines, type: 'INFO')
|
|
36
|
+
"> [!{type}]\n#{lines.map{ |l| "> #{l}"}.join("\n")}\n\n"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def code(lines, type: 'shell')
|
|
40
|
+
"```#{type}\n#{lines.join("\n")}\n```\n\n"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# inline code
|
|
44
|
+
def icode(text)
|
|
45
|
+
"`#{text}`"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def paragraph(text)
|
|
49
|
+
"#{text}\n\n"
|
|
50
|
+
end
|
|
29
51
|
end
|
|
30
52
|
end
|
|
31
53
|
end
|
|
@@ -328,7 +328,7 @@ module Aspera
|
|
|
328
328
|
|
|
329
329
|
def set_json_response(request, response, json, code: 200)
|
|
330
330
|
response.status = code
|
|
331
|
-
response['Content-Type'] =
|
|
331
|
+
response['Content-Type'] = Mime::JSON
|
|
332
332
|
response.body = json.to_json
|
|
333
333
|
Log.log.trace1{Log.obj_dump("response for #{request.request_method} #{request.path}", json)}
|
|
334
334
|
end
|
data/lib/aspera/oauth/base.rb
CHANGED
|
@@ -53,7 +53,7 @@ module Aspera
|
|
|
53
53
|
def create_token_call(creation_params)
|
|
54
54
|
Log.log.debug{'Generating a new token'.bg_green}
|
|
55
55
|
return @api.create(@path_token, nil, query: creation_params, ret: :resp) if @use_query
|
|
56
|
-
return @api.create(@path_token, creation_params, content_type:
|
|
56
|
+
return @api.create(@path_token, creation_params, content_type: Mime::WWW, ret: :resp)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
# Create base parameters for token creation calls
|
|
@@ -99,7 +99,7 @@ module Aspera
|
|
|
99
99
|
# lets try the existing refresh token
|
|
100
100
|
# NOTE: AoC admin token has no refresh, and lives by default 1800secs
|
|
101
101
|
if !refresh_token.nil?
|
|
102
|
-
Log.log.
|
|
102
|
+
Log.log.debug{"refresh token=[#{refresh_token}]"}
|
|
103
103
|
begin
|
|
104
104
|
http = create_token_call(base_params(add_secret: true).merge(grant_type: 'refresh_token', refresh_token: refresh_token))
|
|
105
105
|
# Save only if success
|
|
@@ -24,9 +24,9 @@ module Aspera
|
|
|
24
24
|
operation: 'POST',
|
|
25
25
|
subpath: path_token,
|
|
26
26
|
query: @query.merge(scope: params[:scope]), # scope is here because it may change over time (node)
|
|
27
|
-
content_type:
|
|
27
|
+
content_type: Mime::JSON,
|
|
28
28
|
body: @body,
|
|
29
|
-
headers: {'Accept' =>
|
|
29
|
+
headers: {'Accept' => Mime::JSON},
|
|
30
30
|
ret: :resp
|
|
31
31
|
)
|
|
32
32
|
end
|
data/lib/aspera/oauth/web.rb
CHANGED
|
@@ -35,7 +35,7 @@ module Aspera
|
|
|
35
35
|
base_params.merge(response_type: 'code', redirect_uri: @redirect_uri, state: random_state)
|
|
36
36
|
)
|
|
37
37
|
# here, we need a human to authorize on a web page
|
|
38
|
-
Log.log.
|
|
38
|
+
Log.log.debug{"login_page_url=#{login_page_url}"}
|
|
39
39
|
# start a web server to receive request code
|
|
40
40
|
web_server = WebAuth.new(@redirect_uri, self.class.additional_info)
|
|
41
41
|
# start browser on login page
|
|
@@ -23,18 +23,18 @@ module Aspera
|
|
|
23
23
|
# one of CONVERSION_TYPES
|
|
24
24
|
attr_reader :conversion_type
|
|
25
25
|
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
26
|
+
# Node API MIME types are from: http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
|
|
27
|
+
# The resulting preview file type is taken from destination file extension.
|
|
28
|
+
# Conversion methods are provided by private methods: convert_<conversion_type>_to_<preview_format>
|
|
29
29
|
# -> conversion_type is one of FileTypes::CONVERSION_TYPES
|
|
30
30
|
# -> preview_format is one of Generator::PREVIEW_FORMATS
|
|
31
|
-
#
|
|
31
|
+
# The conversion video->mp4 is implemented in methods: convert_video_to_mp4_using_<video_conversion>
|
|
32
32
|
# -> conversion method is one of Generator::VIDEO_CONVERSION_METHODS
|
|
33
33
|
# @param src [String] source file path
|
|
34
34
|
# @param dst [String] destination file path
|
|
35
35
|
# @param options [Options] All conversion options
|
|
36
36
|
# @param main_temp_dir [String] Main temp folder, sub folder will be created for generation
|
|
37
|
-
# @param api_mime_type [String,nil] Optional
|
|
37
|
+
# @param api_mime_type [String,nil] Optional MIME type as provided by node api (or nil)
|
|
38
38
|
def initialize(src, dst, options, main_temp_dir, api_mime_type)
|
|
39
39
|
@source_file_path = src
|
|
40
40
|
@destination_file_path = dst
|
|
@@ -57,9 +57,9 @@ module Aspera
|
|
|
57
57
|
Aspera.assert(respond_to?(@processing_method, true)){"no processing known for #{conversion_type} -> #{@preview_format_sym}"}
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
#
|
|
60
|
+
# Create preview as specified in constructor.
|
|
61
61
|
def generate
|
|
62
|
-
Log.log.
|
|
62
|
+
Log.log.debug{"#{@source_file_path}->#{@destination_file_path} (#{@processing_method})"}
|
|
63
63
|
begin
|
|
64
64
|
send(@processing_method)
|
|
65
65
|
# check that generated size does not exceed maximum
|
|
@@ -76,17 +76,17 @@ module Aspera
|
|
|
76
76
|
|
|
77
77
|
private
|
|
78
78
|
|
|
79
|
-
#
|
|
79
|
+
# Creates a unique temp folder for file.
|
|
80
80
|
def this_tmpdir
|
|
81
81
|
FileUtils.mkdir_p(@temp_folder)
|
|
82
82
|
return @temp_folder
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
# @return offset in seconds suitable for ffmpeg -ss option
|
|
86
85
|
# @param duration of video
|
|
87
86
|
# @param start_offset of parts
|
|
88
87
|
# @param total_count of parts
|
|
89
88
|
# @param index of part (start at 1)
|
|
89
|
+
# @return [Integer] offset in seconds suitable for ffmpeg -ss option
|
|
90
90
|
def get_offset(duration, start_offset, total_count, index)
|
|
91
91
|
Aspera.assert_type(duration, Float){'duration'}
|
|
92
92
|
return start_offset + ((index - 1) * (duration - start_offset) / total_count)
|