Home
/sse-webnotepad-python
import asyncio
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, StreamingResponse
import uvicorn
app = FastAPI()
NOTE_FILE = Path("note.txt")
NOTE_FILE.touch(exist_ok=True)
clients = set()
HTML = """
<!DOCTYPE html>
<html>
<head>
<title>SSE Notepad</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 900px;
margin: 20px auto;
}
textarea {
width: 100%;
height: 500px;
font-size: 16px;
padding: 10px;
box-sizing: border-box;
}
</style>
</head>
<body>
<h2>Live Notepad (SSE)</h2>
<textarea id="editor"></textarea>
<script>
const editor = document.getElementById("editor");
let suppressSend = false;
fetch("/content")
.then(r => r.text())
.then(text => {
editor.value = text;
});
const events = new EventSource("/events");
events.onmessage = (event) => {
const incoming = event.data;
if (editor.value !== incoming) {
suppressSend = true;
editor.value = incoming;
suppressSend = false;
}
};
let timer;
editor.addEventListener("input", () => {
if (suppressSend) return;
clearTimeout(timer);
timer = setTimeout(() => {
fetch("/update", {
method: "POST",
headers: {
"Content-Type": "text/plain"
},
body: editor.value
});
}, 150);
});
</script>
</body>
</html>
"""
@app.get("/", response_class=HTMLResponse)
async def index():
return HTML
@app.get("/content")
async def content():
return NOTE_FILE.read_text(encoding="utf-8")
@app.post("/update")
async def update(request: Request):
text = (await request.body()).decode("utf-8")
NOTE_FILE.write_text(text, encoding="utf-8")
for queue in list(clients):
await queue.put(text)
return {"status": "ok"}
@app.get("/events")
async def events():
queue = asyncio.Queue()
clients.add(queue)
async def event_stream():
try:
yield f"data: {NOTE_FILE.read_text(encoding='utf-8')}\n\n"
while True:
data = await queue.get()
data = (
data.replace("\\", "\\\\")
.replace("\\r", "")
.replace("\\n", "\\ndata: ")
)
yield f"data: {data}\n\n"
finally:
clients.discard(queue)
return StreamingResponse(
event_stream(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
},
)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)