aspera-cli 4.21.1 → 4.21.2

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 (48) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +4 -2
  3. data/CHANGELOG.md +22 -10
  4. data/CONTRIBUTING.md +68 -143
  5. data/README.md +175 -145
  6. data/bin/ascli +5 -14
  7. data/bin/asession +1 -3
  8. data/examples/get_proto_file.rb +4 -3
  9. data/examples/proxy.pac +20 -20
  10. data/lib/aspera/agent/base.rb +2 -0
  11. data/lib/aspera/agent/{alpha.rb → desktop.rb} +7 -7
  12. data/lib/aspera/agent/direct.rb +9 -1
  13. data/lib/aspera/agent/transferd.rb +24 -17
  14. data/lib/aspera/api/alee.rb +1 -1
  15. data/lib/aspera/api/cos_node.rb +1 -1
  16. data/lib/aspera/api/node.rb +4 -4
  17. data/lib/aspera/ascp/installation.rb +40 -58
  18. data/lib/aspera/cli/extended_value.rb +9 -3
  19. data/lib/aspera/cli/formatter.rb +8 -1
  20. data/lib/aspera/cli/info.rb +1 -0
  21. data/lib/aspera/cli/main.rb +2 -2
  22. data/lib/aspera/cli/manager.rb +3 -3
  23. data/lib/aspera/cli/plugins/aoc.rb +106 -55
  24. data/lib/aspera/cli/plugins/config.rb +10 -31
  25. data/lib/aspera/cli/plugins/faspex5.rb +8 -5
  26. data/lib/aspera/cli/plugins/node.rb +6 -3
  27. data/lib/aspera/cli/version.rb +1 -1
  28. data/lib/aspera/coverage.rb +5 -3
  29. data/lib/aspera/environment.rb +20 -11
  30. data/lib/aspera/faspex_postproc.rb +3 -5
  31. data/lib/aspera/hash_ext.rb +2 -12
  32. data/lib/aspera/oauth/base.rb +6 -1
  33. data/lib/aspera/preview/generator.rb +12 -9
  34. data/lib/aspera/preview/options.rb +2 -2
  35. data/lib/aspera/preview/terminal.rb +1 -1
  36. data/lib/aspera/preview/utils.rb +4 -4
  37. data/lib/aspera/products/connect.rb +34 -0
  38. data/lib/aspera/products/{alpha.rb → desktop.rb} +2 -2
  39. data/lib/aspera/products/transferd.rb +8 -1
  40. data/lib/aspera/rest.rb +4 -4
  41. data/lib/aspera/secret_hider.rb +7 -0
  42. data/lib/aspera/temp_file_manager.rb +5 -4
  43. data/lib/aspera/uri_reader.rb +18 -1
  44. data.tar.gz.sig +0 -0
  45. metadata +4 -174
  46. metadata.gz.sig +0 -0
  47. data/examples/build_exec +0 -74
  48. data/examples/build_exec_rubyc +0 -40
@@ -348,7 +348,7 @@ module Aspera
348
348
  transfer.agent_instance = Agent::Node.new(
349
349
  url: client_apfid[:api].base_url,
350
350
  username: client_apfid[:api].app_info[:node_info]['access_key'],
351
- password: client_apfid[:api].oauth.token,
351
+ password: client_apfid[:api].oauth.authorization,
352
352
  root_id: client_apfid[:file_id]
353
353
  )
354
354
  # additional node to node TS info
@@ -473,60 +473,111 @@ module Aspera
473
473
  when :subscription
474
474
  org = aoc_api.read('organization')
475
475
  bss_graphql = api_from_options('bss/platform/graphql')
476
- # cspell:disable
477
- graphql_query = <<-GRAPHQL
478
- query ($organization_id: ID!) {
479
- aoc (organization_id: $organization_id) {
480
- bssSubscription {
481
- aocVersion
482
- endDate
483
- startDate
484
- termMonths
485
- plan
486
- trial
487
- termType
488
- aocOrganizations {
489
- id
490
- }
491
- additionalStorageVolumeGb
492
- additionalEgressVolumeGb
493
- term {
494
- startDate
495
- endDate
496
- transferVolumeGb
497
- egressVolumeGb
498
- storageVolumeGb
499
- transferVolumeOffsetGb
500
- }
501
- paygoRate {
502
- transferRate
503
- storageRate
504
- currency
505
- }
506
- aocPlanData {
507
- tier
508
- trial
509
- workspaces { max }
510
- users {
511
- planAmount
512
- max
476
+ command_subscription = options.get_next_command(%i[account usage])
477
+ case command_subscription
478
+ when :account
479
+ # cspell:disable
480
+ graphql_query = <<-GRAPHQL
481
+ query ($organization_id: ID!) {
482
+ aoc (organization_id: $organization_id) {
483
+ bssSubscription {
484
+ aocVersion
485
+ endDate
486
+ startDate
487
+ termMonths
488
+ plan
489
+ trial
490
+ termType
491
+ aocOrganizations {
492
+ id
493
+ }
494
+ additionalStorageVolumeGb
495
+ additionalEgressVolumeGb
496
+ term {
497
+ startDate
498
+ endDate
499
+ transferVolumeGb
500
+ egressVolumeGb
501
+ storageVolumeGb
502
+ transferVolumeOffsetGb
503
+ }
504
+ paygoRate {
505
+ transferRate
506
+ storageRate
507
+ currency
508
+ }
509
+ aocPlanData {
510
+ tier
511
+ trial
512
+ workspaces { max }
513
+ users {
514
+ planAmount
515
+ max
516
+ }
517
+ samlIntegration
518
+ activity
519
+ sharedInboxes
520
+ uniqueUrls
521
+ support
522
+ watermarking
523
+ byok
524
+ automation { planAmount, max }
525
+ }
526
+ }
527
+ }
513
528
  }
514
- samlIntegration
515
- activity
516
- sharedInboxes
517
- uniqueUrls
518
- support
519
- watermarking
520
- byok
521
- automation { planAmount, max }
522
- }
523
- }
524
- }
525
- }
526
- GRAPHQL
527
- # cspell:enable
528
- result = bss_graphql.create(nil, {query: graphql_query, variables: {organization_id: org['id']}})['data']
529
- return {type: :single_object, data: result['aoc']['bssSubscription']}
529
+ GRAPHQL
530
+ # cspell:enable
531
+ result = bss_graphql.create(nil, {query: graphql_query, variables: {organization_id: org['id']}})['data']
532
+ return {type: :single_object, data: result['aoc']['bssSubscription']}
533
+ when :usage
534
+ # cspell:disable
535
+ graphql_query = <<-GRAPHQL
536
+ query ($organization_id: ID!, $startDate: Date!, $endDate: Date!, $aggregate: TransferUsageAggregateOption!) {
537
+ aoc (organization_id: $organization_id) {
538
+ bssSubscription {
539
+ aocOrganizations { id }
540
+ additionalStorageVolumeGb
541
+ additionalEgressVolumeGb
542
+ aocPlanData {
543
+ tier
544
+ trial
545
+ }
546
+ term {
547
+ transferVolumeGb
548
+ egressVolumeGb
549
+ storageVolumeGb
550
+ startDate
551
+ endDate
552
+ transferVolumeOffsetGb
553
+ }
554
+ termMonths
555
+ transferUsages (startDate: $startDate, endDate: $endDate, aggregate: $aggregate) { mbTotal }
556
+ egressUsages (startDate: $startDate, endDate: $endDate, aggregate: $aggregate) { usageMb }
557
+ }
558
+ subscriptionEntitlements {
559
+ id
560
+ transferUsages (startDate: $startDate, endDate: $endDate, aggregate: $aggregate) { mbTotal }
561
+ egressUsages (startDate: $startDate, endDate: $endDate, aggregate: $aggregate) { usageMb }
562
+ }
563
+ }
564
+ }
565
+ GRAPHQL
566
+ aggregate = options.get_next_argument('aggregation', accept_list: %i[ALL MONTHLY], default: :ALL)
567
+ today = Date.today
568
+ start_date = options.get_next_argument('start date', mandatory: false, default: today.prev_year.strftime('%Y-%m-%d'))
569
+ end_date = options.get_next_argument('end date', mandatory: false, default: today.strftime('%Y-%m-%d'))
570
+ # cspell:enable
571
+ result = bss_graphql.create(
572
+ nil,
573
+ {query: graphql_query,
574
+ variables: {
575
+ organization_id: org['id'],
576
+ aggregate: aggregate,
577
+ startDate: start_date,
578
+ endDate: end_date}})['data']
579
+ return {type: :single_object, data: result['aoc']}
580
+ end
530
581
  when :ats
531
582
  ats_api = Rest.new(**aoc_api.params.deep_merge({
532
583
  base_url: "#{aoc_api.base_url}/admin/ats/pub/v1",
@@ -690,7 +741,7 @@ module Aspera
690
741
  when :servers
691
742
  return {type: :object_list, data: Rest.new(base_url: "#{Api::AoC.api_base_url}/#{Api::AoC::API_V1}").read('servers')}
692
743
  when :bearer_token
693
- return {type: :text, data: aoc_api.oauth.token}
744
+ return {type: :text, data: aoc_api.oauth.authorization}
694
745
  when :organization
695
746
  return { type: :single_object, data: aoc_api.read('organization') }
696
747
  when :tier_restrictions
@@ -54,8 +54,6 @@ module Aspera
54
54
  ASPERA = 'aspera'
55
55
  SERVER_COMMAND = 'server'
56
56
  DIR_SDK = 'sdk'
57
- CONNECT_WEB_URL = 'https://d3gcli72yxqn2z.cloudfront.net/connect'
58
- CONNECT_VERSIONS = 'connectversions.js' # cspell: disable-line
59
57
  DEMO_SERVER = 'demo'
60
58
  DEMO_PRESET = 'demoserver' # cspell: disable-line
61
59
  EMAIL_TEST_TEMPLATE = <<~END_OF_TEMPLATE
@@ -150,7 +148,6 @@ module Aspera
150
148
  @use_plugin_defaults = true
151
149
  @config_presets = nil
152
150
  @config_checksum_on_disk = nil
153
- @connect_versions = nil
154
151
  @vault = nil
155
152
  @pac_exec = nil
156
153
  @sdk_default_location = false
@@ -213,7 +210,8 @@ module Aspera
213
210
  # Transfer SDK options
214
211
  options.declare(:ascp_path, 'Path to ascp', handler: {o: Ascp::Installation.instance, m: :ascp_path})
215
212
  options.declare(:use_product, 'Use ascp from specified product', handler: {o: self, m: :option_use_product})
216
- options.declare(:sdk_url, 'URL to get SDK', default: SpecialValues::DEF)
213
+ options.declare(:sdk_url, 'URL to get Aspera Transfer Daemon', default: SpecialValues::DEF)
214
+ options.declare(:locations_url, 'URL to get locations of Aspera Transfer Daemon', handler: {o: Ascp::Installation.instance, m: :transferd_urls})
217
215
  options.declare(:sdk_folder, 'SDK folder path', handler: {o: Products::Transferd, m: :sdk_directory})
218
216
  options.declare(:progress_bar, 'Display progress bar', values: :bool, default: Environment.terminal?)
219
217
  # email options
@@ -439,23 +437,6 @@ module Aspera
439
437
  end if check_data[:need_update]
440
438
  end
441
439
 
442
- # retrieve structure from cloud (CDN) with all versions available
443
- def connect_versions
444
- if @connect_versions.nil?
445
- api_connect_cdn = Rest.new(base_url: CONNECT_WEB_URL)
446
- javascript = api_connect_cdn.call(operation: 'GET', subpath: CONNECT_VERSIONS)
447
- # get result on one line
448
- connect_versions_javascript = javascript[:http].body.gsub(/\r?\n\s*/, '')
449
- Log.log.debug{"javascript=[\n#{connect_versions_javascript}\n]"}
450
- # get javascript object only
451
- found = connect_versions_javascript.match(/^.*? = (.*);/)
452
- raise Cli::Error, 'Problem when getting connect versions from internet' if found.nil?
453
- all_data = JSON.parse(found[1])
454
- @connect_versions = all_data['entries']
455
- end
456
- return @connect_versions
457
- end
458
-
459
440
  # loads default parameters of plugin if no -P parameter
460
441
  # and if there is a section defined for the plugin in the "default" section
461
442
  # try to find: conf[conf["default"][plugin_str]]
@@ -659,12 +640,12 @@ module Aspera
659
640
  command = options.get_next_command(%i[list info version])
660
641
  if %i[info version].include?(command)
661
642
  connect_id = options.get_next_argument('id or title')
662
- one_res = connect_versions.find{|i|i['id'].eql?(connect_id) || i['title'].eql?(connect_id)}
643
+ one_res = Products::Connect.instance.versions.find{|i|i['id'].eql?(connect_id) || i['title'].eql?(connect_id)}
663
644
  raise Cli::NoSuchIdentifier.new(:connect, connect_id) if one_res.nil?
664
645
  end
665
646
  case command
666
647
  when :list
667
- return Main.result_object_list(connect_versions, fields: %w[id title version])
648
+ return Main.result_object_list(Products::Connect.instance.versions, fields: %w[id title version])
668
649
  when :info
669
650
  one_res.delete('links')
670
651
  return Main.result_single_object(one_res)
@@ -674,18 +655,16 @@ module Aspera
674
655
  if %i[download open].include?(command)
675
656
  link_title = options.get_next_argument('title or rel')
676
657
  one_link = all_links.find {|i| i['title'].eql?(link_title) || i['rel'].eql?(link_title)}
677
- raise 'no such value' if one_link.nil?
658
+ raise "no such value: #{link_title}" if one_link.nil?
678
659
  end
679
660
  case command
680
661
  when :list
681
662
  return Main.result_object_list(all_links)
682
663
  when :download
683
- folder_dest = transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE)
684
- api_connect_cdn = Rest.new(base_url: CONNECT_WEB_URL)
685
- file_url = one_link['href']
686
- filename = file_url.gsub(%r{.*/}, '')
687
- api_connect_cdn.call(operation: 'GET', subpath: file_url, save_to_file: File.join(folder_dest, filename))
688
- return Main.result_status("Downloaded: #{filename}")
664
+ archive_path = one_link['href']
665
+ save_to_path = File.join(transfer.destination_folder(Transfer::Spec::DIRECTION_RECEIVE), archive_path.gsub(%r{.*/}, ''))
666
+ Products::Connect.instance.cdn_api.call(operation: 'GET', subpath: archive_path, save_to_file: save_to_path)
667
+ return Main.result_status("Downloaded: #{save_to_path}")
689
668
  when :open
690
669
  Environment.instance.open_uri(one_link['href'])
691
670
  return Main.result_status("Opened: #{one_link['href']}")
@@ -759,7 +738,7 @@ module Aspera
759
738
  n, v = Ascp::Installation.instance.install_sdk(url: options.get_option(:sdk_url, mandatory: true), version: version)
760
739
  return Main.result_status("Installed #{n} version #{v}")
761
740
  when :list
762
- sdk_list = Ascp::Installation.sdk_locations
741
+ sdk_list = Ascp::Installation.instance.sdk_locations
763
742
  return Main.result_object_list(
764
743
  sdk_list,
765
744
  fields: sdk_list.first.keys - ['url']
@@ -228,10 +228,8 @@ module Aspera
228
228
  config.progress_bar&.event(:transfer, session_id: id, info: status['bytes_written'].to_i)
229
229
  end
230
230
  if status_list.include?(status['upload_status'])
231
- # if status['upload_status'].eql?('completed')
232
231
  config.progress_bar&.event(:end, session_id: id)
233
232
  return status
234
- # end
235
233
  end
236
234
  sleep(1.0)
237
235
  end
@@ -467,7 +465,8 @@ module Aspera
467
465
  end
468
466
  return browse_folder("packages/#{package_id}/files/#{location}")
469
467
  when :status
470
- status = wait_package_status(package_id, status_list: nil)
468
+ status_list = options.get_next_argument('list of states, or nothing', mandatory: false, validation: Array)
469
+ status = wait_package_status(package_id, status_list: status_list)
471
470
  return {type: :single_object, data: status}
472
471
  when :delete
473
472
  ids = package_id
@@ -600,7 +599,11 @@ module Aspera
600
599
 
601
600
  end
602
601
  when :browse
603
- return browse_folder("#{res_path}/#{instance_identifier}/browse")
602
+ node_id = instance_identifier do |field, value|
603
+ lookup_entity_by_field(
604
+ type: res_type, value: value, field: field, real_path: res_path, item_list_key: list_key, query: res_id_query)['id']
605
+ end
606
+ return browse_folder("#{res_path}/#{node_id}/browse")
604
607
  when :invite_external_collaborator
605
608
  shared_inbox_id = instance_identifier { |field, value| lookup_entity_by_field(type: res_type.to_s, field: field, value: value, query: res_id_query)['id']}
606
609
  creation_payload = value_create_modify(command: res_command, type: [Hash, String])
@@ -744,7 +747,7 @@ fields: %w[event_type created_at application user.name]}
744
747
  end
745
748
  end
746
749
  when :bearer_token
747
- return {type: :text, data: @api_v5.oauth.token}
750
+ return {type: :text, data: @api_v5.oauth.authorization}
748
751
  when :packages
749
752
  return package_action
750
753
  when :shared_folders
@@ -477,7 +477,7 @@ module Aspera
477
477
  result[:password] = apifid[:api].auth_params[:password]
478
478
  when :oauth2
479
479
  result[:username] = apifid[:api].params[:headers][Api::Node::HEADER_X_ASPERA_ACCESS_KEY]
480
- result[:password] = apifid[:api].oauth.token
480
+ result[:password] = apifid[:api].oauth.authorization
481
481
  else Aspera.error_unreachable_line
482
482
  end
483
483
  return {type: :single_object, data: result} if command_repo.eql?(:node_info)
@@ -601,7 +601,7 @@ module Aspera
601
601
  return Main.result_image(result[:http].body, formatter: formatter)
602
602
  when :permission
603
603
  apifid = apifid_from_next_arg(top_file_id)
604
- command_perm = options.get_next_command(%i[list create delete])
604
+ command_perm = options.get_next_command(%i[list show create delete])
605
605
  case command_perm
606
606
  when :list
607
607
  list_query = query_read_delete(default: {'include' => Rest.array_params(%w[access_level permission_count])})
@@ -611,6 +611,9 @@ module Aspera
611
611
  # NOTE: supports per_page and page and header X-Total-Count
612
612
  items = apifid[:api].read('permissions', list_query)
613
613
  return {type: :object_list, data: items}
614
+ when :show
615
+ perm_id = instance_identifier
616
+ return Main.result_single_object(apifid[:api].read("permissions/#{perm_id}"))
614
617
  when :delete
615
618
  return do_bulk_operation(command: command_perm, descr: 'identifier', values: :identifier) do |one_id|
616
619
  apifid[:api].delete("permissions/#{one_id}")
@@ -1013,7 +1016,7 @@ module Aspera
1013
1016
  Environment.instance.open_uri("#{options.get_option(:asperabrowserurl)}?goto=#{encoded_params}")
1014
1017
  return Main.result_status('done')
1015
1018
  when :basic_token
1016
- return Main.result_status(Rest.basic_token(options.get_option(:username, mandatory: true), options.get_option(:password, mandatory: true)))
1019
+ return Main.result_status(Rest.basic_authorization(options.get_option(:username, mandatory: true), options.get_option(:password, mandatory: true)))
1017
1020
  when :bearer_token
1018
1021
  private_key = OpenSSL::PKey::RSA.new(options.get_next_argument('private RSA key PEM value', validation: String))
1019
1022
  token_info = options.get_next_argument('user and group identification', validation: Hash)
@@ -4,6 +4,6 @@ module Aspera
4
4
  module Cli
5
5
  # for beta add extension : .beta1
6
6
  # for dev version add extension : .pre
7
- VERSION = '4.21.1'
7
+ VERSION = '4.21.2'
8
8
  end
9
9
  end
@@ -20,14 +20,16 @@ if ENV.key?('ENABLE_COVERAGE')
20
20
  # lines with those words are ignored from coverage
21
21
  no_cov_functions = %w[error_unreachable_line error_unexpected_value Log.log.trace].freeze
22
22
  SimpleCov.start do
23
- add_filter 'lib/aspera/cli/plugins/faspex.rb'
24
- add_filter 'lib/aspera/node_simulator.rb'
25
- add_filter 'lib/aspera/keychain/macos_security.rb'
23
+ # assert usually do not trigger
26
24
  add_filter do |source_file|
27
25
  source_file.lines.each do |line|
28
26
  line.skipped! if no_cov_functions.any?{|i|line.src.include?(i)}
29
27
  end
30
28
  false
31
29
  end
30
+ # no coverage test in those
31
+ add_filter 'lib/aspera/cli/plugins/faspex.rb'
32
+ add_filter 'lib/aspera/node_simulator.rb'
33
+ add_filter 'lib/aspera/keychain/macos_security.rb'
32
34
  end
33
35
  end
@@ -109,23 +109,28 @@ module Aspera
109
109
  ].compact.flatten.join(' ')
110
110
  end
111
111
 
112
- # start process in background, or raise exception
112
+ # Start process in background
113
113
  # caller can call Process.wait on returned value
114
- # @param env [Hash, nil] environment variables
115
- # @param exec [String] path to executable
116
- # @param args [Array, nil] arguments
117
- # @return [String] PID of process
118
- def secure_spawn(exec:, args: nil, env: nil)
114
+ # @param exec [String] path to executable
115
+ # @param args [Array, nil] arguments for executable
116
+ # @param env [Hash, nil] environment variables
117
+ # @param options [Hash, nil] spawn options
118
+ # @return [String] PID of process
119
+ # @raise [Exception] if problem
120
+ def secure_spawn(exec:, args: nil, env: nil, **options)
119
121
  Aspera.assert_type(exec, String)
120
122
  Aspera.assert_type(args, Array) unless args.nil?
121
123
  Aspera.assert_type(env, Hash) unless env.nil?
124
+ Aspera.assert_type(options, Hash) unless options.nil?
122
125
  Log.log.debug {log_spawn(exec: exec, args: args, env: env)}
123
126
  # start ascp in separate process
124
127
  spawn_args = []
125
128
  spawn_args.push(env) unless env.nil?
126
129
  spawn_args.push([exec, exec])
127
130
  spawn_args.concat(args) unless args.nil?
128
- ascp_pid = Process.spawn(*spawn_args, close_others: true)
131
+ opts = {close_others: true}
132
+ opts.merge!(options) unless options.nil?
133
+ ascp_pid = Process.spawn(*spawn_args, **opts)
129
134
  Log.log.debug{"pid: #{ascp_pid}"}
130
135
  return ascp_pid
131
136
  end
@@ -135,24 +140,28 @@ module Aspera
135
140
  # @param exec [String] path to executable
136
141
  # @param args [Array, nil] arguments
137
142
  # @return [String] PID of process
138
- def secure_execute(exec:, args: nil, env: nil)
143
+ def secure_execute(exec:, args: nil, env: nil, **system_args)
139
144
  Aspera.assert_type(exec, String)
140
145
  Aspera.assert_type(args, Array) unless args.nil?
141
146
  Aspera.assert_type(env, Hash) unless env.nil?
142
147
  Log.log.debug {log_spawn(exec: exec, args: args, env: env)}
143
- # start ascp in separate process
148
+ # start in separate process
144
149
  spawn_args = []
145
150
  spawn_args.push(env) unless env.nil?
151
+ # ensure no shell expansion
146
152
  spawn_args.push([exec, exec])
147
153
  spawn_args.concat(args) unless args.nil?
148
- Kernel.system(*spawn_args, exception: true)
154
+ kwargs = {exception: true}
155
+ kwargs.merge!(system_args)
156
+ Kernel.system(*spawn_args, **kwargs)
149
157
  nil
150
158
  end
151
159
 
160
+ # Execute process and capture stdout
152
161
  # @param exec [String] path to executable
153
162
  # @param args [Array] arguments to executable
154
163
  # @param opts [Hash] options to capture3
155
- # @return stdout of executable or raise expcetion
164
+ # @return stdout of executable or raise exception
156
165
  def secure_capture(exec:, args: [], **opts)
157
166
  Aspera.assert_type(exec, String)
158
167
  Aspera.assert_type(args, Array)
@@ -39,7 +39,7 @@ module Aspera
39
39
  response.body = {status: 'error', message: 'Empty request'}.to_json
40
40
  return
41
41
  end
42
- # build script path by removing domain, and adding script folder
42
+ # build script path by removing domain and adding script folder
43
43
  script_file = request.path[@parameters[:root].size..]
44
44
  Log.log.debug{"script file=#{script_file}"}
45
45
  script_path = File.join(@parameters[:script_folder], script_file)
@@ -48,11 +48,9 @@ module Aspera
48
48
  Log.log.debug{Log.dump(:webhook_parameters, webhook_parameters)}
49
49
  # env expects only strings
50
50
  environment = webhook_parameters.each_with_object({}) { |(k, v), h| h[k] = v.to_s }
51
- post_proc_pid = Process.spawn(environment, [script_path, script_path])
52
- Log.log.debug{"pid=#{post_proc_pid}"}
53
- raise 'no pid' if post_proc_pid.nil?
54
- # "wait" for process to avoid zombie
51
+ post_proc_pid = Environment.secure_spawn(env: environment, exec: script_path)
55
52
  Timeout.timeout(@parameters[:timeout_seconds]) do
53
+ # "wait" for process to avoid zombie
56
54
  Process.wait(post_proc_pid)
57
55
  post_proc_pid = nil
58
56
  end
@@ -20,17 +20,7 @@ class ::Hash
20
20
  end
21
21
  end
22
22
 
23
- # in 2.5
24
- unless Hash.method_defined?(:transform_keys)
25
- class Hash
26
- def transform_keys
27
- raise 'missing block' unless block_given?
28
- return each_with_object({}){|(k, v), memo|memo[yield(k)] = v}
29
- end
30
- end
31
- end
32
-
33
- # rails
23
+ # Exists in Rails
34
24
  unless Hash.method_defined?(:symbolize_keys)
35
25
  class Hash
36
26
  def symbolize_keys
@@ -39,7 +29,7 @@ unless Hash.method_defined?(:symbolize_keys)
39
29
  end
40
30
  end
41
31
 
42
- # rails
32
+ # Exists in Rails
43
33
  unless Hash.method_defined?(:stringify_keys)
44
34
  class Hash
45
35
  def stringify_keys
@@ -79,6 +79,11 @@ module Aspera
79
79
  return call_params
80
80
  end
81
81
 
82
+ # @return value suitable for Authorization header
83
+ def authorization(**kwargs)
84
+ return OAuth::Factory.bearer_build(token(**kwargs))
85
+ end
86
+
82
87
  # get an OAuth v2 token (generated, cached, refreshed)
83
88
  # call token() to get a token.
84
89
  # if a token is expired (api returns 4xx), call again token(refresh: true)
@@ -129,7 +134,7 @@ module Aspera
129
134
  end
130
135
  Aspera.assert(token_data.key?(@token_field)){"API error: No such field in answer: #{@token_field}"}
131
136
  # ok we shall have a token here
132
- return OAuth::Factory.bearer_build(token_data[@token_field])
137
+ return token_data[@token_field]
133
138
  end
134
139
  end
135
140
  end
@@ -4,7 +4,6 @@
4
4
  # spellchecker:ignore pauseframes libx264 trunc bufsize muxer apng libmp3lame maxrate posterize movflags faststart
5
5
  # spellchecker:ignore palettegen paletteuse pointsize bordercolor repage lanczos unoconv optipng reencode conv transframes
6
6
 
7
- require 'open3'
8
7
  require 'aspera/preview/options'
9
8
  require 'aspera/preview/utils'
10
9
  require 'aspera/preview/file_types'
@@ -24,17 +23,18 @@ module Aspera
24
23
  # one of CONVERSION_TYPES
25
24
  attr_reader :conversion_type
26
25
 
27
- # @param src source file path
28
- # @param dst destination file path
29
- # @param api_mime_type optional mime type as provided by node api (or nil)
30
26
  # node API mime types are from: http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
31
- # supported preview type is one of Preview::PREVIEW_FORMATS
32
27
  # the resulting preview file type is taken from destination file extension.
33
28
  # conversion methods are provided by private methods: convert_<conversion_type>_to_<preview_format>
34
29
  # -> conversion_type is one of FileTypes::CONVERSION_TYPES
35
30
  # -> preview_format is one of Generator::PREVIEW_FORMATS
36
31
  # the conversion video->mp4 is implemented in methods: convert_video_to_mp4_using_<video_conversion>
37
32
  # -> conversion method is one of Generator::VIDEO_CONVERSION_METHODS
33
+ # @param src [String] source file path
34
+ # @param dst [String] destination file path
35
+ # @param options [Options] All conversion options
36
+ # @param main_temp_dir [String] Main temp folder, sub folder will be created for generation
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
@@ -54,7 +54,7 @@ module Aspera
54
54
  end
55
55
  @processing_method = @processing_method.to_sym
56
56
  Log.log.debug{"method: #{@processing_method}"}
57
- Aspera.assert(respond_to?(@processing_method, true)){"no processing know for #{conversion_type} -> #{@preview_format_sym}"}
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
@@ -215,7 +215,8 @@ module Aspera
215
215
 
216
216
  def convert_pdf_to_png(source_file_path=nil)
217
217
  source_file_path ||= @source_file_path
218
- Utils.external_command(:convert, [
218
+ Utils.external_command(:magick, [
219
+ 'convert',
219
220
  '-size', "x#{@options.thumb_img_size}",
220
221
  '-background', 'white',
221
222
  '-flatten',
@@ -224,7 +225,8 @@ module Aspera
224
225
  end
225
226
 
226
227
  def convert_image_to_png
227
- Utils.external_command(:convert, [
228
+ Utils.external_command(:magick, [
229
+ 'convert',
228
230
  '-auto-orient',
229
231
  '-thumbnail', "#{@options.thumb_img_size}x#{@options.thumb_img_size}>",
230
232
  '-quality', 95,
@@ -239,7 +241,8 @@ module Aspera
239
241
  def convert_plaintext_to_png
240
242
  # get 100 first lines of text file
241
243
  first_lines = File.open(@source_file_path){|f|Array.new(100){f.readline rescue ''}.join}
242
- Utils.external_command(:convert, [
244
+ Utils.external_command(:magick, [
245
+ 'convert',
243
246
  '-size', "#{@options.thumb_img_size}x#{@options.thumb_img_size}",
244
247
  'xc:white', # define canvas with background color (xc, or canvas) of preceding size
245
248
  '-font', @options.thumb_text_font,
@@ -19,10 +19,10 @@ module Aspera
19
19
  { name: :thumb_vid_scale, default: "-1:'min(ih,100)'", description: 'png: video: size (ffmpeg scale argument)' },
20
20
  { name: :thumb_vid_fraction, default: 0.1, description: 'png: video: time percent position of snapshot' },
21
21
  { name: :thumb_img_size, default: 800, description: 'png: non-video: height (and width)' },
22
- { name: :thumb_text_font, default: 'Courier', description: 'png: plaintext: font to render text with imagemagick convert (identify -list font)'},
22
+ { name: :thumb_text_font, default: 'Courier', description: 'png: plaintext: font for text rendering: `magick identify -list font`'},
23
23
  { name: :video_conversion, default: :reencode, description: 'mp4: method for preview generation', values: VIDEO_CONVERSION_METHODS },
24
24
  { name: :video_png_conv, default: :fixed, description: 'mp4: method for thumbnail generation', values: VIDEO_THUMBNAIL_METHODS },
25
- { name: :video_scale, default: "'min(iw,360)':-2", description: 'mp4: all: video scale (ffmpeg)' },
25
+ { name: :video_scale, default: "'min(iw,360)':-2", description: 'mp4: all: video scale (ffmpeg scale argument)' },
26
26
  { name: :video_start_sec, default: 10, description: 'mp4: all: start offset (seconds) of video preview' },
27
27
  { name: :reencode_ffmpeg, default: {}, description: 'mp4: reencode: options to ffmpeg' },
28
28
  { name: :blend_keyframes, default: 30, description: 'mp4: blend: # key frames' },
@@ -44,7 +44,7 @@ module Aspera
44
44
  fit_term_ratio = [term_rows.to_f * font_ratio / image.rows.to_f, term_columns.to_f / image.columns.to_f].min
45
45
  height_ratio = double ? 2.0 : 1.0
46
46
  image = image.scale((image.columns * fit_term_ratio).to_i, (image.rows * fit_term_ratio * height_ratio / font_ratio).to_i)
47
- # quantum depth is 8 or 16, see: `convert xc: -format "%q" info:`
47
+ # quantum depth is 8 or 16, see: `magick xc: -format "%q" info:`
48
48
  shift_for_8_bit = Magick::MAGICKCORE_QUANTUM_DEPTH - 8
49
49
  # get all pixel colors, adjusted for Rainbow
50
50
  pixel_colors = []