Add --capture disabled mode + capture-mode status in PWA

Server:
- --capture accepts 'disabled'; no backend is created, capture_mode exposed
- /api/status returns capture_mode; capture start/stop return 403 when
  disabled; latest/status/delete_session are None-safe

PWA:
- captureMode state; conn-status shows server version
- new capture-mode line (Settings) explaining gsmtap/direct/disabled
- hide capture + New capture UI when disabled; trace empty-state shows
  'Capture unavailable'
- 7 new EN/RU i18n keys

Version 1.2.0 (server + PWA); tests: 111.
This commit is contained in:
catarrh committed 2026-08-14 23:49:10 +03:00
1 parent b900a8a3e1
commit 24d0decd51
7 files changed
+130 -22

No files matched your search

+8 -6
View File
@@ -29,8 +29,8 @@ def main():
help='HTTP server port (default: 8081)')
p.add_argument('--db', default=DEFAULT_DB_PATH,
help=f'SQLite database path (default: {DEFAULT_DB_PATH})')
p.add_argument('--capture', choices=['gsmtap', 'direct'], default='gsmtap',
help='Capture mode: gsmtap (listen UDP 4729) or direct (SIMtrace2 USB)')
p.add_argument('--capture', choices=['gsmtap', 'direct', 'disabled'], default='gsmtap',
help='Capture mode: gsmtap (listen UDP 4729), direct (SIMtrace2 USB), or disabled (no capture)')
p.add_argument('--gsmtap-port', type=int, default=4729,
help='UDP port for GSMTAP listener (default: 4729)')
p.add_argument('--web-dir', default=_default_web_dir(), metavar='PATH',
@@ -39,15 +39,17 @@ def main():
db = Database(args.db)
capture = None
if args.capture == 'gsmtap':
backend = GsmtapListener(bind_port=args.gsmtap_port)
else:
capture = CaptureManager(backend, db)
elif args.capture == 'direct':
backend = DirectSniffer()
capture = CaptureManager(backend, db)
capture = CaptureManager(backend, db)
RequestHandler.db = db
RequestHandler.capture = capture
RequestHandler.capture_mode = args.capture
server = HTTPServer(('127.0.0.1', args.port), RequestHandler)
server.web_dir = args.web_dir
@@ -65,7 +67,7 @@ def main():
except KeyboardInterrupt:
pass
finally:
if capture.active:
if capture and capture.active:
capture.stop_session()
server.server_close()
+16 -7
View File
@@ -42,6 +42,7 @@ def _content_disposition(filename):
class RequestHandler(BaseHTTPRequestHandler):
db: Database = None
capture: CaptureManager = None
capture_mode: str = 'gsmtap'
def log_message(self, fmt, *args):
print(f'[{self.log_date_time_string()}] {args[0]}', file=sys.stderr)
@@ -197,13 +198,15 @@ class RequestHandler(BaseHTTPRequestHandler):
def _handle_status(self):
active_session = self.db.get_active_session()
capture = self.capture
self._send_json({
'server': 'simtrace-analyser-server',
'version': __version__,
'capture_active': self.capture.active,
'session_id': self.capture.session_id,
'capture_mode': self.capture_mode,
'capture_active': capture.active if capture else False,
'session_id': capture.session_id if capture else None,
'mode': active_session['mode'] if active_session else None,
'messages_count': self.db.count_messages(self.capture.session_id) if self.capture.session_id else 0,
'messages_count': self.db.count_messages(capture.session_id) if capture and capture.session_id else 0,
})
def _handle_list_sessions(self):
@@ -259,7 +262,7 @@ class RequestHandler(BaseHTTPRequestHandler):
def _handle_capture_latest(self, params):
after_id = int(params.get('after', [0])[0])
if not self.capture.active:
if not self.capture or not self.capture.active:
self._send_json({'messages': [], 'next_after': after_id, 'active': False})
return
msg_id = self.capture.latest_msg_id
@@ -273,11 +276,14 @@ class RequestHandler(BaseHTTPRequestHandler):
def _handle_capture_status(self):
self._send_json({
'active': self.capture.active,
'session_id': self.capture.session_id,
'active': self.capture.active if self.capture else False,
'session_id': self.capture.session_id if self.capture else None,
})
def _handle_capture_start(self):
if self.capture_mode == 'disabled' or self.capture is None:
self._send_error(403, 'Capture disabled')
return
if self.capture.active:
self.capture.stop_session()
session_id = self.capture.start_session()
@@ -285,6 +291,9 @@ class RequestHandler(BaseHTTPRequestHandler):
self._send_json({'session_id': session_id, 'started': started})
def _handle_capture_stop(self):
if self.capture_mode == 'disabled' or self.capture is None:
self._send_error(403, 'Capture disabled')
return
if not self.capture.active:
self._send_error(400, 'No active capture')
return
@@ -336,7 +345,7 @@ class RequestHandler(BaseHTTPRequestHandler):
self._send_json({'ok': True})
def _handle_delete_session(self, session_id):
if self.capture.session_id == session_id:
if self.capture and self.capture.session_id == session_id:
self.capture.stop_session()
self.db.delete_session(session_id)
self.db.vacuum()