Skip to content

Commit

Permalink
Merge pull request #385 from roflcoopter/feature/websocket-ping
Browse files Browse the repository at this point in the history
add websocket ping for more stable connections
  • Loading branch information
roflcoopter committed Nov 3, 2022
2 parents fafd095 + 26d08bd commit b0ce319
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 1 deletion.
6 changes: 6 additions & 0 deletions frontend/src/lib/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ export function restartViseron() {
type: "restart_viseron",
};
}

export function ping() {
return {
type: "ping",
};
}
6 changes: 6 additions & 0 deletions frontend/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ export type CameraRegisteredEvent = EventBase & {
};


type WebSocketPongResponse = {
command_id: number;
type: "pong";
};

export type WebSocketEventResponse = {
command_id: number;
type: "event";
Expand All @@ -72,6 +77,7 @@ export type WebSocketResultErrorResponse = {
};

export type WebSocketResponse =
| WebSocketPongResponse
| WebSocketEventResponse
| WebSocketResultResponse
| WebSocketResultErrorResponse;
23 changes: 22 additions & 1 deletion frontend/src/lib/websockets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export class Connection {
// Internal event listeners
eventListeners = new Map();

pingInterval: NodeJS.Timeout | undefined;

async connect() {
if (this.socket) {
return;
Expand Down Expand Up @@ -91,7 +93,7 @@ export class Connection {
toast("Connected to server!", {
toastId: connectedToastId,
type: toast.TYPE.INFO,
autoClose: 5000,
autoClose: 1000,
pauseOnFocusLoss: false,
});
clearTimeout(this.reconnectTimer);
Expand Down Expand Up @@ -129,6 +131,8 @@ export class Connection {
}
}

this.pingInterval = setInterval(() => { this.ping() }, 30000);

this.fireEvent("connected");
}

Expand Down Expand Up @@ -167,12 +171,25 @@ export class Connection {
}
}
break;

case "pong":
if (command_info) {
command_info.resolve();
this.commands.delete(message.command_id);
} else {
console.warn(`Received unknown pong response ${message.command_id}`);
}
break;
default:
console.warn("Unhandled message", message);
}
}

private _handleClose = async () => {
if (this.pingInterval) {
clearInterval(this.pingInterval);
}

if (!this.reconnectTimer) {
console.debug("Connection closed");
if (this.socket) {
Expand Down Expand Up @@ -250,6 +267,10 @@ export class Connection {
}
}

ping() {
return this.sendMessagePromise(messages.ping());
}

private _sendMessage(message: Message) {
console.log("Sending", message);
this.socket!.send(JSON.stringify(message));
Expand Down
3 changes: 3 additions & 0 deletions viseron/components/webserver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from .websocket_api.commands import (
get_cameras,
get_config,
ping,
restart_viseron,
save_config,
subscribe_event,
Expand Down Expand Up @@ -78,6 +79,7 @@ def setup(vis: Viseron, config):
webserver = WebServer(vis, config)
vis.register_signal_handler(VISERON_SIGNAL_SHUTDOWN, webserver.stop)

webserver.register_websocket_command(ping)
webserver.register_websocket_command(subscribe_event)
webserver.register_websocket_command(get_cameras)
webserver.register_websocket_command(get_config)
Expand Down Expand Up @@ -157,6 +159,7 @@ def create_application(self):
],
default_handler_class=NotFoundHandler,
static_path=PATH_STATIC,
websocket_ping_interval=10,
debug=self._config[CONFIG_DEBUG],
)
application.add_handlers(
Expand Down
7 changes: 7 additions & 0 deletions viseron/components/webserver/websocket_api/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
error_message,
event_message,
message_to_json,
pong_message,
result_message,
)

Expand All @@ -44,6 +45,12 @@ def decorate(func):
return decorate


@websocket_command({vol.Required("type"): "ping"})
def ping(connection: WebSocketHandler, message):
"""Respond to ping."""
connection.send_message(pong_message(message["command_id"]))


@websocket_command(
{vol.Required("type"): "subscribe_event", vol.Required("event"): str}
)
Expand Down
5 changes: 5 additions & 0 deletions viseron/components/webserver/websocket_api/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,8 @@ def event_message(command_id: int, event: Event) -> dict[str, Any]:
"type": "event",
"event": event,
}


def pong_message(command_id: int) -> dict[str, Any]:
"""Return a pong message."""
return {"command_id": command_id, "type": "pong"}

0 comments on commit b0ce319

Please sign in to comment.