I found this example of using faye for a chatroom type app as I am
trying to get a feel for push servers:
I got some of that to work, although multiuser from the same browser
doesn’t exactly make sense.
I then tried to look into a server side client. I am using a windows
laptop for everything.
I have the following code below which publishes a message to the
chatroom fine, but it never really exits.
The last statement “puts ‘end’” is never reached. If I put EM.stop or
an exit statement inside the event machine block, then the messages
don’t make it to the chat room.
The other thin I noticed is if I have a loop that puts say 5 messages
to the chat room, but sleeps for several seconds between each. They
don’t show up until they have all been published. It’s like it needs
to reach the bottom of the block, but once there it never exits the
block.
require ‘eventmachine’
require ‘faye’
client = Faye::Client.new(‘http://localhost:9292/faye’)
EM.run {
client.subscribe(‘/messages/public’) do |message|
puts message.inspect
end
client.publish(‘/messages/public’, ‘username’ => ‘Joe’,
‘msg’ => “hey there again”)
}
puts ‘end’
When you enter a eventmachine block it never return control to your app.
You have to turn it on but dont stay inside the evented block.
Use this method before initializing comunication to faye
def self.ensure_reactor_running
Thread.new { EM.run } unless EM.reactor_running?
sleep 0.1 until EM.reactor_running?
end
this will start eventmachine in a thread that is not the one your rails
app
is running if not already running.
Just call
ensure_reactor_running
before subscribing
On Thu, Mar 29, 2012 at 7:28 PM, [email protected]
[email protected]wrote:
I guess if I do everything inside of a EM that doesn’t take too long,
client.subscribe('/messages/public') do |message|
client.publish('/messages/public', 'username' => 'Joe',
sleep 30
puts ‘end of client’
Ok, Rails is a single threaded application, once you start event machine
inside the application flow, control is lost until a event triggers a
return somehow.
Do not put your code inside the EM block.
This is how i do it
class CommBridge
def self.set_connection
ensure_reactor_running
@@client ||= self.set
@@client
end
private
def self.set
client = Faye::Client.new(“http://localhost:9292/faye”, {timeout:
20})
client.add_extension(ClientAuth.new)
return client
end
def self.ensure_reactor_running
Thread.new { EM.run } unless EM.reactor_running?
sleep 0.1 until EM.reactor_running?
end
end
class ClientAuth
def outgoing(message, callback)
if message[‘channel’] !~ %r{^/meta/}
message[‘ext’] ||= {}
message[‘ext’][‘authToken’] = “#{FAYE_TOKEN}”
end
callback.call(message)
end
end
This calls takes care of creating a client fot he rails server.
Then anywhere in your app
client = CommBridge.set_connection
client.publish(“/user/#{channel}”,msg.to_json)
Your post has been very helpful, I tried something like what you
posted, but it didn’t
quite make sense to me.
If you look at what I have currently below, I have to have this
sleep(30) at the bottom which is not optimal.
a join on the thread doesn’t work.
I also tried run_block() instead of run() with no luck.
I guess if I do everything inside of a EM that doesn’t take too long,
it wouldn’t matter, but I am trying to get an idea of
how this sort of thing should work
#########################
require ‘eventmachine’
require ‘faye’
client = Faye::Client.new(‘http://localhost:9292/faye’)
thr = nil
if !EM.reactor_running?
thr = Thread.new do
EM.run do
puts 'in ev machine'
client.subscribe('/messages/public') do |message|
puts message.inspect
end
puts '1'
client.publish('/messages/public', 'username' => 'Joe',
'msg' => "hey there againzoggle")
sleep 10
puts '2'
client.publish('/messages/public', 'username' => 'Joe',
'msg' => "hey there again")
puts 'end of ev machine block'
end
end
end
puts ‘wait for running’
sleep 0.1 until EM.reactor_running?
sleep 30
puts ‘end of client’