I'm writing rails app and i want user to receive notification as soon as new message is saved to DB. For websocket i'm using em-websocket gem. After connection, i store client id and socket instance in array.
Question: How to push data to the client from controller\model action (before_save for example)? Is it able to do so with em-websocket?
chat.rb
EVENTCHAT_CONFIG = YAML.load_file("#{Rails.root}/config/eventchat.yml")[Rails.env].symbolize_keys
#escape html/xss
include ERB::Util
Thread.abort_on_exception = true
Thread.new {
EventMachine.run {
@sockets = Array.new
EventMachine::WebSocket.start(EVENTCHAT_CONFIG) do |ws|
ws.onopen do
end
ws.onclose do
index = @sockets.index {|i| i[:socket] == ws}
client = @sockets.delete_at index
@sockets.each {|s| s[:socket].send h("#{client[:id]} has disconnected!")}
end
ws.onmessage do |msg|
client = JSON.parse(msg).symbolize_keys
case client[:action]
when 'connect'
@sockets.push({:id=>client[:id], :socket=>ws})
@sockets.each {|s| s[:socket].send h("#{client[:id]} has connected!")}
when 'say'
@sockets.each {|s| s[:socket].send h("#{client[:id]} says : #{client[:data]}")}
end
end
end
}
}
When deploying - you may have problems related to having a separate EM reactor in each rails worker (for example errors about some failing to bind to socket or not all users receiving all messages)
Rails controllers in relation to websocket reactor are just another type of client, easiest way is to open a connection with special client id, push some data and close it afterwards. More efficient way - is to keep a open connection from each rails worker
If a EM-based single-process server is used(for example -
thin), you can useEM::Queueto deliver messages to websocket worker in-process or even write to websocket directly from controller