Fix streamer timeout (closes #1753).
Cowboy handles automatically responding to the client's ping, but doesn't automatically send a :ping frame to the client.
This commit is contained in:
parent
e432314105
commit
e2b15e8ad3
|
@ -12,8 +12,10 @@ defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
|
||||||
|
|
||||||
@behaviour :cowboy_websocket
|
@behaviour :cowboy_websocket
|
||||||
|
|
||||||
|
# Client ping period.
|
||||||
|
@tick :timer.seconds(30)
|
||||||
# Cowboy timeout period.
|
# Cowboy timeout period.
|
||||||
@timeout :timer.seconds(30)
|
@timeout :timer.seconds(60)
|
||||||
# Hibernate every X messages
|
# Hibernate every X messages
|
||||||
@hibernate_every 100
|
@hibernate_every 100
|
||||||
|
|
||||||
|
@ -44,7 +46,8 @@ def init(%{qs: qs} = req, state) do
|
||||||
req
|
req
|
||||||
end
|
end
|
||||||
|
|
||||||
{:cowboy_websocket, req, %{user: user, topic: topic, count: 0}, %{idle_timeout: @timeout}}
|
{:cowboy_websocket, req, %{user: user, topic: topic, count: 0, timer: nil},
|
||||||
|
%{idle_timeout: @timeout}}
|
||||||
else
|
else
|
||||||
{:error, code} ->
|
{:error, code} ->
|
||||||
Logger.debug("#{__MODULE__} denied connection: #{inspect(code)} - #{inspect(req)}")
|
Logger.debug("#{__MODULE__} denied connection: #{inspect(code)} - #{inspect(req)}")
|
||||||
|
@ -66,11 +69,18 @@ def websocket_init(state) do
|
||||||
)
|
)
|
||||||
|
|
||||||
Streamer.add_socket(state.topic, state.user)
|
Streamer.add_socket(state.topic, state.user)
|
||||||
{:ok, state}
|
{:ok, %{state | timer: timer()}}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Client's Pong frame.
|
||||||
|
def websocket_handle(:pong, state) do
|
||||||
|
if state.timer, do: Process.cancel_timer(state.timer)
|
||||||
|
{:ok, %{state | timer: timer()}}
|
||||||
end
|
end
|
||||||
|
|
||||||
# We never receive messages.
|
# We never receive messages.
|
||||||
def websocket_handle(_frame, state) do
|
def websocket_handle(frame, state) do
|
||||||
|
Logger.error("#{__MODULE__} received frame: #{inspect(frame)}")
|
||||||
{:ok, state}
|
{:ok, state}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -94,6 +104,14 @@ def websocket_info({:text, message}, state) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Ping tick. We don't re-queue a timer there, it is instead queued when :pong is received.
|
||||||
|
# As we hibernate there, reset the count to 0.
|
||||||
|
# If the client misses :pong, Cowboy will automatically timeout the connection after
|
||||||
|
# `@idle_timeout`.
|
||||||
|
def websocket_info(:tick, state) do
|
||||||
|
{:reply, :ping, %{state | timer: nil, count: 0}, :hibernate}
|
||||||
|
end
|
||||||
|
|
||||||
def terminate(reason, _req, state) do
|
def terminate(reason, _req, state) do
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
"#{__MODULE__} terminating websocket connection for user #{
|
"#{__MODULE__} terminating websocket connection for user #{
|
||||||
|
@ -149,4 +167,8 @@ defp expand_topic("list", params) do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp expand_topic(topic, _), do: topic
|
defp expand_topic(topic, _), do: topic
|
||||||
|
|
||||||
|
defp timer do
|
||||||
|
Process.send_after(self(), :tick, @tick)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue