Skip to content

Commit af79c8e

Browse files
committed
Add websocket notif/ops and process appropriately.
1 parent f01e184 commit af79c8e

File tree

2 files changed

+98
-9
lines changed

2 files changed

+98
-9
lines changed

api/server.py

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from .middleware.auth import AuthBackend
3636
from .routes.applications import Applications
3737
from .routes.auth import Auth
38+
from .routes.members import Members
3839
from .routes.users import Users
3940

4041

@@ -43,15 +44,15 @@ def __init__(self, *, session: aiohttp.ClientSession, database: core.Database) -
4344
self.session = session
4445
self.database = database
4546

46-
views: list[core.View] = [Users(self), Auth(self), Applications(self)]
47+
views: list[core.View] = [Users(self), Auth(self), Applications(self), Members(self)]
4748
middleware: list[Middleware] = [
4849
Middleware(CORSMiddleware, allow_origins=['*'], allow_methods=['*'], allow_headers=['*']),
4950
Middleware(AuthenticationMiddleware, backend=AuthBackend(self)),
5051
]
5152

5253
self.sockets: dict[int, WebSocket] = {}
5354
self.subscription_sockets: dict[str, set[int]] = {
54-
'discord_py_mod_log': set()
55+
core.WebsocketSubscriptions.DPY_MOD_LOG: set()
5556
}
5657

5758
super().__init__(
@@ -82,7 +83,7 @@ async def websocket_connector(self, websocket: WebSocket) -> None:
8283

8384
# Send the initial accepted response. Includes user_id and subscriptions... op: 0
8485
data: dict[str, Any] = {
85-
'op': core.WebsocketOPCodes.ACCEPTED,
86+
'op': core.WebsocketOPCodes.HELLO,
8687
'user_id': uid,
8788
'subscriptions': subscriptions
8889
}
@@ -93,14 +94,73 @@ async def websocket_connector(self, websocket: WebSocket) -> None:
9394
while True:
9495

9596
try:
96-
message: dict[str | int, Any] = await websocket.receive_json()
97+
message: dict[str, Any] = await websocket.receive_json()
9798
except WebSocketDisconnect:
9899
break
99100

100-
# TODO: Process messages...
101-
print(message)
101+
op: str | None = message.get('op')
102+
103+
if op == core.WebsocketOPCodes.SUBSCRIBE:
104+
response = self.websocket_subscribe(uid=uid, message=message)
105+
await websocket.send_json(data=response)
106+
107+
elif op == core.WebsocketOPCodes.UNSUBSCRIBE:
108+
response = self.websocket_unsubscribe(uid=uid, message=message)
109+
await websocket.send_json(data=response)
110+
111+
else:
112+
response = {
113+
'op': core.WebsocketOPCodes.NOTIFICATION,
114+
'type': core.WebsocketNotificationTypes.UNKNOWN_OP,
115+
'received': op
116+
}
117+
await websocket.send_json(data=response)
102118

103119
# Remove the websocket and it's subscriptions...
104120
del self.sockets[uid]
105121
for sub in subscriptions:
106122
self.subscription_sockets[sub].remove(uid)
123+
124+
def websocket_subscribe(self, *, uid: int, message: dict[str, Any]) -> dict[str, Any]:
125+
subs: list[str] = message.get('subscriptions', [])
126+
127+
# Filter out bad subscriptions...
128+
valid: list[str] = list(self.subscription_sockets.keys())
129+
subscriptions: list[str] = [sub for sub in subs if sub in valid]
130+
131+
for sub in subscriptions:
132+
self.subscription_sockets[sub].add(uid)
133+
134+
subscribed: list[str] = [sub for sub in self.subscription_sockets if uid in self.subscription_sockets[sub]]
135+
136+
data: dict[str, Any] = {
137+
'op': core.WebsocketOPCodes.NOTIFICATION,
138+
'type': core.WebsocketNotificationTypes.SUBSCRIPTION_ADDED,
139+
'user_id': uid,
140+
'added': subscriptions,
141+
'subscriptions': subscribed
142+
}
143+
144+
return data
145+
146+
def websocket_unsubscribe(self, *, uid: int, message: dict[str, Any]) -> dict[str, Any]:
147+
subs: list[str] = message.get('subscriptions', [])
148+
149+
# Filter out bad subscriptions...
150+
valid: list[str] = list(self.subscription_sockets.keys())
151+
subscriptions: list[str] = [sub for sub in subs if sub in valid]
152+
153+
for sub in subscriptions:
154+
self.subscription_sockets[sub].remove(uid)
155+
156+
subscribed: list[str] = [sub for sub in self.subscription_sockets if uid in self.subscription_sockets[sub]]
157+
158+
data: dict[str, Any] = {
159+
'op': core.WebsocketOPCodes.NOTIFICATION,
160+
'type': core.WebsocketNotificationTypes.SUBSCRIPTION_REMOVED,
161+
'user_id': uid,
162+
'removed': subscriptions,
163+
'subscriptions': subscribed
164+
}
165+
166+
return data

core/utils.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,15 @@
3232
from starlette.types import Receive, Scope, Send
3333

3434

35-
__all__ = ('route', 'View', 'Application', 'WebsocketCloseCodes', 'WebsocketOPCodes')
35+
__all__ = (
36+
'route',
37+
'View',
38+
'Application',
39+
'WebsocketCloseCodes',
40+
'WebsocketOPCodes',
41+
'WebsocketSubscriptions',
42+
'WebsocketNotificationTypes'
43+
)
3644

3745
ResponseType: TypeAlias = Coroutine[Any, Any, Response]
3846

@@ -213,9 +221,30 @@ class WebsocketCloseCodes:
213221

214222
NORMAL: int = 1000
215223
ABNORMAL: int = 1006
216-
INVALID_SUBSCRIPTION: int = 4005
217224

218225

219226
class WebsocketOPCodes:
220227

221-
ACCEPTED: int = 0
228+
# Sent...
229+
HELLO: int = 0
230+
EVENT: int = 1
231+
NOTIFICATION: int = 2
232+
233+
# Received...
234+
SUBSCRIBE: str = 'subscribe'
235+
UNSUBSCRIBE: str = 'unsubscribe'
236+
237+
238+
class WebsocketSubscriptions:
239+
240+
DPY_MOD_LOG: str = 'discord_py_mod_log'
241+
242+
243+
class WebsocketNotificationTypes:
244+
245+
# Subscriptions...
246+
SUBSCRIPTION_ADDED: str = 'subscription_added'
247+
SUBSCRIPTION_REMOVED: str = 'subscription_removed'
248+
249+
# Failures...
250+
UNKNOWN_OP: str = 'unknown_op'

0 commit comments

Comments
 (0)