Home

/notepad-websockets-python

from pathlib import Path
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
import uvicorn

app = FastAPI()

NOTE_FILE = Path("note.txt")
if not NOTE_FILE.exists():
    NOTE_FILE.write_text("", encoding="utf-8")

connections: list[WebSocket] = []


HTML = """
<!DOCTYPE html>
<html>
<head>
    <title>Live Notepad</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 900px;
            margin: 20px auto;
        }

        textarea {
            width: 100%;
            height: 500px;
            padding: 10px;
            font-size: 16px;
            box-sizing: border-box;
        }

        .status {
            margin-bottom: 10px;
            color: green;
        }
    </style>
</head>
<body>
    <h2>Live Notepad</h2>
    <div class="status" id="status">Connected</div>

    <textarea id="editor"></textarea>

    <script>
        const editor = document.getElementById("editor");

        const ws = new WebSocket(
            `${location.protocol === "https:" ? "wss" : "ws"}://${location.host}/ws`
        );

        ws.onmessage = (event) => {
            if (editor.value !== event.data) {
                editor.value = event.data;
            }
        };

        editor.addEventListener("input", () => {
            ws.send(editor.value);
        });

        ws.onclose = () => {
            document.getElementById("status").textContent = "Disconnected";
        };
    </script>
</body>
</html>
"""


@app.get("/", response_class=HTMLResponse)
async def index():
    return HTML


@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    connections.append(websocket)

    try:
        current_text = NOTE_FILE.read_text(encoding="utf-8")
        await websocket.send_text(current_text)

        while True:
            text = await websocket.receive_text()

            NOTE_FILE.write_text(text, encoding="utf-8")

            dead = []
            for conn in connections:
                try:
                    await conn.send_text(text)
                except Exception:
                    dead.append(conn)

            for conn in dead:
                connections.remove(conn)

    except WebSocketDisconnect:
        if websocket in connections:
            connections.remove(websocket)


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)