aspera-cli 4.13.0 → 4.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +81 -7
  4. data/CONTRIBUTING.md +22 -6
  5. data/README.md +2038 -1080
  6. data/bin/ascli +18 -9
  7. data/bin/asession +12 -14
  8. data/examples/dascli +1 -1
  9. data/examples/proxy.pac +1 -1
  10. data/examples/rubyc +24 -0
  11. data/lib/aspera/aoc.rb +219 -159
  12. data/lib/aspera/ascmd.rb +25 -14
  13. data/lib/aspera/cli/basic_auth_plugin.rb +12 -9
  14. data/lib/aspera/cli/error.rb +17 -0
  15. data/lib/aspera/cli/extended_value.rb +47 -12
  16. data/lib/aspera/cli/formatter.rb +260 -179
  17. data/lib/aspera/cli/hints.rb +80 -0
  18. data/lib/aspera/cli/main.rb +104 -156
  19. data/lib/aspera/cli/manager.rb +259 -209
  20. data/lib/aspera/cli/plugin.rb +123 -63
  21. data/lib/aspera/cli/plugins/alee.rb +2 -3
  22. data/lib/aspera/cli/plugins/aoc.rb +341 -261
  23. data/lib/aspera/cli/plugins/ats.rb +22 -21
  24. data/lib/aspera/cli/plugins/bss.rb +5 -5
  25. data/lib/aspera/cli/plugins/config.rb +578 -627
  26. data/lib/aspera/cli/plugins/console.rb +44 -6
  27. data/lib/aspera/cli/plugins/cos.rb +15 -17
  28. data/lib/aspera/cli/plugins/faspex.rb +114 -100
  29. data/lib/aspera/cli/plugins/faspex5.rb +411 -264
  30. data/lib/aspera/cli/plugins/node.rb +354 -259
  31. data/lib/aspera/cli/plugins/orchestrator.rb +61 -29
  32. data/lib/aspera/cli/plugins/preview.rb +82 -90
  33. data/lib/aspera/cli/plugins/server.rb +79 -32
  34. data/lib/aspera/cli/plugins/shares.rb +55 -42
  35. data/lib/aspera/cli/sync_actions.rb +68 -0
  36. data/lib/aspera/cli/transfer_agent.rb +66 -73
  37. data/lib/aspera/cli/transfer_progress.rb +74 -0
  38. data/lib/aspera/cli/version.rb +1 -1
  39. data/lib/aspera/colors.rb +12 -8
  40. data/lib/aspera/command_line_builder.rb +14 -11
  41. data/lib/aspera/cos_node.rb +3 -2
  42. data/lib/aspera/data/6 +0 -0
  43. data/lib/aspera/environment.rb +24 -9
  44. data/lib/aspera/fasp/agent_aspera.rb +126 -0
  45. data/lib/aspera/fasp/agent_base.rb +31 -77
  46. data/lib/aspera/fasp/agent_connect.rb +25 -21
  47. data/lib/aspera/fasp/agent_direct.rb +89 -103
  48. data/lib/aspera/fasp/agent_httpgw.rb +231 -149
  49. data/lib/aspera/fasp/agent_node.rb +41 -34
  50. data/lib/aspera/fasp/agent_trsdk.rb +75 -32
  51. data/lib/aspera/fasp/error_info.rb +4 -2
  52. data/lib/aspera/fasp/faux_file.rb +52 -0
  53. data/lib/aspera/fasp/installation.rb +53 -195
  54. data/lib/aspera/fasp/management.rb +244 -0
  55. data/lib/aspera/fasp/parameters.rb +71 -37
  56. data/lib/aspera/fasp/parameters.yaml +76 -8
  57. data/lib/aspera/fasp/products.rb +162 -0
  58. data/lib/aspera/fasp/resume_policy.rb +3 -3
  59. data/lib/aspera/fasp/transfer_spec.rb +7 -6
  60. data/lib/aspera/fasp/uri.rb +26 -24
  61. data/lib/aspera/faspex_gw.rb +2 -2
  62. data/lib/aspera/faspex_postproc.rb +2 -2
  63. data/lib/aspera/hash_ext.rb +14 -4
  64. data/lib/aspera/json_rpc.rb +49 -0
  65. data/lib/aspera/keychain/macos_security.rb +13 -13
  66. data/lib/aspera/line_logger.rb +23 -0
  67. data/lib/aspera/log.rb +58 -16
  68. data/lib/aspera/node.rb +157 -92
  69. data/lib/aspera/oauth.rb +37 -19
  70. data/lib/aspera/open_application.rb +4 -4
  71. data/lib/aspera/persistency_action_once.rb +1 -1
  72. data/lib/aspera/persistency_folder.rb +2 -2
  73. data/lib/aspera/preview/file_types.rb +4 -2
  74. data/lib/aspera/preview/generator.rb +22 -35
  75. data/lib/aspera/preview/options.rb +2 -0
  76. data/lib/aspera/preview/terminal.rb +73 -16
  77. data/lib/aspera/preview/utils.rb +21 -28
  78. data/lib/aspera/proxy_auto_config.js +2 -2
  79. data/lib/aspera/rest.rb +136 -68
  80. data/lib/aspera/rest_call_error.rb +1 -1
  81. data/lib/aspera/rest_error_analyzer.rb +15 -14
  82. data/lib/aspera/rest_errors_aspera.rb +37 -34
  83. data/lib/aspera/secret_hider.rb +18 -15
  84. data/lib/aspera/ssh.rb +5 -2
  85. data/lib/aspera/sync.rb +127 -119
  86. data/lib/aspera/temp_file_manager.rb +10 -3
  87. data/lib/aspera/web_auth.rb +10 -7
  88. data/lib/aspera/web_server_simple.rb +9 -4
  89. data.tar.gz.sig +0 -0
  90. metadata +34 -17
  91. metadata.gz.sig +0 -0
  92. data/docs/test_env.conf +0 -186
  93. data/lib/aspera/cli/listener/line_dump.rb +0 -19
  94. data/lib/aspera/cli/listener/logger.rb +0 -22
  95. data/lib/aspera/cli/listener/progress.rb +0 -50
  96. data/lib/aspera/cli/listener/progress_multi.rb +0 -84
  97. data/lib/aspera/cli/plugins/sync.rb +0 -44
  98. data/lib/aspera/data/7 +0 -0
  99. data/lib/aspera/fasp/listener.rb +0 -13
@@ -2,12 +2,13 @@
2
2
  # accepted_types : accepted types for non-enum
3
3
  # default : default value if not specified
4
4
  # enum : set with list of values for enum types accepted in transfer spec
5
- # agents : supported agents (for doc only)
5
+ # agents : supported agents (for doc only), if not specified: all
6
6
  # required : optional, default: false
7
7
  # cli.type : ascp: type of parameter, one of CLI_OPTION_TYPES
8
8
  # cli.switch : ascp: switch for ascp command line
9
9
  # cli.convert : ascp: transform value: either a Hash with conversion values, or name of class
10
10
  # cli.variable : ascp: name of env var
11
+ # cspell:words dgram dnat dnats faspmgr asperanoded xattrs keepalive datagram
11
12
  ---
12
13
  cipher:
13
14
  :desc: "In transit encryption type."
@@ -78,7 +79,11 @@ destination_root:
78
79
  :cli:
79
80
  :type: :special
80
81
  destination_root_id:
81
- :desc: The file ID of the destination root directory. Required when using Bearer token auth for the destination node.
82
+ :desc: |-
83
+ The file ID of the destination root directory.
84
+ Required when using Bearer token auth for the destination node.
85
+
86
+
82
87
  :accepted_types: :string
83
88
  :agents:
84
89
  - :sdk
@@ -176,7 +181,7 @@ multi_session:
176
181
 
177
182
  :accepted_types: :int
178
183
  :cli:
179
- :type: :ignore
184
+ :type: :special
180
185
  :switch: "-C"
181
186
  multi_session_threshold:
182
187
  :desc: |-
@@ -226,15 +231,37 @@ precalculate_job_size:
226
231
  :cli:
227
232
  :type: :opt_without_arg
228
233
  preserve_access_time:
234
+ :desc: |-
235
+ Preserve the source-file access timestamps at the destination.
236
+ Because source access times are updated by the transfer operation,
237
+ the timestamp that is preserved is the one just before to the transfer.
238
+
239
+
229
240
  :cli:
230
241
  :type: :opt_without_arg
231
242
  preserve_creation_time:
243
+ :desc: |-
244
+ (Windows only) Preserve source-file creation timestamps at the destination.
245
+ Only Windows systems retain information about creation time.
246
+ If the destination is not a Windows computer, this option is ignored.
247
+
248
+
232
249
  :cli:
233
250
  :type: :opt_without_arg
234
251
  preserve_modification_time:
252
+ :desc: |-
253
+ Set the modification time, the last time a file or directory was modified (written), of a transferred file
254
+ to the modification of the source file or directory.
255
+ Preserve source-file modification timestamps at the destination.
256
+
257
+
235
258
  :cli:
236
259
  :type: :opt_without_arg
237
260
  preserve_times:
261
+ :desc: Preserve file timestamps.
262
+ :agents:
263
+ - :sdk
264
+ - :node
238
265
  :cli:
239
266
  :type: :opt_without_arg
240
267
  rate_policy:
@@ -436,6 +463,7 @@ use_ascp4:
436
463
  :cli:
437
464
  :type: :special
438
465
  use_system_ssh:
466
+ :desc: TODO, comment...
439
467
  :accepted_types: :string
440
468
  :agents:
441
469
  - :sdk
@@ -453,22 +481,46 @@ source_root:
453
481
  :switch: "--source-prefix64"
454
482
  :convert: Aspera::Fasp::Parameters.convert_base64
455
483
  min_rate_cap_kbps:
484
+ :desc: |-
485
+ The highest minimum rate that an incoming transfer can request, in kilobits per second.
486
+ Client minimum rate requests that exceed the minimum rate cap are ignored.
487
+ The default value of unlimited applies no cap to the minimum rate. (Default: 0)
488
+
489
+
456
490
  :accepted_types: :int
457
491
  :cli:
458
492
  :type: :ignore
459
493
  lock_rate_policy:
494
+ :desc: If true, lock the rate policy to the default value.
460
495
  :accepted_types: :bool
496
+ :agents:
497
+ - :sdk
498
+ - :connect
461
499
  :cli:
462
500
  :type: :ignore
463
501
  lock_target_rate_kbps:
502
+ :desc: |-
503
+ If true, lock the target transfer rate to the default value set for target_rate_kbps.
504
+ If false, users can adjust the transfer rate up to the value set for target_rate_cap_kbps.
505
+
506
+
464
507
  :accepted_types: :bool
465
508
  :cli:
466
509
  :type: :ignore
467
510
  lock_min_rate_kbps:
511
+ :desc: |-
512
+ If true, lock the minimum transfer rate to the value set for min_rate_kbps.
513
+ If false, users can adjust the transfer rate up to the value set for target_rate_cap_kbps.
514
+
515
+
468
516
  :accepted_types: :bool
517
+ :agents:
518
+ - :sdk
519
+ - :connect
469
520
  :cli:
470
521
  :type: :ignore
471
522
  apply_local_docroot:
523
+ :desc: Apply local docroot to source paths.
472
524
  :agents:
473
525
  - :direct
474
526
  - :sdk
@@ -560,7 +612,7 @@ remove_empty_source_directory:
560
612
  :type: :opt_without_arg
561
613
  EX_at_rest_password:
562
614
  :desc: Content protection password
563
- :deprecation: "Use standard spec parameter: content_protection_password"
615
+ :deprecation: "(4.13) Use standard spec parameter: content_protection_password"
564
616
  :agents:
565
617
  - :direct
566
618
  :cli:
@@ -569,9 +621,10 @@ EX_at_rest_password:
569
621
  EX_proxy_password:
570
622
  :desc: |-
571
623
  Password used for Aspera proxy server authentication.
572
- May be overridden by password in URL EX_fasp_proxy_url.
624
+ May be overridden by password in URL provided in parameter: proxy.
573
625
 
574
626
 
627
+ :deprecation: (4.14) Use env var ASPERA_PROXY_PASS
575
628
  :agents:
576
629
  - :direct
577
630
  :cli:
@@ -579,14 +632,17 @@ EX_proxy_password:
579
632
  :variable: ASPERA_PROXY_PASS
580
633
  EX_license_text:
581
634
  :desc: "License file text override.\nBy default ascp looks for license file near executable."
635
+ :deprecation: (4.14) Use env var ASPERA_SCP_LICENSE
582
636
  :agents:
583
637
  - :direct
584
638
  :cli:
585
639
  :type: :envvar
586
640
  :variable: ASPERA_SCP_LICENSE
587
641
  keepalive:
642
+ :desc: The session is running in persistent session mode.
588
643
  :agents:
589
- - :none
644
+ - :sdk
645
+ - :direct
590
646
  :cli:
591
647
  :type: :opt_without_arg
592
648
  dgram_size:
@@ -609,6 +665,7 @@ sshfp:
609
665
  :switch: "--check-sshfp"
610
666
  EX_http_proxy_url:
611
667
  :desc: Specify the proxy server address used by HTTP Fallback
668
+ :deprecation: (4.14) TODO, use proxy option ?
612
669
  :agents:
613
670
  - :direct
614
671
  :cli:
@@ -616,6 +673,7 @@ EX_http_proxy_url:
616
673
  :switch: "-x"
617
674
  EX_ssh_key_paths:
618
675
  :desc: Use public key authentication for SSH and specify the private key file paths
676
+ :deprecation: (4.14) Use option transfer_info.ascp_args
619
677
  :accepted_types: :array
620
678
  :agents:
621
679
  - :direct
@@ -624,6 +682,7 @@ EX_ssh_key_paths:
624
682
  :switch: "-i"
625
683
  EX_http_transfer_jpeg:
626
684
  :desc: HTTP transfers as JPEG file
685
+ :deprecation: (4.14) Use option transfer_info.ascp_args
627
686
  :accepted_types: :int
628
687
  :default: '0'
629
688
  :agents:
@@ -633,6 +692,7 @@ EX_http_transfer_jpeg:
633
692
  :switch: "-j"
634
693
  EX_no_read:
635
694
  :desc: no read source
695
+ :deprecation: (4.14) Use option transfer_info.ascp_args
636
696
  :agents:
637
697
  - :direct
638
698
  :cli:
@@ -640,12 +700,14 @@ EX_no_read:
640
700
  :switch: "--no-read"
641
701
  EX_no_write:
642
702
  :desc: no write on destination
703
+ :deprecation: (4.14) Use option transfer_info.ascp_args
643
704
  :agents:
644
705
  - :direct
645
706
  :cli:
646
707
  :type: :opt_without_arg
647
708
  :switch: "--no-write"
648
709
  target_rate_percentage:
710
+ :desc: "TODO: remove ?"
649
711
  :cli:
650
712
  :type: :ignore
651
713
  rate_policy_allowed:
@@ -660,15 +722,18 @@ rate_policy_allowed:
660
722
  :cli:
661
723
  :type: :ignore
662
724
  fasp_url:
725
+ :desc: Only used in Faspex.
663
726
  :agents:
664
727
  - :unknown
665
728
  :cli:
666
729
  :type: :ignore
667
730
  lock_min_rate:
731
+ :desc: "TODO: remove ?"
668
732
  :accepted_types: :bool
669
733
  :cli:
670
734
  :type: :ignore
671
735
  lock_target_rate:
736
+ :desc: "TODO: remove ?"
672
737
  :accepted_types: :bool
673
738
  :cli:
674
739
  :type: :ignore
@@ -683,13 +748,15 @@ cipher_allowed:
683
748
  :cli:
684
749
  :type: :ignore
685
750
  obfuscate_file_names:
751
+ :desc: HTTP Gateway obfuscates file names when set to true.
686
752
  :accepted_types: :bool
687
753
  :agents:
688
- - :unknown
754
+ - :httpgw
689
755
  :cli:
690
756
  :type: :ignore
691
757
  EX_file_list:
692
758
  :desc: source file list
759
+ :deprecation: (4.14) Use command line file list, or option transfer_info.ascp_args
693
760
  :agents:
694
761
  - :direct
695
762
  :cli:
@@ -697,6 +764,7 @@ EX_file_list:
697
764
  :switch: "--file-list"
698
765
  EX_file_pair_list:
699
766
  :desc: source file pair list
767
+ :deprecation: (4.14) Use command line file pair list, or option transfer_info.ascp_args
700
768
  :agents:
701
769
  - :direct
702
770
  :cli:
@@ -704,7 +772,7 @@ EX_file_pair_list:
704
772
  :switch: "--file-pair-list"
705
773
  EX_ascp_args:
706
774
  :desc: Add native command line arguments to ascp
707
- :deprecation: Use parameter ascp_args in option transfer_info
775
+ :deprecation: (4.13) Use option transfer_info.ascp_args
708
776
  :accepted_types: :array
709
777
  :agents:
710
778
  - :direct
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ # cspell:ignore LOCALAPPDATA
4
+ require 'aspera/environment'
5
+
6
+ module Aspera
7
+ module Fasp
8
+ # find Aspera standard products installation in standard paths
9
+ class Products
10
+ # known product names
11
+ CONNECT = 'IBM Aspera Connect'
12
+ ASPERA = 'IBM Aspera (Client)'
13
+ CLI_V1 = 'Aspera CLI (deprecated)'
14
+ DRIVE = 'Aspera Drive (deprecated)'
15
+ HSTS = 'IBM Aspera High-Speed Transfer Server'
16
+ # product information manifest: XML (part of aspera product)
17
+ INFO_META_FILE = 'product-info.mf'
18
+ BIN_SUBFOLDER = 'bin'
19
+ ETC_SUBFOLDER = 'etc'
20
+ VAR_RUN_SUBFOLDER = File.join('var', 'run')
21
+
22
+ @@found_products = nil # rubocop:disable Style/ClassVars
23
+ class << self
24
+ # @return product folders depending on OS fields
25
+ # :expected M app name is taken from the manifest if present, else defaults to this value
26
+ # :app_root M main folder for the application
27
+ # :log_root O location of log files (Linux uses syslog)
28
+ # :run_root O only for Connect Client, location of http port file
29
+ # :sub_bin O subfolder with executables, default : bin
30
+ def product_locations_on_current_os
31
+ result =
32
+ case Aspera::Environment.os
33
+ when Aspera::Environment::OS_WINDOWS then [{
34
+ expected: CONNECT,
35
+ app_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Programs', 'Aspera', 'Aspera Connect'),
36
+ log_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Aspera', 'Aspera Connect', 'var', 'log'),
37
+ run_root: File.join(ENV.fetch('LOCALAPPDATA', nil), 'Aspera', 'Aspera Connect')
38
+ }, {
39
+ expected: CLI_V1,
40
+ app_root: File.join('C:', 'Program Files', 'Aspera', 'cli'),
41
+ log_root: File.join('C:', 'Program Files', 'Aspera', 'cli', 'var', 'log')
42
+ }, {
43
+ expected: HSTS,
44
+ app_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server'),
45
+ log_root: File.join('C:', 'Program Files', 'Aspera', 'Enterprise Server', 'var', 'log')
46
+ }]
47
+ when Aspera::Environment::OS_X then [{
48
+ expected: CONNECT,
49
+ app_root: File.join(Dir.home, 'Applications', 'Aspera Connect.app'),
50
+ log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
51
+ run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
52
+ sub_bin: File.join('Contents', 'Resources')
53
+ }, {
54
+ expected: CONNECT,
55
+ app_root: File.join('', 'Applications', 'Aspera Connect.app'),
56
+ log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Connect'),
57
+ run_root: File.join(Dir.home, 'Library', 'Application Support', 'Aspera', 'Aspera Connect'),
58
+ sub_bin: File.join('Contents', 'Resources')
59
+ }, {
60
+ expected: CLI_V1,
61
+ app_root: File.join(Dir.home, 'Applications', 'Aspera CLI'),
62
+ log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
63
+ }, {
64
+ expected: HSTS,
65
+ app_root: File.join('', 'Library', 'Aspera'),
66
+ log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera')
67
+ }, {
68
+ expected: DRIVE,
69
+ app_root: File.join('', 'Applications', 'Aspera Drive.app'),
70
+ log_root: File.join(Dir.home, 'Library', 'Logs', 'Aspera_Drive'),
71
+ sub_bin: File.join('Contents', 'Resources')
72
+ }, {
73
+ expected: ASPERA,
74
+ app_root: File.join('', 'Applications', 'IBM Aspera.app'),
75
+ log_root: File.join(Dir.home, 'Library', 'Logs', 'IBM Aspera'),
76
+ sub_bin: File.join('Contents', 'Resources', 'sdk', 'aspera', 'bin')
77
+ }]
78
+ else [{ # other: Linux and Unix family
79
+ expected: CONNECT,
80
+ app_root: File.join(Dir.home, '.aspera', 'connect'),
81
+ run_root: File.join(Dir.home, '.aspera', 'connect')
82
+ }, {
83
+ expected: CLI_V1,
84
+ app_root: File.join(Dir.home, '.aspera', 'cli')
85
+ }, {
86
+ expected: HSTS,
87
+ app_root: File.join('', 'opt', 'aspera')
88
+ }]
89
+ end
90
+ result # .each {|item| item.deep_do {|h, _k, _v, _m|h.freeze}}.freeze
91
+ end
92
+
93
+ # @return the list of installed products in format of product_locations_on_current_os
94
+ def installed_products
95
+ if @@found_products.nil?
96
+ scan_locations = product_locations_on_current_os.clone
97
+ # add SDK as first search path
98
+ scan_locations.unshift({
99
+ expected: 'SDK',
100
+ app_root: Installation.instance.sdk_folder,
101
+ sub_bin: ''
102
+ })
103
+ # search installed products: with ascp
104
+ @@found_products = scan_locations.select! do |item| # rubocop:disable Style/ClassVars
105
+ # skip if not main folder
106
+ next false unless Dir.exist?(item[:app_root])
107
+ Log.log.debug{"Found #{item[:app_root]}"}
108
+ sub_bin = item[:sub_bin] || BIN_SUBFOLDER
109
+ item[:ascp_path] = File.join(item[:app_root], sub_bin, ascp_filename)
110
+ # skip if no ascp
111
+ next false unless File.exist?(item[:ascp_path])
112
+ # read info from product info file if present
113
+ product_info_file = "#{item[:app_root]}/#{INFO_META_FILE}"
114
+ if File.exist?(product_info_file)
115
+ res_s = XmlSimple.xml_in(File.read(product_info_file), {'ForceArray' => false})
116
+ item[:name] = res_s['name']
117
+ item[:version] = res_s['version']
118
+ else
119
+ item[:name] = item[:expected]
120
+ end
121
+ true # select this version
122
+ end
123
+ end
124
+ return @@found_products
125
+ end
126
+
127
+ # filename for ascp with optional extension (Windows)
128
+ def ascp_filename
129
+ return 'ascp' + Environment.exe_extension
130
+ end
131
+
132
+ # @return folder paths for specified applications
133
+ # @param name Connect or CLI
134
+ def folders(name)
135
+ found = Products.installed_products.select{|i|i[:expected].eql?(name) || i[:name].eql?(name)}
136
+ raise "Product: #{name} not found, please install." if found.empty?
137
+ return found.first
138
+ end
139
+
140
+ # @return the file path of local connect where API's URI can be read
141
+ def connect_uri
142
+ connect = folders(CONNECT)
143
+ folder = File.join(connect[:run_root], VAR_RUN_SUBFOLDER)
144
+ ['', 's'].each do |ext|
145
+ uri_file = File.join(folder, "http#{ext}.uri")
146
+ Log.log.debug{"checking connect port file: #{uri_file}"}
147
+ if File.exist?(uri_file)
148
+ return File.open(uri_file, &:gets).strip
149
+ end
150
+ end
151
+ raise "no connect uri file found in #{folder}"
152
+ end
153
+
154
+ # @ return path to configuration file of aspera CLI
155
+ # def cli_conf_file
156
+ # connect = folders(PRODUCT_CLI_V1)
157
+ # return File.join(connect[:app_root], BIN_SUBFOLDER, '.aspera_cli_conf')
158
+ # end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -49,11 +49,11 @@ module Aspera
49
49
  # failure in ascp
50
50
  if e.retryable?
51
51
  # exit if we exceed the max number of retry
52
- raise Fasp::Error, 'Maximum number of retry reached' if remaining_resumes <= 0
52
+ raise Fasp::Error, "Maximum number of retry reached (#{@parameters[:iter_max]})" if remaining_resumes <= 0
53
53
  else
54
54
  # give one chance only to non retryable errors
55
55
  unless remaining_resumes.eql?(@parameters[:iter_max])
56
- Log.log.error('non-retryable error')
56
+ Log.log.error('non-retryable error'.red.blink)
57
57
  raise e
58
58
  end
59
59
  end
@@ -61,7 +61,7 @@ module Aspera
61
61
 
62
62
  # take this retry in account
63
63
  remaining_resumes -= 1
64
- Log.log.warn{"resuming in #{sleep_seconds} seconds (retry left:#{remaining_resumes})"}
64
+ Log.log.warn{"Resuming in #{sleep_seconds} seconds (retry left:#{remaining_resumes})"}
65
65
 
66
66
  # wait a bit before retrying, maybe network condition will be better
67
67
  sleep(sleep_seconds)
@@ -17,11 +17,12 @@ module Aspera
17
17
  }.freeze
18
18
  # reserved tag for Aspera
19
19
  TAG_RESERVED = 'aspera'
20
- # define constants for enums of parameters: <parameter>_<enum>, e.g. CIPHER_AES_128
21
- Aspera::Fasp::Parameters.description.each do |k, v|
22
- next unless v[:enum].is_a?(Array)
23
- v[:enum].each do |enum|
24
- TransferSpec.const_set("#{k.to_s.upcase}_#{enum.upcase.gsub(/[^A-Z0-9]/, '_')}", enum.freeze)
20
+ # define constants for enums of parameters: <parameter>_<enum>, e.g. CIPHER_AES_128, DIRECTION_SEND, ...
21
+ Aspera::Fasp::Parameters.description.each do |name, description|
22
+ next unless description[:enum].is_a?(Array)
23
+ TransferSpec.const_set("#{name.to_s.upcase}_ENUM_VALUES", description[:enum])
24
+ description[:enum].each do |enum|
25
+ TransferSpec.const_set("#{name.to_s.upcase}_#{enum.upcase.gsub(/[^A-Z0-9]/, '_')}", enum.freeze)
25
26
  end
26
27
  end
27
28
  class << self
@@ -40,7 +41,7 @@ module Aspera
40
41
  return case tspec['direction']
41
42
  when DIRECTION_SEND then :upload
42
43
  when DIRECTION_RECEIVE then :download
43
- else raise 'Error: upload or download only'
44
+ else raise "Error: upload or download only, not #{tspec['direction']} (#{tspec['direction'].class})"
44
45
  end
45
46
  end
46
47
  end
@@ -1,14 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # cspell:words httpport targetrate minrate bwcap createpath lockpolicy lockminrate faspe
4
+
3
5
  require 'aspera/log'
6
+ require 'aspera/rest'
4
7
  require 'aspera/command_line_builder'
5
8
 
6
9
  module Aspera
7
10
  module Fasp
8
11
  # translates a "faspe:" URI (used in Faspex 4) into transfer spec hash
9
12
  class Uri
10
- def initialize(fasplink)
11
- @fasp_uri = URI.parse(fasplink.gsub(' ', '%20'))
13
+ SCHEME = 'faspe'
14
+ def initialize(fasp_link)
15
+ @fasp_uri = URI.parse(fasp_link.gsub(' ', '%20'))
12
16
  # TODO: check scheme is faspe
13
17
  end
14
18
 
@@ -18,32 +22,30 @@ module Aspera
18
22
  result_ts['remote_user'] = @fasp_uri.user
19
23
  result_ts['ssh_port'] = @fasp_uri.port
20
24
  result_ts['paths'] = [{'source' => URI.decode_www_form_component(@fasp_uri.path)}]
21
- # faspex does not encode trailing base64 encoded tags, fix that
25
+ # faspex does not encode trailing base64 padding, fix that to be able to decode properly
22
26
  fixed_query = @fasp_uri.query.gsub(/(=+)$/){|x|'%3D' * x.length}
23
27
 
24
- URI.decode_www_form(fixed_query).each do |i|
25
- name = i[0]
26
- value = i[1]
28
+ Rest.decode_query(fixed_query).each do |name, value|
27
29
  case name
28
- when 'cookie' then result_ts['cookie'] = value
29
- when 'token' then result_ts['token'] = value
30
- when 'sshfp' then result_ts['sshfp'] = value
31
- when 'policy' then result_ts['rate_policy'] = value
32
- when 'httpport' then result_ts['http_fallback_port'] = value.to_i
33
- when 'targetrate' then result_ts['target_rate_kbps'] = value.to_i
34
- when 'minrate' then result_ts['min_rate_kbps'] = value.to_i
35
- when 'port' then result_ts['fasp_port'] = value.to_i
36
- when 'bwcap' then result_ts['target_rate_cap_kbps'] = value.to_i
37
- when 'enc' then result_ts['cipher'] = value.gsub(/^aes/, 'aes-').gsub(/cfb$/, '-cfb').gsub(/gcm$/, '-gcm').gsub(/--/, '-')
38
- when 'tags64' then result_ts['tags'] = JSON.parse(Base64.strict_decode64(value))
39
- when 'createpath' then result_ts['create_dir'] = CommandLineBuilder.yes_to_true(value)
40
- when 'fallback' then result_ts['http_fallback'] = CommandLineBuilder.yes_to_true(value)
41
- when 'lockpolicy' then result_ts['lock_rate_policy'] = CommandLineBuilder.yes_to_true(value)
30
+ when 'cookie' then result_ts['cookie'] = value
31
+ when 'token' then result_ts['token'] = value
32
+ when 'sshfp' then result_ts['sshfp'] = value
33
+ when 'policy' then result_ts['rate_policy'] = value
34
+ when 'httpport' then result_ts['http_fallback_port'] = value.to_i
35
+ when 'targetrate' then result_ts['target_rate_kbps'] = value.to_i
36
+ when 'minrate' then result_ts['min_rate_kbps'] = value.to_i
37
+ when 'port' then result_ts['fasp_port'] = value.to_i
38
+ 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 'tags64' then result_ts['tags'] = JSON.parse(Base64.strict_decode64(value))
41
+ when 'createpath' then result_ts['create_dir'] = CommandLineBuilder.yes_to_true(value)
42
+ when 'fallback' then result_ts['http_fallback'] = CommandLineBuilder.yes_to_true(value)
43
+ when 'lockpolicy' then result_ts['lock_rate_policy'] = CommandLineBuilder.yes_to_true(value)
42
44
  when 'lockminrate' then result_ts['lock_min_rate'] = CommandLineBuilder.yes_to_true(value)
43
- when 'auth' then Log.log.debug{"ignoring auth #{name}=#{value}"} # TODO: translate into transfer spec ? yes/no
44
- when 'v' then Log.log.debug{"ignoring v #{name}=#{value}"} # TODO: translate into transfer spec ? 2
45
- when 'protect' then Log.log.debug{"ignoring protect #{name}=#{value}"} # TODO: translate into transfer spec ?
46
- else Log.log.warn{"URI parameter ignored: #{name} = #{value}"}
45
+ 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 'protect' then Log.log.debug{"ignoring #{name}=#{value}"} # rubocop:disable Lint/DuplicateBranch TODO: what is this ?
48
+ else Log.log.warn{"URI parameter ignored: #{name} = #{value}"}
47
49
  end
48
50
  end
49
51
  return result_ts
@@ -68,9 +68,9 @@ module Aspera
68
68
  faspex_pkg_parameters = JSON.parse(request.body)
69
69
  Log.log.debug{"faspex pkg create parameters=#{faspex_pkg_parameters}"}
70
70
  faspex_package_create_result =
71
- if @app_api.is_a?(Aspera::AoC)
71
+ if @app_api.class.name.eql?('Aspera::AoC')
72
72
  faspex4_send_to_aoc(faspex_pkg_parameters)
73
- elsif @app_api.is_a?(Aspera::Rest)
73
+ elsif @app_api.class.name.eql?('Aspera::Rest')
74
74
  faspex4_send_to_faspex5(faspex_pkg_parameters)
75
75
  else
76
76
  raise "No such adapter: #{@app_api.class}"
@@ -13,7 +13,7 @@ module Aspera
13
13
  def initialize(server, parameters)
14
14
  raise 'parameters must be Hash' unless parameters.is_a?(Hash)
15
15
  @parameters = parameters.symbolize_keys
16
- Log.dump(:postproc_parameters, @parameters)
16
+ Log.log.debug{Log.dump(:post_proc_parameters, @parameters)}
17
17
  raise "unexpected key in parameters config: only: #{ALLOWED_PARAMETERS.join(', ')}" if @parameters.keys.any?{|k|!ALLOWED_PARAMETERS.include?(k)}
18
18
  @parameters[:script_folder] ||= '.'
19
19
  @parameters[:fail_on_error] ||= false
@@ -44,7 +44,7 @@ module Aspera
44
44
  script_path = File.join(@parameters[:script_folder], script_file)
45
45
  Log.log.debug{"script=#{script_path}"}
46
46
  webhook_parameters = JSON.parse(request.body)
47
- Log.dump(:webhook_parameters, webhook_parameters)
47
+ Log.log.debug{Log.dump(:webhook_parameters, webhook_parameters)}
48
48
  # env expects only strings
49
49
  environment = webhook_parameters.each_with_object({}) { |(k, v), h| h[k] = v.to_s }
50
50
  post_proc_pid = Process.spawn(environment, [script_path, script_path])
@@ -2,11 +2,21 @@
2
2
 
3
3
  class ::Hash
4
4
  def deep_merge(second)
5
- merge(second){|_key, v1, v2|Hash === v1 && Hash === v2 ? v1.deep_merge(v2) : v2}
5
+ merge(second){|_key, v1, v2|v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.deep_merge(v2) : v2}
6
6
  end
7
7
 
8
8
  def deep_merge!(second)
9
- merge!(second){|_key, v1, v2|Hash === v1 && Hash === v2 ? v1.deep_merge!(v2) : v2}
9
+ merge!(second){|_key, v1, v2|v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.deep_merge!(v2) : v2}
10
+ end
11
+
12
+ def deep_do(memory=nil, &block)
13
+ each do |key, value|
14
+ if value.is_a?(Hash)
15
+ value.deep_do(memory, &block)
16
+ else
17
+ yield(self, key, value, memory)
18
+ end
19
+ end
10
20
  end
11
21
  end
12
22
 
@@ -14,8 +24,8 @@ end
14
24
  unless Hash.method_defined?(:transform_keys)
15
25
  class Hash
16
26
  def transform_keys
17
- return each_with_object({}){|(k, v), memo|memo[yield(k)] = v} if block_given?
18
- raise 'missing block'
27
+ raise 'missing block' unless block_given?
28
+ return each_with_object({}){|(k, v), memo|memo[yield(k)] = v}
19
29
  end
20
30
  end
21
31
  end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # cspell:ignore blankslate
4
+
5
+ require 'aspera/rest_error_analyzer'
6
+ require 'blankslate'
7
+
8
+ Aspera::RestErrorAnalyzer.instance.add_simple_handler(name: 'JSON RPC', path: %w[error message], always: true)
9
+
10
+ module Aspera
11
+ # a very simple JSON RPC client
12
+ class JsonRpcClient < BlankSlate
13
+ JSON_RPC_VERSION = '2.0'
14
+ reveal :instance_variable_get
15
+ reveal :inspect
16
+ reveal :to_s
17
+
18
+ def initialize(api, namespace = nil)
19
+ super()
20
+ @api = api
21
+ @namespace = namespace
22
+ @request_id = 0
23
+ end
24
+
25
+ def respond_to_missing?(sym, include_private = false)
26
+ true
27
+ end
28
+
29
+ def method_missing(method, *args, &block)
30
+ args = args.first if args.size == 1 && args.first.is_a?(Hash)
31
+ data = @api.create('', {
32
+ jsonrpc: JSON_RPC_VERSION,
33
+ method: "#{@namespace}#{method}",
34
+ params: args,
35
+ id: @request_id += 1
36
+ })[:data]
37
+ raise 'response shall be Hash' unless data.is_a?(Hash)
38
+ raise 'bad version in response' unless data['jsonrpc'] == JSON_RPC_VERSION
39
+ raise 'missing id in response' unless data.key?('id')
40
+ raise 'both error and response' if data.key?('error') && data.key?('result')
41
+ raise 'bad error response' unless
42
+ !data.key?('error') ||
43
+ data['error'].is_a?(Hash) &&
44
+ data['error']['code'].is_a?(Integer) &&
45
+ data['error']['message'].is_a?(String)
46
+ return data['result']
47
+ end
48
+ end
49
+ end