go-socket.io

repository·master·Indexed 26 days ago

https://github.com/googollee/go-socket.io

A Golang implementation of the Socket.IO realtime application framework supporting client version 1.4. It provides features for rooms, namespaces, broadcasting, and acknowledgements. The package includes a server implementation for net/http, a beta Go client, and a Redis broadcast adapter for cross-server communication. It also includes the go-engine.io sub-package, a transport-based communication layer supporting long-polling and websocket transports.

Tokens
8.2K
Snippets
22
Records
64
Agent score
90%

What's inside go-socket.io

  1. Override the internal Socket.io logger

    master

    You can replace the default internal logger used by go-socket.io with your own implementation by assigning a logger instance to logger.Log. This is useful for integrating Socket.io logs into your existing application logging framework (e.g., using slog).

    import (
        "os"
        "log/slog"
        "github.com/googollee/go-socket.io/logger"
    )
    
    func main() {
        json_logger := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
            Level: slog.LevelInfo, // Set Level for each handler
        })
    
        log := slog.New(json_logger).With("server", "socket.io") // attach attribute to all log lines
        logger.Log = log
    }
  2. Install go-engine.io

    master

    Install the go-engine.io package using go get and import it into your Go project. It serves as the transport-based communication layer for go-socket.io, supporting both long-polling and websocket transports and maintaining compatibility with the Node.js implementation.

    go get github.com/googollee/go-socket.io/engineio@v1
    import "github.com/googollee/go-socket.io/engineio"
  3. Implement a Socket.IO server with net/http

    master

    To create a Socket.IO server, use socketio.NewServer(nil) and register it with a standard Go http.Handler. You can define event handlers using OnConnect, OnEvent, OnError, and OnDisconnect methods.

    Note: To prevent memory leaks, call server.Remove(s.ID()) inside the OnDisconnect handler.

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    
    	socketio "github.com/googollee/go-socket.io"
    )
    
    func main() {
    	server := socketio.NewServer(nil)
    	
    	server.OnConnect("/", func(s socketio.Conn) error {
    		s.SetContext("")
    		fmt.Println("connected:", s.ID())
    		return nil
    	})
    
    	server.OnEvent("/", "notice", func(s socketio.Conn, msg string) {
    		fmt.Println("notice:", msg)
    		s.Emit("reply", "have "+msg)
    	})
    
    	server.OnDisconnect("/", func(s socketio.Conn, reason string) {
    		// Add the Remove session id. Fixed the connection & mem leak
    		server.Remove(s.ID())
    		fmt.Println("closed", reason)
    	})
    
    	go server.Serve()
    	defer server.Close()
    
    	http.Handle("/socket.io/", server)
    	log.Fatal(http.ListenAndServe(":8000", nil))
    }
  4. Broadcast messages to all connected clients

    master

    To broadcast to all clients, you can use a common room (e.g., "bcast").

    1. Use s.Join("room_name") inside the OnConnect handler to add the connection to a room.
    2. Use server.BroadcastToRoom("", "room_name", "event:name", msg) to send the message to everyone in that room.
    // On the server
    server.OnConnect("/", func(s socketio.Conn) error {
    	s.Join("bcast")
    	return nil
    })
    
    // To broadcast
    server.BroadcastToRoom("", "bcast", "event:name", msg)
  5. Handle Acknowledgements (ACK) in go-socket.io

    master

    Acknowledgements in go-socket.io follow specific patterns depending on the direction of the data flow:

    1. Server to Client ACK

    To send an acknowledgement from the server to the client, use a return statement within your OnEvent handler. The return value is automatically wrapped and sent to the client's callback.

    Server-side:

    server.On("some:event", func(msg string) string {
    	return msg // The return value is sent as the ACK data
    })

    2. Client to Server ACK

    To receive an acknowledgement from a client, provide a callback function as the last argument to Emit or BroadcastTo.

    Server-side:

    server.Emit("some:event", dataForClient, func (so socketio.Socket, data string) {
    	log.Println("Client ACK with data: ", data)
    })
  6. Install go-socket.io

    master

    To use go-socket.io in your Golang project, install the package using go get and import it using the package path. Use socketio as the package name in your code.

    go get github.com/googollee/go-socket.io
    import "github.com/googollee/go-socket.io"
  7. Implement Polling Transport for Engine.IO

    master
    The polling package provides a serverConn implementation for the Engine.IO polling transport. It handles HTTP requests (GET, POST, OPTIONS) to facilitate communication between the client and server using long-polling or short-polling mechanisms. It supports JSONP for cross-domain compatibility and binary data via specific MIME types.
  8. Configure the Redis broadcast adapter

    master

    To enable cross-server broadcasting using Redis, use the server.Adapter() method with a socketio.RedisAdapterOptions configuration object.

    server := socketio.NewServer(nil)
    
    _, err := server.Adapter(&socketio.RedisAdapterOptions{
        Addr:   "127.0.0.1:6379",
        Host:   "127.0.0.1",
        Port:   "6379",
        Prefix: "socket.io", 
        DB: 1,
    })
    if err != nil {
        log.Fatal("error:", err)
    }
  9. Use the Socket.IO Go client

    master

    The Go client allows you to connect to a Socket.IO server. Use socketio.NewClient(uri, nil) to initialize the client, client.OnEvent to register listeners for incoming events, and client.Connect() to establish the connection.

    Warning: The client implementation is currently in beta and should not be relied upon for production.

    package main
    
    import (
    	"log"
    	socketio "github.com/googollee/go-socket.io"
    )
    
    func main() {
    	uri := "http://127.0.0.1:8000"
    
    	client, _ := socketio.NewClient(uri, nil)
    
    	// Handle an incoming event
    	client.OnEvent("reply", func(s socketio.Conn, msg string) {
    		log.Println("Receive Message /reply: ", "reply", msg)
    	})
    
    	client.Connect()
    	client.Emit("notice", "hello")
    	client.Close()
    }
  10. Use go-engine.io in a Go server

    master

    To use go-engine.io, create a new server using engineio.NewServer(nil). You can then handle incoming connections by calling server.Accept() in a loop. Each connection provides NextReader() and NextWriter() methods to facilitate bi-directional communication. Finally, register the server as an HTTP handler at a specific path (e.g., /engine.io/).

    package main
    
    import (
    	"io/ioutil"
    	"log"
    	"net/http"
    
    	"github.com/googollee/go-socket.io/engineio"
    )
    
    func main() {
    	server := engineio.NewServer(nil)
    
    	go func() {
    		for {
    			conn, err := server.Accept()
    			if err != nil {
    				log.Fatalln("accept error:", err)
    			}
    		
    			go func() {
    				defer conn.Close()
    			
    				for {
    					t, r, _ := conn.NextReader()
    					b, _ := ioutil.ReadAll(r)
    					r.Close()
    
    					w, _ := conn.NextWriter(t)
    					w.Write(b)
    					w.Close()
    				}
    			}()
    		}
    	}()
    
    	http.Handle("/engine.io/", server)
    	log.Println("Serving at localhost:5000...")
    	
    	log.Fatal(http.ListenAndServe(":5000", nil))
    }