WebSocket

Rue provides a full RFC 6455 WebSocket implementation with support for broadcasting via Hub.

Basic Usage

Create a simple WebSocket endpoint:

go
r := rue.Default()

r.GET("/ws", func(c *rue.Context) {
    handler := &rue.WebSocketHandler{
        OnConnect: func(conn *rue.WebSocketConn) {
            log.Println("Client connected:", conn.ID())
        },
        OnMessage: func(conn *rue.WebSocketConn, msgType int, data []byte) {
            log.Printf("Received: %s", data)
            // Echo the message back
            conn.Send(msgType, data)
        },
        OnClose: func(conn *rue.WebSocketConn) {
            log.Println("Client disconnected:", conn.ID())
        },
        OnError: func(conn *rue.WebSocketConn, err error) {
            log.Println("Error:", err)
        },
    }
    handler.Handle(c)
})

r.Run(":8080")

Hub for Broadcasting

Use a Hub to manage multiple connections and broadcast messages:

go
r := rue.Default()

// Create and start the hub
hub := rue.NewWebSocketHub()
go hub.Run()

r.GET("/ws", func(c *rue.Context) {
    handler := &rue.WebSocketHandler{
        Hub: hub,
        OnConnect: func(conn *rue.WebSocketConn) {
            log.Printf("Client %s connected", conn.ID())
        },
        OnMessage: func(conn *rue.WebSocketConn, msgType int, data []byte) {
            // Broadcast to all connected clients
            hub.Broadcast(msgType, data)
        },
    }
    handler.Handle(c)
})

r.Run(":8080")

Message Types

WebSocket supports different message types:

go
OnMessage: func(conn *rue.WebSocketConn, msgType int, data []byte) {
    switch msgType {
    case rue.TextMessage:
        // Handle text message
        log.Printf("Text: %s", data)
    case rue.BinaryMessage:
        // Handle binary message
        log.Printf("Binary: %d bytes", len(data))
    }
    
    // Send text message
    conn.Send(rue.TextMessage, []byte("Hello"))
    
    // Send binary message
    conn.Send(rue.BinaryMessage, binaryData)
}

Room-based Broadcasting

Implement chat rooms or channels:

go
type ChatServer struct {
    rooms map[string]map[*rue.WebSocketConn]bool
    mu    sync.RWMutex
}

func NewChatServer() *ChatServer {
    return &ChatServer{
        rooms: make(map[string]map[*rue.WebSocketConn]bool),
    }
}

func (s *ChatServer) Join(room string, conn *rue.WebSocketConn) {
    s.mu.Lock()
    defer s.mu.Unlock()
    
    if s.rooms[room] == nil {
        s.rooms[room] = make(map[*rue.WebSocketConn]bool)
    }
    s.rooms[room][conn] = true
}

func (s *ChatServer) Leave(room string, conn *rue.WebSocketConn) {
    s.mu.Lock()
    defer s.mu.Unlock()
    
    if s.rooms[room] != nil {
        delete(s.rooms[room], conn)
    }
}

func (s *ChatServer) Broadcast(room string, msgType int, data []byte) {
    s.mu.RLock()
    defer s.mu.RUnlock()
    
    for conn := range s.rooms[room] {
        conn.Send(msgType, data)
    }
}

// Usage
chat := NewChatServer()

r.GET("/ws/:room", func(c *rue.Context) {
    room := c.Param("room")
    
    handler := &rue.WebSocketHandler{
        OnConnect: func(conn *rue.WebSocketConn) {
            chat.Join(room, conn)
        },
        OnMessage: func(conn *rue.WebSocketConn, msgType int, data []byte) {
            chat.Broadcast(room, msgType, data)
        },
        OnClose: func(conn *rue.WebSocketConn) {
            chat.Leave(room, conn)
        },
    }
    handler.Handle(c)
})

JSON Messages

Handle structured JSON messages:

go
type Message struct {
    Type    string `json:"type"`
    Content string `json:"content"`
    From    string `json:"from"`
}

OnMessage: func(conn *rue.WebSocketConn, msgType int, data []byte) {
    var msg Message
    if err := json.Unmarshal(data, &msg); err != nil {
        log.Println("Invalid JSON:", err)
        return
    }
    
    switch msg.Type {
    case "chat":
        // Handle chat message
        response, _ := json.Marshal(Message{
            Type:    "chat",
            Content: msg.Content,
            From:    msg.From,
        })
        hub.Broadcast(rue.TextMessage, response)
        
    case "ping":
        // Handle ping
        pong, _ := json.Marshal(Message{Type: "pong"})
        conn.Send(rue.TextMessage, pong)
    }
}

Client Example

JavaScript client code:

javascript
const ws = new WebSocket('ws://localhost:8080/ws');

ws.onopen = () => {
    console.log('Connected');
    ws.send(JSON.stringify({
        type: 'chat',
        content: 'Hello!',
        from: 'user1'
    }));
};

ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    console.log('Received:', msg);
};

ws.onclose = () => {
    console.log('Disconnected');
};

ws.onerror = (error) => {
    console.error('Error:', error);
};

Connection Methods

Method Description
conn.ID() Get unique connection ID
conn.Send(type, data) Send message to client
conn.Close() Close the connection

Hub Methods

Method Description
hub.Run() Start the hub (run in goroutine)
hub.Broadcast(type, data) Send to all connections
hub.Count() Get number of connections