Skip to content

Commit 3605afe

Browse files
authored
Update allowed notifications (#75)
1 parent f38f92f commit 3605afe

5 files changed

Lines changed: 106 additions & 6 deletions

File tree

AGENTS.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# AGENTS.md
2+
3+
## Development workflow
4+
5+
### Red-Green TDD for new features
6+
7+
Whenever a new feature is added, follow the red-green TDD cycle:
8+
9+
1. **Red** — write a failing test that describes the desired behavior. Run it and confirm it fails for the expected reason.
10+
2. **Green** — write the minimum production code needed to make the test pass. Run the test and confirm it passes.
11+
3. **Refactor** — clean up the implementation and tests while keeping the suite green.
12+
13+
Do not write production code for a new feature before a failing test exists for it.

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
AGENTS.md

fishjam/events/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
# Exported messages
44
from fishjam.events._protos.fishjam import (
5+
ServerMessageChannelAdded,
6+
ServerMessageChannelRemoved,
57
ServerMessagePeerAdded,
68
ServerMessagePeerConnected,
79
ServerMessagePeerCrashed,
@@ -14,6 +16,8 @@
1416
ServerMessageRoomDeleted,
1517
ServerMessageStreamConnected,
1618
ServerMessageStreamDisconnected,
19+
ServerMessageStreamerConnected,
20+
ServerMessageStreamerDisconnected,
1721
ServerMessageTrackAdded,
1822
ServerMessageTrackMetadataUpdated,
1923
ServerMessageTrackRemoved,
@@ -34,6 +38,10 @@
3438
"ServerMessagePeerCrashed",
3539
"ServerMessageStreamConnected",
3640
"ServerMessageStreamDisconnected",
41+
"ServerMessageStreamerConnected",
42+
"ServerMessageStreamerDisconnected",
43+
"ServerMessageChannelAdded",
44+
"ServerMessageChannelRemoved",
3745
"ServerMessageTrackAdded",
3846
"ServerMessageTrackMetadataUpdated",
3947
"ServerMessageTrackRemoved",

fishjam/events/allowed_notifications.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from typing import Union
22

33
from fishjam.events import (
4+
ServerMessageChannelAdded,
5+
ServerMessageChannelRemoved,
46
ServerMessagePeerAdded,
57
ServerMessagePeerConnected,
68
ServerMessagePeerCrashed,
@@ -10,8 +12,8 @@
1012
ServerMessageRoomCrashed,
1113
ServerMessageRoomCreated,
1214
ServerMessageRoomDeleted,
13-
ServerMessageStreamConnected,
14-
ServerMessageStreamDisconnected,
15+
ServerMessageStreamerConnected,
16+
ServerMessageStreamerDisconnected,
1517
ServerMessageTrackAdded,
1618
ServerMessageTrackMetadataUpdated,
1719
ServerMessageTrackRemoved,
@@ -29,8 +31,10 @@
2931
ServerMessagePeerDisconnected,
3032
ServerMessagePeerMetadataUpdated,
3133
ServerMessagePeerCrashed,
32-
ServerMessageStreamConnected,
33-
ServerMessageStreamDisconnected,
34+
ServerMessageStreamerConnected,
35+
ServerMessageStreamerDisconnected,
36+
ServerMessageChannelAdded,
37+
ServerMessageChannelRemoved,
3438
ServerMessageViewerConnected,
3539
ServerMessageViewerDisconnected,
3640
ServerMessageTrackAdded,
@@ -48,8 +52,10 @@
4852
ServerMessagePeerDisconnected,
4953
ServerMessagePeerMetadataUpdated,
5054
ServerMessagePeerCrashed,
51-
ServerMessageStreamConnected,
52-
ServerMessageStreamDisconnected,
55+
ServerMessageStreamerConnected,
56+
ServerMessageStreamerDisconnected,
57+
ServerMessageChannelAdded,
58+
ServerMessageChannelRemoved,
5359
ServerMessageViewerConnected,
5460
ServerMessageViewerDisconnected,
5561
ServerMessageTrackAdded,
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import dataclasses
2+
3+
from fishjam import events
4+
from fishjam.events import _protos
5+
from fishjam.events._protos.fishjam import ServerMessage
6+
from fishjam.events.allowed_notifications import ALLOWED_NOTIFICATIONS
7+
8+
# Types intentionally NOT published as SDK notifications.
9+
# Adding a new oneof member to ServerMessage.content forces a maintainer
10+
# decision: either add it to ALLOWED_NOTIFICATIONS (and re-export from
11+
# fishjam.events), or add it here with a comment.
12+
IGNORED_NOTIFICATIONS = {
13+
# Auth / subscribe handshake — transport-level, not user-facing events.
14+
"ServerMessageAuthenticated",
15+
"ServerMessageAuthRequest",
16+
"ServerMessageSubscribeRequest",
17+
"ServerMessageSubscribeResponse",
18+
# Not surfaced to SDK users - support for compositions is REST api only
19+
# and not supported in SDKs
20+
"ServerMessageTrackForwarding",
21+
"ServerMessageTrackForwardingRemoved",
22+
"ServerMessageVadNotification",
23+
# Deprecated in the proto.
24+
"ServerMessageStreamConnected",
25+
"ServerMessageStreamDisconnected",
26+
"ServerMessageHlsPlayable",
27+
"ServerMessageHlsUploaded",
28+
"ServerMessageHlsUploadCrashed",
29+
"ServerMessageComponentCrashed",
30+
}
31+
32+
33+
def _oneof_content_types() -> list[type]:
34+
types = []
35+
for field in dataclasses.fields(ServerMessage):
36+
meta = field.metadata.get("betterproto")
37+
if meta is not None and getattr(meta, "group", None) == "content":
38+
types.append(getattr(_protos.fishjam, field.type))
39+
return types
40+
41+
42+
def test_every_content_oneof_is_allowed_or_explicitly_ignored():
43+
allowed_names = {cls.__name__ for cls in ALLOWED_NOTIFICATIONS}
44+
undecided = [
45+
cls.__name__
46+
for cls in _oneof_content_types()
47+
if cls.__name__ not in allowed_names
48+
and cls.__name__ not in IGNORED_NOTIFICATIONS
49+
]
50+
assert not undecided, (
51+
"New ServerMessage.content oneof members found without a maintainer "
52+
"decision. Add each to ALLOWED_NOTIFICATIONS (and re-export from "
53+
"fishjam.events) or to IGNORED_NOTIFICATIONS in this test:\n - "
54+
+ "\n - ".join(sorted(undecided))
55+
)
56+
57+
58+
def test_allowed_and_ignored_are_disjoint():
59+
overlap = {cls.__name__ for cls in ALLOWED_NOTIFICATIONS} & IGNORED_NOTIFICATIONS
60+
assert not overlap, f"Types cannot be both allowed and ignored: {overlap}"
61+
62+
63+
def test_allowed_notifications_are_reexported_from_package():
64+
missing = [
65+
cls.__name__
66+
for cls in ALLOWED_NOTIFICATIONS
67+
if cls.__name__ not in events.__all__ or not hasattr(events, cls.__name__)
68+
]
69+
assert not missing, (
70+
"Every ALLOWED_NOTIFICATIONS type must be re-exported from "
71+
f"fishjam.events. Missing: {missing}"
72+
)

0 commit comments

Comments
 (0)