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)