Ruby 和 Net::SFTP:为什么我不能将它移到一个单独的函数中?

Ruby and Net::SFTP: why can't I move this to a separate function?

编写一个函数,通过 SFTP 检查服务器上是否存在文件。

我已经编写了一个有效的函数 sftp_file_exists_1?。现在我想把这个函数拆分成两个函数,令我惊讶的是,这不起作用。

require "net/sftp"

def sftp_file_exists_1?(host, user, filename)
  Net::SFTP.start(host, user, verify_host_key: :always) do |sftp|
    sftp.stat(filename) do |response|
      return response.ok?
    end
  end
end

def sftp_stat_ok?(sftp, filename)
  sftp.stat(filename) do |response|
    return response.ok?
  end
end

def sftp_file_exists_2?(host, user, filename)
  Net::SFTP.start(host, user, verify_host_key: :always) do |sftp|
    return sftp_stat_ok?(sftp, filename)
  end
end

p sftp_file_exists_1?("localhost", "user", "repos")
p sftp_file_exists_2?("localhost", "user", "repos")

我预计:

true
true

因为文件 repos 实际上存在于服务器上。但是,我得到(缩写):

true
#<Net::SFTP::Request:0x000055f3b56732d0 @callback=#<Proc:0x000055f3b5673280@./test.rb:14>, ...

附录:有效:

def sftp_stat_ok?(sftp, filename)
  begin
    sftp.stat!(filename)
  rescue Net::SFTP::StatusException
    return false
  end
  return true
end

有趣的问题。

老派调试

让我们添加一些 puts 看看会发生什么:

require "net/sftp"

def sftp_file_exists_1?(host, user, filename)
  Net::SFTP.start(host, user, verify_host_key: :always) do |sftp|
    puts "  BEFORE STAT"
    sftp.stat(filename) do |response|
      puts "  REQUEST FINISHED"
      return response.ok?
    end
    puts "  AFTER STAT"
  end
  puts "  NOT EXECUTED"
end

def sftp_stat_ok?(sftp, filename)
  request = sftp.stat(filename) do |response|
    puts "  REQUEST FINISHED"
    return response.ok?
  end
  puts "  REQUEST SENT"
  request
end

def sftp_file_exists_2?(host, user, filename)
  Net::SFTP.start(host, user, verify_host_key: :always) do |sftp|
    puts "  CALL STAT_OK?"
    return sftp_stat_ok?(sftp, filename)
  end
  puts "  NOT EXECUTED"
end

sftp_file_exists_1? 输出:

  BEFORE STAT
  AFTER STAT
  REQUEST FINISHED
true

虽然 sftp_file_exists_2? 输出:

  CALL STAT_OK?
  REQUEST SENT
#<Net::SFTP::Request:0x0000000001db2558>

" REQUEST FINISHED" 没有出现。

异步逻辑

您传递给 stat is a callback 的区块。它仅在服务器响应时被调用。要确保块在 sftp_stat_ok? returns 之前执行,您需要等待请求完成:

def sftp_stat_ok?(sftp, filename)
  request = sftp.stat(filename) do |response|
    return response.ok?
  end
  request.wait
end

def sftp_file_exists_2?(host, user, filename)
  Net::SFTP.start(host, user, verify_host_key: :always) do |sftp|
    return sftp_stat_ok?(sftp, filename)
  end
end

第一个版本不需要它,因为 start:

If a block is given, it will be passed to the SFTP session and will be called once the SFTP session is fully open and initialized. When the block terminates, the new SSH session will automatically be closed.