gws

package module
v1.2.3 Latest Latest
Warning

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

Go to latest
Published: Jan 7, 2023 License: MIT Imports: 16 Imported by: 64

README

gws

event-driven websocket server

Build Status

Highlight
  • zero dependency
  • zero extra goroutine to control websocket
  • zero error to read/write message, errors have been handled appropriately
  • event driven
  • fully passes the WebSocket autobahn-testsuite
Attention
  • It's designed for api server, do not write big message
  • It's recommended not to enable data compression in the intranet
  • WebSocket Events are emitted synchronously, manage goroutines yourself
Core Interface
type Event interface {
    OnOpen(socket *Conn)
    OnError(socket *Conn, err error)
    OnClose(socket *Conn, code uint16, reason []byte)
    OnPing(socket *Conn, payload []byte)
    OnPong(socket *Conn, payload []byte)
    OnMessage(socket *Conn, message *Message)
}
Install
go get -v github.com/lxzan/gws@latest
Quick Start
package main

import (
	"context"
	"fmt"
	"github.com/lxzan/gws"
	"net/http"
)

func main() {
	var config = gws.Config{CompressEnabled: true, CheckTextEncoding: true, MaxContentLength: 32 * 1024 * 1024}
	var handler = new(WebSocket)

	http.HandleFunc("/connect", func(writer http.ResponseWriter, request *http.Request) {
		socket, err := gws.Accept(context.Background(), writer, request, handler, config)
		if err != nil {
			return
		}
		socket.Listen()
	})

	_ = http.ListenAndServe(":3000", nil)
}

type WebSocket struct{}

func (c *WebSocket) OnClose(socket *gws.Conn, code uint16, reason []byte) {
	fmt.Printf("onclose: code=%d, payload=%s\n", code, string(reason))
}

func (c *WebSocket) OnError(socket *gws.Conn, err error) {
	fmt.Printf("onerror: err=%s\n", err.Error())
}

func (c *WebSocket) OnOpen(socket *gws.Conn) {
	println("connected")
}

func (c *WebSocket) OnPing(socket *gws.Conn, payload []byte) {
	fmt.Printf("onping: payload=%s\n", string(payload))
	socket.WritePong(payload)
}

func (c *WebSocket) OnPong(socket *gws.Conn, payload []byte) {}

func (c *WebSocket) OnMessage(socket *gws.Conn, message *gws.Message) {
	socket.WriteMessage(message.Typ(), message.Bytes())
	message.Close()
}
HeartBeat
const PingInterval = 5*time.Second

type WebSocket struct {}

func (c *WebSocket) OnOpen(socket *gws.Conn) {
	socket.SetDeadline(time.Now().Add(3*PingInterval))
}

func (c *WebSocket) OnPing(socket *gws.Conn, payload []byte) {
	socket.WritePong(nil)
	socket.SetDeadline(time.Now().Add(3*PingInterval))
}
Test
// Terminal 1
git clone https://github.com/lxzan/gws.git 
cd gws
go run github.com/lxzan/gws/examples/testsuite

// Terminal 2
cd examples/testsuite
docker run -it --rm \
    -v ${PWD}/config:/config \
    -v ${PWD}/reports:/reports \
    crossbario/autobahn-testsuite \
    wstest -m fuzzingclient -s /config/fuzzingclient.json

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config added in v1.2.0

type Config struct {
	// whether to compress data
	CompressEnabled bool

	// compress level eg: flate.BestSpeed
	CompressLevel int

	// max message size
	MaxContentLength int

	// whether to check utf8 encoding, disabled for better performance
	CheckTextEncoding bool

	// client authentication
	Authenticate func(r *Request) bool
}

type Conn

type Conn struct {

	// Concurrent Variable
	// store session information
	SessionStorage SessionStorage
	// contains filtered or unexported fields
}

func Accept added in v1.2.0

func Accept(ctx context.Context, w http.ResponseWriter, r *http.Request, eventHandler Event, config Config) (*Conn, error)

Accept http protocol upgrade to websocket ctx done means server stopping

func (*Conn) Close

func (c *Conn) Close(code uint16, reason []byte)

Close write closed frame code: https://developer.mozilla.org/zh-CN/docs/Web/API/CloseEvent#status_codes 发送关闭帧, 并将连接状态置为关闭

func (*Conn) Listen added in v1.1.2

func (c *Conn) Listen()

Listen listening to websocket messages through a dead loop 通过死循环监听websocket消息

func (*Conn) LocalAddr added in v1.0.1

func (c *Conn) LocalAddr() net.Addr

func (*Conn) RemoteAddr added in v1.0.1

func (c *Conn) RemoteAddr() net.Addr

func (*Conn) SetDeadline

func (c *Conn) SetDeadline(t time.Time)

SetDeadline sets deadline

func (*Conn) SetReadDeadline added in v1.1.2

func (c *Conn) SetReadDeadline(t time.Time)

SetReadDeadline sets read deadline

func (*Conn) SetWriteDeadline added in v1.1.2

func (c *Conn) SetWriteDeadline(t time.Time)

SetWriteDeadline sets write deadline

func (*Conn) WriteMessage added in v1.1.0

func (c *Conn) WriteMessage(opcode Opcode, payload []byte)

WriteMessage write text/binary message text message must be utf8 encoding 发送文本/二进制消息, 文本消息必须是utf8编码

func (*Conn) WritePing

func (c *Conn) WritePing(payload []byte)

WritePing write ping frame

func (*Conn) WritePong

func (c *Conn) WritePong(payload []byte)

WritePong write pong frame

type Event added in v1.1.2

type Event interface {
	OnOpen(socket *Conn)
	OnError(socket *Conn, err error)
	OnClose(socket *Conn, code uint16, reason []byte)
	OnPing(socket *Conn, payload []byte)
	OnPong(socket *Conn, payload []byte)
	OnMessage(socket *Conn, message *Message)
}

WebSocket Event OnError and OnClose will not both be called

type Map added in v1.2.3

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

func NewMap added in v1.2.3

func NewMap() *Map

func (*Map) Delete added in v1.2.3

func (c *Map) Delete(key interface{})

Delete deletes the value for a key.

func (*Map) Len added in v1.2.3

func (c *Map) Len() int

func (*Map) Load added in v1.2.3

func (c *Map) Load(key interface{}) (value interface{}, exist bool)

func (*Map) Range added in v1.2.3

func (c *Map) Range(f func(key, value interface{}) bool)

Range calls f sequentially for each key and value present in the map. If f returns false, range stops the iteration.

func (*Map) Store added in v1.2.3

func (c *Map) Store(key interface{}, value interface{})

Store sets the value for a key.

type Message

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

func (*Message) Bytes

func (c *Message) Bytes() []byte

Bytes get message content

func (*Message) Close

func (c *Message) Close()

Close recycle buffer

func (*Message) Read added in v1.1.0

func (c *Message) Read(p []byte) (n int, err error)

func (*Message) Typ added in v1.1.0

func (c *Message) Typ() Opcode

Typ get message type

type Opcode

type Opcode uint8
const (
	OpcodeContinuation    Opcode = 0x0
	OpcodeText            Opcode = 0x1
	OpcodeBinary          Opcode = 0x2
	OpcodeCloseConnection Opcode = 0x8
	OpcodePing            Opcode = 0x9
	OpcodePong            Opcode = 0xA
)

func (Opcode) IsDataFrame added in v1.1.2

func (c Opcode) IsDataFrame() bool

type Request

type Request struct {
	*http.Request                 // http request
	SessionStorage SessionStorage // store user session
}

type SessionStorage added in v1.2.3

type SessionStorage interface {
	Load(key interface{}) (value interface{}, exist bool)
	Delete(key interface{})
	Store(key interface{}, value interface{})
	Range(f func(key, value interface{}) bool)
}

SessionStorage because sync.Map is not easy to debug, so I implemented my own map. if you don't like it, you can also use sync.Map instead.

Directories

Path Synopsis
examples
bench command
chatroom command
testsuite command

Jump to

Keyboard shortcuts

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