Room chat¶
core ยท v0.1.0
A chat room: history replayed on connect, plus a live roster from the presence kit. Pluggable store, with an in-process default for demos and tests.
| Install | copit add @chanx-kit/room-chat |
| Import from | room_chat |
| Requires kits | presence |
| Python packages | chanx>=2.10.0,<3 |
| Tags | chat, rooms, history, persistence |
| Source | kits/room_chat |
A chat room: persisted history replayed on connect, plus a live roster.
Use it¶
List the topic on a consumer and add ChatMessage to its event union:
from chanx.fast_channels.websocket import AsyncJsonWebsocketConsumer
from .ws_kits.room_chat import RoomChatTopic, ChatMessage
class RoomConsumer(AsyncJsonWebsocketConsumer[ChatMessage]):
channel_layer_alias = "default"
topics = [RoomChatTopic]
A client subscribes to chat:<room> and receives chat_backlog with recent history,
then chat_message for anything posted afterwards.
Posting persists before it publishes, so a message that fails to save is never shown to anyone as delivered.
The roster comes with it¶
This kit installs presence alongside it. List both topics on the consumer and a
client can subscribe to chat:<room> and presence:<room> on the same connection.
Each kit keeps its own handlers, and either works alone.
Post without a connection¶
await RoomChatTopic.post_to_room(
"general", "deploy finished", ChatAuthor(id="bot", name="CI")
)
entries = await RoomChatTopic.history("general", limit=20)
Customise¶
| Hook | Default | Purpose |
|---|---|---|
chat_author() |
authenticated user | Who the connection posts as |
message_store |
InMemoryMessageStore() |
Where history lives |
backlog_limit |
50 |
How much history a joiner gets |
publish(entry) |
persist + broadcast | Hook moderation, rate limits, fan-out |
The room itself is the topic parameter: a subscription to chat:general is in room
general, and one connection can be in several rooms at once.
Production: replace the store¶
InMemoryMessageStore is bounded and per-process, so history is lost on restart and
differs between workers. Implement MessageStore against your database:
class DjangoMessageStore(MessageStore):
async def append(self, entry: ChatEntry) -> None:
await Message.objects.acreate(**entry.model_dump())
async def backlog(self, room: str, limit: int) -> list[ChatEntry]:
rows = Message.objects.filter(room=room).order_by("-sent_at")[:limit]
return [ChatEntry.model_validate(row, from_attributes=True) async for row in rows][::-1]
Messages¶
| Action | Direction | Payload |
|---|---|---|
chat_send |
client โ server | body |
chat_message |
server โ client | id, body, author, room, sent_at |
chat_backlog |
server โ client | room, entries |
Message reference¶
Generated from the kit's message classes.
chat_backlog¶
ChatBacklogMessage
| Field | Type | Required |
|---|---|---|
room |
string | yes |
entries |
ChatEntry[] | yes |
chat_backlog_request¶
ChatBacklogRequestMessage
| Field | Type | Required |
|---|---|---|
limit |
integer | null | no |
chat_message¶
ChatMessage
| Field | Type | Required |
|---|---|---|
body |
string | yes |
author |
ChatAuthor | yes |
room |
string | yes |
id |
string | no |
sent_at |
string | no |
chat_send¶
ChatSendMessage
| Field | Type | Required |
|---|---|---|
body |
string | yes |