From e5ecc6c212d87048c50d3a47b347a2dd386a367c Mon Sep 17 00:00:00 2001 From: deacon Date: Sun, 15 Mar 2026 23:45:09 -0400 Subject: [PATCH 1/2] Fix session endpoint errors causing 'Error refreshing Manx' toast Wrap tcp_handler.refresh() and session list comprehensions in try/except blocks so that transient TCP errors (e.g. deprecated socket API) do not crash the page load or return HTTP 500 from the sessions endpoint. On failure, an empty session list is returned instead, keeping the UI functional. Fixes #52 --- app/term_api.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/app/term_api.py b/app/term_api.py index b3b074e..14992e9 100644 --- a/app/term_api.py +++ b/app/term_api.py @@ -22,25 +22,34 @@ def __init__(self, services): @template('manx.html') async def splash(self, request): - await self.term_svc.socket_conn.tcp_handler.refresh() try: + await self.term_svc.socket_conn.tcp_handler.refresh() sessions = [dict(id=s.id, info=a.paw, platform=a.platform, executors=a.executors) for s in self.term_svc.socket_conn.tcp_handler.sessions for a in await self.data_svc.locate('agents', match=dict(paw=s.paw))] - return dict(sessions=sessions, websocket=self.get_config('app.contact.websocket')) except Exception as e: print(e) + sessions = [] + return dict(sessions=sessions, websocket=self.get_config('app.contact.websocket')) async def get_sessions(self, request): - await self.term_svc.socket_conn.tcp_handler.refresh() - sessions = [dict(id=s.id, info=a.paw, platform=a.platform, executors=a.executors) - for s in self.term_svc.socket_conn.tcp_handler.sessions - for a in await self.data_svc.locate('agents', match=dict(paw=s.paw))] + try: + await self.term_svc.socket_conn.tcp_handler.refresh() + sessions = [dict(id=s.id, info=a.paw, platform=a.platform, executors=a.executors) + for s in self.term_svc.socket_conn.tcp_handler.sessions + for a in await self.data_svc.locate('agents', match=dict(paw=s.paw))] + except Exception as e: + print(e) + sessions = [] return web.json_response(dict(sessions=sessions)) async def sessions(self, request): - await self.term_svc.socket_conn.tcp_handler.refresh() - sessions = [dict(id=s.id, info=s.paw) for s in self.term_svc.socket_conn.tcp_handler.sessions] + try: + await self.term_svc.socket_conn.tcp_handler.refresh() + sessions = [dict(id=s.id, info=s.paw) for s in self.term_svc.socket_conn.tcp_handler.sessions] + except Exception as e: + print(e) + sessions = [] return web.json_response(sessions) async def get_history(self, request): From 7a43fead17653491b085866de5e021702aba4605 Mon Sep 17 00:00:00 2001 From: deacon Date: Mon, 16 Mar 2026 00:29:34 -0400 Subject: [PATCH 2/2] fix: narrow exception handling in term_api and use structured logging - Wrap only tcp_handler.refresh() in try/except (not the agent lookup) - Replace print(e) with log.error() using module-level logger - get_sessions and sessions now raise HTTPInternalServerError on refresh failure instead of silently returning 200 with empty list --- app/term_api.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/app/term_api.py b/app/term_api.py index 14992e9..a16cb1e 100644 --- a/app/term_api.py +++ b/app/term_api.py @@ -1,3 +1,4 @@ +import logging import os import pathlib from shutil import which @@ -8,6 +9,8 @@ from app.utility.base_service import BaseService from plugins.manx.app.term_svc import TermService +log = logging.getLogger(__name__) + class TermApi(BaseService): @@ -24,32 +27,32 @@ def __init__(self, services): async def splash(self, request): try: await self.term_svc.socket_conn.tcp_handler.refresh() - sessions = [dict(id=s.id, info=a.paw, platform=a.platform, executors=a.executors) - for s in self.term_svc.socket_conn.tcp_handler.sessions - for a in await self.data_svc.locate('agents', match=dict(paw=s.paw))] except Exception as e: - print(e) - sessions = [] + log.error('Failed to refresh TCP handler: %s', e) + return dict(sessions=[], websocket=self.get_config('app.contact.websocket')) + sessions = [dict(id=s.id, info=a.paw, platform=a.platform, executors=a.executors) + for s in self.term_svc.socket_conn.tcp_handler.sessions + for a in await self.data_svc.locate('agents', match=dict(paw=s.paw))] return dict(sessions=sessions, websocket=self.get_config('app.contact.websocket')) async def get_sessions(self, request): try: await self.term_svc.socket_conn.tcp_handler.refresh() - sessions = [dict(id=s.id, info=a.paw, platform=a.platform, executors=a.executors) - for s in self.term_svc.socket_conn.tcp_handler.sessions - for a in await self.data_svc.locate('agents', match=dict(paw=s.paw))] except Exception as e: - print(e) - sessions = [] + log.error('Failed to refresh TCP handler: %s', e) + raise web.HTTPInternalServerError(reason='Failed to refresh sessions') + sessions = [dict(id=s.id, info=a.paw, platform=a.platform, executors=a.executors) + for s in self.term_svc.socket_conn.tcp_handler.sessions + for a in await self.data_svc.locate('agents', match=dict(paw=s.paw))] return web.json_response(dict(sessions=sessions)) async def sessions(self, request): try: await self.term_svc.socket_conn.tcp_handler.refresh() - sessions = [dict(id=s.id, info=s.paw) for s in self.term_svc.socket_conn.tcp_handler.sessions] except Exception as e: - print(e) - sessions = [] + log.error('Failed to refresh TCP handler: %s', e) + raise web.HTTPInternalServerError(reason='Failed to refresh sessions') + sessions = [dict(id=s.id, info=s.paw) for s in self.term_svc.socket_conn.tcp_handler.sessions] return web.json_response(sessions) async def get_history(self, request):