Skip to content

izetmolla/socket.io

Repository files navigation

Socket.IO Go Server

A high-performance Socket.IO server implementation in Go, designed to work seamlessly with Fiber v3 web framework. This module provides real-time bidirectional communication capabilities with support for namespaces, rooms, and Redis clustering.

Features

  • 🚀 High Performance: Built on top of Fiber v3 and FastHTTP WebSocket
  • 🔌 Socket.IO Protocol: Full Socket.IO protocol support
  • 🏠 Namespaces & Rooms: Organize connections into logical groups
  • 🗄️ Redis Adapter: Built-in Redis support for horizontal scaling
  • 🔐 Authentication: Built-in connection authorization
  • 📡 Event System: Full event emission and handling
  • 🧵 Goroutine Safe: Thread-safe operations with proper locking

Installation

go get github.com/izetmolla/socket.io

Quick Start

Basic Server Setup with Fiber v3

package main

import (
    "log"
    "github.com/gofiber/fiber/v3"
    "github.com/izetmolla/socket.io"
)

func main() {
    // Create Fiber app
    app := fiber.New()

    // Initialize Socket.IO server
    io := socketio.New(nil) // No Redis config for basic setup

    // Serve static files (Socket.IO client)
    app.Use("/socket.io/", fiber.Static("client-dist"))

    // Handle Socket.IO connections
    app.Get("/socket.io/*", socketio.NewWSHandler(func(conn *socketio.WSConn) {
        // Handle WebSocket upgrade
        log.Printf("WebSocket connection established")
    }))

    // Socket.IO connection handler
    io.OnConnection(func(socket *socketio.Socket) {
        log.Printf("New socket connected: %s", socket.Id)

        // Handle custom events
        socket.On("message", func(data interface{}) {
            log.Printf("Received message: %v", data)
            
            // Echo back to client
            socket.Emit("message", "Server received: "+data.(string))
        })

        // Handle disconnection
        socket.On("disconnect", func(data interface{}) {
            log.Printf("Socket disconnected: %s", socket.Id)
        })
    })

    // Start server
    log.Fatal(app.Listen(":3000"))
}

Server with Redis Adapter

package main

import (
    "log"
    "github.com/gofiber/fiber/v3"
    "github.com/izetmolla/socket.io"
)

func main() {
    // Create Fiber app
    app := fiber.New()

    // Initialize Socket.IO server with Redis
    config := &socketio.ServerConfig{
        RedisURL: "redis://localhost:6379",
        RedisConfig: &socketio.RedisConfig{
            PersistData: true,
        },
    }
    io := socketio.New(config)

    // Serve static files
    app.Use("/socket.io/", fiber.Static("client-dist"))

    // Handle Socket.IO connections
    app.Get("/socket.io/*", socketio.NewWSHandler(func(conn *socketio.WSConn) {
        log.Printf("WebSocket connection established")
    }))

    // Socket.IO connection handler
    io.OnConnection(func(socket *socketio.Socket) {
        log.Printf("New socket connected: %s", socket.Id)

        // Join a room
        socket.Join("general")

        // Handle chat messages
        socket.On("chat_message", func(data interface{}) {
            message := data.(map[string]interface{})
            
            // Broadcast to room
            io.Of("general").To("general").Emit("chat_message", message)
        })
    })

    log.Fatal(app.Listen(":3000"))
}

Advanced Server with Namespaces

package main

import (
    "log"
    "github.com/gofiber/fiber/v3"
    "github.com/izetmolla/socket.io"
)

func main() {
    // Create Fiber app
    app := fiber.New()

    // Initialize Socket.IO server
    io := socketio.New(nil)

    // Serve static files
    app.Use("/socket.io/", fiber.Static("client-dist"))

    // Handle Socket.IO connections
    app.Get("/socket.io/*", socketio.NewWSHandler(func(conn *socketio.WSConn) {
        log.Printf("WebSocket connection established")
    }))

    // Main namespace
    io.OnConnection(func(socket *socketio.Socket) {
        log.Printf("Main namespace connection: %s", socket.Id)
        
        socket.On("ping", func(data interface{}) {
            socket.Emit("pong", "pong")
        })
    })

    // Admin namespace
    adminNamespace := io.Of("/admin")
    adminNamespace.OnConnection(func(socket *socketio.Socket) {
        log.Printf("Admin namespace connection: %s", socket.Id)
        
        // Join admin room
        socket.Join("admins")
        
        socket.On("admin_message", func(data interface{}) {
            // Broadcast to all admins
            adminNamespace.To("admins").Emit("admin_message", data)
        })
    })

    // Chat namespace
    chatNamespace := io.Of("/chat")
    chatNamespace.OnConnection(func(socket *socketio.Socket) {
        log.Printf("Chat namespace connection: %s", socket.Id)
        
        socket.On("join_room", func(data interface{}) {
            room := data.(string)
            socket.Join(room)
            socket.Emit("joined_room", room)
        })
        
        socket.On("leave_room", func(data interface{}) {
            room := data.(string)
            socket.Leave(room)
            socket.Emit("left_room", room)
        })
        
        socket.On("room_message", func(data interface{}) {
            message := data.(map[string]interface{})
            room := message["room"].(string)
            content := message["content"].(string)
            
            // Send to specific room
            chatNamespace.To(room).Emit("room_message", map[string]interface{}{
                "content": content,
                "socketId": socket.Id,
            })
        })
    })

    log.Fatal(app.Listen(":3000"))
}

Client Connection Examples

JavaScript/Node.js Client

<!DOCTYPE html>
<html>
<head>
    <title>Socket.IO Client</title>
    <script src="/socket.io/socket.io.js"></script>
</head>
<body>
    <div id="messages"></div>
    <input type="text" id="messageInput" placeholder="Type a message...">
    <button onclick="sendMessage()">Send</button>

    <script>
        // Connect to main namespace
        const socket = io();

        // Connect to specific namespace
        const adminSocket = io('/admin');
        const chatSocket = io('/chat');

        // Connection events
        socket.on('connect', () => {
            console.log('Connected to main namespace');
            document.getElementById('messages').innerHTML += '<p>Connected to main namespace</p>';
        });

        adminSocket.on('connect', () => {
            console.log('Connected to admin namespace');
        });

        chatSocket.on('connect', () => {
            console.log('Connected to chat namespace');
        });

        // Listen for messages
        socket.on('message', (data) => {
            console.log('Received:', data);
            document.getElementById('messages').innerHTML += `<p>${data}</p>`;
        });

        // Chat room events
        chatSocket.on('room_message', (data) => {
            console.log('Room message:', data);
        });

        // Send message function
        function sendMessage() {
            const input = document.getElementById('messageInput');
            const message = input.value;
            
            if (message.trim()) {
                socket.emit('message', message);
                input.value = '';
            }
        }

        // Join chat room
        function joinRoom(roomName) {
            chatSocket.emit('join_room', roomName);
        }

        // Leave chat room
        function leaveRoom(roomName) {
            chatSocket.emit('leave_room', roomName);
        }

        // Send room message
        function sendRoomMessage(roomName, content) {
            chatSocket.emit('room_message', {
                room: roomName,
                content: content
            });
        }
    </script>
</body>
</html>

API Reference

Server Methods

  • New(config *ServerConfig) *Io - Create new Socket.IO server
  • NewWithRedis(redisConfig *redis.Config) *Io - Create server with Redis adapter
  • OnConnection(callback connectionEventCallback) - Set connection handler
  • Of(namespace string) *Namespace - Get or create namespace

Socket Methods

  • On(event string, callback eventCallback) - Listen for events
  • Emit(event string, args ...interface{}) - Emit event to client
  • Join(room string) - Join a room
  • Leave(room string) - Leave a room
  • Disconnect() - Disconnect socket

Namespace Methods

  • OnConnection(callback connectionEventCallback) - Set namespace connection handler
  • Emit(event string, args ...interface{}) - Emit to all sockets in namespace
  • To(room string) *Room - Target specific room
  • Sockets() []*Socket - Get all sockets in namespace

Room Methods

  • Emit(event string, args ...interface{}) - Emit to all sockets in room
  • Sockets() []*Socket - Get all sockets in room

Configuration

Server Configuration

type ServerConfig struct {
    RedisURL    string
    RedisConfig *redis.Config
}

Redis Configuration

type RedisConfig struct {
    RedisURL    string
    PersistData bool
}

Middleware Integration

The Socket.IO server integrates seamlessly with Fiber v3 middleware:

app := fiber.New()

// CORS middleware
app.Use(cors.New(cors.Config{
    AllowOrigins: "*",
    AllowMethods: "GET,POST,PUT,DELETE",
    AllowHeaders: "Origin,Content-Type,Accept",
}))

// Authentication middleware
app.Use(func(c fiber.Ctx) error {
    // Your auth logic here
    return c.Next()
})

// Socket.IO after middleware
io := socketio.New(nil)

Error Handling

io.OnConnection(func(socket *socketio.Socket) {
    socket.On("error", func(err interface{}) {
        log.Printf("Socket error: %v", err)
    })
    
    // Handle disconnection
    socket.On("disconnect", func(reason interface{}) {
        log.Printf("Socket %s disconnected: %v", socket.Id, reason)
    })
})

Performance Considerations

  • Use Redis adapter for horizontal scaling
  • Implement proper room management
  • Handle disconnections gracefully
  • Use appropriate event naming conventions
  • Monitor memory usage with large numbers of connections

License

This project is licensed under the MIT License.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors