aspera-cli 4.19.0 → 4.21.1
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 +46 -0
 - data/CONTRIBUTING.md +18 -4
 - data/README.md +886 -510
 - data/bin/asession +27 -20
 - data/examples/build_exec +65 -76
 - data/examples/build_exec_rubyc +40 -0
 - data/examples/get_proto_file.rb +7 -0
 - data/lib/aspera/agent/alpha.rb +18 -24
 - data/lib/aspera/agent/base.rb +2 -18
 - data/lib/aspera/agent/connect.rb +34 -15
 - data/lib/aspera/agent/direct.rb +44 -54
 - data/lib/aspera/agent/httpgw.rb +2 -3
 - data/lib/aspera/agent/node.rb +11 -21
 - data/lib/aspera/agent/{trsdk.rb → transferd.rb} +27 -51
 - data/lib/aspera/api/alee.rb +15 -0
 - data/lib/aspera/api/aoc.rb +139 -105
 - data/lib/aspera/api/ats.rb +1 -1
 - data/lib/aspera/api/cos_node.rb +1 -1
 - data/lib/aspera/api/httpgw.rb +15 -10
 - data/lib/aspera/api/node.rb +70 -32
 - data/lib/aspera/ascmd.rb +56 -48
 - data/lib/aspera/ascp/installation.rb +166 -70
 - data/lib/aspera/ascp/management.rb +30 -8
 - data/lib/aspera/assert.rb +10 -5
 - data/lib/aspera/cli/formatter.rb +166 -162
 - data/lib/aspera/cli/hints.rb +2 -1
 - data/lib/aspera/cli/info.rb +12 -10
 - data/lib/aspera/cli/main.rb +28 -13
 - data/lib/aspera/cli/manager.rb +7 -2
 - data/lib/aspera/cli/plugin.rb +17 -31
 - data/lib/aspera/cli/plugins/alee.rb +3 -3
 - data/lib/aspera/cli/plugins/aoc.rb +246 -208
 - data/lib/aspera/cli/plugins/ats.rb +16 -14
 - data/lib/aspera/cli/plugins/config.rb +154 -94
 - data/lib/aspera/cli/plugins/console.rb +3 -3
 - data/lib/aspera/cli/plugins/cos.rb +1 -0
 - data/lib/aspera/cli/plugins/faspex.rb +15 -23
 - data/lib/aspera/cli/plugins/faspex5.rb +64 -50
 - data/lib/aspera/cli/plugins/faspio.rb +2 -2
 - data/lib/aspera/cli/plugins/httpgw.rb +1 -1
 - data/lib/aspera/cli/plugins/node.rb +174 -109
 - data/lib/aspera/cli/plugins/orchestrator.rb +14 -13
 - data/lib/aspera/cli/plugins/preview.rb +8 -9
 - data/lib/aspera/cli/plugins/server.rb +5 -9
 - data/lib/aspera/cli/plugins/shares.rb +2 -2
 - data/lib/aspera/cli/sync_actions.rb +2 -2
 - data/lib/aspera/cli/transfer_agent.rb +12 -14
 - data/lib/aspera/cli/transfer_progress.rb +37 -17
 - data/lib/aspera/cli/version.rb +1 -1
 - data/lib/aspera/command_line_builder.rb +4 -5
 - data/lib/aspera/coverage.rb +13 -1
 - data/lib/aspera/environment.rb +75 -25
 - data/lib/aspera/faspex_gw.rb +2 -2
 - data/lib/aspera/json_rpc.rb +1 -1
 - data/lib/aspera/keychain/macos_security.rb +7 -12
 - data/lib/aspera/log.rb +3 -4
 - data/lib/aspera/node_simulator.rb +230 -112
 - data/lib/aspera/oauth/base.rb +64 -83
 - data/lib/aspera/oauth/factory.rb +52 -6
 - data/lib/aspera/oauth/generic.rb +4 -8
 - data/lib/aspera/oauth/jwt.rb +6 -3
 - data/lib/aspera/oauth/url_json.rb +1 -2
 - data/lib/aspera/oauth/web.rb +5 -2
 - data/lib/aspera/persistency_action_once.rb +16 -8
 - data/lib/aspera/persistency_folder.rb +20 -2
 - data/lib/aspera/preview/generator.rb +1 -1
 - data/lib/aspera/preview/utils.rb +11 -17
 - data/lib/aspera/products/alpha.rb +30 -0
 - data/lib/aspera/products/connect.rb +48 -0
 - data/lib/aspera/products/other.rb +82 -0
 - data/lib/aspera/products/transferd.rb +54 -0
 - data/lib/aspera/rest.rb +116 -87
 - data/lib/aspera/secret_hider.rb +2 -2
 - data/lib/aspera/ssh.rb +31 -24
 - data/lib/aspera/transfer/faux_file.rb +4 -4
 - data/lib/aspera/transfer/parameters.rb +16 -17
 - data/lib/aspera/transfer/spec.rb +12 -12
 - data/lib/aspera/transfer/spec.yaml +22 -20
 - data/lib/aspera/transfer/sync.rb +2 -10
 - data/lib/aspera/transfer/uri.rb +3 -3
 - data/lib/aspera/uri_reader.rb +1 -1
 - data/lib/aspera/web_auth.rb +166 -17
 - data/lib/aspera/web_server_simple.rb +4 -3
 - data/lib/transferd_pb.rb +86 -0
 - data/lib/transferd_services_pb.rb +84 -0
 - data.tar.gz.sig +0 -0
 - metadata +58 -22
 - metadata.gz.sig +0 -0
 - data/lib/aspera/ascp/products.rb +0 -156
 
| 
         @@ -22,6 +22,10 @@ module Aspera 
     | 
|
| 
       22 
22 
     | 
    
         
             
                  class Node < Cli::BasicAuthPlugin
         
     | 
| 
       23 
23 
     | 
    
         
             
                    include SyncActions
         
     | 
| 
       24 
24 
     | 
    
         
             
                    class << self
         
     | 
| 
      
 25 
     | 
    
         
            +
                      # directory: node, container: shares
         
     | 
| 
      
 26 
     | 
    
         
            +
                      FOLDER_TYPES = %w[directory container].freeze
         
     | 
| 
      
 27 
     | 
    
         
            +
                      private_constant :FOLDER_TYPES
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
       25 
29 
     | 
    
         
             
                      def application_name
         
     | 
| 
       26 
30 
     | 
    
         
             
                        'HSTS Node API'
         
     | 
| 
       27 
31 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -43,9 +47,9 @@ module Aspera 
     | 
|
| 
       43 
47 
     | 
    
         
             
                          test_endpoint = 'ping'
         
     | 
| 
       44 
48 
     | 
    
         
             
                          result = api.call(operation: 'GET', subpath: test_endpoint)
         
     | 
| 
       45 
49 
     | 
    
         
             
                          next unless result[:http].body.eql?('')
         
     | 
| 
       46 
     | 
    
         
            -
                           
     | 
| 
      
 50 
     | 
    
         
            +
                          url_end = -2 - test_endpoint.length
         
     | 
| 
       47 
51 
     | 
    
         
             
                          return {
         
     | 
| 
       48 
     | 
    
         
            -
                            url:     result[:http].uri.to_s[0.. 
     | 
| 
      
 52 
     | 
    
         
            +
                            url:     result[:http].uri.to_s[0..url_end],
         
     | 
| 
       49 
53 
     | 
    
         
             
                            version: 'requires authentication'
         
     | 
| 
       50 
54 
     | 
    
         
             
                          }
         
     | 
| 
       51 
55 
     | 
    
         
             
                        rescue StandardError => e
         
     | 
| 
         @@ -69,16 +73,25 @@ module Aspera 
     | 
|
| 
       69 
73 
     | 
    
         
             
                      end
         
     | 
| 
       70 
74 
     | 
    
         | 
| 
       71 
75 
     | 
    
         
             
                      def declare_options(options)
         
     | 
| 
      
 76 
     | 
    
         
            +
                        return if @options_declared
         
     | 
| 
      
 77 
     | 
    
         
            +
                        @options_declared = true
         
     | 
| 
       72 
78 
     | 
    
         
             
                        options.declare(:validator, 'Identifier of validator (optional for central)')
         
     | 
| 
       73 
79 
     | 
    
         
             
                        options.declare(:asperabrowserurl, 'URL for simple aspera web ui', default: 'https://asperabrowser.mybluemix.net')
         
     | 
| 
       74 
80 
     | 
    
         
             
                        options.declare(:sync_name, 'Sync name')
         
     | 
| 
       75 
81 
     | 
    
         
             
                        options.declare(
         
     | 
| 
       76 
82 
     | 
    
         
             
                          :default_ports, 'Use standard FASP ports or get from node api (gen4)', values: :bool, default: :yes,
         
     | 
| 
       77 
83 
     | 
    
         
             
                          handler: {o: Api::Node, m: :use_standard_ports})
         
     | 
| 
       78 
     | 
    
         
            -
                        options.declare( 
     | 
| 
      
 84 
     | 
    
         
            +
                        options.declare(
         
     | 
| 
      
 85 
     | 
    
         
            +
                          :node_cache, 'Set to no to force actual file system read (gen4)', values: :bool,
         
     | 
| 
      
 86 
     | 
    
         
            +
                          handler: {o: Api::Node, m: :use_node_cache})
         
     | 
| 
      
 87 
     | 
    
         
            +
                        options.declare(:root_id, 'File id of top folder when using access key (override AK root id)')
         
     | 
| 
       79 
88 
     | 
    
         
             
                        SyncActions.declare_options(options)
         
     | 
| 
       80 
89 
     | 
    
         
             
                        options.parse_options!
         
     | 
| 
       81 
90 
     | 
    
         
             
                      end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                      def gen3_entry_folder?(entry)
         
     | 
| 
      
 93 
     | 
    
         
            +
                        FOLDER_TYPES.include?(entry['type'])
         
     | 
| 
      
 94 
     | 
    
         
            +
                      end
         
     | 
| 
       82 
95 
     | 
    
         
             
                    end
         
     | 
| 
       83 
96 
     | 
    
         | 
| 
       84 
97 
     | 
    
         
             
                    # spellchecker: disable
         
     | 
| 
         @@ -114,10 +127,13 @@ module Aspera 
     | 
|
| 
       114 
127 
     | 
    
         
             
                    # commands for execute_command_gen4
         
     | 
| 
       115 
128 
     | 
    
         
             
                    COMMANDS_GEN4 = %i[mkdir rename delete upload download sync http_node_download show modify permission thumbnail v3].concat(NODE4_READ_ACTIONS).freeze
         
     | 
| 
       116 
129 
     | 
    
         | 
| 
      
 130 
     | 
    
         
            +
                    # commands supported in ATS for COS
         
     | 
| 
       117 
131 
     | 
    
         
             
                    COMMANDS_COS = %i[upload download info access_keys api_details transfer].freeze
         
     | 
| 
       118 
132 
     | 
    
         
             
                    COMMANDS_SHARES = (BASE_ACTIONS - %i[search]).freeze
         
     | 
| 
       119 
133 
     | 
    
         
             
                    COMMANDS_FASPEX = COMMON_ACTIONS
         
     | 
| 
       120 
134 
     | 
    
         | 
| 
      
 135 
     | 
    
         
            +
                    GEN4_LS_FIELDS = %w[name type recursive_size size modified_time access_level].freeze
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
       121 
137 
     | 
    
         
             
                    def initialize(api: nil, **env)
         
     | 
| 
       122 
138 
     | 
    
         
             
                      super(**env, basic_options: api.nil?)
         
     | 
| 
       123 
139 
     | 
    
         
             
                      Node.declare_options(options) if api.nil?
         
     | 
| 
         @@ -164,7 +180,7 @@ module Aspera 
     | 
|
| 
       164 
180 
     | 
    
         
             
                    def c_result_translate_rem_prefix(response, type, success_msg, path_prefix)
         
     | 
| 
       165 
181 
     | 
    
         
             
                      errors = []
         
     | 
| 
       166 
182 
     | 
    
         
             
                      final_result = {type: :object_list, data: [], fields: [type, 'result']}
         
     | 
| 
       167 
     | 
    
         
            -
                       
     | 
| 
      
 183 
     | 
    
         
            +
                      response['paths'].each do |p|
         
     | 
| 
       168 
184 
     | 
    
         
             
                        result = success_msg
         
     | 
| 
       169 
185 
     | 
    
         
             
                        if p.key?('error')
         
     | 
| 
       170 
186 
     | 
    
         
             
                          Log.log.error{"#{p['error']['user_message']} : #{p['path']}"}
         
     | 
| 
         @@ -180,9 +196,6 @@ module Aspera 
     | 
|
| 
       180 
196 
     | 
    
         
             
                      return c_result_remove_prefix_path(final_result, type, path_prefix)
         
     | 
| 
       181 
197 
     | 
    
         
             
                    end
         
     | 
| 
       182 
198 
     | 
    
         | 
| 
       183 
     | 
    
         
            -
                    # directory: node, container: shares
         
     | 
| 
       184 
     | 
    
         
            -
                    FOLDER_TYPE = %w[directory container].freeze
         
     | 
| 
       185 
     | 
    
         
            -
             
     | 
| 
       186 
199 
     | 
    
         
             
                    def browse_gen3(prefix_path)
         
     | 
| 
       187 
200 
     | 
    
         
             
                      folders_to_process = [get_one_argument_with_prefix(prefix_path, 'path')]
         
     | 
| 
       188 
201 
     | 
    
         
             
                      query = options.get_option(:query, default: {})
         
     | 
| 
         @@ -206,26 +219,21 @@ module Aspera 
     | 
|
| 
       206 
219 
     | 
    
         
             
                        result = nil
         
     | 
| 
       207 
220 
     | 
    
         
             
                        loop do
         
     | 
| 
       208 
221 
     | 
    
         
             
                          # example: send_result={'items'=>[{'file'=>"filename1","permissions"=>[{'name'=>'read'},{'name'=>'write'}]}]}
         
     | 
| 
       209 
     | 
    
         
            -
                          response = @api_node. 
     | 
| 
       210 
     | 
    
         
            -
                            operation:   'POST',
         
     | 
| 
       211 
     | 
    
         
            -
                            subpath:     'files/browse',
         
     | 
| 
       212 
     | 
    
         
            -
                            headers:     {'Accept' => 'application/json'},
         
     | 
| 
       213 
     | 
    
         
            -
                            body:        query,
         
     | 
| 
       214 
     | 
    
         
            -
                            body_type:   :json)
         
     | 
| 
      
 222 
     | 
    
         
            +
                          response = @api_node.create('files/browse', query)
         
     | 
| 
       215 
223 
     | 
    
         
             
                          # 'file','symbolic_link'
         
     | 
| 
       216 
     | 
    
         
            -
                          if  
     | 
| 
       217 
     | 
    
         
            -
                            result = { type: :single_object, data: response[ 
     | 
| 
      
 224 
     | 
    
         
            +
                          if !Node.gen3_entry_folder?(response['self']) || only_path
         
     | 
| 
      
 225 
     | 
    
         
            +
                            result = { type: :single_object, data: response['self']}
         
     | 
| 
       218 
226 
     | 
    
         
             
                            break
         
     | 
| 
       219 
227 
     | 
    
         
             
                          end
         
     | 
| 
       220 
     | 
    
         
            -
                          items = response[ 
     | 
| 
       221 
     | 
    
         
            -
                          total_count ||= response[ 
     | 
| 
      
 228 
     | 
    
         
            +
                          items = response['items']
         
     | 
| 
      
 229 
     | 
    
         
            +
                          total_count ||= response['total_count']
         
     | 
| 
       222 
230 
     | 
    
         
             
                          all_items.concat(items)
         
     | 
| 
       223 
231 
     | 
    
         
             
                          if single_call
         
     | 
| 
       224 
     | 
    
         
            -
                            formatter.display_item_count(response[ 
     | 
| 
      
 232 
     | 
    
         
            +
                            formatter.display_item_count(response['item_count'], total_count)
         
     | 
| 
       225 
233 
     | 
    
         
             
                            break
         
     | 
| 
       226 
234 
     | 
    
         
             
                          end
         
     | 
| 
       227 
235 
     | 
    
         
             
                          if recursive
         
     | 
| 
       228 
     | 
    
         
            -
                            folders_to_process.concat(items.select{|i| 
     | 
| 
      
 236 
     | 
    
         
            +
                            folders_to_process.concat(items.select{|i|Node.gen3_entry_folder?(i)}.map{|i|i['path']})
         
     | 
| 
       229 
237 
     | 
    
         
             
                          end
         
     | 
| 
       230 
238 
     | 
    
         
             
                          if !max_items.nil? && (all_items.count >= max_items)
         
     | 
| 
       231 
239 
     | 
    
         
             
                            all_items = all_items.slice(0, max_items) if all_items.count > max_items
         
     | 
| 
         @@ -239,6 +247,7 @@ module Aspera 
     | 
|
| 
       239 
247 
     | 
    
         
             
                        query.delete('skip')
         
     | 
| 
       240 
248 
     | 
    
         
             
                      end
         
     | 
| 
       241 
249 
     | 
    
         
             
                      result ||= {type: :object_list, data: all_items}
         
     | 
| 
      
 250 
     | 
    
         
            +
                      formatter.long_operation_terminated
         
     | 
| 
       242 
251 
     | 
    
         
             
                      return c_result_remove_prefix_path(result, 'path', prefix_path)
         
     | 
| 
       243 
252 
     | 
    
         
             
                    end
         
     | 
| 
       244 
253 
     | 
    
         | 
| 
         @@ -253,19 +262,19 @@ module Aspera 
     | 
|
| 
       253 
262 
     | 
    
         
             
                      when :search
         
     | 
| 
       254 
263 
     | 
    
         
             
                        search_root = get_one_argument_with_prefix(prefix_path, 'search root')
         
     | 
| 
       255 
264 
     | 
    
         
             
                        parameters = {'path' => search_root}
         
     | 
| 
       256 
     | 
    
         
            -
                        other_options =  
     | 
| 
      
 265 
     | 
    
         
            +
                        other_options = options.get_option(:query)
         
     | 
| 
       257 
266 
     | 
    
         
             
                        parameters.merge!(other_options) unless other_options.nil?
         
     | 
| 
       258 
267 
     | 
    
         
             
                        resp = @api_node.create('files/search', parameters)
         
     | 
| 
       259 
     | 
    
         
            -
                        result = { type: :object_list, data: resp[ 
     | 
| 
      
 268 
     | 
    
         
            +
                        result = { type: :object_list, data: resp['items']}
         
     | 
| 
       260 
269 
     | 
    
         
             
                        return Main.result_empty if result[:data].empty?
         
     | 
| 
       261 
270 
     | 
    
         
             
                        result[:fields] = result[:data].first.keys.reject{|i|SEARCH_REMOVE_FIELDS.include?(i)}
         
     | 
| 
       262 
     | 
    
         
            -
                        formatter.display_item_count(resp[ 
     | 
| 
       263 
     | 
    
         
            -
                        formatter.display_status("params: #{resp[ 
     | 
| 
      
 271 
     | 
    
         
            +
                        formatter.display_item_count(resp['item_count'], resp['total_count'])
         
     | 
| 
      
 272 
     | 
    
         
            +
                        formatter.display_status("params: #{resp['parameters'].keys.map{|k|"#{k}:#{resp['parameters'][k]}"}.join(',')}")
         
     | 
| 
       264 
273 
     | 
    
         
             
                        return c_result_remove_prefix_path(result, 'path', prefix_path)
         
     | 
| 
       265 
274 
     | 
    
         
             
                      when :space
         
     | 
| 
       266 
275 
     | 
    
         
             
                        path_list = get_all_arguments_with_prefix(prefix_path, 'folder path or ext.val. list')
         
     | 
| 
       267 
276 
     | 
    
         
             
                        resp = @api_node.create('space', { 'paths' => path_list.map {|i| { path: i} } })
         
     | 
| 
       268 
     | 
    
         
            -
                        result = { type: :object_list, data: resp[ 
     | 
| 
      
 277 
     | 
    
         
            +
                        result = { type: :object_list, data: resp['paths']}
         
     | 
| 
       269 
278 
     | 
    
         
             
                        # return c_result_translate_rem_prefix(resp,'folder','created',prefix_path)
         
     | 
| 
       270 
279 
     | 
    
         
             
                        return c_result_remove_prefix_path(result, 'path', prefix_path)
         
     | 
| 
       271 
280 
     | 
    
         
             
                      when :mkdir
         
     | 
| 
         @@ -311,7 +320,7 @@ module Aspera 
     | 
|
| 
       311 
320 
     | 
    
         
             
                          # prepare payload for single request
         
     | 
| 
       312 
321 
     | 
    
         
             
                          setup_payload = {transfer_requests: [{transfer_request: request_transfer_spec}]}
         
     | 
| 
       313 
322 
     | 
    
         
             
                          # only one request, so only one answer
         
     | 
| 
       314 
     | 
    
         
            -
                          transfer_spec = @api_node.create('files/sync_setup', setup_payload)[ 
     | 
| 
      
 323 
     | 
    
         
            +
                          transfer_spec = @api_node.create('files/sync_setup', setup_payload)['transfer_specs'].first['transfer_spec']
         
     | 
| 
       315 
324 
     | 
    
         
             
                          # API returns null tag... but async does not like it
         
     | 
| 
       316 
325 
     | 
    
         
             
                          transfer_spec.delete_if{ |_k, v| v.nil? }
         
     | 
| 
       317 
326 
     | 
    
         
             
                          # delete this part, as the returned value contains only destination, and not sources
         
     | 
| 
         @@ -333,7 +342,7 @@ module Aspera 
     | 
|
| 
       333 
342 
     | 
    
         
             
                        # prepare payload for single request
         
     | 
| 
       334 
343 
     | 
    
         
             
                        setup_payload = {transfer_requests: [{transfer_request: request_transfer_spec}]}
         
     | 
| 
       335 
344 
     | 
    
         
             
                        # only one request, so only one answer
         
     | 
| 
       336 
     | 
    
         
            -
                        transfer_spec = @api_node.create("files/#{command}_setup", setup_payload)[ 
     | 
| 
      
 345 
     | 
    
         
            +
                        transfer_spec = @api_node.create("files/#{command}_setup", setup_payload)['transfer_specs'].first['transfer_spec']
         
     | 
| 
       337 
346 
     | 
    
         
             
                        # delete this part, as the returned value contains only destination, and not sources
         
     | 
| 
       338 
347 
     | 
    
         
             
                        transfer_spec.delete('paths') if command.eql?(:upload)
         
     | 
| 
       339 
348 
     | 
    
         
             
                        return Main.result_transfer(transfer.start(transfer_spec))
         
     | 
| 
         @@ -363,13 +372,13 @@ module Aspera 
     | 
|
| 
       363 
372 
     | 
    
         
             
                        when *Plugin::ALL_OPS
         
     | 
| 
       364 
373 
     | 
    
         
             
                          return entity_command(ak_command, @api_node, 'access_keys') do |field, value|
         
     | 
| 
       365 
374 
     | 
    
         
             
                                   raise 'only selector: %id:self' unless field.eql?('id') && value.eql?('self')
         
     | 
| 
       366 
     | 
    
         
            -
                                   @api_node.read('access_keys/self')[ 
     | 
| 
      
 375 
     | 
    
         
            +
                                   @api_node.read('access_keys/self')['id']
         
     | 
| 
       367 
376 
     | 
    
         
             
                                 end
         
     | 
| 
       368 
377 
     | 
    
         
             
                        when :do
         
     | 
| 
       369 
378 
     | 
    
         
             
                          access_key_id = options.get_next_argument('access key id')
         
     | 
| 
       370 
379 
     | 
    
         
             
                          root_file_id = options.get_option(:root_id)
         
     | 
| 
       371 
380 
     | 
    
         
             
                          if root_file_id.nil?
         
     | 
| 
       372 
     | 
    
         
            -
                            ak_info = @api_node.read("access_keys/#{access_key_id}") 
     | 
| 
      
 381 
     | 
    
         
            +
                            ak_info = @api_node.read("access_keys/#{access_key_id}")
         
     | 
| 
       373 
382 
     | 
    
         
             
                            # change API credentials if different access key
         
     | 
| 
       374 
383 
     | 
    
         
             
                            if !access_key_id.eql?('self')
         
     | 
| 
       375 
384 
     | 
    
         
             
                              @api_node.auth_params[:username] = ak_info['id']
         
     | 
| 
         @@ -381,7 +390,7 @@ module Aspera 
     | 
|
| 
       381 
390 
     | 
    
         
             
                          return execute_command_gen4(command_repo, root_file_id)
         
     | 
| 
       382 
391 
     | 
    
         
             
                        when :set_bearer_key
         
     | 
| 
       383 
392 
     | 
    
         
             
                          access_key_id = options.get_next_argument('access key id')
         
     | 
| 
       384 
     | 
    
         
            -
                          access_key_id = @api_node.read('access_keys/self')[ 
     | 
| 
      
 393 
     | 
    
         
            +
                          access_key_id = @api_node.read('access_keys/self')['id'] if access_key_id.eql?('self')
         
     | 
| 
       385 
394 
     | 
    
         
             
                          bearer_key_pem = options.get_next_argument('public or private RSA key PEM value', validation: String)
         
     | 
| 
       386 
395 
     | 
    
         
             
                          key = OpenSSL::PKey.read(bearer_key_pem)
         
     | 
| 
       387 
396 
     | 
    
         
             
                          key = key.public_key if key.private?
         
     | 
| 
         @@ -392,7 +401,7 @@ module Aspera 
     | 
|
| 
       392 
401 
     | 
    
         
             
                      when :health
         
     | 
| 
       393 
402 
     | 
    
         
             
                        nagios = Nagios.new
         
     | 
| 
       394 
403 
     | 
    
         
             
                        begin
         
     | 
| 
       395 
     | 
    
         
            -
                          info = @api_node.read('info') 
     | 
| 
      
 404 
     | 
    
         
            +
                          info = @api_node.read('info')
         
     | 
| 
       396 
405 
     | 
    
         
             
                          nagios.add_ok('node api', 'accessible')
         
     | 
| 
       397 
406 
     | 
    
         
             
                          nagios.check_time_offset(info['current_time'], 'node api')
         
     | 
| 
       398 
407 
     | 
    
         
             
                          nagios.check_product_version('node api', 'entsrv', info['version'])
         
     | 
| 
         @@ -412,17 +421,17 @@ module Aspera 
     | 
|
| 
       412 
421 
     | 
    
         
             
                        end
         
     | 
| 
       413 
422 
     | 
    
         
             
                        return nagios.result
         
     | 
| 
       414 
423 
     | 
    
         
             
                      when :events
         
     | 
| 
       415 
     | 
    
         
            -
                        events = @api_node.read('events', query_read_delete) 
     | 
| 
      
 424 
     | 
    
         
            +
                        events = @api_node.read('events', query_read_delete)
         
     | 
| 
       416 
425 
     | 
    
         
             
                        return { type: :object_list, data: events, fields: ->(f){!f.start_with?('data')} }
         
     | 
| 
       417 
426 
     | 
    
         
             
                      when :info
         
     | 
| 
       418 
     | 
    
         
            -
                        nd_info = @api_node.read('info') 
     | 
| 
      
 427 
     | 
    
         
            +
                        nd_info = @api_node.read('info')
         
     | 
| 
       419 
428 
     | 
    
         
             
                        return { type: :single_object, data: nd_info}
         
     | 
| 
       420 
429 
     | 
    
         
             
                      when :slash
         
     | 
| 
       421 
     | 
    
         
            -
                        nd_info = @api_node.read('') 
     | 
| 
      
 430 
     | 
    
         
            +
                        nd_info = @api_node.read('')
         
     | 
| 
       422 
431 
     | 
    
         
             
                        return { type: :single_object, data: nd_info}
         
     | 
| 
       423 
432 
     | 
    
         
             
                      when :license
         
     | 
| 
       424 
433 
     | 
    
         
             
                        # requires: asnodeadmin -mu <node user> --acl-add=internal --internal
         
     | 
| 
       425 
     | 
    
         
            -
                        node_license = @api_node.read('license') 
     | 
| 
      
 434 
     | 
    
         
            +
                        node_license = @api_node.read('license')
         
     | 
| 
       426 
435 
     | 
    
         
             
                        if node_license['failure'].is_a?(String) && node_license['failure'].include?('ACL')
         
     | 
| 
       427 
436 
     | 
    
         
             
                          Log.log.error('server must have: asnodeadmin -mu <node user> --acl-add=internal --internal')
         
     | 
| 
       428 
437 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -432,8 +441,8 @@ module Aspera 
     | 
|
| 
       432 
441 
     | 
    
         
             
                      end
         
     | 
| 
       433 
442 
     | 
    
         
             
                    end
         
     | 
| 
       434 
443 
     | 
    
         | 
| 
       435 
     | 
    
         
            -
                    #  
     | 
| 
       436 
     | 
    
         
            -
                    #  
     | 
| 
      
 444 
     | 
    
         
            +
                    # Allows to specify a file by its path or by its id on the node in command line
         
     | 
| 
      
 445 
     | 
    
         
            +
                    # @return [Hash] api and main file id for given path or id in next argument
         
     | 
| 
       437 
446 
     | 
    
         
             
                    def apifid_from_next_arg(top_file_id)
         
     | 
| 
       438 
447 
     | 
    
         
             
                      file_path = instance_identifier(description: 'path or %id:<id>') do |attribute, value|
         
     | 
| 
       439 
448 
     | 
    
         
             
                        raise 'Only selection "id" is supported (file id)' unless attribute.eql?('id')
         
     | 
| 
         @@ -445,6 +454,9 @@ module Aspera 
     | 
|
| 
       445 
454 
     | 
    
         
             
                    end
         
     | 
| 
       446 
455 
     | 
    
         | 
| 
       447 
456 
     | 
    
         
             
                    def execute_command_gen4(command_repo, top_file_id)
         
     | 
| 
      
 457 
     | 
    
         
            +
                      override_file_id = options.get_option(:root_id)
         
     | 
| 
      
 458 
     | 
    
         
            +
                      top_file_id = override_file_id unless override_file_id.nil?
         
     | 
| 
      
 459 
     | 
    
         
            +
                      raise 'Specify root file id with option root_id' if top_file_id.nil?
         
     | 
| 
       448 
460 
     | 
    
         
             
                      case command_repo
         
     | 
| 
       449 
461 
     | 
    
         
             
                      when :v3
         
     | 
| 
       450 
462 
     | 
    
         
             
                        # NOTE: other common actions are unauthorized with user scope
         
     | 
| 
         @@ -453,7 +465,7 @@ module Aspera 
     | 
|
| 
       453 
465 
     | 
    
         
             
                        apifid = @api_node.resolve_api_fid(top_file_id, '')
         
     | 
| 
       454 
466 
     | 
    
         
             
                        return Node.new(**init_params, api: apifid[:api]).execute_action(command_legacy)
         
     | 
| 
       455 
467 
     | 
    
         
             
                      when :node_info, :bearer_token_node
         
     | 
| 
       456 
     | 
    
         
            -
                        apifid =  
     | 
| 
      
 468 
     | 
    
         
            +
                        apifid = apifid_from_next_arg(top_file_id)
         
     | 
| 
       457 
469 
     | 
    
         
             
                        result = {
         
     | 
| 
       458 
470 
     | 
    
         
             
                          url:     apifid[:api].base_url,
         
     | 
| 
       459 
471 
     | 
    
         
             
                          root_id: apifid[:file_id]
         
     | 
| 
         @@ -473,36 +485,41 @@ module Aspera 
     | 
|
| 
       473 
485 
     | 
    
         
             
                        OAuth::Factory.bearer_extract(result[:password])
         
     | 
| 
       474 
486 
     | 
    
         
             
                        return Main.result_status(result[:password])
         
     | 
| 
       475 
487 
     | 
    
         
             
                      when :browse
         
     | 
| 
       476 
     | 
    
         
            -
                        apifid =  
     | 
| 
       477 
     | 
    
         
            -
                        file_info = apifid[:api]. 
     | 
| 
       478 
     | 
    
         
            -
                         
     | 
| 
       479 
     | 
    
         
            -
                           
     | 
| 
       480 
     | 
    
         
            -
                           
     | 
| 
       481 
     | 
    
         
            -
                          formatter.display_item_count(result[:data].length, result[:http]['X-Total-Count'])
         
     | 
| 
       482 
     | 
    
         
            -
                        else
         
     | 
| 
       483 
     | 
    
         
            -
                          items = [file_info]
         
     | 
| 
      
 488 
     | 
    
         
            +
                        apifid = apifid_from_next_arg(top_file_id)
         
     | 
| 
      
 489 
     | 
    
         
            +
                        file_info = apifid[:api].read_with_cache("files/#{apifid[:file_id]}")
         
     | 
| 
      
 490 
     | 
    
         
            +
                        unless file_info['type'].eql?('folder')
         
     | 
| 
      
 491 
     | 
    
         
            +
                          # a single file
         
     | 
| 
      
 492 
     | 
    
         
            +
                          return {type: :object_list, data: [file_info], fields: GEN4_LS_FIELDS}
         
     | 
| 
       484 
493 
     | 
    
         
             
                        end
         
     | 
| 
       485 
     | 
    
         
            -
                        return {type: :object_list, data:  
     | 
| 
      
 494 
     | 
    
         
            +
                        return {type: :object_list, data: apifid[:api].list_files(apifid[:file_id]), fields: GEN4_LS_FIELDS}
         
     | 
| 
       486 
495 
     | 
    
         
             
                      when :find
         
     | 
| 
       487 
     | 
    
         
            -
                        apifid =  
     | 
| 
       488 
     | 
    
         
            -
                         
     | 
| 
       489 
     | 
    
         
            -
                        return {type: :object_list, data: @api_node.find_files(apifid[:file_id],  
     | 
| 
      
 496 
     | 
    
         
            +
                        apifid = apifid_from_next_arg(top_file_id)
         
     | 
| 
      
 497 
     | 
    
         
            +
                        find_lambda = Api::Node.file_matcher_from_argument(options)
         
     | 
| 
      
 498 
     | 
    
         
            +
                        return {type: :object_list, data: @api_node.find_files(apifid[:file_id], find_lambda), fields: ['path']}
         
     | 
| 
       490 
499 
     | 
    
         
             
                      when :mkdir
         
     | 
| 
       491 
500 
     | 
    
         
             
                        containing_folder_path = options.get_next_argument('path').split(Api::Node::PATH_SEPARATOR)
         
     | 
| 
       492 
501 
     | 
    
         
             
                        new_folder = containing_folder_path.pop
         
     | 
| 
       493 
     | 
    
         
            -
                         
     | 
| 
       494 
     | 
    
         
            -
                         
     | 
| 
      
 502 
     | 
    
         
            +
                        # add trailing slash to force last link to be resolved
         
     | 
| 
      
 503 
     | 
    
         
            +
                        apifid = @api_node.resolve_api_fid(top_file_id, containing_folder_path.join(Api::Node::PATH_SEPARATOR), true)
         
     | 
| 
      
 504 
     | 
    
         
            +
                        result = apifid[:api].create("files/#{apifid[:file_id]}/files", {name: new_folder, type: :folder})
         
     | 
| 
       495 
505 
     | 
    
         
             
                        return Main.result_status("created: #{result['name']} (id=#{result['id']})")
         
     | 
| 
       496 
506 
     | 
    
         
             
                      when :rename
         
     | 
| 
       497 
507 
     | 
    
         
             
                        file_path = options.get_next_argument('source path')
         
     | 
| 
       498 
508 
     | 
    
         
             
                        apifid = @api_node.resolve_api_fid(top_file_id, file_path)
         
     | 
| 
       499 
509 
     | 
    
         
             
                        newname = options.get_next_argument('new name')
         
     | 
| 
       500 
     | 
    
         
            -
                        result = apifid[:api].update("files/#{apifid[:file_id]}", {name: newname}) 
     | 
| 
      
 510 
     | 
    
         
            +
                        result = apifid[:api].update("files/#{apifid[:file_id]}", {name: newname})
         
     | 
| 
       501 
511 
     | 
    
         
             
                        return Main.result_status("renamed to #{newname}")
         
     | 
| 
       502 
512 
     | 
    
         
             
                      when :delete
         
     | 
| 
       503 
513 
     | 
    
         
             
                        return do_bulk_operation(command: command_repo, descr: 'path', values: String, id_result: 'path') do |l_path|
         
     | 
| 
       504 
     | 
    
         
            -
                          apifid =  
     | 
| 
       505 
     | 
    
         
            -
             
     | 
| 
      
 514 
     | 
    
         
            +
                          apifid = if (m = l_path.match(REGEX_LOOKUP_ID_BY_FIELD))
         
     | 
| 
      
 515 
     | 
    
         
            +
                            {
         
     | 
| 
      
 516 
     | 
    
         
            +
                              api:     @api_node,
         
     | 
| 
      
 517 
     | 
    
         
            +
                              file_id: m[2]
         
     | 
| 
      
 518 
     | 
    
         
            +
                            }
         
     | 
| 
      
 519 
     | 
    
         
            +
                          else
         
     | 
| 
      
 520 
     | 
    
         
            +
                            @api_node.resolve_api_fid(top_file_id, l_path)
         
     | 
| 
      
 521 
     | 
    
         
            +
                          end
         
     | 
| 
      
 522 
     | 
    
         
            +
                          result = apifid[:api].delete("files/#{apifid[:file_id]}")
         
     | 
| 
       506 
523 
     | 
    
         
             
                          {'path' => l_path}
         
     | 
| 
       507 
524 
     | 
    
         
             
                        end
         
     | 
| 
       508 
525 
     | 
    
         
             
                      when :sync
         
     | 
| 
         @@ -522,27 +539,24 @@ module Aspera 
     | 
|
| 
       522 
539 
     | 
    
         
             
                          transfer_spec
         
     | 
| 
       523 
540 
     | 
    
         
             
                        end
         
     | 
| 
       524 
541 
     | 
    
         
             
                      when :upload
         
     | 
| 
       525 
     | 
    
         
            -
                        apifid = @api_node.resolve_api_fid(top_file_id, transfer.destination_folder(Transfer::Spec::DIRECTION_SEND))
         
     | 
| 
      
 542 
     | 
    
         
            +
                        apifid = @api_node.resolve_api_fid(top_file_id, transfer.destination_folder(Transfer::Spec::DIRECTION_SEND), true)
         
     | 
| 
       526 
543 
     | 
    
         
             
                        return Main.result_transfer(transfer.start(apifid[:api].transfer_spec_gen4(apifid[:file_id], Transfer::Spec::DIRECTION_SEND)))
         
     | 
| 
       527 
544 
     | 
    
         
             
                      when :download
         
     | 
| 
       528 
545 
     | 
    
         
             
                        source_paths = transfer.ts_source_paths
         
     | 
| 
       529 
546 
     | 
    
         
             
                        # special case for AoC : all files must be in same folder
         
     | 
| 
       530 
547 
     | 
    
         
             
                        source_folder = source_paths.shift['source']
         
     | 
| 
       531 
548 
     | 
    
         
             
                        # if a single file: split into folder and path
         
     | 
| 
       532 
     | 
    
         
            -
                        apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
         
     | 
| 
      
 549 
     | 
    
         
            +
                        apifid = @api_node.resolve_api_fid(top_file_id, source_folder, true)
         
     | 
| 
       533 
550 
     | 
    
         
             
                        if source_paths.empty?
         
     | 
| 
       534 
551 
     | 
    
         
             
                          # get precise info in this element
         
     | 
| 
       535 
     | 
    
         
            -
                          file_info = apifid[:api].read("files/#{apifid[:file_id]}") 
     | 
| 
      
 552 
     | 
    
         
            +
                          file_info = apifid[:api].read("files/#{apifid[:file_id]}")
         
     | 
| 
       536 
553 
     | 
    
         
             
                          case file_info['type']
         
     | 
| 
       537 
554 
     | 
    
         
             
                          when 'file'
         
     | 
| 
       538 
555 
     | 
    
         
             
                            # if the single source is a file, we need to split into folder path and filename
         
     | 
| 
       539 
556 
     | 
    
         
             
                            src_dir_elements = source_folder.split(Api::Node::PATH_SEPARATOR)
         
     | 
| 
       540 
557 
     | 
    
         
             
                            # filename is the last one, source folder is what remains
         
     | 
| 
       541 
558 
     | 
    
         
             
                            source_paths = [{'source' => src_dir_elements.pop}]
         
     | 
| 
       542 
     | 
    
         
            -
                             
     | 
| 
       543 
     | 
    
         
            -
                            src_dir_elements.push('')
         
     | 
| 
       544 
     | 
    
         
            -
                            source_folder = src_dir_elements.join(Api::Node::PATH_SEPARATOR)
         
     | 
| 
       545 
     | 
    
         
            -
                            apifid = @api_node.resolve_api_fid(top_file_id, source_folder)
         
     | 
| 
      
 559 
     | 
    
         
            +
                            apifid = @api_node.resolve_api_fid(top_file_id, src_dir_elements.join(Api::Node::PATH_SEPARATOR), true)
         
     | 
| 
       546 
560 
     | 
    
         
             
                          when 'link', 'folder'
         
     | 
| 
       547 
561 
     | 
    
         
             
                            # single source is 'folder' or 'link'
         
     | 
| 
       548 
562 
     | 
    
         
             
                            # TODO: add this ? , 'destination'=>file_info['name']
         
     | 
| 
         @@ -570,12 +584,12 @@ module Aspera 
     | 
|
| 
       570 
584 
     | 
    
         
             
                        return Main.result_status("downloaded: #{file_name}")
         
     | 
| 
       571 
585 
     | 
    
         
             
                      when :show
         
     | 
| 
       572 
586 
     | 
    
         
             
                        apifid = apifid_from_next_arg(top_file_id)
         
     | 
| 
       573 
     | 
    
         
            -
                        items = apifid[:api].read("files/#{apifid[:file_id]}") 
     | 
| 
      
 587 
     | 
    
         
            +
                        items = apifid[:api].read("files/#{apifid[:file_id]}")
         
     | 
| 
       574 
588 
     | 
    
         
             
                        return {type: :single_object, data: items}
         
     | 
| 
       575 
589 
     | 
    
         
             
                      when :modify
         
     | 
| 
       576 
590 
     | 
    
         
             
                        apifid = apifid_from_next_arg(top_file_id)
         
     | 
| 
       577 
591 
     | 
    
         
             
                        update_param = options.get_next_argument('update data', validation: Hash)
         
     | 
| 
       578 
     | 
    
         
            -
                        apifid[:api].update("files/#{apifid[:file_id]}", update_param) 
     | 
| 
      
 592 
     | 
    
         
            +
                        apifid[:api].update("files/#{apifid[:file_id]}", update_param)
         
     | 
| 
       579 
593 
     | 
    
         
             
                        return Main.result_status('Done')
         
     | 
| 
       580 
594 
     | 
    
         
             
                      when :thumbnail
         
     | 
| 
       581 
595 
     | 
    
         
             
                        apifid = apifid_from_next_arg(top_file_id)
         
     | 
| 
         @@ -590,18 +604,19 @@ module Aspera 
     | 
|
| 
       590 
604 
     | 
    
         
             
                        command_perm = options.get_next_command(%i[list create delete])
         
     | 
| 
       591 
605 
     | 
    
         
             
                        case command_perm
         
     | 
| 
       592 
606 
     | 
    
         
             
                        when :list
         
     | 
| 
       593 
     | 
    
         
            -
                           
     | 
| 
       594 
     | 
    
         
            -
                           
     | 
| 
       595 
     | 
    
         
            -
                           
     | 
| 
       596 
     | 
    
         
            -
                           
     | 
| 
       597 
     | 
    
         
            -
                           
     | 
| 
       598 
     | 
    
         
            -
                          items = apifid[:api].read('permissions',  
     | 
| 
      
 607 
     | 
    
         
            +
                          list_query = query_read_delete(default: {'include' => Rest.array_params(%w[access_level permission_count])})
         
     | 
| 
      
 608 
     | 
    
         
            +
                          # specify file to get permissions for unless not specified
         
     | 
| 
      
 609 
     | 
    
         
            +
                          list_query['file_id'] = apifid[:file_id] unless apifid[:file_id].to_s.empty?
         
     | 
| 
      
 610 
     | 
    
         
            +
                          list_query['inherited'] = false if list_query.key?('file_id') && !list_query.key?('inherited')
         
     | 
| 
      
 611 
     | 
    
         
            +
                          # NOTE: supports per_page and page and header X-Total-Count
         
     | 
| 
      
 612 
     | 
    
         
            +
                          items = apifid[:api].read('permissions', list_query)
         
     | 
| 
       599 
613 
     | 
    
         
             
                          return {type: :object_list, data: items}
         
     | 
| 
       600 
614 
     | 
    
         
             
                        when :delete
         
     | 
| 
       601 
615 
     | 
    
         
             
                          return do_bulk_operation(command: command_perm, descr: 'identifier', values: :identifier) do |one_id|
         
     | 
| 
       602 
616 
     | 
    
         
             
                            apifid[:api].delete("permissions/#{one_id}")
         
     | 
| 
       603 
617 
     | 
    
         
             
                            # notify application of deletion
         
     | 
| 
       604 
     | 
    
         
            -
                            the_app[:api]. 
     | 
| 
      
 618 
     | 
    
         
            +
                            the_app = apifid[:api].app_info
         
     | 
| 
      
 619 
     | 
    
         
            +
                            the_app&.[](:api)&.permissions_send_event(event_data: {}, app_info: the_app, types: ['permission.deleted'])
         
     | 
| 
       605 
620 
     | 
    
         
             
                            {'id' => one_id}
         
     | 
| 
       606 
621 
     | 
    
         
             
                          end
         
     | 
| 
       607 
622 
     | 
    
         
             
                        when :create
         
     | 
| 
         @@ -611,11 +626,11 @@ module Aspera 
     | 
|
| 
       611 
626 
     | 
    
         
             
                          create_param['access_levels'] = Api::Node::ACCESS_LEVELS unless create_param.key?('access_levels')
         
     | 
| 
       612 
627 
     | 
    
         
             
                          # add application specific tags (AoC)
         
     | 
| 
       613 
628 
     | 
    
         
             
                          the_app = apifid[:api].app_info
         
     | 
| 
       614 
     | 
    
         
            -
                          the_app[:api 
     | 
| 
      
 629 
     | 
    
         
            +
                          the_app&.[](:api)&.permissions_set_create_params(perm_data: create_param, app_info: the_app)
         
     | 
| 
       615 
630 
     | 
    
         
             
                          # create permission
         
     | 
| 
       616 
     | 
    
         
            -
                          created_data = apifid[:api].create('permissions', create_param) 
     | 
| 
      
 631 
     | 
    
         
            +
                          created_data = apifid[:api].create('permissions', create_param)
         
     | 
| 
       617 
632 
     | 
    
         
             
                          # notify application of creation
         
     | 
| 
       618 
     | 
    
         
            -
                          the_app[:api 
     | 
| 
      
 633 
     | 
    
         
            +
                          the_app&.[](:api)&.permissions_send_event(event_data: created_data, app_info: the_app)
         
     | 
| 
       619 
634 
     | 
    
         
             
                          return { type: :single_object, data: created_data}
         
     | 
| 
       620 
635 
     | 
    
         
             
                        else Aspera.error_unreachable_line
         
     | 
| 
       621 
636 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -632,14 +647,14 @@ module Aspera 
     | 
|
| 
       632 
647 
     | 
    
         
             
                        if async_name.nil?
         
     | 
| 
       633 
648 
     | 
    
         
             
                          async_id = instance_identifier
         
     | 
| 
       634 
649 
     | 
    
         
             
                          if async_id.eql?(SpecialValues::ALL) && %i[show delete].include?(command)
         
     | 
| 
       635 
     | 
    
         
            -
                            async_ids = @api_node.read('async/list')[ 
     | 
| 
      
 650 
     | 
    
         
            +
                            async_ids = @api_node.read('async/list')['sync_ids']
         
     | 
| 
       636 
651 
     | 
    
         
             
                          else
         
     | 
| 
       637 
652 
     | 
    
         
             
                            Integer(async_id) # must be integer
         
     | 
| 
       638 
653 
     | 
    
         
             
                            async_ids = [async_id]
         
     | 
| 
       639 
654 
     | 
    
         
             
                          end
         
     | 
| 
       640 
655 
     | 
    
         
             
                        else
         
     | 
| 
       641 
     | 
    
         
            -
                          async_ids = @api_node.read('async/list')[ 
     | 
| 
       642 
     | 
    
         
            -
                          summaries = @api_node.create('async/summary', {'syncs' => async_ids})[ 
     | 
| 
      
 656 
     | 
    
         
            +
                          async_ids = @api_node.read('async/list')['sync_ids']
         
     | 
| 
      
 657 
     | 
    
         
            +
                          summaries = @api_node.create('async/summary', {'syncs' => async_ids})['sync_summaries']
         
     | 
| 
       643 
658 
     | 
    
         
             
                          selected = summaries.find{|s|s['name'].eql?(async_name)}
         
     | 
| 
       644 
659 
     | 
    
         
             
                          raise "no such sync: #{async_name}" if selected.nil?
         
     | 
| 
       645 
660 
     | 
    
         
             
                          async_id = selected['snid']
         
     | 
| 
         @@ -649,19 +664,19 @@ module Aspera 
     | 
|
| 
       649 
664 
     | 
    
         
             
                      end
         
     | 
| 
       650 
665 
     | 
    
         
             
                      case command
         
     | 
| 
       651 
666 
     | 
    
         
             
                      when :list
         
     | 
| 
       652 
     | 
    
         
            -
                        resp = @api_node.read('async/list')[ 
     | 
| 
      
 667 
     | 
    
         
            +
                        resp = @api_node.read('async/list')['sync_ids']
         
     | 
| 
       653 
668 
     | 
    
         
             
                        return { type: :value_list, data: resp, name: 'id' }
         
     | 
| 
       654 
669 
     | 
    
         
             
                      when :show
         
     | 
| 
       655 
     | 
    
         
            -
                        resp = @api_node.create('async/summary', post_data)[ 
     | 
| 
      
 670 
     | 
    
         
            +
                        resp = @api_node.create('async/summary', post_data)['sync_summaries']
         
     | 
| 
       656 
671 
     | 
    
         
             
                        return Main.result_empty if resp.empty?
         
     | 
| 
       657 
672 
     | 
    
         
             
                        return { type: :object_list, data: resp, fields: %w[snid name local_dir remote_dir] } if async_id.eql?(SpecialValues::ALL)
         
     | 
| 
       658 
673 
     | 
    
         
             
                        return { type: :single_object, data: resp.first }
         
     | 
| 
       659 
674 
     | 
    
         
             
                      when :delete
         
     | 
| 
       660 
     | 
    
         
            -
                        resp = @api_node.create('async/delete', post_data) 
     | 
| 
      
 675 
     | 
    
         
            +
                        resp = @api_node.create('async/delete', post_data)
         
     | 
| 
       661 
676 
     | 
    
         
             
                        return { type: :single_object, data: resp, name: 'id' }
         
     | 
| 
       662 
677 
     | 
    
         
             
                      when :bandwidth
         
     | 
| 
       663 
678 
     | 
    
         
             
                        post_data['seconds'] = 100 # TODO: as parameter with --value
         
     | 
| 
       664 
     | 
    
         
            -
                        resp = @api_node.create('async/bandwidth', post_data) 
     | 
| 
      
 679 
     | 
    
         
            +
                        resp = @api_node.create('async/bandwidth', post_data)
         
     | 
| 
       665 
680 
     | 
    
         
             
                        data = resp['bandwidth_data']
         
     | 
| 
       666 
681 
     | 
    
         
             
                        return Main.result_empty if data.empty?
         
     | 
| 
       667 
682 
     | 
    
         
             
                        data = data.first[async_id]['data']
         
     | 
| 
         @@ -671,9 +686,9 @@ module Aspera 
     | 
|
| 
       671 
686 
     | 
    
         
             
                        # filename str
         
     | 
| 
       672 
687 
     | 
    
         
             
                        # skip int
         
     | 
| 
       673 
688 
     | 
    
         
             
                        # status int
         
     | 
| 
       674 
     | 
    
         
            -
                        filter =  
     | 
| 
      
 689 
     | 
    
         
            +
                        filter = options.get_option(:query)
         
     | 
| 
       675 
690 
     | 
    
         
             
                        post_data.merge!(filter) unless filter.nil?
         
     | 
| 
       676 
     | 
    
         
            -
                        resp = @api_node.create('async/files', post_data) 
     | 
| 
      
 691 
     | 
    
         
            +
                        resp = @api_node.create('async/files', post_data)
         
     | 
| 
       677 
692 
     | 
    
         
             
                        data = resp['sync_files']
         
     | 
| 
       678 
693 
     | 
    
         
             
                        data = data.first[async_id] unless data.empty?
         
     | 
| 
       679 
694 
     | 
    
         
             
                        iteration_data = []
         
     | 
| 
         @@ -696,7 +711,7 @@ module Aspera 
     | 
|
| 
       696 
711 
     | 
    
         
             
                        skip_ids_persistency&.save
         
     | 
| 
       697 
712 
     | 
    
         
             
                        return { type: :object_list, data: data, name: 'id' }
         
     | 
| 
       698 
713 
     | 
    
         
             
                      when :counters
         
     | 
| 
       699 
     | 
    
         
            -
                        resp = @api_node.create('async/counters', post_data)[ 
     | 
| 
      
 714 
     | 
    
         
            +
                        resp = @api_node.create('async/counters', post_data)['sync_counters'].first[async_id].last
         
     | 
| 
       700 
715 
     | 
    
         
             
                        return Main.result_empty if resp.nil?
         
     | 
| 
       701 
716 
     | 
    
         
             
                        return { type: :single_object, data: resp }
         
     | 
| 
       702 
717 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -708,8 +723,8 @@ module Aspera 
     | 
|
| 
       708 
723 
     | 
    
         
             
                    # @param [String] value value of the field to search
         
     | 
| 
       709 
724 
     | 
    
         
             
                    def ssync_lookup(field, value)
         
     | 
| 
       710 
725 
     | 
    
         
             
                      raise Cli::BadArgument, "Only search by name is supported (#{field})" unless field.eql?('name')
         
     | 
| 
       711 
     | 
    
         
            -
                      @api_node.read('asyncs')[ 
     | 
| 
       712 
     | 
    
         
            -
                        sync_info = @api_node.read("asyncs/#{id}")[ 
     | 
| 
      
 726 
     | 
    
         
            +
                      @api_node.read('asyncs')['ids'].each do |id|
         
     | 
| 
      
 727 
     | 
    
         
            +
                        sync_info = @api_node.read("asyncs/#{id}")['configuration']
         
     | 
| 
       713 
728 
     | 
    
         
             
                        # name is unique, so we can return
         
     | 
| 
       714 
729 
     | 
    
         
             
                        return id if sync_info[field].eql?(value)
         
     | 
| 
       715 
730 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -750,27 +765,27 @@ module Aspera 
     | 
|
| 
       750 
765 
     | 
    
         
             
                            return Main.result_status('Done')
         
     | 
| 
       751 
766 
     | 
    
         
             
                          end
         
     | 
| 
       752 
767 
     | 
    
         
             
                          parameters = nil
         
     | 
| 
       753 
     | 
    
         
            -
                          parameters =  
     | 
| 
       754 
     | 
    
         
            -
                          return { type: :single_object, data: @api_node.read("asyncs/#{asyncs_id}/#{sync_command}", parameters) 
     | 
| 
      
 768 
     | 
    
         
            +
                          parameters = options.get_option(:query, default: {}) if %i[bandwidth counters files].include?(sync_command)
         
     | 
| 
      
 769 
     | 
    
         
            +
                          return { type: :single_object, data: @api_node.read("asyncs/#{asyncs_id}/#{sync_command}", parameters) }
         
     | 
| 
       755 
770 
     | 
    
         
             
                        end
         
     | 
| 
       756 
771 
     | 
    
         
             
                      when :stream
         
     | 
| 
       757 
772 
     | 
    
         
             
                        command = options.get_next_command(%i[list create show modify cancel])
         
     | 
| 
       758 
773 
     | 
    
         
             
                        case command
         
     | 
| 
       759 
774 
     | 
    
         
             
                        when :list
         
     | 
| 
       760 
775 
     | 
    
         
             
                          resp = @api_node.read('ops/transfers', query_read_delete)
         
     | 
| 
       761 
     | 
    
         
            -
                          return { type: :object_list, data: resp 
     | 
| 
      
 776 
     | 
    
         
            +
                          return { type: :object_list, data: resp, fields: %w[id status] } # TODO: useful?
         
     | 
| 
       762 
777 
     | 
    
         
             
                        when :create
         
     | 
| 
       763 
778 
     | 
    
         
             
                          resp = @api_node.create('streams', value_create_modify(command: command))
         
     | 
| 
       764 
     | 
    
         
            -
                          return { type: :single_object, data: resp 
     | 
| 
      
 779 
     | 
    
         
            +
                          return { type: :single_object, data: resp }
         
     | 
| 
       765 
780 
     | 
    
         
             
                        when :show
         
     | 
| 
       766 
781 
     | 
    
         
             
                          resp = @api_node.read("ops/transfers/#{options.get_next_argument('transfer id')}")
         
     | 
| 
       767 
     | 
    
         
            -
                          return { type: :other_struct, data: resp 
     | 
| 
      
 782 
     | 
    
         
            +
                          return { type: :other_struct, data: resp }
         
     | 
| 
       768 
783 
     | 
    
         
             
                        when :modify
         
     | 
| 
       769 
784 
     | 
    
         
             
                          resp = @api_node.update("streams/#{options.get_next_argument('transfer id')}", value_create_modify(command: command))
         
     | 
| 
       770 
     | 
    
         
            -
                          return { type: :other_struct, data: resp 
     | 
| 
      
 785 
     | 
    
         
            +
                          return { type: :other_struct, data: resp }
         
     | 
| 
       771 
786 
     | 
    
         
             
                        when :cancel
         
     | 
| 
       772 
787 
     | 
    
         
             
                          resp = @api_node.cancel("streams/#{options.get_next_argument('transfer id')}")
         
     | 
| 
       773 
     | 
    
         
            -
                          return { type: :other_struct, data: resp 
     | 
| 
      
 788 
     | 
    
         
            +
                          return { type: :other_struct, data: resp }
         
     | 
| 
       774 
789 
     | 
    
         
             
                        else
         
     | 
| 
       775 
790 
     | 
    
         
             
                          raise 'error'
         
     | 
| 
       776 
791 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -783,14 +798,61 @@ module Aspera 
     | 
|
| 
       783 
798 
     | 
    
         
             
                        end
         
     | 
| 
       784 
799 
     | 
    
         
             
                        case command
         
     | 
| 
       785 
800 
     | 
    
         
             
                        when :list
         
     | 
| 
       786 
     | 
    
         
            -
                           
     | 
| 
      
 801 
     | 
    
         
            +
                          transfer_filter = query_read_delete(default: {})
         
     | 
| 
      
 802 
     | 
    
         
            +
                          last_iteration_token = nil
         
     | 
| 
      
 803 
     | 
    
         
            +
                          iteration_persistency = nil
         
     | 
| 
      
 804 
     | 
    
         
            +
                          if options.get_option(:once_only, mandatory: true)
         
     | 
| 
      
 805 
     | 
    
         
            +
                            iteration_persistency = PersistencyActionOnce.new(
         
     | 
| 
      
 806 
     | 
    
         
            +
                              manager: persistency,
         
     | 
| 
      
 807 
     | 
    
         
            +
                              data:    [],
         
     | 
| 
      
 808 
     | 
    
         
            +
                              id:      IdGenerator.from_list([
         
     | 
| 
      
 809 
     | 
    
         
            +
                                'node_transfers',
         
     | 
| 
      
 810 
     | 
    
         
            +
                                options.get_option(:url, mandatory: true),
         
     | 
| 
      
 811 
     | 
    
         
            +
                                options.get_option(:username, mandatory: true)
         
     | 
| 
      
 812 
     | 
    
         
            +
                              ]))
         
     | 
| 
      
 813 
     | 
    
         
            +
                            if transfer_filter.delete('reset')
         
     | 
| 
      
 814 
     | 
    
         
            +
                              iteration_persistency.data.clear
         
     | 
| 
      
 815 
     | 
    
         
            +
                              iteration_persistency.save
         
     | 
| 
      
 816 
     | 
    
         
            +
                              return Main.result_status('Persistency reset')
         
     | 
| 
      
 817 
     | 
    
         
            +
                            end
         
     | 
| 
      
 818 
     | 
    
         
            +
                            last_iteration_token = iteration_persistency.data.first
         
     | 
| 
      
 819 
     | 
    
         
            +
                          end
         
     | 
| 
      
 820 
     | 
    
         
            +
                          raise 'reset only with once_only' if transfer_filter.key?('reset') && iteration_persistency.nil?
         
     | 
| 
      
 821 
     | 
    
         
            +
                          max_items = transfer_filter.delete(MAX_ITEMS)
         
     | 
| 
      
 822 
     | 
    
         
            +
                          transfers_data = []
         
     | 
| 
      
 823 
     | 
    
         
            +
                          loop do
         
     | 
| 
      
 824 
     | 
    
         
            +
                            transfer_filter['iteration_token'] = last_iteration_token unless last_iteration_token.nil?
         
     | 
| 
      
 825 
     | 
    
         
            +
                            result = @api_node.call(operation: 'GET', subpath: res_class_path, query: transfer_filter)
         
     | 
| 
      
 826 
     | 
    
         
            +
                            # no data
         
     | 
| 
      
 827 
     | 
    
         
            +
                            break if result[:data].empty?
         
     | 
| 
      
 828 
     | 
    
         
            +
                            # get next iteration token from link
         
     | 
| 
      
 829 
     | 
    
         
            +
                            next_iteration_token = nil
         
     | 
| 
      
 830 
     | 
    
         
            +
                            link_info = result[:http]['Link']
         
     | 
| 
      
 831 
     | 
    
         
            +
                            unless link_info.nil?
         
     | 
| 
      
 832 
     | 
    
         
            +
                              m = link_info.match(/<([^>]+)>/)
         
     | 
| 
      
 833 
     | 
    
         
            +
                              raise "Cannot parse iteration in Link: #{link_info}" if m.nil?
         
     | 
| 
      
 834 
     | 
    
         
            +
                              next_iteration_token = CGI.parse(URI.parse(m[1]).query)['iteration_token']&.first
         
     | 
| 
      
 835 
     | 
    
         
            +
                            end
         
     | 
| 
      
 836 
     | 
    
         
            +
                            # same as last iteration: stop
         
     | 
| 
      
 837 
     | 
    
         
            +
                            break if next_iteration_token&.eql?(last_iteration_token)
         
     | 
| 
      
 838 
     | 
    
         
            +
                            last_iteration_token = next_iteration_token
         
     | 
| 
      
 839 
     | 
    
         
            +
                            transfers_data.concat(result[:data])
         
     | 
| 
      
 840 
     | 
    
         
            +
                            if max_items&.<=(transfers_data.length)
         
     | 
| 
      
 841 
     | 
    
         
            +
                              # if !max_items.nil? && (transfers_data.length >= max_items)
         
     | 
| 
      
 842 
     | 
    
         
            +
                              transfers_data = transfers_data.slice(0, max_items)
         
     | 
| 
      
 843 
     | 
    
         
            +
                              break
         
     | 
| 
      
 844 
     | 
    
         
            +
                            end
         
     | 
| 
      
 845 
     | 
    
         
            +
                            break if last_iteration_token.nil?
         
     | 
| 
      
 846 
     | 
    
         
            +
                          end
         
     | 
| 
      
 847 
     | 
    
         
            +
                          iteration_persistency&.data&.[]=(0, last_iteration_token)
         
     | 
| 
      
 848 
     | 
    
         
            +
                          iteration_persistency&.save
         
     | 
| 
       787 
849 
     | 
    
         
             
                          return {
         
     | 
| 
       788 
850 
     | 
    
         
             
                            type:   :object_list,
         
     | 
| 
       789 
851 
     | 
    
         
             
                            data:   transfers_data,
         
     | 
| 
       790 
852 
     | 
    
         
             
                            fields: %w[id status start_spec.direction start_spec.remote_user start_spec.remote_host start_spec.destination_path]
         
     | 
| 
       791 
853 
     | 
    
         
             
                          }
         
     | 
| 
       792 
854 
     | 
    
         
             
                        when :sessions
         
     | 
| 
       793 
     | 
    
         
            -
                          transfers_data = @api_node.read(res_class_path, query_read_delete) 
     | 
| 
      
 855 
     | 
    
         
            +
                          transfers_data = @api_node.read(res_class_path, query_read_delete)
         
     | 
| 
       794 
856 
     | 
    
         
             
                          sessions = transfers_data.map{|t|t['sessions']}.flatten
         
     | 
| 
       795 
857 
     | 
    
         
             
                          sessions.each do |session|
         
     | 
| 
       796 
858 
     | 
    
         
             
                            session['start_time'] = Time.at(session['start_time_usec'] / 1_000_000.0).utc.iso8601(0)
         
     | 
| 
         @@ -803,15 +865,15 @@ module Aspera 
     | 
|
| 
       803 
865 
     | 
    
         
             
                          }
         
     | 
| 
       804 
866 
     | 
    
         
             
                        when :cancel
         
     | 
| 
       805 
867 
     | 
    
         
             
                          resp = @api_node.cancel(one_res_path)
         
     | 
| 
       806 
     | 
    
         
            -
                          return { type: :other_struct, data: resp 
     | 
| 
      
 868 
     | 
    
         
            +
                          return { type: :other_struct, data: resp }
         
     | 
| 
       807 
869 
     | 
    
         
             
                        when :show
         
     | 
| 
       808 
870 
     | 
    
         
             
                          resp = @api_node.read(one_res_path)
         
     | 
| 
       809 
     | 
    
         
            -
                          return { type: :other_struct, data: resp 
     | 
| 
      
 871 
     | 
    
         
            +
                          return { type: :other_struct, data: resp }
         
     | 
| 
       810 
872 
     | 
    
         
             
                        when :modify
         
     | 
| 
       811 
873 
     | 
    
         
             
                          resp = @api_node.update(one_res_path, options.get_next_argument('update value', validation: Hash))
         
     | 
| 
       812 
     | 
    
         
            -
                          return { type: :other_struct, data: resp 
     | 
| 
      
 874 
     | 
    
         
            +
                          return { type: :other_struct, data: resp }
         
     | 
| 
       813 
875 
     | 
    
         
             
                        when :bandwidth_average
         
     | 
| 
       814 
     | 
    
         
            -
                          transfers_data = @api_node.read(res_class_path, query_read_delete) 
     | 
| 
      
 876 
     | 
    
         
            +
                          transfers_data = @api_node.read(res_class_path, query_read_delete)
         
     | 
| 
       815 
877 
     | 
    
         
             
                          # collect all key dates
         
     | 
| 
       816 
878 
     | 
    
         
             
                          bandwidth_period = {}
         
     | 
| 
       817 
879 
     | 
    
         
             
                          dir_info = %i[avg_kbps sessions].freeze
         
     | 
| 
         @@ -866,12 +928,12 @@ module Aspera 
     | 
|
| 
       866 
928 
     | 
    
         
             
                        case command
         
     | 
| 
       867 
929 
     | 
    
         
             
                        when :list
         
     | 
| 
       868 
930 
     | 
    
         
             
                          resp = @api_node.read('rund/services')
         
     | 
| 
       869 
     | 
    
         
            -
                          return { type: :object_list, data: resp[ 
     | 
| 
      
 931 
     | 
    
         
            +
                          return { type: :object_list, data: resp['services'] }
         
     | 
| 
       870 
932 
     | 
    
         
             
                        when :create
         
     | 
| 
       871 
933 
     | 
    
         
             
                          # @json:'{"type":"WATCHFOLDERD","run_as":{"user":"user1"}}'
         
     | 
| 
       872 
934 
     | 
    
         
             
                          params = options.get_next_argument('creation data', validation: Hash)
         
     | 
| 
       873 
935 
     | 
    
         
             
                          resp = @api_node.create('rund/services', params)
         
     | 
| 
       874 
     | 
    
         
            -
                          return Main.result_status("#{resp[ 
     | 
| 
      
 936 
     | 
    
         
            +
                          return Main.result_status("#{resp['id']} created")
         
     | 
| 
       875 
937 
     | 
    
         
             
                        when :delete
         
     | 
| 
       876 
938 
     | 
    
         
             
                          @api_node.delete("rund/services/#{service_id}")
         
     | 
| 
       877 
939 
     | 
    
         
             
                          return Main.result_status("#{service_id} deleted")
         
     | 
| 
         @@ -889,36 +951,37 @@ module Aspera 
     | 
|
| 
       889 
951 
     | 
    
         
             
                        case command
         
     | 
| 
       890 
952 
     | 
    
         
             
                        when :create
         
     | 
| 
       891 
953 
     | 
    
         
             
                          resp = @api_node.create(res_class_path, value_create_modify(command: command))
         
     | 
| 
       892 
     | 
    
         
            -
                          return Main.result_status("#{resp[ 
     | 
| 
      
 954 
     | 
    
         
            +
                          return Main.result_status("#{resp['id']} created")
         
     | 
| 
       893 
955 
     | 
    
         
             
                        when :list
         
     | 
| 
       894 
956 
     | 
    
         
             
                          resp = @api_node.read(res_class_path, query_read_delete)
         
     | 
| 
       895 
     | 
    
         
            -
                          return { type: :value_list, data: resp[ 
     | 
| 
      
 957 
     | 
    
         
            +
                          return { type: :value_list, data: resp['ids'], name: 'id' }
         
     | 
| 
       896 
958 
     | 
    
         
             
                        when :show
         
     | 
| 
       897 
     | 
    
         
            -
                          return { type: :single_object, data: @api_node.read(one_res_path) 
     | 
| 
      
 959 
     | 
    
         
            +
                          return { type: :single_object, data: @api_node.read(one_res_path)}
         
     | 
| 
       898 
960 
     | 
    
         
             
                        when :modify
         
     | 
| 
       899 
     | 
    
         
            -
                          @api_node.update(one_res_path,  
     | 
| 
      
 961 
     | 
    
         
            +
                          @api_node.update(one_res_path, options.get_option(:query, mandatory: true))
         
     | 
| 
       900 
962 
     | 
    
         
             
                          return Main.result_status("#{one_res_id} updated")
         
     | 
| 
       901 
963 
     | 
    
         
             
                        when :delete
         
     | 
| 
       902 
964 
     | 
    
         
             
                          @api_node.delete(one_res_path)
         
     | 
| 
       903 
965 
     | 
    
         
             
                          return Main.result_status("#{one_res_id} deleted")
         
     | 
| 
       904 
966 
     | 
    
         
             
                        when :state
         
     | 
| 
       905 
     | 
    
         
            -
                          return { type: :single_object, data: @api_node.read("#{one_res_path}/state") 
     | 
| 
      
 967 
     | 
    
         
            +
                          return { type: :single_object, data: @api_node.read("#{one_res_path}/state") }
         
     | 
| 
       906 
968 
     | 
    
         
             
                        end
         
     | 
| 
       907 
969 
     | 
    
         
             
                      when :central
         
     | 
| 
       908 
970 
     | 
    
         
             
                        command = options.get_next_command(%i[session file])
         
     | 
| 
       909 
971 
     | 
    
         
             
                        validator_id = options.get_option(:validator)
         
     | 
| 
       910 
972 
     | 
    
         
             
                        validation = {'validator_id' => validator_id} unless validator_id.nil?
         
     | 
| 
       911 
     | 
    
         
            -
                        request_data =  
     | 
| 
      
 973 
     | 
    
         
            +
                        request_data = options.get_option(:query, default: {})
         
     | 
| 
       912 
974 
     | 
    
         
             
                        case command
         
     | 
| 
       913 
975 
     | 
    
         
             
                        when :session
         
     | 
| 
       914 
976 
     | 
    
         
             
                          command = options.get_next_command([:list])
         
     | 
| 
       915 
977 
     | 
    
         
             
                          case command
         
     | 
| 
       916 
978 
     | 
    
         
             
                          when :list
         
     | 
| 
      
 979 
     | 
    
         
            +
                            request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
         
     | 
| 
       917 
980 
     | 
    
         
             
                            request_data.deep_merge!({'validation' => validation}) unless validation.nil?
         
     | 
| 
       918 
981 
     | 
    
         
             
                            resp = @api_node.create('services/rest/transfers/v1/sessions', request_data)
         
     | 
| 
       919 
982 
     | 
    
         
             
                            return {
         
     | 
| 
       920 
983 
     | 
    
         
             
                              type:   :object_list,
         
     | 
| 
       921 
     | 
    
         
            -
                              data:   resp[ 
     | 
| 
      
 984 
     | 
    
         
            +
                              data:   resp['session_info_result']['session_info'],
         
     | 
| 
       922 
985 
     | 
    
         
             
                              fields: %w[session_uuid status transport direction bytes_transferred]
         
     | 
| 
       923 
986 
     | 
    
         
             
                            }
         
     | 
| 
       924 
987 
     | 
    
         
             
                          end
         
     | 
| 
         @@ -926,12 +989,14 @@ module Aspera 
     | 
|
| 
       926 
989 
     | 
    
         
             
                          command = options.get_next_command(%i[list modify])
         
     | 
| 
       927 
990 
     | 
    
         
             
                          case command
         
     | 
| 
       928 
991 
     | 
    
         
             
                          when :list
         
     | 
| 
      
 992 
     | 
    
         
            +
                            request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
         
     | 
| 
       929 
993 
     | 
    
         
             
                            request_data.deep_merge!({'validation' => validation}) unless validation.nil?
         
     | 
| 
       930 
     | 
    
         
            -
                            resp = @api_node.create('services/rest/transfers/v1/files', request_data) 
     | 
| 
      
 994 
     | 
    
         
            +
                            resp = @api_node.create('services/rest/transfers/v1/files', request_data)
         
     | 
| 
       931 
995 
     | 
    
         
             
                            resp = JSON.parse(resp) if resp.is_a?(String)
         
     | 
| 
       932 
996 
     | 
    
         
             
                            Log.log.debug{Log.dump(:resp, resp)}
         
     | 
| 
       933 
997 
     | 
    
         
             
                            return { type: :object_list, data: resp['file_transfer_info_result']['file_transfer_info'], fields: %w[session_uuid file_id status path]}
         
     | 
| 
       934 
998 
     | 
    
         
             
                          when :modify
         
     | 
| 
      
 999 
     | 
    
         
            +
                            request_data = options.get_next_argument('request data', mandatory: false, validation: Hash, default: {})
         
     | 
| 
       935 
1000 
     | 
    
         
             
                            request_data.deep_merge!(validation) unless validation.nil?
         
     | 
| 
       936 
1001 
     | 
    
         
             
                            @api_node.update('services/rest/transfers/v1/files', request_data)
         
     | 
| 
       937 
1002 
     | 
    
         
             
                            return Main.result_status('updated')
         
     | 
| 
         @@ -961,7 +1026,7 @@ module Aspera 
     | 
|
| 
       961 
1026 
     | 
    
         
             
                        raise 'Missing key: url' unless parameters.key?(:url)
         
     | 
| 
       962 
1027 
     | 
    
         
             
                        uri = URI.parse(parameters[:url])
         
     | 
| 
       963 
1028 
     | 
    
         
             
                        server = WebServerSimple.new(uri, certificate: parameters[:certificate])
         
     | 
| 
       964 
     | 
    
         
            -
                        server.mount(uri.path, NodeSimulatorServlet, parameters[:credentials],  
     | 
| 
      
 1029 
     | 
    
         
            +
                        server.mount(uri.path, NodeSimulatorServlet, parameters[:credentials], NodeSimulator.new)
         
     | 
| 
       965 
1030 
     | 
    
         
             
                        server.start
         
     | 
| 
       966 
1031 
     | 
    
         
             
                        return Main.result_status('Simulator terminated')
         
     | 
| 
       967 
1032 
     | 
    
         
             
                      end
         
     |