Skip to content

Commit

Permalink
fix: BroadcastMessageChannel needs a separate broadcast_encoder to ca…
Browse files Browse the repository at this point in the history
…ter for all use-cases
  • Loading branch information
ntamas committed Sep 5, 2024
1 parent cdf8d09 commit 239d5d3
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 7 deletions.
27 changes: 21 additions & 6 deletions src/flockwave/channels/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@
from flockwave.connections.capabilities import get_connection_capabilities
from flockwave.connections.errors import NoBroadcastAddressError

from .types import Encoder, MessageType, Parser, RawType, RPCRequestHandler
from .types import (
BroadcastMessageType,
Encoder,
MessageType,
Parser,
RawType,
RPCRequestHandler,
)

__all__ = ("BroadcastMessageChannel", "MessageChannel")

Expand Down Expand Up @@ -143,11 +150,16 @@ async def _read(self) -> None:
self._pending.extend(self._parser(data))


class BroadcastMessageChannel(MessageChannel[MessageType, RawType]):
class BroadcastMessageChannel(
Generic[MessageType, RawType, BroadcastMessageType],
MessageChannel[MessageType, RawType],
):
"""MessageChannel_ subclass that provides a dedicated method for sending a
message with broadcast semantics.
"""

_broadcast_encoder: Encoder[BroadcastMessageType, RawType]

_can_broadcast: bool = False
"""Cached property that holds whether the underlying connection can
broadcast.
Expand All @@ -158,24 +170,27 @@ def __init__(
connection: RWConnection[RawType, RawType],
parser: Parser[RawType, MessageType],
encoder: Encoder[MessageType, RawType],
broadcast_encoder: Encoder[BroadcastMessageType, RawType],
):
super().__init__(connection, parser, encoder)

self._broadcast_encoder = broadcast_encoder

cap = get_connection_capabilities(self._connection)
self._can_broadcast = cap["can_broadcast"]

async def broadcast(self, value: MessageType) -> None:
async def broadcast(self, value: BroadcastMessageType) -> None:
"""Broadcasts the given message on the channel. No-op if the underlying
connection has no broadcast address at the moment but _could_ broadcast
in theory. Falls back to sending the message if the underlying
connection has no broadcast capabilities.
"""
encoded = self._broadcast_encoder(value)
if self._can_broadcast:
encoded = self._encoder(value)
conn = cast(BroadcastConnection, self._connection)
conn = cast(BroadcastConnection[RawType], self._connection)
try:
await conn.broadcast(encoded)
except NoBroadcastAddressError:
pass
else:
await self.send(value)
await self._connection.write(encoded)
12 changes: 11 additions & 1 deletion src/flockwave/channels/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,17 @@

MessageType = TypeVar("MessageType")
"""Type variable that is used to indicate the decoded, object-like type of a
message on a MessageChannel.
message on a MessageChannel. For channels that involve addressing, this is
usually a tuple of a "real" message type and an address. For channels that do
not involve addressing, this is the "real" message type only.
"""

BroadcastMessageType = TypeVar("BroadcastMessageType")
"""Type variable that is used to indicate the decoded, object-like type of a
message on a MessageChannel when the message is used for broadcasting purposes.
Since broadcasting does not need a target address, this is different from
MessageType in the sense that it is always the "real" message type only, without
an address component, even for channels that use addressing.
"""

Reader = Union[Callable[[], Awaitable[RawType]], ReadableConnection[RawType]]
Expand Down

0 comments on commit 239d5d3

Please sign in to comment.