#!/usr/bin/env python

import argparse
import asyncio
import os
import logging
import re
import sys
from logging.handlers import RotatingFileHandler
from websockets.asyncio.server import serve, broadcast

parser = argparse.ArgumentParser(
	description="Spelloff shoutbox websocket server")
parser.add_argument("-H", "--host", help="Host",
                    default=os.environ.get("SPELLOFF_SHOUTBOX_HOST") or "localhost")
parser.add_argument("-p", "--port", help="Port",
                    default=os.environ.get("SPELLOFF_SHOUTBOX_PORT") or 8765)
parser.add_argument("-l", "--log-path", help="Logfile path",
                    default=os.environ.get("SPELLOFF_LOG_PATH") or "messages.log")
parser.add_argument("-m", "--max-log-size", help="Maximum logfile size (in bytes)",
                    default=os.environ.get("SPELLOFF_MAX_LOG_SIZE") or 1024 * 100)
args = vars(parser.parse_args())
host, port, log_path, max_log_size = map(
	args.get, ("host", "port", "log_path", "max_log_size"))

websockets = set()
messages_log_level = 100  # Custom logging level
logger = logging.getLogger(__name__)
ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')


async def shoutbox(websocket):
	websockets.add(websocket)

	try:
		welcome_message = "Connected to shoutbox.\n"
		await websocket.send(welcome_message)

		with open(log_path, "r") as past_messages:
			await websocket.send(past_messages.read().rstrip())
			past_messages.close()

		async for message in websocket:
			clean_message = ansi_escape.sub("", message)
			logger.log(messages_log_level, clean_message)
			broadcast(websockets, clean_message)
	finally:
		websockets.remove(websocket)


async def main():
	logging.basicConfig(format='%(message)s',
                     filename=log_path, level=messages_log_level)
	handler = RotatingFileHandler(log_path, maxBytes=max_log_size, backupCount=1)
	logger.addHandler(handler)
	logger.propagate = False

	async with serve(shoutbox, host, port) as server:
		await server.serve_forever()


if __name__ == "__main__":
	asyncio.run(main())
