Skip to content

Commit

Permalink
Add support for a keep-alive ping/pong (default to at most 10 seconds).
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Sep 25, 2024
1 parent 9df8e93 commit ae3a358
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 3 deletions.
31 changes: 28 additions & 3 deletions lib/live/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,22 +113,47 @@ def process_message(message)

# Run the event handling loop with the given websocket connection.
# @parameter connection [Async::WebSocket::Connection]
def run(connection)
def run(connection, keep_alive: 10)
Sync do |task|
last_update = Async::Clock.now

queue_task = task.async do
while update = @updates.dequeue
::Protocol::WebSocket::TextMessage.generate(update).send(connection)
if update == :ping
connection.send_ping
else
::Protocol::WebSocket::TextMessage.generate(update).send(connection)
end

# Flush the output if there are no more updates:
connection.flush if @updates.empty?
if @updates.empty?
connection.flush
end
end
end

keep_alive_task = task.async do
while true
sleep(keep_alive)

duration = Async::Clock.now - last_update

# We synchronize all writes to the update queue:
if duration > keep_alive
@updates.enqueue(:ping)
end
end
end

while message = connection.read
last_update = Async::Clock.now
process_message(message.parse)
end
ensure
keep_alive_task&.stop

self.close

queue_task&.stop
end
end
Expand Down
26 changes: 26 additions & 0 deletions test/live/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
require "live/view"
require "live/resolver"

require "async/websocket/client"
require "async/websocket/adapters/http"
require "sus/fixtures/async/http/server_context"

class MyView < Live::View
end

Expand Down Expand Up @@ -38,4 +42,26 @@ class MyView < Live::View
expect(page.resolve(view.id)).to be_nil
end
end

with "a server" do
include Sus::Fixtures::Async::HTTP::ServerContext

let(:app) do
::Protocol::HTTP::Middleware.for do |request|
Async::WebSocket::Adapters::HTTP.open(request) do |connection|
Live::Page.new(resolver).run(connection, keep_alive: 0.001)
end
end
end

it "can connect to server and receives ping" do
Async::WebSocket::Client.connect(client_endpoint) do |connection|
expect(connection).to receive(:receive_ping)

frame = connection.read_frame

expect(frame).to be_a(Protocol::WebSocket::PingFrame)
end
end
end
end

0 comments on commit ae3a358

Please sign in to comment.