WebSocket server that accepts game client connections and publishes player actions to Kafka.
Browser Client (test-client.html)
↓ WebSocket
WebSocket Gateway (port 8090)
↓ Kafka Producer
Kafka Topic: player.movement
↓ Kafka Consumer
Player Movement Consumer → Redis
{
"type": "AUTH",
"realm": "EU",
"name": "Alice",
"arenaId": "arena_5"
}
Response:
{
"type": "AUTH_SUCCESS",
"playerId": "EU:Alice",
"roomX": 0,
"roomY": 0
}
{
"type": "MOVE",
"toRoomX": 1,
"toRoomY": 0,
"timestamp": 1702500000000
}
Response:
{
"type": "MOVE_ACK",
"fromRoomX": 0,
"fromRoomY": 0,
"toRoomX": 1,
"toRoomY": 0
}
{
"type": "ERROR",
"message": "Not authenticated. Send AUTH message first."
}
const ws = new WebSocket('ws://localhost:8090/ws/game');
ws.send(JSON.stringify({
type: 'AUTH',
realm: 'EU',
name: 'Alice',
arenaId: 'arena_5'
}));
Server behavior:
- Checks if player exists in Redis
- If new player: Initializes at (0,0)
- Returns current position to client
ws.send(JSON.stringify({
type: 'MOVE',
toRoomX: 1,
toRoomY: 0
}));
Server behavior:
- Gets current position from Redis
- Creates full movement event with fromRoom/toRoom
- Publishes to Kafka topic player.movement
- Sends ACK back to client
The PlayerMovementRedisConsumer you already built:
- Validates adjacency
- Checks room locks
- Updates Redis if valid
- Denies if invalid
Note: Client receives ACK immediately (optimistic), but actual movement may be denied by consumer. In production, you'd need a feedback mechanism.
# In Eclipse: File → New → Maven Project
Group ID: kepzeletmuhely.hu
Artifact ID: heist-websocket-gateway
Add these files:
- src/main/java/kepzeletmuhely/hu/WebSocketGateway.java
- src/main/java/kepzeletmuhely/hu/WebSocketServer.java
- pom.xml
- test-client.html (anywhere accessible)
mvn clean package
Creates: target/heist-websocket-gateway-1.0.0.jar
Make sure these are running:
- Kafka (localhost:9092, localhost:9093)
- Redis (localhost:6379)
- PlayerMovementRedisConsumer
In Eclipse:
Right-click WebSocketServer.java → Run As → Java Application
Via command line:
java -jar target/heist-websocket-gateway-1.0.0.jar
Output:
=== WebSocket Gateway Server ===
Configuration:
WebSocket Port: 8090
Kafka: localhost:9092,localhost:9093
Redis: localhost:6379 (DB 1)
WebSocket Gateway initialized:
Kafka: localhost:9092,localhost:9093
Redis: localhost:6379:6379 (DB 1)
✅ WebSocket server started on ws://localhost:8090/ws/game
Press Ctrl+C to stop...
Open test-client.html in your browser (just double-click it).
You should see a beautiful UI with:
- Authentication form
- 5x5 grid for movement
- Real-time log
- Realm: EU
- Name: TestPlayer
- Arena: arena_test
- Watch WebSocket server logs
- Should see "Player authenticated"
- Click cell (1,0) to move right
- Watch logs in browser
- Watch WebSocket server logs
- Watch Consumer logs
docker exec -it redis-cache redis-cli
> SELECT 1
> SMEMBERS room:arena_test:1,0:players
["EU:TestPlayer"]
# Run PlayerMovementRedisConsumer
Output:
Player Movement Consumer started...
✅ Processed: Player EU:TestPlayer moved from (0,0) to (1,0)
# Run WebSocketServer
Output:
✅ WebSocket server started on ws://localhost:8090/ws/game
New WebSocket connection: session-abc123
Player authenticated: EU:TestPlayer at (0,0)
Published: EU:TestPlayer move from (0,0) to (1,0) [partition=1, offset=5]
docker exec -it redis-cache redis-cli
> SELECT 1
> SMEMBERS room:arena_test:1,0:players
> HGETALL player:arena_test:EU:TestPlayer
Configure via environment variables:
# Kafka
export KAFKA_BOOTSTRAP_SERVERS="localhost:9092,localhost:9093"
# Redis
export REDIS_HOST="localhost"
export REDIS_PORT="6379"
export REDIS_DB="1"
# WebSocket
export WS_PORT="8090"
case "GAIN_ITEM":
handleGainItem(msg, session);
break;
Publish to player.items topic.
case "WEBRTC_OFFER":
handleWebRTCOffer(msg, session);
break;
Publish to player.signaling topic.
When consumer detects multiple players in same room:
- Publish encounter event to Kafka
- Gateway consumes and notifies affected clients
- Clients initiate WebRTC
Current code has no real auth. Add:
- JWT tokens
- Session validation
- Rate limiting
Consumer should publish validation results:
- If movement denied → notify client
- Client can rollback optimistic update
Consumer detects teleport
↓
Publish to player.movement.rejected topic
↓
Gateway consumes and notifies client
↓
Client resets position
Track connected players:
- Heartbeat/ping
- Disconnect handling
- Reconnection logic
Multiple gateway instances:
- Use session affinity (sticky sessions)
- Or use Redis pub/sub for inter-gateway communication
WebSocket won't connect:
- Check port 8090 is not in use
- Check firewall settings
- Try telnet localhost 8090
Authentication fails:
- Check Redis is running
- Check Redis DB 1 is accessible
- Check consumer is running
Moves not processing:
- Check Kafka is running
- Check topic player.movement exists
- Check consumer is subscribed
Invalid moves not denied:
- Check consumer validation logic
- Check consumer is running
- Check Redis has room lock data
This gateway is the bridge between your game clients and the Kafka-based backend! 🎮