3

如何在后台进程中使用 Ruby 将数据发送到 WebSocket?

背景

我已经有一个使用websocket-eventmachine-servergem 运行 Websocket 服务器的单独 ruby​​ 文件。但是,在我的 Rails 应用程序中,我想在后台任务中将数据发送到 websocket。

这是我的 WebSocket 服务器:

EM.run do
  trap('TERM') { stop }
  trap('INT') { stop }

  WebSocket::EventMachine::Server.start(host: options[:host], port: options[:port]) do |ws|

    ws.onopen do
      puts 'Client connected'
    end

    ws.onmessage do |msg, type|
      ws.send msg, type: type
    end

    ws.onclose do
      puts 'Client disconnected'
    end

  end

  def stop
    puts 'Terminating WebSocket Server'
    EventMachine.stop
  end
end

但是,在我的后台进程中(我正在使用 Sidekiq),我不确定如何连接到 WebSocket 并向其发送数据。

这是我的 Sidekiq 工人:

class MyWorker
  include Sidekiq::Worker

  def perform(command)
    100.times do |i|
      # Send 'I am on #{i}' to the Websocket
    end  
  end

end

我希望能够做类似的事情,EventMachine::WebSocket.send 'My message!'但我没有看到 API 或类似的东西。在 Ruby 中将数据发送到 WebSocket 的正确方法是什么?

4

2 回答 2

3

接受的答案

如果您保留当前的 ​​websocket 服务器:

您可以使用Iodine作为简单的 websocket 客户端进行测试。它使用自己的基于反应器模式的代码运行后台任务,并有一个 websocket 客户端(我有偏见,我是作者)。

你可以这样做:

require 'iodine/http'
Iodine.protocol = :timers
# force Iodine to start immediately
Iodine.force_start!

options = {}
options[:on_message] = Proc.new {|data| puts data}

100.times do |i|
    options[:on_open] = Proc.new {write "I am number #{i}"}
    Iodine.run do
        Iodine::Http.ws_connect('ws://localhost:3000', options) 
    end
end

附言

我建议为您的 websockets 使用框架,例如Plezi(我是作者)。一些框架允许您在 Rails/Sinatra 应用程序中运行他们的代码(Plezi 可以做到这一点,我认为 Faye 虽然不是严格意义上的框架,但也可以这样做)。

直接使用 EM 是相当硬核的,在处理 Websockets 时有很多事情需要管理,一个好的框架可以帮助您管理。

编辑 3

从 Iodine 0.7.17 开始(重新)支持 Iodine WebSocket 客户端连接,包括 OpenSSL 时的 TLS 连接>= 1.1.0

以下代码是原始答案的更新版本:

require 'iodine'

class MyClient
  def on_open connection
    connection.subscribe :updates
    puts "Connected"
  end
  def on_message connection, data
    puts data
  end
  def on_close connection
    # auto-reconnect after 250ms.
    puts "Connection lost, re-connecting in 250ms"
    Iodine.run_after(250) { MyClient.connect }
  end

  def self.connect
    Iodine.connect(url: "ws://localhost:3000/path", handler: MyClient.new)
  end
end


Iodine.threads = 1
Iodine.defer { MyClient.connect if Iodine.master? }
Thread.new { Iodine.start }

100.times {|i| Iodine.publish :updates, "I am number #{i}" }

编辑 2

这个答案现在已经过时了,因为 Iodine 0.2.x 不再包含客户端。为 websocket 客户端使用 Iodine 0.1.x 或其他 gem

于 2014-12-07T11:44:45.247 回答
1

websocket-eventmachine-server是一个 websockets服务器

如果你想使用 ruby​​ 连接到 websocket 服务器,你可以用一些 gem 来完成,比如

于 2013-06-04T16:33:36.060 回答