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.
- 🚀 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
go get github.com/izetmolla/socket.iopackage 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"))
}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"))
}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"))
}<!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>New(config *ServerConfig) *Io- Create new Socket.IO serverNewWithRedis(redisConfig *redis.Config) *Io- Create server with Redis adapterOnConnection(callback connectionEventCallback)- Set connection handlerOf(namespace string) *Namespace- Get or create namespace
On(event string, callback eventCallback)- Listen for eventsEmit(event string, args ...interface{})- Emit event to clientJoin(room string)- Join a roomLeave(room string)- Leave a roomDisconnect()- Disconnect socket
OnConnection(callback connectionEventCallback)- Set namespace connection handlerEmit(event string, args ...interface{})- Emit to all sockets in namespaceTo(room string) *Room- Target specific roomSockets() []*Socket- Get all sockets in namespace
Emit(event string, args ...interface{})- Emit to all sockets in roomSockets() []*Socket- Get all sockets in room
type ServerConfig struct {
RedisURL string
RedisConfig *redis.Config
}type RedisConfig struct {
RedisURL string
PersistData bool
}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)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)
})
})- 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
This project is licensed under the MIT License.
Contributions are welcome! Please feel free to submit a Pull Request.