FastAPI-websocket, two channels

This commit is contained in:
marys
2025-09-30 13:28:58 +02:00
parent 5a14ab7be0
commit 26da9259ea
2 changed files with 70 additions and 61 deletions

View File

@@ -5,34 +5,50 @@
</head> </head>
<body> <body>
<h1>WebSocket Chat</h1> <h1>WebSocket Chat</h1>
<h2>Your ID: <span id="ws-id"></span></h2>
<form action="" onsubmit="sendMessage(event)"> <form action="" onsubmit="sendMessage(event)">
<label>Item ID: <input type="text" id="itemId" autocomplete="off" value="foo"/></label> <input type="text" id="messageText" autocomplete="off"/>
<label>Token: <input type="text" id="token" autocomplete="off" value="some-key-token"/></label>
<button onclick="connect(event)">Connect</button>
<hr>
<label>Message: <input type="text" id="messageText" autocomplete="off"/></label>
<button>Send</button> <button>Send</button>
<br>
<input type="text" id="messageText2" autocomplete="off"/>
<button onclick="sentMessage2(event)">Send 1</button>
</form> </form>
Channel 1
<ul id='messages'> <ul id='messages'>
</ul> </ul>
Channel 2
<ul id="messages2">
</ul>
<script> <script>
var ws = null; var client_id = Date.now()
function connect(event) { document.querySelector("#ws-id").textContent = client_id;
var itemId = document.getElementById("itemId") <!-- channel 1 -->
var token = document.getElementById("token") var ws_channel1 = new WebSocket(`ws://localhost:8000/ws/${client_id}`);
ws = new WebSocket("ws://localhost:8000/items/" + itemId.value + "/ws?token=" + token.value); ws_channel1.onmessage = function(event) {
ws.onmessage = function(event) {
var messages = document.getElementById('messages') var messages = document.getElementById('messages')
var message = document.createElement('li') var message = document.createElement('li')
var content = document.createTextNode(event.data) var content = document.createTextNode(event.data)
message.appendChild(content) message.appendChild(content)
messages.appendChild(message) messages.appendChild(message)
}; };
event.preventDefault()
}
function sendMessage(event) { function sendMessage(event) {
var input = document.getElementById("messageText") var input = document.getElementById("messageText")
ws.send(input.value) ws_channel1.send(input.value)
input.value = ''
event.preventDefault()
}
<!-- channel 2 -->
var ws_channel2 = new WebSocket(`ws://localhost:8000/ws1/${client_id}`);
ws_channel2.onmessage = function(event) {
var messages = document.getElementById('messages2')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
};
function sentMessage2(event) {
var input = document.getElementById("messageText2")
ws_channel2.send(input.value)
input.value = '' input.value = ''
event.preventDefault() event.preventDefault()
} }

View File

@@ -1,70 +1,49 @@
import logging
from fastapi import FastAPI, WebSocket, WebSocketDisconnect from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse from fastapi.responses import HTMLResponse
logging.basicConfig(
level=logging.DEBUG, # Use DEBUG or INFO for dev
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
logger = logging.getLogger(__name__)
app = FastAPI() app = FastAPI()
html = """
<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<h2>Your ID: <span id="ws-id"></span></h2>
<form action="" onsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<script>
var client_id = Date.now()
document.querySelector("#ws-id").textContent = client_id;
var ws = new WebSocket(`ws://localhost:8000/ws/${client_id}`);
ws.onmessage = function(event) {
var messages = document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message)
};
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value)
input.value = ''
event.preventDefault()
}
</script>
</body>
</html>
"""
class ConnectionManager: class ConnectionManager:
def __init__(self): def __init__(self):
self.active_connections: list[WebSocket] = [] self.active_connections: list[WebSocket] = []
self.logger = logging.getLogger(self.__class__.__name__)
async def connect(self, websocket: WebSocket): async def connect(self, websocket: WebSocket):
await websocket.accept() await websocket.accept()
self.logger.info("connect")
self.active_connections.append(websocket) self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket): def disconnect(self, websocket: WebSocket):
self.logger.info("disconnect")
self.active_connections.remove(websocket) self.active_connections.remove(websocket)
async def send_personal_message(self, message: str, websocket: WebSocket): async def send_personal_message(self, message: str, websocket: WebSocket):
await websocket.send_text(message) self.logger.info("send_personal_message")
print(f"send_personal_message: {message}")
await websocket.send_text(f"personal: {message}")
async def broadcast(self, message: str): async def broadcast(self, message: str):
self.logger.info("broadcast")
for connection in self.active_connections: for connection in self.active_connections:
await connection.send_text(message) await connection.send_text(message)
manager = ConnectionManager() manager = ConnectionManager()
manager2 = ConnectionManager()
@app.get("/") @app.get("/")
async def get(): async def get():
with open("html/index.html") as html_index:
html = html_index.read()
return HTMLResponse(html) return HTMLResponse(html)
@@ -74,8 +53,22 @@ async def websocket_endpoint(websocket: WebSocket, client_id: int):
try: try:
while True: while True:
data = await websocket.receive_text() data = await websocket.receive_text()
logger.info(f"channel 1: {data}")
await manager.send_personal_message(f"You wrote: {data}", websocket) await manager.send_personal_message(f"You wrote: {data}", websocket)
await manager.broadcast(f"Client #{client_id} says: {data}") await manager.broadcast(f"Client #{client_id} says: {data}")
except WebSocketDisconnect: except WebSocketDisconnect:
manager.disconnect(websocket) manager.disconnect(websocket)
await manager.broadcast(f"Client #{client_id} left the chat") await manager.broadcast(f"Client #{client_id} left the chat")
@app.websocket("/ws1/{client_id}")
async def websocket_endpoint1(websocket: WebSocket, client_id: int):
await manager2.connect(websocket)
try:
while True:
data = await websocket.receive_text()
logger.info(f"channel 2: {data}")
await manager2.send_personal_message(f"You wrote: {data}", websocket)
await manager2.broadcast(f"Client #{client_id} says: {data}")
except WebSocketDisconnect:
manager2.disconnect(websocket)
await manager2.broadcast(f"Client #{client_id} left the chat")