]> git.cworth.org Git - lmno-server/commitdiff
base.html: Add a new ReconnectingEventSource
authorCarl Worth <cworth@cworth.org>
Mon, 9 Mar 2026 01:55:39 +0000 (21:55 -0400)
committerCarl Worth <cworth@cworth.org>
Mon, 9 Mar 2026 01:55:39 +0000 (21:55 -0400)
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

index 42b38bd2bf9f113d447d283187741b9c99533e00..3da8587f760f75c2ef45812274ea315afb093faf 100644 (file)
@@ -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();
+        }
+      }
     </script>
     {% block head %}
     {% endblock %}