websocket-eventmachine-server icon indicating copy to clipboard operation
websocket-eventmachine-server copied to clipboard

Send message form outside EM block

Open gathuku opened this issue 5 years ago • 6 comments

hey @imanel

I have been trying to send a message to the client from outside the EM block without success. I have the implementation in a Biometric module. I want from my controller to be able to set a message which will be sent to the client Biometric.set_message. When the message @@ms is not nil, send then message ws.send @@ms.

How can I be able to implement it?

require 'websocket-eventmachine-server'
require 'json'

module Biometric
  @@ms = nil

  def self.start
    EM.run do
      WebSocket::EventMachine::Server.start(host: '0.0.0.0', port: 7788) do |ws|
        ws.onopen do
          puts 'Client connected'
        end

        ws.onmessage do |msg, type|
          puts "Received message: #{msg} #{type}"
        end

        ws.onclose do
          puts 'client disconnected'
        end

        ws.send @@ms.to_json unless @@ms.nil?
       
      end
    end
  end

  def self.set_message(msg)
    @@ms = msg
  end
end

Biometric.start
Biometric.set_message('hello there')

gathuku avatar Oct 09 '20 15:10 gathuku

The issue here is that EM.run is starting EventMachine, an infinite loop, so it will never exit it (unless server shutdown). So after Biometric.start next line is not executed unless you press "ctrl+c", at which point server will stop no longer be active.

The question is when would you like to send message to client? On connect? Or basing on some external trigger? If during connection then you want to use ws.send inside onopen, otherwise the logic that will trigger ws.send still need to be handled within EM.run block.

If you will describe exact use case you would like to achieve then I will gladly help.

imanel avatar Oct 12 '20 07:10 imanel

@imanel Thanks for the response. I want to send a message based on an external trigger, For example, when a user clicks a button on the user interface I initiate an action from my controller which goes to the EM block and sends data.

gathuku avatar Oct 12 '20 07:10 gathuku

If that's the case then usually you should have WS client build into your web server, and send messages from it. Overall WS server should be as lightweight as possible, and only relay messages (or apply small filtering logic about to whom particular message should be delivered). Combining Web and WS server will often lead to much less stable applications, especially during deploys (WS server should rarely be restarted or re-deployed).

imanel avatar Oct 14 '20 17:10 imanel

Hey, @imanel I deployed the implementation, and was running well, I noticed after adding new changes they don't pick. I guess there might be a problem with restarting the Eventmachine to use the latest changes. I using passanger server with nginx with Capistrano for deployment.

gathuku avatar Nov 09 '20 11:11 gathuku

Capistrano will restart Rails server, however not EM one, so you need to script it by yourself. Unfortunately it's been a while since the last time I was using Capistrano, so I won't be able to help you with writing the script.

imanel avatar Nov 09 '20 11:11 imanel

Thank you, I will research more.

gathuku avatar Nov 09 '20 12:11 gathuku