Techioz Blog

Rails: アプリケーション コントローラー内のソケット ハイジャック

概要

Rails アプリケーションを使用して生のビデオ ストリームを提供したいと考えています。これを行うための最良の方法は、ソケットをハイジャックしてビデオ ストリーム (遠隔地から送信される) を直接送信することであると理解しました。 つまり、基本的にはビデオリバースプロキシです。 また、これをアプリケーション内でロジックを適用できるようにしたいと考えています。それ以外の場合は、nginxを使用するだけです。 プーマを使っています。

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

アプリケーションコントローラーのメソッドに同じものを入れても機能せず、空の応答が返されます。 TemplateError を回避するために :head ok を追加し、 run app 行と app 変数の割り当てを削除しました。 私は Rails にまったく慣れていないので、間違った方法で取り組んでいる可能性があります。私が見つけることができるほとんどのリソースは WebSocket のみに関するものであるため、正しい方向を示す助けをいただければ幸いです。

また、この投稿も知っています。「Rack 用の軽量ストリーミング HTTP プロキシ (Ruby CPU-light HTTP クライアント ライブラリ)」は、私に良い方向を示し、吸収して学ぶべき多くの情報でした。 sendfile gem は最終的な解決策のように思えますが、ソケットをハイジャックしてアプリケーションコントローラーが生データをクライアントにストリーミングするだけの方法がわかりません。

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

解決策

あなたが直面している問題は、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 メソッドは、送信するファイルへのパスとファイルのコンテンツ タイプという 2 つの引数を取ります。この場合、ファイルは /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

このコードは、まずビデオ ストリームをリモートの場所から応答と呼ばれる変数にダウンロードします。次に、send_file メソッドを使用してビデオ ストリームをクライアントに送信します。

お役に立てれば幸いです!