Thanks to visit codestin.com
Credit goes to Github.com

Skip to content
/ omiro Public

Scalable real-time chat + WebRTC video matching system using Go, Redis, WebSockets, and microservices. Includes distributed matchmaking, signaling via Pub/Sub, TURN/STUN support, and horizontal scalability.

License

Notifications You must be signed in to change notification settings

r0ld3x/omiro

Repository files navigation

πŸŽ₯ Omiro - Real-Time Random Video Chat Platform

A modern, high-performance random video chat application built with Go, WebRTC, and Redis. Connect with strangers worldwide through HD video, audio, and text chat with seamless matchmaking.

Go Version WebRTC Redis Docker License Docker Build


πŸš€ Quick Start - Docker (Easiest Way!)

Get started in 30 seconds with our pre-built Docker image:

docker run -d \
  --name omiro \
  -p 8080:8080 \
  -e REDIS_HOST=redis \
  -e REDIS_PORT=6379 \
  --network omiro-net \
  ghcr.io/r0ld3x/omiro:latest

Or use Docker Compose (Recommended):

# Create docker-compose.yml
curl -O https://raw.githubusercontent.com/r0ld3x/omiro/main/docker-compose.yml

# Start everything
docker-compose up -d

# Access at http://localhost:8080

That's it! No need to install Go, Redis, or build anything. πŸŽ‰

πŸ”§ Environment Variables

Configure Omiro with these environment variables:

Variable Description Default Required
REDIS_HOST Redis server hostname localhost βœ…
REDIS_PORT Redis server port 6379 βœ…
REDIS_PASSWORD Redis password (if protected) - ❌
PORT Application HTTP port 8080 ❌

Example with all options:

docker run -d \
  --name omiro \
  -p 8080:8080 \
  -e REDIS_HOST=my-redis-server \
  -e REDIS_PORT=6379 \
  -e REDIS_PASSWORD=mypassword \
  -e PORT=8080 \
  ghcr.io/r0ld3x/omiro:latest

πŸ“‹ Table of Contents


✨ Features

Core Functionality

  • πŸŽ₯ HD Video & Audio Chat - WebRTC P2P connections with automatic quality adaptation
  • πŸ’¬ Real-time Text Messaging - Instant chat with message history
  • πŸ”€ Smart Matchmaking - Queue-based random matching system
  • ⏭️ Next Person - Skip to next match seamlessly (Omegle-style)
  • πŸ”„ Auto-reconnect - Automatic queue rejoining on partner disconnect

Technical Features

  • πŸ”’ Session Management - HMAC-signed session tokens
  • 🚫 Rate Limiting - Per-IP WebSocket connection limits
  • 🌐 IP Ban System - Redis-backed IP banning with TTL
  • πŸ“Š Multi-Server Support - Redis pub/sub for horizontal scaling
  • 🎯 Smart WebRTC Negotiation - Deterministic caller/callee assignment
  • 🌍 NAT Traversal - STUN/TURN server support
  • ⚑ High Performance - Goroutine-based concurrent handling

User Experience

  • 🎨 Modern UI - Beautiful animated gradient design
  • πŸ’« Smooth Animations - Fade-ins, pulses, and interactive effects
  • πŸ“± Fully Responsive - Mobile, tablet, and desktop support
  • 🌈 Glassmorphism - Modern backdrop blur effects
  • ✨ Interactive Elements - Ripple effects and hover animations

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                         Frontend (Browser)                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  WebRTC P2P  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”‚
β”‚  β”‚   Client A     β”‚ ◄──────────► β”‚   Client B     β”‚         β”‚
β”‚  β”‚  (Video/Audio) β”‚              β”‚  (Video/Audio) β”‚         β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜              β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚
β”‚           β”‚                               β”‚                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚ WebSocket + Session Token     β”‚
            β–Ό                               β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚          Go Backend (Echo Framework)          β”‚
    β”‚                                               β”‚
    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”‚
    β”‚  β”‚  WebSocket  β”‚  β”‚   HTTP API   β”‚          β”‚
    β”‚  β”‚  Handler    β”‚  β”‚  /session    β”‚          β”‚
    β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
    β”‚         β”‚                                     β”‚
    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
    β”‚  β”‚     Matchmaking Engine              β”‚    β”‚
    β”‚  β”‚   (Queue-based Algorithm)           β”‚    β”‚
    β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β”‚ Redis Pub/Sub + Data Operations
              β–Ό
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚             Redis Database              β”‚
    β”‚                                         β”‚
    β”‚  β€’ Session Tokens                       β”‚
    β”‚  β€’ Matchmaking Queue                    β”‚
    β”‚  β€’ Active Connections                   β”‚
    β”‚  β€’ Rate Limiting Counters               β”‚
    β”‚  β€’ IP Ban List                          β”‚
    β”‚  β€’ Server Registry (for scaling)        β”‚
    β”‚  β€’ Pub/Sub Channels                     β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Components

Component Technology Purpose
Frontend Vanilla JavaScript + WebRTC Video chat UI and P2P connections
Backend Go + Echo Framework WebSocket server and API
Database Redis Session management, queuing, pub/sub
Signaling WebSocket WebRTC negotiation (SDP/ICE)
Media WebRTC Peer-to-peer video/audio streams

πŸš€ Quick Start

Prerequisites

Ensure you have the following installed:

Installation

  1. Clone the repository

    git clone https://github.com/r0ld3x/omiro.git
    cd omiro
  2. Install dependencies

    go mod download
  3. Start Redis server

    # Linux/Mac
    redis-server
    
    # Windows (if installed via MSI)
    redis-server.exe
    
    # Docker
    docker run -d -p 6379:6379 redis:7-alpine
  4. Run the application

    go run .
  5. Open in browser

    http://localhost:8080
    
  6. Test with multiple tabs

    • Open 2+ browser tabs/windows
    • Click "Connect" β†’ "Start Video" β†’ "Find Match" in each
    • The tabs will match and start video calling!

βš™οΈ Configuration

Redis Configuration

Edit main.go to configure Redis connection:

redis.Init(redis.Config{
    Host:     "localhost",  // Redis host
    Port:     "6379",       // Redis port
    Password: "",           // Redis password (if any)
    DB:       0,            // Redis database number
})

WebSocket Configuration

Adjust WebSocket settings in main.go:

var upgrader = websocket.Upgrader{
    CheckOrigin:       func(r *http.Request) bool { return true },
    ReadBufferSize:    1024,
    WriteBufferSize:   1024,
    HandshakeTimeout:  10 * time.Second,
    EnableCompression: true,
}

Server Port

Change the default port (8080) in main.go:

e.Start(":8080")  // Change to your desired port

πŸ“‘ API Documentation

HTTP Endpoints

GET /session/new

Generate a new session token for WebSocket authentication.

Response:

{
  "token": "550e8400-e29b-41d4-a716-446655440000:1700672400:a3f5e7..."
}

Token Format: uuid:timestamp:hmac_signature

GET /

Serves the main HTML application.

WebSocket Endpoint

Connect: ws://localhost:8080/ws?token={session_token}

WebSocket Message Protocol

All messages follow this format:

{
  "op": "operation_name",
  "data": {
    /* optional payload */
  }
}

Client β†’ Server Messages

Operation Description Payload
join_queue Join matchmaking queue None
next Skip to next partner None
chat Send text message {"message": "text"}
webrtc_offer Send WebRTC offer {"sdp": "..."}
webrtc_answer Send WebRTC answer {"sdp": "..."}
ice_candidate Send ICE candidate {"candidate": {...}}
disconnect Fully disconnect None

Server β†’ Client Messages

Operation Description Payload
match_found Match found {"partner": "uuid", "should_call": bool}
partner_disconnected Partner left None
chat Receive message {"message": "text"}
webrtc_offer Receive offer {"sdp": "...", "from": "uuid"}
webrtc_answer Receive answer {"sdp": "...", "from": "uuid"}
ice_candidate Receive ICE candidate {"candidate": {...}, "from": "uuid"}

Example Message Flow

// 1. Connect with session token
const token = await fetch("/session/new").then((r) => r.json());
const ws = new WebSocket(`ws://localhost:8080/ws?token=${token.token}`);

// 2. Join queue
ws.send(JSON.stringify({ op: "join_queue" }));

// 3. Receive match
// Server sends: {"op":"match_found","partner":"...", "should_call":true}

// 4. If should_call=true, create and send offer
ws.send(
  JSON.stringify({
    op: "webrtc_offer",
    data: { sdp: offer.sdp },
  })
);

// 5. Send chat message
ws.send(
  JSON.stringify({
    op: "chat",
    data: { message: "Hello!" },
  })
);

πŸ“ Project Structure

omiro/
β”œβ”€β”€ main.go                    # Application entry point
β”œβ”€β”€ client.go                  # Client struct and methods
β”œβ”€β”€ chat.go                    # Chat message handling
β”œβ”€β”€ handle_websocket.go        # WebSocket upgrade and connection
β”œβ”€β”€ handle_webrtc.go           # WebRTC signaling (offer/answer/ICE)
β”œβ”€β”€ incoming.go                # Message routing and readPump
β”œβ”€β”€ join_queue.go              # Matchmaking queue logic
β”‚
β”œβ”€β”€ middleware/
β”‚   β”œβ”€β”€ is_allowed.go         # Rate limiting and IP banning
β”‚   └── session_token.go      # Token generation and validation
β”‚
β”œβ”€β”€ redis/
β”‚   β”œβ”€β”€ client.go             # Redis connection initialization
β”‚   β”œβ”€β”€ operations.go         # Core Redis operations (queue, stats)
β”‚   β”œβ”€β”€ chat.go               # Chat message storage
β”‚   └── ips.go                # IP ban management
β”‚
β”œβ”€β”€ helper/
β”‚   └── helper.go             # Utility functions (GetRealIP, etc.)
β”‚
β”œβ”€β”€ index.html                 # Frontend application (WebRTC client)
β”œβ”€β”€ go.mod                     # Go module dependencies
β”œβ”€β”€ go.sum                     # Dependency checksums
β”œβ”€β”€ Dockerfile                 # Docker build configuration
β”œβ”€β”€ docker-compose.yml         # Multi-container setup
└── README.md                  # This file

Core File Descriptions

File Purpose
main.go Initializes Redis, starts matchmaker, sets up Echo routes
handle_websocket.go Upgrades HTTP to WebSocket, validates session tokens
incoming.go Routes WebSocket messages to appropriate handlers
join_queue.go Manages matchmaking queue and partner assignment
handle_webrtc.go Forwards WebRTC signaling between peers
chat.go Handles text chat between matched partners

🌐 Deployment

Option 1: Docker Compose (Recommended)

Build and run:

docker-compose up -d

Stop:

docker-compose down

The docker-compose.yml automatically sets up:

  • Go application on port 8080
  • Redis on port 6379
  • Persistent Redis volume

Option 2: Docker (Manual)

Build image:

docker build -t omiro:latest .

Run container:

docker run -d \
  -p 8080:8080 \
  -e REDIS_HOST=host.docker.internal \
  -e REDIS_PORT=6379 \
  omiro:latest

Option 3: Production Deployment

Option 4: Production Deployment with Reverse Proxy

Using Nginx

Using Nginx

Nginx Configuration:

server {
    listen 80;
    server_name omiro.yourdomain.com;

    location / {
        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Using Ngrok (Quick Testing)

# Start Omiro with Docker
docker run -d -p 8080:8080 ghcr.io/r0ld3x/omiro:latest

# In another terminal
ngrok http 8080

Using Cloudflare Tunnel (Production)

# Start Omiro with Docker
docker run -d -p 8080:8080 \
  -e REDIS_HOST=redis \
  ghcr.io/r0ld3x/omiro:latest

# Set up Cloudflare tunnel
cloudflared tunnel create omiro
cloudflared tunnel route dns omiro omiro.yourdomain.com
cloudflared tunnel run omiro

Production Checklist

  • Use HTTPS/WSS (required for camera/microphone)
  • Set up reverse proxy (Nginx/Caddy)
  • Enable Redis persistence (appendonly yes)
  • Configure firewall (allow ports 80, 443)
  • Set up monitoring (Prometheus/Grafana)
  • Enable log rotation
  • Use dedicated TURN servers
  • Set up automatic backups
  • Configure SSL certificates (Let's Encrypt)

πŸ”’ Security

Implemented Security Measures

βœ… Session Token Authentication

  • HMAC-SHA256 signed tokens
  • Timestamp-based expiration
  • Prevents token forgery

βœ… Rate Limiting

  • Per-IP connection limits
  • Configurable time windows
  • Redis-backed counters

βœ… IP Banning

  • Persistent ban storage in Redis
  • TTL-based automatic unbanning
  • Admin API for ban management

βœ… Real IP Detection

  • Cloudflare header support (CF-Connecting-IP)
  • X-Forwarded-For parsing
  • Proxy-aware IP extraction

βœ… Input Validation

  • JSON payload validation
  • Message length limits
  • XSS protection in chat

βœ… Origin Checking

  • WebSocket origin validation
  • CORS configuration
  • Cross-site request protection

Security Configuration

Rate Limiting (in redis/operations.go):

allowed, _ := redis.CheckRateLimit(ip, 10, 1*time.Minute)
// Allows 10 connections per minute per IP

Session Token (in middleware/session_token.go):

token := fmt.Sprintf("%s:%d:%s", sessionID, timestamp, signature)
// Format: uuid:timestamp:hmac

⚑ Performance

Optimization Features

  • Goroutines - Concurrent message handling per client
  • Redis Pub/Sub - Efficient multi-server communication
  • WebSocket Compression - Reduced bandwidth usage
  • Connection Pooling - Redis connection reuse
  • Channel Buffering - 256-message buffer per client
  • Lazy Peer Connection - Created only when needed

Scalability

Horizontal Scaling:

Load Balancer (Nginx/HAProxy)
    β”œβ”€β”€ Go Server 1 ─┐
    β”œβ”€β”€ Go Server 2 ─┼─► Redis (Central coordination)
    └── Go Server 3 β”€β”˜

Each server:

  • Registers with Redis on startup
  • Subscribes to its own channel
  • Uses pub/sub for cross-server messaging

Performance Metrics

Metric Value
Concurrent Connections 10,000+
Messages/sec 50,000+
Latency (avg) <10ms
Memory/client ~100KB

πŸ› Troubleshooting

Common Issues

Camera/Microphone Not Working

Problem: Browser can't access media devices

Solutions:

  • Use HTTPS (browsers require secure context)
  • Check browser permissions
  • Verify device is not in use by another app
  • Test in browser console: navigator.mediaDevices.getUserMedia({video: true, audio: true})

Video Not Connecting

Problem: Peer connection fails, video doesn't show

Solutions:

  • Check STUN/TURN server configuration in index.html
  • Verify firewall allows WebRTC traffic (UDP ports)
  • Check browser console for ICE connection errors
  • Test with both users on same network first

WebSocket Connection Fails

Problem: Can't establish WebSocket connection

Solutions:

# Check Redis is running
redis-cli ping  # Should return PONG

# Check server is running
curl http://localhost:8080/session/new

# Check WebSocket endpoint
wscat -c ws://localhost:8080/ws?token=YOUR_TOKEN

"Missing 'to' field" Error

Problem: WebRTC signaling error in logs

Solution: This has been fixed in the current version. Update incoming.go to use direct handler functions instead of forwardWebRTC.

Both Clients are CALLEE

Problem: Neither client initiates WebRTC offer

Solution: Server now sends should_call: true/false in match_found message. First client in queue becomes caller.


🀝 Contributing

We welcome contributions! Here's how to get started:

Development Setup

  1. Fork the repository

  2. Create a feature branch:

    git checkout -b feature/amazing-feature
  3. Make your changes and test

  4. Commit with meaningful messages:

    git commit -m "feat: add amazing feature"
  5. Push to your fork:

    git push origin feature/amazing-feature
  6. Open a Pull Request

Code Standards

  • Follow Go best practices and idioms
  • Run gofmt before committing
  • Add comments for complex logic
  • Write tests for new features
  • Update documentation

Commit Message Format

type(scope): subject

body (optional)

footer (optional)

Types: feat, fix, docs, style, refactor, test, chore


πŸ“Š Dependencies

// Core dependencies
github.com/gorilla/websocket v1.5.3      // WebSocket protocol
github.com/labstack/echo/v4 v4.13.4      // HTTP framework
github.com/redis/go-redis/v9 v9.17.0     // Redis client
github.com/google/uuid v1.6.0             // UUID generation
golang.org/x/crypto v0.38.0               // Cryptographic functions

πŸ“ License

This project is licensed under the MIT License - see the LICENSE file for details.

MIT License

Copyright (c) 2024 Omiro Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software...

πŸ™ Acknowledgments


πŸ“§ Support & Contact


🌟 Show Your Support

If you find this project useful, please consider:

  • ⭐ Starring the repository
  • πŸ› Reporting bugs
  • πŸ’‘ Suggesting features
  • πŸ”€ Contributing code
  • πŸ“’ Sharing with others

Built with ❀️ using Go, WebRTC, and Redis

Making real-time communication accessible to everyone

About

Scalable real-time chat + WebRTC video matching system using Go, Redis, WebSockets, and microservices. Includes distributed matchmaking, signaling via Pub/Sub, TURN/STUN support, and horizontal scalability.

Topics

Resources

License

Stars

Watchers

Forks