Files
jensandClaude Sonnet 4.6 0f31cc41cc Handle abrupt WebSocket disconnect (e.g. Safari tab close)
Catch ConnectionClosed in User.send() and handler_recv() so that an
unclean client disconnect no longer produces "Task exception was never
retrieved" / "connection handler failed" log noise.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SH2D4LRuCnhLSzoYerAfJX
2026-06-28 15:34:53 +02:00

137 lines
2.3 KiB
Python

import dpath.util as dp
import json
import websockets.exceptions
def update(d, u, only_existing=True):
for k, v in u.items():
if isinstance(v, dict):
if only_existing:
r = update(d.get(k, {}), v)
d[k] = r
else:
d[k] = v
else:
d[k] = u[k]
return d
class User:
def __init__(self, socket):
self.socket = socket
self.paths = []
async def send(self, data):
result = {}
for path in self.paths:
msg = dp.search(data, path)
result.update(msg)
if len(result) != 0:
try:
await self.socket.send(json.dumps(result))
except websockets.exceptions.ConnectionClosed:
pass
async def process(self, data):
handled = True
try:
# Handle message subscription
d = json.loads(data)
if "+" in d:
path = d['+']
print("Received subscribe {}".format(path))
self.path_add(path)
elif "-" in d:
path = d['-']
print("Received unsubscribe {}".format(path))
self.path_remove(path)
elif "?" in d:
print("Subscriptions: {}".format(self.paths))
await self.socket.send(json.dumps({"?": self.paths}))
else:
handled = False
except Exception as e:
print(e)
return handled
def path_add(self, path):
if path not in self.paths:
self.paths.append(path)
def path_remove(self, path):
if path in self.paths:
self.paths.remove(path)
class UserSet:
def __init__(self):
self.users = {}
self.keys = None
def __len__(self):
return len(self.users)
def clear(self):
self.users = {}
self.keys = None
def add(self, key, user):
self.users[key] = user
def remove(self, key):
self.users.pop(key, None)
def get(self, key):
return self.users[key]
def __iter__(self):
self.keys = iter(self.users.keys())
return self
def __next__(self):
return self.users[next(self.keys)]
def check_fill(u):
if u:
print("Is occupied")
else:
print("Is empty")
if __name__ == '__main__':
userset = UserSet()
check_fill(userset)
userset.add(1, "A")
userset.add(2, "B")
userset.add(3, "C")
check_fill(userset)
print("Len(userset) = {}".format(userset))
for i in userset:
print(i)
userset.remove(3)
for i in userset:
print(i)
userset.remove(2)
for i in userset:
print(i)
userset.remove(1)
for i in userset:
print(i)
a = {'Pot': {'Temp': 15.5}}
b = {'Pot': {'Power': 2400}}
print(a)
print(b)
a = update(a, b)
print("a | b = {}".format(a))