Skip to content

AyushPandey003/Gowebsocket

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

2 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Momentum Contest - Real-Time Quiz Competition Platform

A production-ready, horizontally-scalable real-time quiz contest application built with Go, WebSockets, Redis Pub/Sub, and PostgreSQL. some fixes

๐Ÿš€ Features

  • Real-time Multiplayer Contests: Up to 6 players can compete simultaneously
  • Synchronized Gameplay: All players see questions at the same time
  • Instant Question Progression: When one player answers correctly, everyone moves to the next question
  • Speed-Based Scoring: Faster correct answers earn more points (up to 1000 points per question)
  • Horizontal Scalability: Redis Pub/Sub enables multiple server instances
  • JWT Authentication: Secure authentication for all API endpoints
  • Graceful Shutdown: Properly closes all connections and saves data
  • WebSocket Communication: Low-latency, bidirectional communication

๐Ÿ—๏ธ Architecture

momentum-contest/
โ”œโ”€โ”€ cmd/
โ”‚   โ””โ”€โ”€ server/
โ”‚       โ””โ”€โ”€ main.go              # Application entry point
โ”œโ”€โ”€ internal/
โ”‚   โ”œโ”€โ”€ api/
โ”‚   โ”‚   โ”œโ”€โ”€ auth.go              # JWT authentication & middleware
โ”‚   โ”‚   โ””โ”€โ”€ router.go            # HTTP routes & handlers
โ”‚   โ”œโ”€โ”€ config/
โ”‚   โ”‚   โ””โ”€โ”€ config.go            # Configuration management
โ”‚   โ”œโ”€โ”€ contest/
โ”‚   โ”‚   โ”œโ”€โ”€ client.go            # WebSocket client management
โ”‚   โ”‚   โ”œโ”€โ”€ hub.go               # Contest room logic
โ”‚   โ”‚   โ”œโ”€โ”€ manager.go           # Multi-room management
โ”‚   โ”‚   โ”œโ”€โ”€ message.go           # Message protocol definitions
โ”‚   โ”‚   โ””โ”€โ”€ pubsub.go            # Redis Pub/Sub integration
โ”‚   โ””โ”€โ”€ storage/
โ”‚       โ””โ”€โ”€ postgres.go          # Database operations
โ”œโ”€โ”€ go.mod
โ”œโ”€โ”€ go.sum
โ”œโ”€โ”€ README.md
โ””โ”€โ”€ schema.sql                    # Database schema

๐Ÿ“‹ Prerequisites

๐Ÿ”ง Installation

1. Clone the Repository

git clone <repository-url>
cd momentum-contest

2. Install Dependencies

go mod download

3. Set Up PostgreSQL

Create a database and run the schema:

# Connect to PostgreSQL
psql -U postgres

# Create database
CREATE DATABASE contest_db;

# Exit psql
\q

# Run the schema
psql -U postgres -d contest_db -f schema.sql

4. Set Up Redis

Start Redis server:

# Using Docker (recommended)
docker run -d -p 6379:6379 redis:latest

# Or install locally and run
redis-server

5. Configure Environment Variables

Create a .env file or set environment variables:

# Server Configuration
PORT=8080

# Database Configuration
DATABASE_URL=postgres://postgres:postgres@localhost:5432/contest_db?sslmode=disable

# Redis Configuration
REDIS_ADDR=localhost:6379
REDIS_PASSWORD=
REDIS_DB=0

# JWT Configuration (CHANGE IN PRODUCTION!)
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production

# Game Configuration
QUESTION_TIMER=15    # Seconds per question
MAX_PLAYERS=6        # Maximum players per contest

6. Build and Run

# Build
go build -o server ./cmd/server

# Run
./server

# Or run directly
go run ./cmd/server/main.go

The server will start on http://localhost:8080

๐Ÿ“ก API Endpoints

1. Login (Get JWT Token)

POST /login
Content-Type: application/json

{
  "username": "player1",
  "password": "any-password"
}

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "user_id": "user_player1_1234567890",
  "username": "player1",
  "expires_at": "2025-11-03T12:00:00Z"
}

2. Create Contest

POST /api/contests
Authorization: Bearer <token>
Content-Type: application/json

{
  "difficulty": "medium",
  "question_count": 10
}

Response:

{
  "contest_id": "550e8400-e29b-41d4-a716-446655440000",
  "difficulty": "medium",
  "question_count": 10,
  "websocket_url": "/ws/contests/550e8400-e29b-41d4-a716-446655440000",
  "message": "Contest created successfully. Connect to the WebSocket to join."
}

3. Health Check

GET /health

Response:

{
  "status": "healthy",
  "active_contests": 5
}

๐Ÿ”Œ WebSocket Protocol

Connection

ws://localhost:8080/ws/contests/{contestID}?token={jwt_token}

Client โ†’ Server Messages

Start Game (Host Only)

{
  "type": "START_GAME"
}

Submit Answer

{
  "type": "SUBMIT_ANSWER",
  "question_id": "q123",
  "answer": "Option A"
}

Server โ†’ Client Messages

Player Joined

{
  "type": "PLAYER_JOINED",
  "payload": {
    "user_id": "user123",
    "username": "player1",
    "is_host": false,
    "player_count": 3,
    "players": [...]
  }
}

Contest Started

{
  "type": "CONTEST_STARTED",
  "payload": {
    "message": "Contest has started! Good luck!",
    "total_questions": 10,
    "question_timer": 15,
    "players": [...]
  }
}

New Question

{
  "type": "NEW_QUESTION",
  "payload": {
    "question_number": 1,
    "total_questions": 10,
    "question_id": "q123",
    "question_text": "What is the capital of France?",
    "options": ["London", "Paris", "Berlin", "Madrid"],
    "timer": 15
  }
}

Answer Result (Personal)

{
  "type": "ANSWER_RESULT",
  "payload": {
    "question_id": "q123",
    "is_correct": true,
    "correct_answer": "Paris",
    "points_awarded": 850,
    "time_taken": 2.5,
    "new_score": 1700
  }
}

Score Update (Broadcast)

{
  "type": "SCORE_UPDATE",
  "payload": {
    "user_id": "user123",
    "username": "player1",
    "score": 1700,
    "points_earned": 850
  }
}

Game Over

{
  "type": "GAME_OVER",
  "payload": {
    "message": "Contest finished! Here are the final results.",
    "final_scoreboard": [
      {
        "user_id": "user123",
        "username": "player1",
        "score": 8500,
        "is_host": true,
        "rank": 1
      }
    ],
    "questions": [...]
  }
}

๐ŸŽฎ Game Flow

  1. Contest Creation: Creator calls /api/contests to create a room
  2. Players Join: All players (including creator) connect via WebSocket
  3. Start Game: Host sends START_GAME message
  4. Question Loop:
    • Server sends question to all players
    • 15-second timer starts
    • Players submit answers
    • First correct answer: Award points, broadcast update, next question
    • Timer expires: No points, next question
  5. Game End: After final question, server sends results and saves to DB

๐Ÿ” Security Features

  • JWT Authentication: All endpoints require valid JWT tokens
  • Token Validation: Tokens validated via middleware
  • WebSocket Security: Token required in query parameter or header
  • CORS Protection: Configurable origin checking (set properly in production)

๐Ÿšฆ Scaling

Horizontal Scaling with Redis

The application uses Redis Pub/Sub to synchronize state across multiple server instances:

  1. Each server instance subscribes to contest:* pattern
  2. When an event occurs, it's published to Redis
  3. All server instances receive the event and update their local clients
  4. This allows contests to span multiple servers

Running Multiple Instances

# Terminal 1
PORT=8080 go run ./cmd/server/main.go

# Terminal 2
PORT=8081 go run ./cmd/server/main.go

# Use a load balancer (nginx, HAProxy) to distribute traffic

๐Ÿ“Š Database Schema

The application requires three main tables:

  • questions: Stores quiz questions with options and correct answers
  • contests: Stores contest metadata
  • contest_results: Stores final player scores and rankings
  • player_answers: Stores individual answer submissions (bulk inserted)

See schema.sql for the complete schema.

๐Ÿงช Testing

Quick Start - Automated Testing

We provide three automated test scripts for easy testing:

Option 1: Node.js Test Script (Recommended)

# Install dependencies
npm install -g wscat ws

# Run interactive mode
node test_contest.js

# Or run auto-play mode directly
node test_contest.js --auto

# Or join existing contest
node test_contest.js <contest-id>

Features:

  • โœ… Interactive menu for test scenarios
  • โœ… Auto-play mode with AI players
  • โœ… Colored console output
  • โœ… Automatic answer submission
  • โœ… Real-time score tracking

Option 2: Python Test Script

# Install dependencies
pip install websockets requests

# Run interactive mode
python test_contest.py

# Or run auto-play mode
python test_contest.py --auto

# Or join existing contest
python test_contest.py <contest-id>

Features:

  • โœ… Async/await support
  • โœ… Clean output with emojis
  • โœ… Multiple AI players
  • โœ… Easy to extend

Option 3: Bash Script (Simple)

# Make executable
chmod +x test_contest.sh

# Run full test setup
./test_contest.sh

# Create a contest
./test_contest.sh create TestHost medium 5

# Connect to existing contest
./test_contest.sh connect <contest-id> TestUser

Features:

  • โœ… No dependencies (except curl and wscat)
  • โœ… Creates multiple players automatically
  • โœ… Saves tokens for manual testing
  • โœ… Provides connection commands

Manual Testing with cURL

# 1. Login
TOKEN=$(curl -s -X POST http://localhost:8080/login \
  -H "Content-Type: application/json" \
  -d '{"username":"testuser","password":"test"}' \
  | jq -r '.token')

# 2. Create Contest
CONTEST=$(curl -s -X POST http://localhost:8080/api/contests \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"difficulty":"medium","question_count":5}')

echo $CONTEST

# 3. Extract Contest ID
CONTEST_ID=$(echo $CONTEST | grep -o '"contest_id":"[^"]*"' | cut -d'"' -f4)

# 4. Connect via WebSocket
wscat -c "ws://localhost:8080/ws/contests/$CONTEST_ID?token=$TOKEN"

WebSocket Testing

Use a WebSocket client like wscat:

# Install wscat
npm install -g wscat

# Connect (use actual values, not placeholders!)
wscat -c "ws://localhost:8080/ws/contests/$CONTEST_ID?token=$TOKEN"

# Send start game (if you're the host)
{"type":"START_GAME"}

# Submit answer
{"type":"SUBMIT_ANSWER","question_id":"q123","answer":"Paris"}

Test Scenarios

The automated scripts support several test scenarios:

  1. Basic Flow (3 players, manual control)

    • Creates host and 2 additional players
    • Manual answer submission
    • Good for debugging and understanding flow
  2. Auto-Play (4 AI players, automatic)

    • All players auto-answer questions
    • Simulates real game conditions
    • Great for performance testing
  3. Join Existing (single player)

    • Join an already created contest
    • Good for testing late-joining behavior

๐Ÿ› Troubleshooting

Database Connection Issues

  • Ensure PostgreSQL is running
  • Verify DATABASE_URL is correct
  • Check firewall/network settings

Redis Connection Issues

  • Ensure Redis is running: redis-cli ping should return PONG
  • Verify REDIS_ADDR is correct

WebSocket Connection Issues

  • Ensure JWT token is valid and not expired
  • Check that token is passed in query parameter
  • Verify contest exists before connecting

๐Ÿ“ Production Deployment Checklist

  • Change JWT_SECRET to a strong random value
  • Configure proper CORS origins in router.go
  • Use environment variables for all sensitive data
  • Enable PostgreSQL SSL mode
  • Set up Redis authentication
  • Configure load balancer for multiple instances
  • Set up monitoring and logging
  • Implement rate limiting
  • Add database migrations tool
  • Configure proper user authentication (replace dummy login)
  • Set up HTTPS/TLS certificates
  • Implement database connection pooling tuning

๐Ÿค Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Commit your changes
  4. Push to the branch
  5. Create a Pull Request

๐Ÿ“„ License

This project is licensed under the MIT License.

๐Ÿ‘จโ€๐Ÿ’ป Author

Built with โค๏ธ using Go, WebSockets, Redis, and PostgreSQL


Happy Coding! ๐ŸŽ‰

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors