Web Sockets

from fasthtml.common import *
from collections import deque

app, rt = fast_app(exts='ws')

# All messages here, but only most recent 15 are stored
messages = deque(maxlen=15)
users = {}

# Takes all the messages and renders them
box_style = "border: 1px solid #ccc; border-radius: 10px; padding: 10px; margin: 5px 0;"
def render_messages(messages):
    return Div(*[Div(m, style=box_style) for m in messages], id='msg-list')

# Input field is reset via hx_swap_oob after submitting a message
def mk_input(): return Input(id='msg', placeholder="Type your message", value="", hx_swap_oob="true")

@rt
def index():
    return Titled("Leave a message for others!"),Div(
        Form(mk_input(), ws_send=True), # input field
        P("Leave a message for others!"),
        Div(render_messages(messages),id='msg-list'), # All the Messages
        hx_ext='ws', ws_connect='ws') # Use a web socket 

def on_connect(ws, send): users[id(ws)] = send
def on_disconnect(ws):users.pop(id(ws),None)

@app.ws('/ws', conn=on_connect, disconn=on_disconnect)
async def ws(msg:str,send):
    await send(mk_input()) # reset the input field immediately
    messages.appendleft(msg) # New messages first
    for u in users.values(): # Get `send` function for a user
        await u(render_messages(messages)) # Send the message to that user

serve()