From ab94c23f2d85930a55412a5457336d5eda69eda6 Mon Sep 17 00:00:00 2001 From: CaffeineFueled Date: Mon, 2 Mar 2026 22:01:03 +0100 Subject: [PATCH] ADD peer counter for websocket - simple indicator in green #12 --- app.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app.py b/app.py index 3d64413..e0a6cd9 100644 --- a/app.py +++ b/app.py @@ -145,6 +145,7 @@ HTML = """ #status { font-size:.9rem; opacity:.7; margin-left:.5rem; } #status::before { content: "●"; margin-right: .3rem; color: #ef4444; } #status.connected::before { color: #22c55e; } + #peers { font-size:.95rem; font-weight:bold; margin-left:.5rem; margin-right:.3rem; color:#22c55e; display:none; } #wrap { display:grid; grid-template-columns: max-content 1fr; border:1px solid #ddd; border-radius:4px; overflow:hidden; flex: 1; } #gutter, #t { font: 14px/var(--line-h) ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; } @@ -179,7 +180,7 @@ HTML = """
- disconnected + disconnected
@@ -332,6 +333,7 @@ function connect(){ if (msg.type === "init") { isProtected = !!msg.protected; updateLockBtn(); + if (msg.peers !== undefined) { const el = $("#peers"); el.textContent = msg.peers; el.style.display = "inline"; } if (isProtected && !isAuthed) { showOverlay(); } else { @@ -354,6 +356,10 @@ function connect(){ ta.value = msg.text; ver = msg.ver; updateGutter(); ta.selectionStart = Math.min(s, ta.value.length); ta.selectionEnd = Math.min(e, ta.value.length); + } else if (msg.type === "peers_changed") { + const el = $("#peers"); + el.textContent = msg.count; + el.style.display = "inline"; } else if (msg.type === "protected_changed") { isProtected = msg.protected; updateLockBtn(); @@ -363,6 +369,7 @@ function connect(){ ws.onclose = () => { $("#status").textContent = "disconnected"; $("#status").classList.remove("connected"); + $("#peers").style.display = "none"; }; } $("#newpad").addEventListener("click", (e) => { e.preventDefault(); location.href = "/" + rand() + "/"; }); @@ -607,6 +614,9 @@ async def ws(doc_id: str, ws: WebSocket): # Update access time update_room_access_time(doc_id) + # Notify all peers of updated count + await _broadcast(doc_id, {"type": "peers_changed", "count": len(room["peers"])}) + # Per-connection auth state: already authed if pad has no password authed = room["pw_hash"] is None @@ -616,6 +626,7 @@ async def ws(doc_id: str, ws: WebSocket): "text": room["text"] if authed else "", "ver": room["ver"], "protected": room["pw_hash"] is not None, + "peers": len(room["peers"]), })) try: while True: @@ -685,6 +696,7 @@ async def ws(doc_id: str, ws: WebSocket): pass finally: room["peers"].discard(ws) + await _broadcast(doc_id, {"type": "peers_changed", "count": len(room["peers"])}) # Decrement connection count for this IP connections_per_ip[client_ip] = max(0, connections_per_ip[client_ip] - 1)