aspera-cli 4.15.0 → 4.17.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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/BUGS.md +29 -3
  4. data/CHANGELOG.md +375 -280
  5. data/CONTRIBUTING.md +71 -18
  6. data/README.md +1978 -1656
  7. data/bin/ascli +13 -31
  8. data/bin/asession +32 -22
  9. data/examples/dascli +2 -2
  10. data/lib/aspera/agent/alpha.rb +117 -0
  11. data/lib/aspera/agent/base.rb +61 -0
  12. data/lib/aspera/{fasp/agent_connect.rb → agent/connect.rb} +13 -11
  13. data/lib/aspera/{fasp/agent_direct.rb → agent/direct.rb} +116 -116
  14. data/lib/aspera/{fasp/agent_httpgw.rb → agent/httpgw.rb} +21 -19
  15. data/lib/aspera/{fasp/agent_node.rb → agent/node.rb} +21 -33
  16. data/lib/aspera/agent/trsdk.rb +188 -0
  17. data/lib/aspera/api/aoc.rb +586 -0
  18. data/lib/aspera/api/ats.rb +46 -0
  19. data/lib/aspera/api/cos_node.rb +95 -0
  20. data/lib/aspera/api/node.rb +344 -0
  21. data/lib/aspera/ascmd.rb +47 -14
  22. data/lib/aspera/{fasp → ascp}/installation.rb +54 -15
  23. data/lib/aspera/{fasp → ascp}/management.rb +14 -14
  24. data/lib/aspera/{fasp → ascp}/products.rb +1 -1
  25. data/lib/aspera/assert.rb +45 -0
  26. data/lib/aspera/cli/basic_auth_plugin.rb +11 -10
  27. data/lib/aspera/cli/extended_value.rb +5 -5
  28. data/lib/aspera/cli/formatter.rb +27 -14
  29. data/lib/aspera/cli/hints.rb +7 -6
  30. data/lib/aspera/cli/main.rb +49 -29
  31. data/lib/aspera/cli/manager.rb +46 -36
  32. data/lib/aspera/cli/plugin.rb +34 -20
  33. data/lib/aspera/cli/plugin_factory.rb +61 -0
  34. data/lib/aspera/cli/plugins/alee.rb +7 -7
  35. data/lib/aspera/cli/plugins/aoc.rb +168 -132
  36. data/lib/aspera/cli/plugins/ats.rb +33 -33
  37. data/lib/aspera/cli/plugins/bss.rb +3 -4
  38. data/lib/aspera/cli/plugins/config.rb +250 -272
  39. data/lib/aspera/cli/plugins/console.rb +8 -6
  40. data/lib/aspera/cli/plugins/cos.rb +20 -19
  41. data/lib/aspera/cli/plugins/faspex.rb +71 -60
  42. data/lib/aspera/cli/plugins/faspex5.rb +212 -133
  43. data/lib/aspera/cli/plugins/node.rb +83 -75
  44. data/lib/aspera/cli/plugins/orchestrator.rb +36 -44
  45. data/lib/aspera/cli/plugins/preview.rb +33 -31
  46. data/lib/aspera/cli/plugins/server.rb +33 -32
  47. data/lib/aspera/cli/plugins/shares.rb +39 -33
  48. data/lib/aspera/cli/sync_actions.rb +9 -9
  49. data/lib/aspera/cli/transfer_agent.rb +45 -25
  50. data/lib/aspera/cli/transfer_progress.rb +2 -3
  51. data/lib/aspera/cli/version.rb +1 -1
  52. data/lib/aspera/colors.rb +5 -0
  53. data/lib/aspera/command_line_builder.rb +16 -14
  54. data/lib/aspera/coverage.rb +21 -0
  55. data/lib/aspera/data_repository.rb +33 -2
  56. data/lib/aspera/environment.rb +5 -4
  57. data/lib/aspera/faspex_gw.rb +13 -11
  58. data/lib/aspera/faspex_postproc.rb +6 -5
  59. data/lib/aspera/id_generator.rb +4 -2
  60. data/lib/aspera/json_rpc.rb +10 -8
  61. data/lib/aspera/keychain/encrypted_hash.rb +46 -11
  62. data/lib/aspera/keychain/macos_security.rb +29 -22
  63. data/lib/aspera/log.rb +5 -4
  64. data/lib/aspera/nagios.rb +7 -2
  65. data/lib/aspera/node_simulator.rb +213 -0
  66. data/lib/aspera/oauth/base.rb +143 -0
  67. data/lib/aspera/oauth/factory.rb +124 -0
  68. data/lib/aspera/oauth/generic.rb +34 -0
  69. data/lib/aspera/oauth/jwt.rb +51 -0
  70. data/lib/aspera/oauth/url_json.rb +31 -0
  71. data/lib/aspera/oauth/web.rb +50 -0
  72. data/lib/aspera/oauth.rb +5 -328
  73. data/lib/aspera/open_application.rb +7 -7
  74. data/lib/aspera/persistency_action_once.rb +13 -14
  75. data/lib/aspera/persistency_folder.rb +3 -2
  76. data/lib/aspera/preview/file_types.rb +53 -267
  77. data/lib/aspera/preview/generator.rb +7 -5
  78. data/lib/aspera/preview/terminal.rb +17 -7
  79. data/lib/aspera/preview/utils.rb +8 -7
  80. data/lib/aspera/proxy_auto_config.rb +6 -3
  81. data/lib/aspera/rest.rb +187 -140
  82. data/lib/aspera/rest_error_analyzer.rb +1 -0
  83. data/lib/aspera/rest_errors_aspera.rb +5 -3
  84. data/lib/aspera/resumer.rb +77 -0
  85. data/lib/aspera/secret_hider.rb +5 -2
  86. data/lib/aspera/ssh.rb +15 -8
  87. data/lib/aspera/temp_file_manager.rb +1 -1
  88. data/lib/aspera/{fasp → transfer}/error.rb +3 -3
  89. data/lib/aspera/{fasp → transfer}/error_info.rb +1 -1
  90. data/lib/aspera/{fasp → transfer}/faux_file.rb +1 -1
  91. data/lib/aspera/{fasp → transfer}/parameters.rb +95 -120
  92. data/lib/aspera/{fasp/transfer_spec.rb → transfer/spec.rb} +23 -19
  93. data/lib/aspera/{fasp/parameters.yaml → transfer/spec.yaml} +4 -99
  94. data/lib/aspera/transfer/sync.rb +273 -0
  95. data/lib/aspera/{fasp → transfer}/uri.rb +10 -9
  96. data/lib/aspera/web_server_simple.rb +12 -3
  97. data.tar.gz.sig +0 -0
  98. metadata +92 -68
  99. metadata.gz.sig +0 -0
  100. data/lib/aspera/aoc.rb +0 -606
  101. data/lib/aspera/ats_api.rb +0 -47
  102. data/lib/aspera/cos_node.rb +0 -93
  103. data/lib/aspera/fasp/agent_aspera.rb +0 -126
  104. data/lib/aspera/fasp/agent_base.rb +0 -48
  105. data/lib/aspera/fasp/agent_trsdk.rb +0 -146
  106. data/lib/aspera/fasp/resume_policy.rb +0 -77
  107. data/lib/aspera/node.rb +0 -338
  108. data/lib/aspera/sync.rb +0 -219
@@ -0,0 +1,273 @@
1
+ # frozen_string_literal: true
2
+
3
+ # cspell:words logdir bidi watchd cooloff asyncadmin
4
+
5
+ require 'aspera/command_line_builder'
6
+ require 'aspera/ascp/installation'
7
+ require 'aspera/log'
8
+ require 'aspera/assert'
9
+ require 'json'
10
+ require 'base64'
11
+ require 'open3'
12
+ require 'English'
13
+
14
+ module Aspera
15
+ module Transfer
16
+ # builds command line arg for async
17
+ module Sync
18
+ # sync direction, default is push
19
+ DIRECTIONS = %i[push pull bidi].freeze
20
+ # custom JSON for async instance command line options
21
+ PARAMS_VX_INSTANCE =
22
+ {
23
+ 'alt_logdir' => { cli: { type: :opt_with_arg}, accepted_types: :string},
24
+ 'watchd' => { cli: { type: :opt_with_arg}, accepted_types: :string},
25
+ 'apply_local_docroot' => { cli: { type: :opt_without_arg}},
26
+ 'quiet' => { cli: { type: :opt_without_arg}},
27
+ 'ws_connect' => { cli: { type: :opt_without_arg}}
28
+ }.freeze
29
+
30
+ # map sync session parameters to transfer spec: sync -> ts, true if same
31
+ PARAMS_VX_SESSION =
32
+ {
33
+ 'name' => { cli: { type: :opt_with_arg}, accepted_types: :string},
34
+ 'local_dir' => { cli: { type: :opt_with_arg}, accepted_types: :string},
35
+ 'remote_dir' => { cli: { type: :opt_with_arg}, accepted_types: :string},
36
+ 'local_db_dir' => { cli: { type: :opt_with_arg}, accepted_types: :string},
37
+ 'remote_db_dir' => { cli: { type: :opt_with_arg}, accepted_types: :string},
38
+ 'host' => { cli: { type: :opt_with_arg}, accepted_types: :string, ts: :remote_host},
39
+ 'user' => { cli: { type: :opt_with_arg}, accepted_types: :string, ts: :remote_user},
40
+ 'private_key_paths' => { cli: { type: :opt_with_arg, switch: '--private-key-path'}, accepted_types: :array},
41
+ 'direction' => { cli: { type: :opt_with_arg}, accepted_types: :string},
42
+ 'checksum' => { cli: { type: :opt_with_arg}, accepted_types: :string},
43
+ 'tags' => { cli: { type: :opt_with_arg, switch: '--tags64', convert: 'Aspera::Transfer::Parameters.convert_json64'},
44
+ accepted_types: :hash, ts: true},
45
+ 'tcp_port' => { cli: { type: :opt_with_arg}, accepted_types: :int, ts: :ssh_port},
46
+ 'rate_policy' => { cli: { type: :opt_with_arg}, accepted_types: :string},
47
+ 'target_rate' => { cli: { type: :opt_with_arg}, accepted_types: :string},
48
+ 'cooloff' => { cli: { type: :opt_with_arg}, accepted_types: :int},
49
+ 'pending_max' => { cli: { type: :opt_with_arg}, accepted_types: :int},
50
+ 'scan_intensity' => { cli: { type: :opt_with_arg}, accepted_types: :string},
51
+ 'cipher' => { cli: { type: :opt_with_arg, convert: 'Aspera::Transfer::Parameters.convert_remove_hyphen'}, accepted_types: :string, ts: true},
52
+ 'transfer_threads' => { cli: { type: :opt_with_arg}, accepted_types: :int},
53
+ 'preserve_time' => { cli: { type: :opt_without_arg}, ts: :preserve_times},
54
+ 'preserve_access_time' => { cli: { type: :opt_without_arg}, ts: nil},
55
+ 'preserve_modification_time' => { cli: { type: :opt_without_arg}, ts: nil},
56
+ 'preserve_uid' => { cli: { type: :opt_without_arg}, ts: :preserve_file_owner_uid},
57
+ 'preserve_gid' => { cli: { type: :opt_without_arg}, ts: :preserve_file_owner_gid},
58
+ 'create_dir' => { cli: { type: :opt_without_arg}, ts: true},
59
+ 'reset' => { cli: { type: :opt_without_arg}},
60
+ # NOTE: only one env var, but multiple sessions... could be a problem
61
+ 'remote_password' => { cli: { type: :envvar, variable: 'ASPERA_SCP_PASS'}, ts: true},
62
+ 'cookie' => { cli: { type: :envvar, variable: 'ASPERA_SCP_COOKIE'}, ts: true},
63
+ 'token' => { cli: { type: :envvar, variable: 'ASPERA_SCP_TOKEN'}, ts: true},
64
+ 'license' => { cli: { type: :envvar, variable: 'ASPERA_SCP_LICENSE'}}
65
+ }.freeze
66
+
67
+ CommandLineBuilder.normalize_description(PARAMS_VX_INSTANCE)
68
+ CommandLineBuilder.normalize_description(PARAMS_VX_SESSION)
69
+
70
+ PARAMS_VX_KEYS = %w[instance sessions].freeze
71
+
72
+ # Translation of transfer spec parameters to async v2 API (asyncs)
73
+ TS_TO_PARAMS_V2 = {
74
+ 'remote_host' => 'remote.host',
75
+ 'remote_user' => 'remote.user',
76
+ 'remote_password' => 'remote.pass',
77
+ 'sshfp' => 'remote.fingerprint',
78
+ 'ssh_port' => 'remote.port',
79
+ 'wss_port' => 'remote.ws_port',
80
+ 'proxy' => 'remote.proxy',
81
+ 'token' => 'remote.token',
82
+ 'tags' => 'tags'
83
+ }.freeze
84
+
85
+ ASYNC_EXECUTABLE = 'async'
86
+ ASYNC_ADMIN_EXECUTABLE = 'asyncadmin'
87
+
88
+ private_constant :PARAMS_VX_INSTANCE, :PARAMS_VX_SESSION, :PARAMS_VX_KEYS, :TS_TO_PARAMS_V2, :ASYNC_EXECUTABLE, :ASYNC_ADMIN_EXECUTABLE
89
+
90
+ class << self
91
+ # Set remote_dir in sync parameters based on transfer spec
92
+ # @param params [Hash] sync parameters, old or new format
93
+ # @param remote_dir_key [String] key to update in above hash
94
+ # @param transfer_spec [Hash] transfer spec
95
+ def update_remote_dir(sync_params, remote_dir_key, transfer_spec)
96
+ if transfer_spec.dig(*%w[tags aspera node file_id])
97
+ # in AoC, use gen4
98
+ sync_params[remote_dir_key] = '/'
99
+ elsif transfer_spec['cookie']&.start_with?('aspera.shares2')
100
+ # TODO : something more generic, independent of Shares
101
+ # in Shares, the actual folder on remote end is not always the same as the name of the share
102
+ actual_remote = transfer_spec['paths']&.first&.[]('source')
103
+ sync_params[remote_dir_key] = actual_remote if actual_remote
104
+ end
105
+ nil
106
+ end
107
+
108
+ def remote_certificates(remote)
109
+ certificates_to_use = []
110
+ # use web socket secure for session ?
111
+ if remote['connect_mode']&.eql?('ws')
112
+ remote.delete('port')
113
+ remote.delete('fingerprint')
114
+ # ignore cert for wss ?
115
+ # if @options[:check_ignore_cb]&.call(remote['host'], remote['ws_port'])
116
+ # wss_cert_file = TempFileManager.instance.new_file_path_global('wss_cert')
117
+ # wss_url = "https://#{remote['host']}:#{remote['ws_port']}"
118
+ # File.write(wss_cert_file, Rest.remote_certificate_chain(wss_url))
119
+ # certificates_to_use.push(wss_cert_file)
120
+ # end
121
+ # set location for CA bundle to be the one of Ruby, see env var SSL_CERT_FILE / SSL_CERT_DIR
122
+ # certificates_to_use.concat(@options[:trusted_certs]) if @options[:trusted_certs]
123
+ else
124
+ # remove unused parameter (avoid warning)
125
+ remote.delete('ws_port')
126
+ # add SSH bypass keys when authentication is token and no auth is provided
127
+ if remote.key?('token') && !remote.key?('pass')
128
+ certificates_to_use.concat(Ascp::Installation.instance.aspera_token_ssh_key_paths)
129
+ end
130
+ end
131
+ return certificates_to_use
132
+ end
133
+
134
+ # @param sync_params [Hash] sync parameters, old or new format
135
+ # @param block [nil, Proc] block to generate transfer spec, takes: direction (one of DIRECTIONS), local_dir, remote_dir
136
+ def start(sync_params, &block)
137
+ Aspera.assert_type(sync_params, Hash)
138
+ env_args = {
139
+ args: [],
140
+ env: {}
141
+ }
142
+ if sync_params.key?('local')
143
+ remote = sync_params['remote']
144
+ # async native JSON format (v2)
145
+ Aspera.assert_type(remote, Hash)
146
+ # get transfer spec if possible, and feed back to new structure
147
+ if block
148
+ transfer_spec = yield((sync_params['direction'] || 'push').to_sym, sync_params['local']['path'], remote['path'])
149
+ # async native JSON format
150
+ Aspera.assert_type(sync_params['local'], Hash)
151
+ # translate transfer spec to async parameters
152
+ TS_TO_PARAMS_V2.each do |ts_param, sy_path|
153
+ next unless transfer_spec.key?(ts_param)
154
+ sy_dig = sy_path.split('.')
155
+ param = sy_dig.pop
156
+ hash = sy_dig.empty? ? sync_params : sync_params[sy_dig.first]
157
+ hash = sync_params[sy_dig.first] = {} if hash.nil?
158
+ hash[param] = transfer_spec[ts_param]
159
+ end
160
+ update_remote_dir(remote, 'path', transfer_spec)
161
+ end
162
+ remote['connect_mode'] ||= remote.key?('ws_port') ? 'ws' : 'ssh'
163
+ add_certificates = remote_certificates(remote)
164
+ if !add_certificates.empty?
165
+ remote['private_key_paths'] ||= []
166
+ remote['private_key_paths'].concat(add_certificates)
167
+ end
168
+ Aspera.assert_type(sync_params, Hash)
169
+ env_args[:args] = ["--conf64=#{Base64.strict_encode64(JSON.generate(sync_params))}"]
170
+ elsif sync_params.key?('sessions')
171
+ # ascli JSON format (v1)
172
+ if block
173
+ sync_params['sessions'].each do |session|
174
+ transfer_spec = yield((session['direction'] || 'push').to_sym, session['local_dir'], session['remote_dir'])
175
+ PARAMS_VX_SESSION.each do |async_param, behavior|
176
+ if behavior.key?(:ts)
177
+ tspec_param = behavior[:ts].is_a?(TrueClass) ? async_param : behavior[:ts].to_s
178
+ session[async_param] ||= transfer_spec[tspec_param] if transfer_spec.key?(tspec_param)
179
+ end
180
+ end
181
+ session['private_key_paths'] = Ascp::Installation.instance.aspera_token_ssh_key_paths if transfer_spec.key?('token')
182
+ update_remote_dir(session, 'remote_dir', transfer_spec)
183
+ end
184
+ end
185
+ raise StandardError, "Only 'sessions', and optionally 'instance' keys are allowed" unless
186
+ sync_params.keys.push('instance').uniq.sort.eql?(PARAMS_VX_KEYS)
187
+ Aspera.assert_type(sync_params['sessions'], Array)
188
+ Aspera.assert_type(sync_params['sessions'].first, Hash)
189
+ if sync_params.key?('instance')
190
+ Aspera.assert_type(sync_params['instance'], Hash)
191
+ instance_builder = CommandLineBuilder.new(sync_params['instance'], PARAMS_VX_INSTANCE)
192
+ instance_builder.process_params
193
+ instance_builder.add_env_args(env_args)
194
+ end
195
+
196
+ sync_params['sessions'].each do |session_params|
197
+ Aspera.assert_type(session_params, Hash)
198
+ Aspera.assert(session_params.key?('name')){'session must contain at least name'}
199
+ session_builder = CommandLineBuilder.new(session_params, PARAMS_VX_SESSION)
200
+ session_builder.process_params
201
+ session_builder.add_env_args(env_args)
202
+ end
203
+ else
204
+ raise 'At least one of `local` or `sessions` must be present in async parameters'
205
+ end
206
+ Log.log.debug{Log.dump(:sync_params, sync_params)}
207
+ Log.log.debug{"execute: #{env_args[:env].map{|k, v| "#{k}=\"#{v}\""}.join(' ')} \"#{ASYNC_EXECUTABLE}\" \"#{env_args[:args].join('" "')}\""}
208
+ res = system(env_args[:env], [ASYNC_EXECUTABLE, ASYNC_EXECUTABLE], *env_args[:args])
209
+ Log.log.debug{"result=#{res}"}
210
+ case res
211
+ when true then return nil
212
+ when false then raise "failed: #{$CHILD_STATUS}"
213
+ when nil then raise "not started: #{$CHILD_STATUS}"
214
+ else Aspera.error_unexpected_value(res)
215
+ end
216
+ end
217
+
218
+ def parse_status(stdout)
219
+ Log.log.trace1{"stdout=#{stdout}"}
220
+ result = {}
221
+ ids = nil
222
+ stdout.split("\n").each do |line|
223
+ info = line.split(':', 2).map(&:lstrip)
224
+ if info[1].eql?('')
225
+ info[1] = ids = []
226
+ elsif info[1].nil?
227
+ ids.push(info[0])
228
+ next
229
+ end
230
+ result[info[0]] = info[1]
231
+ end
232
+ return result
233
+ end
234
+
235
+ def admin_status(sync_params, session_name)
236
+ command_line = [ASYNC_ADMIN_EXECUTABLE, '--quiet']
237
+ if sync_params.key?('local')
238
+ Aspera.assert(!sync_params['name'].nil?){'Missing session name'}
239
+ Aspera.assert(session_name.nil? || session_name.eql?(sync_params['name'])){'Session not found'}
240
+ command_line.push("--name=#{sync_params['name']}")
241
+ if sync_params.key?('local_db_dir')
242
+ command_line.push("--local-db-dir=#{sync_params['local_db_dir']}")
243
+ elsif sync_params.dig('local', 'path')
244
+ command_line.push("--local-dir=#{sync_params.dig('local', 'path')}")
245
+ else
246
+ raise 'Missing either local_db_dir or local.path'
247
+ end
248
+ elsif sync_params.key?('sessions')
249
+ session = session_name.nil? ? sync_params['sessions'].first : sync_params['sessions'].find{|s|s['name'].eql?(session_name)}
250
+ raise "Session #{session_name} not found in #{sync_params['sessions'].map{|s|s['name']}.join(',')}" if session.nil?
251
+ raise 'Missing session name' if session['name'].nil?
252
+ command_line.push("--name=#{session['name']}")
253
+ if session.key?('local_db_dir')
254
+ command_line.push("--local-db-dir=#{session['local_db_dir']}")
255
+ elsif session.key?('local_dir')
256
+ command_line.push("--local-dir=#{session['local_dir']}")
257
+ else
258
+ raise 'Missing either local_db_dir or local_dir'
259
+ end
260
+ else
261
+ raise 'At least one of `local` or `sessions` must be present in async parameters'
262
+ end
263
+ Log.log.debug{"execute: #{command_line.join(' ')}"}
264
+ stdout, stderr, status = Open3.capture3(*command_line)
265
+ Log.log.debug{"status=#{status}, stderr=#{stderr}"}
266
+ Log.log.trace1{"stdout=#{stdout}"}
267
+ raise "Sync failed: #{status.exitstatus} : #{stderr}" unless status.success?
268
+ return parse_status(stdout)
269
+ end
270
+ end
271
+ end
272
+ end
273
+ end
@@ -7,22 +7,23 @@ require 'aspera/rest'
7
7
  require 'aspera/command_line_builder'
8
8
 
9
9
  module Aspera
10
- module Fasp
11
- # translates a "faspe:" URI (used in Faspex 4) into transfer spec hash
10
+ module Transfer
11
+ # translates a "faspe:" URI (used in Faspex 4) into transfer spec (Hash)
12
12
  class Uri
13
13
  SCHEME = 'faspe'
14
14
  def initialize(fasp_link)
15
15
  @fasp_uri = URI.parse(fasp_link.gsub(' ', '%20'))
16
- # TODO: check scheme is faspe
16
+ Aspera.assert(@fasp_uri.scheme == SCHEME, "Invalid scheme: #{@fasp_uri.scheme}")
17
17
  end
18
18
 
19
+ # Generate transfer spec from provided faspe: URL
19
20
  def transfer_spec
20
21
  result_ts = {}
21
22
  result_ts['remote_host'] = @fasp_uri.host
22
23
  result_ts['remote_user'] = @fasp_uri.user
23
24
  result_ts['ssh_port'] = @fasp_uri.port
24
25
  result_ts['paths'] = [{'source' => URI.decode_www_form_component(@fasp_uri.path)}]
25
- # faspex does not encode trailing base64 padding, fix that to be able to decode properly
26
+ # faspex 4 does not encode trailing base64 padding, fix that to be able to decode properly
26
27
  fixed_query = @fasp_uri.query.gsub(/(=+)$/){|x|'%3D' * x.length}
27
28
 
28
29
  Rest.decode_query(fixed_query).each do |name, value|
@@ -36,20 +37,20 @@ module Aspera
36
37
  when 'minrate' then result_ts['min_rate_kbps'] = value.to_i
37
38
  when 'port' then result_ts['fasp_port'] = value.to_i
38
39
  when 'bwcap' then result_ts['target_rate_cap_kbps'] = value.to_i
39
- when 'enc' then result_ts['cipher'] = value.gsub(/^aes/, 'aes-').gsub(/cfb$/, '-cfb').gsub(/gcm$/, '-gcm').gsub(/--/, '-')
40
+ when 'enc' then result_ts['cipher'] = value.gsub(/^aes/, 'aes-').gsub(/cfb$/, '-cfb').gsub(/gcm$/, '-gcm').gsub('--', '-')
40
41
  when 'tags64' then result_ts['tags'] = JSON.parse(Base64.strict_decode64(value))
41
42
  when 'createpath' then result_ts['create_dir'] = CommandLineBuilder.yes_to_true(value)
42
43
  when 'fallback' then result_ts['http_fallback'] = CommandLineBuilder.yes_to_true(value)
43
44
  when 'lockpolicy' then result_ts['lock_rate_policy'] = CommandLineBuilder.yes_to_true(value)
44
45
  when 'lockminrate' then result_ts['lock_min_rate'] = CommandLineBuilder.yes_to_true(value)
45
46
  when 'auth' then Log.log.debug{"ignoring #{name}=#{value}"} # Not used (yes/no)
46
- when 'v' then Log.log.debug{"ignoring #{name}=#{value}"} # rubocop:disable Lint/DuplicateBranch Not used (2)
47
+ when 'v' then Log.log.debug{"ignoring #{name}=#{value}"} # rubocop:disable Lint/DuplicateBranch Not used (shall be 2)
47
48
  when 'protect' then Log.log.debug{"ignoring #{name}=#{value}"} # rubocop:disable Lint/DuplicateBranch TODO: what is this ?
48
49
  else Log.log.warn{"URI parameter ignored: #{name} = #{value}"}
49
50
  end
50
51
  end
51
52
  return result_ts
52
53
  end
53
- end # Uri
54
- end # Fasp
55
- end # Aspera
54
+ end
55
+ end
56
+ end
@@ -3,6 +3,7 @@
3
3
  require 'webrick'
4
4
  require 'webrick/https'
5
5
  require 'aspera/log'
6
+ require 'aspera/assert'
6
7
  require 'openssl'
7
8
 
8
9
  module Aspera
@@ -37,6 +38,7 @@ module Aspera
37
38
 
38
39
  # @param uri [URI]
39
40
  def initialize(uri, certificate: nil)
41
+ @url = uri
40
42
  # see https://www.rubydoc.info/stdlib/webrick/WEBrick/Config
41
43
  webrick_options = {
42
44
  BindAddress: uri.host,
@@ -52,7 +54,7 @@ module Aspera
52
54
  if certificate.nil?
53
55
  webrick_options[:SSLCertName] = [['CN', WEBrick::Utils.getservername]]
54
56
  else
55
- raise 'certificate must be Hash' unless certificate.is_a?(Hash)
57
+ Aspera.assert_type(certificate, Hash)
56
58
  certificate = certificate.symbolize_keys
57
59
  raise "unexpected key in certificate config: only: #{CERT_PARAMETERS.join(', ')}" if certificate.keys.any?{|k|!CERT_PARAMETERS.include?(k)}
58
60
  webrick_options[:SSLPrivateKey] = if certificate.key?(:key)
@@ -71,10 +73,17 @@ module Aspera
71
73
  end
72
74
  end
73
75
  end
76
+ # call constructor of parent class, but capture STDERR
74
77
  # self signed certificate generates characters on STDERR, see create_self_signed_cert in webrick/ssl.rb
75
78
  Log.capture_stderr { super(webrick_options) }
76
- # kill -USR1 for graceful shutdown
77
- Kernel.trap('USR1') { shutdown }
79
+ end
80
+
81
+ # blocking
82
+ def start
83
+ Log.log.info{"Listening on #{@url}"}
84
+ # kill -HUP for graceful shutdown
85
+ Kernel.trap('HUP') { shutdown }
86
+ super
78
87
  end
79
88
 
80
89
  # log web server access ( option AccessLog )
data.tar.gz.sig CHANGED
Binary file