From bcc712927952752816812862de762c512c4dde5a Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Sun, 8 Mar 2026 21:55:39 -0400 Subject: [PATCH] base.html: Add a new ReconnectingEventSource We originally implemented this in lmno.js in the client, but realized it needs to be present in base.html. This wrapper for EventSource will attempt to reconnect after a lost connection (up to 5 times with a 2-second delay between each attempt). With this in place, a quick server restart (< 10 seconds) should be unnoticed by clients. --- templates/base.html | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/templates/base.html b/templates/base.html index 42b38bd..3da8587 100644 --- a/templates/base.html +++ b/templates/base.html @@ -22,6 +22,53 @@ ${message} const message_area = document.getElementById('message-area'); message_area.insertAdjacentHTML('beforeend', message); } + + class ReconnectingEventSource { + constructor(url, { max_retries = 5, retry_delay_ms = 2000, onclose } = {}) { + this._url = url; + this._max_retries = max_retries; + this._retry_delay_ms = retry_delay_ms; + this._onclose = onclose; + this._listeners = []; + this._retries = 0; + this._closed = false; + this._connect(); + } + + _connect() { + this._es = new EventSource(this._url); + + this._es.onopen = () => { + this._retries = 0; + }; + + this._es.onerror = () => { + if (this._es.readyState === EventSource.CLOSED) { + this._es.close(); + if (!this._closed && this._retries < this._max_retries) { + this._retries++; + setTimeout(() => this._connect(), this._retry_delay_ms); + } else if (this._onclose) { + this._onclose(); + } + } + }; + + for (const { type, handler } of this._listeners) { + this._es.addEventListener(type, handler); + } + } + + addEventListener(type, handler) { + this._listeners.push({ type, handler }); + this._es.addEventListener(type, handler); + } + + close() { + this._closed = true; + this._es.close(); + } + } {% block head %} {% endblock %} -- 2.45.2