ruby Rails:应用程序控制器内部的套接字劫持

mv1qrgav  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(104)

我想用rails应用程序提供原始视频流。我知道最好的方法是劫持套接字,直接发送我的视频流(来自远程位置)。所以基本上是一个视频反向代理。我也希望这在我的应用程序中,能够应用逻辑。否则我就直接用nginx了。我使用puma
我可以通过config.ru实现这一点,但我希望它在应用程序控制器中,能够使用更多的逻辑,使对远程的调用更加动态。
我的config.ru:

map '/video' do
    io_lambda = lambda do |io|
    uri = URI("http://10.0.0.20/myvideo.ts")
    Net::HTTP.start(uri.host, uri.port) do |http|
      request = Net::HTTP::Get.new uri
      http.request request do |response|
        response.read_body do |chunk|
          io.write chunk
        end
      end
    end
  end

  app = lambda do |env|
    response_headers = {}
    response_headers['Transfer-Encoding'] = 'binary'
    response_headers["Content-Type"] = "video/mp2t"
    response_headers["rack.hijack"] = io_lambda
    [200, response_headers, nil]
  end
  run app
end

把相同的方法应用程序控制器不工作,我得到一个空的答复。我只是添加了:head ok来规避TemplateError,并删除了run app行和app变量的赋值。我对铁路很陌生,也许我走错了路。任何帮助,以指出我在正确的方向是感激的,因为大多数资源,我可以找到只为websockets。
我也注意到这篇文章:Lightweight streaming HTTP proxy for Rack (Ruby CPU-light HTTP client library)这为我指明了一个很好的方向,对我来说是很多需要吸收和学习的信息。sendfile gem看起来像是最终的解决方案,但我不知道如何劫持套接字并使应用程序控制器将原始数据流传输到客户端。

更新一:

  • 我发现了一个解决方案,ActionController::Live,“工作”,但它读取所有块的远程文件第一,所以有一个长的客户端等待,如果文件是大的。根据docs,它能够在写入数据时将数据流传输到客户端,但它在写入之前首先读取所有数据。我从我的调试输出中看到,每1000个块,它在客户端获得任何数据之前就填满了。我怎么能为客户服务传递块作为进来?
class SocketController < ApplicationController
  include ActionController::Live
  def test
    i = 0
    response.headers['Content-Type'] = 'video/mp4'
    Net::HTTP.start(uri.host, uri.port) do |http|
      request = Net::HTTP::Get.new uri
      http.request request do |remote_response|
        remote_response.read_body do |chunk|
          i += 1
          puts i if i % 1000 == 0
          response.stream.write chunk
        end
      end
    end
  ensure
    response.stream.close
  end
end
t0ybt7op

t0ybt7op1#

您面临的问题是,您试图在Rails应用程序控制器的操作中使用rack.hijack头。但是,rack.hijack头文件仅在config.ru文件中受支持。
要在Rails应用程序中提供原始视频流,可以使用sendfile gem。sendfile gem允许您直接将文件发送到客户端,而无需先将其读入内存。这是提供大文件(如视频流)的理想选择。
要使用sendfile gem,您需要将其添加到Gemfile

gem 'sendfile'

然后,您可以在Rails应用程序控制器中使用send_file方法将视频流发送到客户端:

def stream_video
  send_file '/path/to/video.mp4', type: 'video/mp4'
end

send_file方法有两个参数:要发送的文件的路径和文件的内容类型。在这种情况下,文件位于/path/to/video.mp4,内容类型为video/mp4
您还可以使用sendfile gem从远程位置提供原始视频流。为此,您需要首先使用Net::HTTP库将视频流下载到Rails应用程序中。然后,您可以使用send_file方法将视频流发送到客户端。
以下是如何从远程位置提供原始视频流的示例:

def stream_video
  uri = URI('http://example.com/video.mp4')
  response = Net::HTTP.get(uri)
  send_file response.body, type: 'video/mp4'
end

这段代码首先将视频流从远程位置下载到一个名为response的变量中。然后,它使用send_file方法将视频流发送到客户端。
我希望它有帮助!

相关问题