ws

package
v1.11.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 17, 2024 License: MIT Imports: 7 Imported by: 0

README

WebSocket

ws is based on the github.com/gorilla/websocket library, support automatic client reconnection.


Example of use

1. Default setting

Server side code example:

package main

import (
    "context"
    "log"
    "github.com/zhufuyi/sponge/pkg/ws"
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()
	
    r.GET("/ws", func(c *gin.Context) {
        s := ws.NewServer(c.Writer, c.Request, loopReceiveMessage) // default setting
        err := s.Run(context.Background())
        if err != nil {
            log.Println("webSocket server error:", err)
        }
    })
	
    err := r.Run(":8080")
    if err != nil {
        panic(err)
    }
}

func loopReceiveMessage(ctx context.Context, conn *ws.Conn) {
    for {
        messageType, message, err := conn.ReadMessage()
        if err != nil { // release connection
            return
        }

        // handle message
        log.Println(messageType, message)
    }
}

Client side code example:

package main

import (
    "strconv"
    "log"
    "time"
    "github.com/zhufuyi/sponge/pkg/ws"
    "github.com/gorilla/websocket"
)

var wsURL = "ws://localhost:8080/ws"

func main() {
    c, err := ws.NewClient(wsURL) // default setting
    if err != nil {
        log.Println("connect error:", err)
        return
    }
    defer c.Close()

    go func() {
        for {
            _, message, err := c.GetConn().ReadMessage()
            if err != nil {
                log.Println("client read error:", err)
                return
            }
            log.Printf("client received: %s", message)
        }
    }()
    
    for i := 0; i < 5; i++ {
        data := "Hello, World " + strconv.Itoa(i)
        err = c.GetConn().WriteMessage(websocket.TextMessage, []byte(data))
        if err != nil {
            log.Println("write error:", err)
        }
        time.Sleep(100 * time.Millisecond)
    }
}

2. Custom setting

Server side custom setting, options such as ws.Upgrader, ws.WithNoClientPingTimeout, ws.WithServerLogger, ws.WithResponseHeader can be set.

package main

import (
	"context"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"github.com/zhufuyi/sponge/pkg/logger"
	"github.com/zhufuyi/sponge/pkg/ws"
)

func main() {
	r := gin.Default()
	ug := &websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
	r.GET("/ws", func(c *gin.Context) {
		s := ws.NewServer(c.Writer, c.Request, loopReceiveMessage,
			ws.WithUpgrader(ug),
			ws.WithNoClientPingTimeout(time.Minute), // client side must send ping message in every 1 minutes
			ws.WithServerLogger(logger.Get()),
		)
		err := s.Run(context.Background())
		if err != nil {
			logger.Warn("WebSocket server error:", logger.Err(err))
		}
	})

	err := r.Run(":8080")
	if err != nil {
		panic(err)
	}
}

func loopReceiveMessage(ctx context.Context, conn *ws.Conn) {
	for {
		messageType, message, err := conn.ReadMessage()
		if err != nil {
			logger.Warn("ReadMessage error", logger.Err(err))
			return
		}
		logger.Infof("server side received: %s", message)

		switch messageType {
		case websocket.TextMessage:
			err = conn.WriteMessage(messageType, message)
			if err != nil {
				logger.Warn("WriteMessage error", logger.Err(err))
				continue
			}

		case websocket.PingMessage:
			err = conn.WriteMessage(websocket.PongMessage, []byte("pong"))
			if err != nil {
				logger.Warn("Write pong message error:", logger.Err(err))
				continue
			}
		default:
			logger.Warnf("Unknown message type: %d", messageType)
		}
	}
}

Client side custom setting, options such as ws.Dialer, ws.WithPing, ws.WithClientLogger, ws.WithRequestHeader can be set.

package main

import (
	"strconv"
	"time"

	"github.com/gorilla/websocket"
	"github.com/zhufuyi/sponge/pkg/logger"
	"github.com/zhufuyi/sponge/pkg/ws"
)

var wsURL = "ws://localhost:8080/ws"

func main() {
	c, err := ws.NewClient(wsURL,
		ws.WithPing(time.Second*20), //  It is recommended that the ping timeout time set by the server be less than 1/2
		ws.WithClientLogger(logger.Get()),
	)
	if err != nil {
		logger.Warn("connect error", logger.Err(err))
		return
	}
	defer c.Close()

	go clientLoopReadMessage(c)

	i := 0
	for {
		time.Sleep(time.Second * 3)
		i++
		data := "Hello, World " + strconv.Itoa(i)
		err = c.GetConn().WriteMessage(websocket.TextMessage, []byte(data))
		if err != nil {
			logger.Warn("WriteMessage error", logger.Err(err))
		}
	}
}

func clientLoopReadMessage(c *ws.Client) {
	for {
		select {
		case <-c.GetCtx().Done():
			return
		default:
			_, message, err := c.GetConn().ReadMessage()
			if err != nil {
				logger.Warn("ReadMessage error", logger.Err(err))
				time.Sleep(time.Second * 5)
				continue
			}
			logger.Infof("client side received: %s", message)
		}

	}
}

Documentation

Overview

Package ws provides a websocket server implementation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsClientClose

func IsClientClose(err error) bool

IsClientClose returns true if the error is caused by client close.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a wrapper of gorilla/websocket.

func NewClient

func NewClient(url string, opts ...ClientOption) (*Client, error)

NewClient creates a new client.

func (*Client) Close

func (c *Client) Close() error

Close closes the connection. Note: if set pingDialInterval, the Close method must be called, otherwise it will cause the goroutine to leak

func (*Client) GetConn

func (c *Client) GetConn() *websocket.Conn

GetConn returns the connection of the client.

func (*Client) GetCtx added in v1.10.2

func (c *Client) GetCtx() context.Context

GetCtx returns the context of the client.

func (*Client) TryReconnect added in v1.10.2

func (c *Client) TryReconnect() error

TryReconnect tries to reconnect the websocket server.

type ClientOption

type ClientOption func(*clientOptions)

ClientOption is a functional option for the client.

func WithClientLogger added in v1.10.2

func WithClientLogger(l *zap.Logger) ClientOption

WithClientLogger sets the logger for the client.

func WithDialer

func WithDialer(dialer *websocket.Dialer) ClientOption

WithDialer sets the dialer for the client.

func WithPing

func WithPing(interval time.Duration) ClientOption

WithPing sets the interval for sending ping message to the server.

func WithRequestHeader

func WithRequestHeader(header http.Header) ClientOption

WithRequestHeader sets the request header for the client.

type Conn

type Conn = websocket.Conn

Conn is a WebSocket connection.

type LoopFn

type LoopFn func(ctx context.Context, conn *Conn)

LoopFn is the function that is called for each WebSocket connection.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is a WebSocket server.

func NewServer

func NewServer(w http.ResponseWriter, r *http.Request, loopFn LoopFn, opts ...ServerOption) *Server

NewServer creates a new WebSocket server.

func (*Server) Run

func (s *Server) Run(ctx context.Context) error

Run runs the WebSocket server.

type ServerOption

type ServerOption func(*serverOptions)

ServerOption is a functional option for the Server.

func WithMaxMessageWaitPeriod

func WithMaxMessageWaitPeriod(period time.Duration) ServerOption

WithMaxMessageWaitPeriod sets the maximum waiting period for a message before closing the connection. Deprecated: use WithNoClientPingTimeout instead.

func WithNoClientPingTimeout added in v1.10.2

func WithNoClientPingTimeout(timeout time.Duration) ServerOption

WithNoClientPingTimeout sets the timeout for the client to send a ping message, if timeout, the connection will be closed.

func WithResponseHeader

func WithResponseHeader(header http.Header) ServerOption

WithResponseHeader sets the response header for the WebSocket upgrade response.

func WithServerLogger added in v1.10.2

func WithServerLogger(l *zap.Logger) ServerOption

WithServerLogger sets the logger for the server.

func WithUpgrader

func WithUpgrader(upgrader *websocket.Upgrader) ServerOption

WithUpgrader sets the WebSocket upgrader for the server.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL