1

编写一个通过 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
4

1 回答 1

2

有趣的问题。

老派调试

让我们添加一些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是一个回调。只有在服务器响应时才会调用它。为了确保块在sftp_stat_ok?返回之前被执行,您需要等待请求完成:

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

如果给出一个块,它将被传递给 SFTP 会话,并在 SFTP 会话完全打开和初始化后被调用。当块终止时,新的 SSH 会话将自动关闭。

于 2019-07-21T17:59:51.467 回答