From: Benjamin Braatz Date: Tue, 31 Mar 2026 19:12:20 +0000 (+0200) Subject: Change to new websockets API X-Git-Tag: v0.4.1 X-Git-Url: http://git.graph-it.com/?a=commitdiff_plain;h=1c3145a09bb057815a69dbd712b102da4ec82aeb;p=graphit%2Fcontrolpi-wsserver.git Change to new websockets API --- diff --git a/controlpi_plugins/wsserver.py b/controlpi_plugins/wsserver.py index c0dad68..db2d47d 100644 --- a/controlpi_plugins/wsserver.py +++ b/controlpi_plugins/wsserver.py @@ -7,13 +7,13 @@ import http import json import os import sys -from websockets.datastructures import Headers from websockets.exceptions import ConnectionClosed -from websockets.server import serve, WebSocketServerProtocol +from websockets.asyncio.server import serve, ServerConnection +from websockets.http11 import Request, Response from controlpi import BasePlugin, MessageBus, BusException, Message, MessageTemplate -from typing import Optional, Tuple +from typing import Optional class Connection: @@ -22,7 +22,7 @@ class Connection: Instances are created on external connections to websocket. """ - def __init__(self, bus: MessageBus, websocket: WebSocketServerProtocol) -> None: + def __init__(self, bus: MessageBus, websocket: ServerConnection) -> None: """Initialise conncection. Message bus and websocket are set by websocket server when creating @@ -138,9 +138,6 @@ class Connection: self._bus.unregister(self._name) -Response = Optional[Tuple[http.HTTPStatus, Headers, bytes]] - - class WSServer(BasePlugin): """Websocket server plugin. @@ -216,15 +213,13 @@ class WSServer(BasePlugin): base_url += "/" self._web_proxies[path] = base_url - async def _process_request(self, path: str, request_headers: Headers) -> Response: + async def _process_request( + self, websocket: ServerConnection, request: Request + ) -> Optional[Response]: """Serve as simple web server.""" - if "Upgrade" in request_headers: + if "Upgrade" in request.headers: return None - status = None - body = b"" - response_headers = Headers() - response_headers["Server"] = "controlpi-wsserver websocket server" - response_headers["Connection"] = "close" + path = request.path location = "" url = "" start_path_length = 0 @@ -244,15 +239,19 @@ class WSServer(BasePlugin): start_path += "/" relative_path = path[len(start_path) :] url = base_url + relative_path + response = None if location: if os.path.isdir(location) and not path.endswith("/"): - status = http.HTTPStatus.MOVED_PERMANENTLY - response_headers["Location"] = path + "/" + response = websocket.respond(http.HTTPStatus.MOVED_PERMANENTLY, "") + response.headers["Location"] = path + "/" else: if os.path.isdir(location): location = os.path.join(location, "index.html") if os.path.isfile(location): - status = http.HTTPStatus.OK + # Read body from file: + async with aiofiles.open(location, "rb") as f: + body = (await f.read()).decode() + response = websocket.respond(http.HTTPStatus.OK, body) # Determine MIME type: content_type = "application/octet-stream" extension = os.path.basename(location).split(".")[-1] @@ -264,26 +263,22 @@ class WSServer(BasePlugin): content_type = "text/css" elif extension == "jpg": content_type = "image/jpeg" - response_headers["Content-Type"] = content_type - # Read body from file: - async with aiofiles.open(location, "rb") as f: - body = await f.read() - response_headers["Content-Length"] = str(len(body)) + del response.headers["Content-Type"] + response.headers["Content-Type"] = content_type if url: async with aiohttp.ClientSession() as session: - async with session.get(url) as resp: - status = http.HTTPStatus.OK - response_headers["Content-Type"] = resp.headers["Content-Type"] - response_headers["Content-Length"] = resp.headers["Content-Length"] - body = await resp.read() - if not status: - status = http.HTTPStatus.NOT_FOUND - body = f"'{path}' not found!".encode() - response_headers["Content-Type"] = "text/plain" - response_headers["Content-Length"] = str(len(body)) - return status, response_headers, body + async with session.get(url) as original: + body = (await original.read()).decode() + response = websocket.respond(http.HTTPStatus.OK, body) + del response.headers["Content-Type"] + response.headers["Content-Type"] = original.headers["Content-Type"] + if not response: + response = websocket.respond( + http.HTTPStatus.NOT_FOUND, f"'{path}' not found!" + ) + return response - async def _handler(self, websocket: WebSocketServerProtocol, path: str) -> None: + async def _handler(self, websocket: ServerConnection) -> None: """Create and run connection.""" connection = Connection(self.bus, websocket) await connection.run() diff --git a/setup.py b/setup.py index 7b6165c..4054a7b 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ with open("README.md", "r") as readme_file: setuptools.setup( name="controlpi-wsserver", - version="0.4.0", + version="0.4.1", author="Graph-IT GmbH", author_email="info@graph-it.com", description="ControlPi Plugin for Websocket Servers",