feat(websocket): implement WebSocket gateway and real-time event broa…#919
Merged
Olowodarey merged 3 commits intoMay 31, 2026
Merged
Conversation
…dcasts Closes Arena1X#760 — [Backend] Implement WebSocket Gateway Closes Arena1X#761 — [Backend] Implement Real-time Event Updates ═══════════════════════════════════════════════════════════ ISSUE Arena1X#760 — WebSocket Gateway ═══════════════════════════════════════════════════════════ What was done: Created src/websocket/events.gateway.ts — a NestJS WebSocket gateway using @nestjs/websockets + socket.io (namespace /ws). How it was done: • Installed @nestjs/websockets, @nestjs/platform-socket.io, and socket.io as runtime dependencies. • EventsGateway implements OnGatewayConnection / OnGatewayDisconnect for full lifecycle control. • Connection authentication: on connect, the gateway reads a JWT from handshake.auth.token or the Authorization header, verifies it with JwtService, and auto-joins the authenticated user to their personal user:{address} room. • Room management supports three room patterns: - event:{id} — scoped to a creator event - match:{id} — scoped to a specific match - user:{address} — private room for a single user • join / leave message handlers validate room format with a regex and enforce ownership for user rooms (unauthenticated clients cannot join another user's room). • Heartbeat: the gateway emits a ping every 25 s per connection; the client is expected to respond with pong. • Rate limiting: each socket is allowed 60 messages per 60-second window; excess messages receive an error event. • CORS: configured with origin '*' at the gateway decorator level (tighten to specific origins in production via env config). • WebsocketModule created (src/websocket/websocket.module.ts), importing JwtModule with the app JWT_SECRET, and exporting BroadcasterService so other modules can inject it. • WebsocketModule registered in AppModule. • Tests written in events.gateway.spec.ts covering: authenticated connection, unauthenticated connection, invalid token, disconnect cleanup, valid room joins (event/match/user), invalid room rejection, user-room ownership enforcement, and rate limiting. ═══════════════════════════════════════════════════════════ ISSUE Arena1X#761 — Real-time Event Updates / Broadcaster ═══════════════════════════════════════════════════════════ What was done: Created src/websocket/broadcaster.service.ts — a service that wraps EventsGateway.server and exposes typed broadcast methods for every contract event type. How it was done: • BroadcasterService is an @Injectable() that receives EventsGateway via constructor injection. • One broadcast method per contract event type, each building a consistent payload envelope { event, data } and targeting the correct Socket.IO room(s): - broadcastEventCreated → server.emit (all clients) - broadcastEventUpdated → event:{id} room - broadcastMatchAdded → event:{id} room - broadcastUserJoined → event:{id} room - broadcastPredictionSubmitted → event:{id} AND match:{id} - broadcastMatchResolved → event:{id} AND match:{id} - broadcastWinnersVerified → event:{id} room - broadcastEventCancelled → event:{id} room • Each method logs the broadcast target for observability. • IndexerModule now imports WebsocketModule so IndexerService can receive BroadcasterService via DI. • IndexerService constructor updated to inject BroadcasterService. • Every existing indexer event handler (handleEventCreated, handleMatchAdded, handleUserJoinedEvent, handlePredictionSubmitted, handleMatchResultSubmitted, handleWinnersVerified, handleEventCancelled) now calls the corresponding broadcaster method immediately after the notification generator call, so real-time WebSocket pushes fire alongside in-app notifications. • Tests written in broadcaster.service.spec.ts verifying that each broadcast method calls server.emit / server.to with the correct room name and event name.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@Pvsaint Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…dcasts
Closes #760 — [Backend] Implement WebSocket Gateway Closes #761 — [Backend] Implement Real-time Event Updates
═══════════════════════════════════════════════════════════ ISSUE #760 — WebSocket Gateway
═══════════════════════════════════════════════════════════
What was done:
Created src/websocket/events.gateway.ts — a NestJS WebSocket
gateway using @nestjs/websockets + socket.io (namespace /ws).
How it was done:
• Installed @nestjs/websockets, @nestjs/platform-socket.io, and
socket.io as runtime dependencies.
• EventsGateway implements OnGatewayConnection / OnGatewayDisconnect
for full lifecycle control.
• Connection authentication: on connect, the gateway reads a JWT
from handshake.auth.token or the Authorization header, verifies
it with JwtService, and auto-joins the authenticated user to their
personal user:{address} room.
• Room management supports three room patterns:
- event:{id} — scoped to a creator event
- match:{id} — scoped to a specific match
- user:{address} — private room for a single user
• join / leave message handlers validate room format with a regex
and enforce ownership for user rooms (unauthenticated clients
cannot join another user's room).
• Heartbeat: the gateway emits a ping every 25 s per connection;
the client is expected to respond with pong.
• Rate limiting: each socket is allowed 60 messages per 60-second
window; excess messages receive an error event.
• CORS: configured with origin '*' at the gateway decorator level
(tighten to specific origins in production via env config).
• WebsocketModule created (src/websocket/websocket.module.ts),
importing JwtModule with the app JWT_SECRET, and exporting
BroadcasterService so other modules can inject it.
• WebsocketModule registered in AppModule.
• Tests written in events.gateway.spec.ts covering: authenticated
connection, unauthenticated connection, invalid token, disconnect
cleanup, valid room joins (event/match/user), invalid room
rejection, user-room ownership enforcement, and rate limiting.
═══════════════════════════════════════════════════════════ ISSUE #761 — Real-time Event Updates / Broadcaster ═══════════════════════════════════════════════════════════
What was done:
Created src/websocket/broadcaster.service.ts — a service that
wraps EventsGateway.server and exposes typed broadcast methods
for every contract event type.
How it was done:
• BroadcasterService is an @Injectable() that receives
EventsGateway via constructor injection.
• One broadcast method per contract event type, each building a
consistent payload envelope { event, data } and targeting the
correct Socket.IO room(s):
- broadcastEventCreated → server.emit (all clients)
- broadcastEventUpdated → event:{id} room
- broadcastMatchAdded → event:{id} room
- broadcastUserJoined → event:{id} room
- broadcastPredictionSubmitted → event:{id} AND match:{id}
- broadcastMatchResolved → event:{id} AND match:{id}
- broadcastWinnersVerified → event:{id} room
- broadcastEventCancelled → event:{id} room
• Each method logs the broadcast target for observability.
• IndexerModule now imports WebsocketModule so IndexerService can
receive BroadcasterService via DI.
• IndexerService constructor updated to inject BroadcasterService.
• Every existing indexer event handler (handleEventCreated,
handleMatchAdded, handleUserJoinedEvent, handlePredictionSubmitted,
handleMatchResultSubmitted, handleWinnersVerified,
handleEventCancelled) now calls the corresponding broadcaster
method immediately after the notification generator call, so
real-time WebSocket pushes fire alongside in-app notifications.
• Tests written in broadcaster.service.spec.ts verifying that each
broadcast method calls server.emit / server.to with the correct
room name and event name.