-
(This is all part of my personal project, Syncpad. Source is available under AGPL-3.0.) I'm trying to set up a synchronized editor powered by Server-Side Events. I've got it to the point where it saves the document but then crashes when trying to broadcast an update to the browsers due to a
This comes from the following (trimmed) code: server.rb
require "sinatra/base"
class SyncPad < Sinatra::Base
set :connections, Set.new
get "/doc" do
content_type "text/event-stream"
stream :keep_open do |out|
if settings.connections.add?(out)
out.callback { settings.connections.delete(out) }
end
sleep 1
end
end
post "/doc" do
request.body.rewind
body = request.body.read
# saves the request body off...
# In theory, write to each browser that the document has been updated with the new contents
settings.connections.each do |out|
out << "event: DocUpdate\ndata: #{body}\n\n"
end
204
end
end I'm pretty sure I'm missing something, and would love some help pointing it out. How do I correctly send an update to the list of clients after the document has been updated? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 6 replies
-
The problem is this expression: get "/doc" do
content_type "text/event-stream"
stream :keep_open do |out|
queue = Thread::Queue.new
if settings.connections.add?(queue)
out.callback { settings.connections.delete(out) }
end
while item = queue.pop
out << "event: DocUpdate\ndata: #{item}\n\n"
end
end
end
post "/doc" do
request.body.rewind
body = request.body.read
settings.kv["doc"] = body
settings.connections.each do |queue|
queue << body
end
204
end This will decouple the flow control and life cycle and correctly serialise the output. Hope this example is sufficient - let me know if you need more help/details. |
Beta Was this translation helpful? Give feedback.
Ah right, yes, if you are doing it in-process, yes, 1/16th chance it would work. Otherwise, you need to use a shared backend pub/sub e.g. redis, etc.