Compare commits

..

No commits in common. "b41339a8c5d548da18142ec4cd9991cff8550a69" and "41f5369b2f932d5466411fbb79ece6956f00d8ff" have entirely different histories.

4 changed files with 41 additions and 10 deletions

View file

@ -5,6 +5,9 @@
"kind": { "kind": {
"const": "cocoa", "const": "cocoa",
"default": "cocoa", "default": "cocoa",
"enum": [
"cocoa"
],
"title": "Kind", "title": "Kind",
"type": "string" "type": "string"
} }
@ -49,14 +52,28 @@
"WebsocketsReceiverConfig": { "WebsocketsReceiverConfig": {
"properties": { "properties": {
"host": { "host": {
"description": "The hostname you'd like your WebSockets server to listen on. In most cases the default behaviour, which binds to all network interfaces, will be fine.", "anyOf": [
{
"format": "hostname", "format": "hostname",
"title": "Host",
"type": "string" "type": "string"
}, },
{
"items": {
"format": "hostname",
"type": "string"
},
"type": "array"
}
],
"description": "The hostname you'd like your WebSockets server to listen on. In most cases the default behaviour, which binds to all network interfaces, will be fine.",
"title": "Host"
},
"kind": { "kind": {
"const": "websockets", "const": "websockets",
"default": "websockets", "default": "websockets",
"enum": [
"websockets"
],
"title": "Kind", "title": "Kind",
"type": "string" "type": "string"
}, },

View file

@ -136,6 +136,9 @@
}, },
{ {
"const": "oneshot", "const": "oneshot",
"enum": [
"oneshot"
],
"type": "string" "type": "string"
} }
], ],
@ -169,6 +172,9 @@
}, },
{ {
"const": "oneshot", "const": "oneshot",
"enum": [
"oneshot"
],
"type": "string" "type": "string"
} }
], ],
@ -322,6 +328,9 @@
"state": { "state": {
"const": "stop", "const": "stop",
"default": "stop", "default": "stop",
"enum": [
"stop"
],
"title": "State", "title": "State",
"type": "string" "type": "string"
} }

View file

@ -35,7 +35,7 @@ class WebsocketsReceiverConfig(BaseReceiverConfig):
#: The hostname you'd like your WebSockets server to listen on. In most #: The hostname you'd like your WebSockets server to listen on. In most
#: cases the default behaviour, which binds to all network interfaces, will #: cases the default behaviour, which binds to all network interfaces, will
#: be fine. #: be fine.
host: Optional[Host] = None host: Optional[Host | tuple[Host, ...]] = None
ReceiverConfig = Annotated[ ReceiverConfig = Annotated[

View file

@ -2,7 +2,7 @@ from pathlib import Path
import ormsgpack import ormsgpack
from websockets import broadcast from websockets import broadcast
from websockets.asyncio.server import Server, ServerConnection, serve from websockets.server import WebSocketServerProtocol, serve
from yarl import URL from yarl import URL
from ...config.model import WebsocketsReceiverConfig from ...config.model import WebsocketsReceiverConfig
@ -24,11 +24,12 @@ def default(value: object) -> object:
class WebsocketsReceiver(Receiver): class WebsocketsReceiver(Receiver):
config: WebsocketsReceiverConfig config: WebsocketsReceiverConfig
player: Player player: Player
server: Server connections: set[WebSocketServerProtocol]
last_status: bytes = MSGPACK_NULL last_status: bytes = MSGPACK_NULL
def __init__(self, config: WebsocketsReceiverConfig): def __init__(self, config: WebsocketsReceiverConfig):
self.config = config self.config = config
self.connections = set()
@classmethod @classmethod
def loop_factory(cls) -> DefaultLoopFactory: def loop_factory(cls) -> DefaultLoopFactory:
@ -36,14 +37,18 @@ class WebsocketsReceiver(Receiver):
async def start(self, player: Player) -> None: async def start(self, player: Player) -> None:
self.player = player self.player = player
self.server = await serve( await serve(
self.handle, host=self.config.host, port=self.config.port, reuse_port=True self.handle, host=self.config.host, port=self.config.port, reuse_port=True
) )
async def handle(self, conn: ServerConnection) -> None: async def handle(self, conn: WebSocketServerProtocol) -> None:
self.connections.add(conn)
await conn.send(self.last_status) await conn.send(self.last_status)
try:
await conn.wait_closed() await conn.wait_closed()
finally:
self.connections.remove(conn)
async def update(self, playback: Playback) -> None: async def update(self, playback: Playback) -> None:
self.last_status = ormsgpack.packb(playback, default=default) self.last_status = ormsgpack.packb(playback, default=default)
broadcast(self.server.connections, self.last_status) broadcast(self.connections, self.last_status)