# cPy - Webserver demonstrating websockets
# provided by Anthony Vogelaar, Perth Scotland
# rev 0.10  2025-03-05  initial release

import  platform
import  os;                 os.system('clear')
import  json, time
import  asyncio
from    microdot            import  Microdot, send_file
from    microdot.websocket  import  with_websocket
import  webbrowser

# =========================== local ================================

def openBrowser(port=5000):
    if platform.uname().machine == 'aarch64': pass
        #qpy:webapp:'R&D WebApp'
        #qpy://127.0.0.1:5000
    else: webbrowser.open('localhost:5000', new=1)  # open een new browser window

# ========================== webserver =============================

websockets = set()


def webServer(port=5000):
    app = Microdot()

    @app.route('/')
    async def index(request):
        return send_file('static/index.html')


    @app.route('/static/<path:path>')
    async def static(request, path):
        if '..' in path:
            return 'Not found', 404                 # directory traversal is not allowed
        return send_file('static/' + path)


    @app.route('/ws')
    @with_websocket
    async def onWs(request, ws):
        websockets.add(ws)
        try:
            while True:
                obj = json.loads(await ws.receive())
                print('received from ws:', obj)
        except: print('webServer.onWs: exception')
        websockets.remove(ws)


    return app


async def broadcast(d):
    for ws in websockets:
        await ws.send(json.dumps(d))


# ============================ Main ================================

class Main:

    def __init__(self, port=5000):
        self.port = port
        openBrowser()
        asyncio.run(self.aioInit())


    # launch all aio tasks
    async def aioInit(self):
        app    = webServer()
        async with asyncio.TaskGroup() as tg:
            tg.create_task(app.start_server(port=self.port))
            tg.create_task(self._task())


    # monitor, print '*' and broadcast time @ 1 Hz
    async def _task(self):
        n = 0
        while True:
            print('*', end='', flush=True)
            await broadcast(dict(msg=time.strftime('%H:%M:%S')))
            await asyncio.sleep(1)


try:
    Main()
except KeyboardInterrupt:
    print('\nTerminated by Ctrl-C')

# ============================= end =================================
