import asyncio, datetime, hashlib, base64
def ts(): return datetime.datetime.now().strftime("%H:%M:%S")
GUID="258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
def ws_accept(key):
    return base64.b64encode(hashlib.sha1((key+GUID).encode()).digest()).decode()
def hexs(b): return b.hex()
async def handle(reader, writer):
    peer=writer.get_extra_info('peername')
    print(f"[{ts()}] CONN from {peer}",flush=True)
    try:
        data=await asyncio.wait_for(reader.read(4096), timeout=20)
        if not data:
            print(f"[{ts()}] (closed empty)",flush=True); return
        if data[:1]==b'\x16':
            print(f"[{ts()}] *** TLS/wss ClientHello {len(data)}B {data[:20].hex()}",flush=True); return
        if data[:3]==b'GET':
            txt=data.decode('latin1')
            print(f"[{ts()}] *** WS UPGRADE:\n{txt[:600]}",flush=True)
            key=""
            for line in txt.split("\r\n"):
                if line.lower().startswith("sec-websocket-key:"): key=line.split(":",1)[1].strip()
            resp=("HTTP/1.1 101 Switching Protocols\r\n"
                  "Upgrade: websocket\r\nConnection: Upgrade\r\n"
                  f"Sec-WebSocket-Accept: {ws_accept(key)}\r\n\r\n")
            writer.write(resp.encode()); await writer.drain()
            print(f"[{ts()}] -> sent 101; awaiting Photon frames...",flush=True)
            while True:
                frame=await asyncio.wait_for(reader.read(4096), timeout=30)
                if not frame: print(f"[{ts()}] client closed",flush=True); break
                print(f"[{ts()}] FRAME {len(frame)}B {frame[:120].hex()}",flush=True)
        else:
            print(f"[{ts()}] raw {len(data)}B {data[:120].hex()}",flush=True)
    except asyncio.TimeoutError:
        print(f"[{ts()}] timeout",flush=True)
    except Exception as e:
        print(f"[{ts()}] err {e}",flush=True)
    finally:
        try: writer.close()
        except: pass
async def main():
    await asyncio.start_server(handle,'0.0.0.0',5058)
    print("PHSERV listening 5058",flush=True)
    await asyncio.Event().wait()
asyncio.run(main())
