"""Imports""" import asyncio import os import traceback from datetime import datetime import websockets import aiofiles LOG_DIR = "/var/log/pi-star" LOG_PREFIX = "MMDVM-" LOG_EXT = ".log" KEYWORDS = ["DMR"] # Add more keywords here def get_logfile_path(): """Return the correct logfile path based on UTC.""" date_str = datetime.utcnow().strftime("%Y-%m-%d") return os.path.join(LOG_DIR, f"{LOG_PREFIX}{date_str}{LOG_EXT}") async def tail_log(websocket, path): """Read the latest log file and stream lines with specified keywords.""" last_checked_file = get_logfile_path() print(f"Client connected: {websocket.remote_address}") # Wait for the file to exist while not os.path.exists(last_checked_file): print(f"Waiting for log file: {last_checked_file}") await asyncio.sleep(2) last_checked_file = get_logfile_path() file = await aiofiles.open(last_checked_file, "r") await file.seek(0, 2) # Move to the end of the file try: while True: current_logfile = get_logfile_path() if current_logfile != last_checked_file: print(f"Switching to new log file: {current_logfile}") await file.close() # Explicitly close previous file last_checked_file = current_logfile # Wait until the new log file is ready while not os.path.exists(last_checked_file): print(f"Waiting for new log file: {last_checked_file}") await asyncio.sleep(2) file = await aiofiles.open(last_checked_file, "r") await file.seek(0, 2) # Go to end of new file line = await file.readline() if line: print(f"READ LINE: {line.strip()}") if any(keyword in line for keyword in KEYWORDS): print(f"SENDING: {line.strip()}") await websocket.send(line.strip()) else: await asyncio.sleep(0.5) # Prevent busy-waiting except websockets.exceptions.ConnectionClosed: print(f"Client {websocket.remote_address} disconnected.") except Exception as error: print(f"Unexpected error: {error}") traceback.print_exc() finally: await file.close() # Ensure file closure async def main(): """Start the WebSocket server.""" print("Starting WebSocket server on ws://0.0.0.0:8765") async with websockets.serve(tail_log, "0.0.0.0", 8765): await asyncio.Future() # Run forever if __name__ == "__main__": asyncio.run(main())