Channel
The Channel class is the core component for real-time communication in PyPhoenix. It provides Phoenix-compatible channel functionality with support for joining, leaving, message pushing, broadcasting, and middleware processing.
Channel Class
- class pyphoenix.channel.Channel(topic, params=None, socket=None)[source]
Bases:
objectA Channel represents a conversation on a specific topic between multiple participants.
Channels maintain their own state and handle joining, leaving, pushing messages, and broadcasting to all participants. They support middleware for cross-cutting concerns like authentication, logging, and rate limiting.
- The channel lifecycle follows Phoenix conventions:
CLOSED -> JOINING (when join() is called)
JOINING -> JOINED (when join succeeds)
JOINED -> LEAVING (when leave() is called)
LEAVING -> CLOSED (when leave completes)
Any state -> ERRORED (when errors occur)
- socket
Associated socket connection
- state
Current channel state
- Type:
- middleware
Stack of middleware functions
- Type:
Example
Create a basic room channel:
class RoomChannel(Channel): async def on_join(self, payload, socket): user_id = payload.get("user_id") logger.info(f"User {user_id} joined {self.topic}") return {"status": "ok"} async def on_message(self, payload, socket): message = payload.get("text", "") await self.broadcast("new_message", { "text": message, "timestamp": time.time() })
- use_middleware(middleware)[source]
Add middleware to the channel’s middleware stack.
Middleware is executed in the order it’s added, with each middleware having the opportunity to process or modify requests before they reach the final handler.
- Parameters:
middleware – A middleware instance that implements the required interface (e.g., LoggingMiddleware, AuthMiddleware, RateLimitMiddleware)
- Return type:
Example
Add authentication and logging middleware:
channel.use_middleware(LoggingMiddleware()) channel.use_middleware(AuthMiddleware(authenticate_user)) channel.use_middleware(RateLimitMiddleware(max_messages=10))
- remove_middleware(middleware)[source]
Remove middleware from the channel’s middleware stack.
- Return type:
- async join(params=None)[source]
Join the channel and start receiving messages.
This method initiates the channel join process. If middleware is configured, it will be executed before the final join handler. The method handles authentication, validation, and any other middleware processing.
- Parameters:
params (
Optional[dict[str,Any]]) – Optional parameters to send with join request. These are merged with the channel’s initial params.- Returns:
An object containing the join status and response data. - status: “ok” if join succeeded, “error” if it failed - response: Dict with additional data (success response or error details)
- Return type:
- Raises:
JoinError – If the join operation fails
PyPhoenixTimeoutError – If the join times out
Example
Basic join:
response = await channel.join({"user_id": "123"}) if response.status == "ok": print("Successfully joined channel!")
Join with authentication:
response = await channel.join({ "token": "auth_token", "user_id": "123" })
- async push(event, payload)[source]
Push a message to the channel.
- Parameters:
- Return type:
- Returns:
PushResponse with status and response data
- async broadcast_from(socket, event, payload)[source]
Broadcast a message to all channel participants except the specified socket.
- async presence_count()[source]
Get the number of users present in this channel.
- Return type:
- Returns:
Number of present users
- on(event, callback=None)[source]
Register an event handler.
- Can be used as a decorator:
@channel.on(“event_name”) def handler(payload, ref):
pass
- Or as a regular method:
channel.on(“event_name”, handler)
Channel Lifecycle
Channels follow a strict lifecycle pattern:
CLOSED - Initial state, not connected
JOINING - Join request sent, waiting for response
JOINED - Successfully joined, can send/receive messages
LEAVING - Leave request sent, waiting for completion
ERRORED - Error occurred, channel unusable
State transitions are managed automatically, but you can check the current
state using the state attribute.
Event Handling
Channels support event-based message handling. You can register handlers for specific events:
channel.on("user_joined", handle_user_joined)
channel.on("new_message", handle_new_message)
Built-in events include:
phx_join- Channel join eventphx_leave- Channel leave eventphx_reply- Reply to a push messagephx_error- Channel error eventphx_close- Channel close event
Custom Events
You can define custom event handlers by implementing methods with the on_ prefix:
class ChatChannel(Channel):
async def on_message(self, payload, socket):
# Handle "message" events
await self.broadcast("new_message", payload)
async def on_typing(self, payload, socket):
# Handle "typing" events
await self.broadcast("user_typing", payload, exclude=socket)
Middleware Support
Channels support middleware for cross-cutting concerns:
from pyphoenix import LoggingMiddleware, AuthMiddleware
channel = Channel("room:lobby")
channel.use_middleware(LoggingMiddleware())
channel.use_middleware(AuthMiddleware(auth_function))
Available middleware includes:
LoggingMiddleware- Request/response loggingAuthMiddleware- AuthenticationRateLimitMiddleware- Rate limiting
Broadcasting
Channels can broadcast messages to all joined participants:
# Broadcast to all participants
await channel.broadcast("new_message", {"text": "Hello everyone!"})
# Broadcast to all except sender
await channel.broadcast("typing", {"user": "alice"}, exclude=sender_socket)
Error Handling
Channels provide comprehensive error handling:
try:
response = await channel.join({"token": "invalid"})
except JoinError as e:
print(f"Failed to join: {e}")
except PyPhoenixTimeoutError as e:
print(f"Join timed out: {e}")
Common error types:
JoinError- Join operation failedChannelError- General channel errorTimeoutError- Operation timed out