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

问题描述 投票:0回答:1

我想通过 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 变量的赋值。 我对 Rails 很陌生,也许我的处理方式是错误的。任何帮助我指明正确方向的帮助都是值得赞赏的,因为我能找到的大多数资源仅适用于 websockets。

我还知道这篇文章:Rack 的轻量级流式 HTTP 代理(Ruby CPU-轻量级 HTTP 客户端库),它为我指明了一个好的方向,并且为我提供了很多需要吸收和学习的信息。 sendfile gem 似乎是最终的解决方案,但我不知道如何劫持套接字并使应用程序控制器仅将原始数据流式传输到客户端。

更新1:

  • 我找到了一个“有效”的解决方案,但它首先读取远程文件的所有块,因此如果文件很大,客户端会等待很长时间。 根据
    docs
    ,它能够在写入数据时将数据流式传输到客户端,但它会在写入之前先读取所有数据。我从每 1000 个块的调试输出中看到这一点,它在客户端获取任何数据之前就填满了。 我如何为客户提供传入块的服务?
  • ActionController::Live

ruby-on-rails ruby video reverse-proxy
1个回答
-1
投票
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

标头。但是,rack.hijack 标头仅在

rack.hijack
文件中受支持。
要使用 Rails 应用程序提供原始视频流,您可以使用 

config.ru

gem。

sendfile
gem 允许您直接将文件发送到客户端,而无需先将其读入内存。这非常适合提供大文件(例如视频流)。
要使用 sendfile gem,您需要将其添加到您的 

sendfile

:

Gemfile

然后,您可以使用 Rails 应用程序控制器中的 
gem 'sendfile'

方法将视频流发送到客户端:

send_file

send_file 方法有两个参数:要发送的文件的路径和文件的内容类型。在本例中,文件位于 
def stream_video send_file '/path/to/video.mp4', type: 'video/mp4' end

,内容类型为

/path/to/video.mp4
您还可以使用 

video/mp4

gem 从远程位置提供原始视频流。为此,您需要首先使用

sendfile
库将视频流下载到您的 Rails 应用程序。然后,您可以使用
Net::HTTP
方法将视频流发送到客户端。
以下是如何从远程位置提供原始视频流的示例:

send_file

此代码首先将视频流从远程位置下载到名为“response”的变量中。然后,它使用 
def stream_video uri = URI('http://example.com/video.mp4') response = Net::HTTP.get(uri) send_file response.body, type: 'video/mp4' end

方法将视频流发送到客户端。

希望对你有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.