Skip to content

An ergonomic epoll based websocket server library in Go

License

Notifications You must be signed in to change notification settings

purehyperbole/wsev

Repository files navigation

wsev Go Reference Go Report Card Build Status

An event based websocket server implementation based on epoll, designed for ease of use and high connection concurrency.

Some parts for reading and writing websocket headers have been derrvied from the excellent github.com/gobwas/ws and lightly modified to support buffer reuse.

Features

  • Epoll based websocket handler
  • SO_REUSEPORT for multiple epoll listeners on the same port
  • Pooled write buffers for efficient memory usage
  • Passes the autobahn testsuite
  • Only depends on golang.org/x/sys
  • Detect connection timeouts

Setup

go get github.com/purehyperbole/wsev

Usage

package main

import (
    "log"
    "runtime"

    "github.com/purehyperbole/wsev"
)

func main() {
    h := &wsev.Handler{
        OnConnect: func(conn *wsev.Conn) {
            // client has connected
        },
        OnDisconnect: func(conn *wsev.Conn, err error) {
            // client has disconnected
        },
        OnPing: func(conn *wsev.Conn) {
            // client has sent pong
        },
        OnMessage: func(conn *wsev.Conn, msg []byte) {
            // client has sent a binary/text event
        },
        OnError: func(err error, isFatal bool) {
            // server has experienced an error
        }
    }

    // will start a new websocket server on port 9000
    err := wsev.New(
        h, 
        // the number of listener goroutines that will be started
        // defaults to GOMAXPROCS
        wsev.WithListeners(count int),
        // the deadline that used when reading from sockets that have data
        wsev.WithReadDeadline(time.Millisecond*100),
        // the deadline that data will be flushed to the underlying connection 
        // when the data in the buffer has not exceeded the buffer size
        wsev.WithWriteBufferDeadline(time.Millisecond * 100),
        // the size of the write buffer for a connection. these buffers are 
        // only allocated and used when there is data ready for writing to
        // the connection. Once the buffer has been flushed, the buffer is
        // returned to a pool for reuse. 
        wsev.WithWriteBufferSize(1<<14),
        // sets the size of the read buffer for reading from the connection.
        // a read buffer is allocated per event loop
        wsev.WithReadBufferSize(1<<14),
    ).Serve(9000)

    if err != nil {
        log.Fatal(err)
    }

    runtime.Goexit()
}

Example - Chat Room

package main

import (
    "io"
    "log"
    "net"
    "runtime"
    "sync"

    "github.com/purehyperbole/wsev"
)

func main() {
    // keep a list of all connected members
    var connections []io.Writer
    var lock sync.Mutex

    h := &wsev.Handler{
        OnConnect: func(conn *wsev.Conn) {
            // client has connected, so add it to the list
            lock.Lock()
            defer lock.Unlock()

            connections = append(connections, conn)
        },
        OnDisconnect: func(conn *wsev.Conn, err error) {
            // client has disconnected, so remove it from the list
            lock.Lock()
            defer lock.Unlock()

            for i := len(connections) - 1; i >= 0; i-- {
                if connections[i] == conn {
                    connections = append(connections[:i], connections[i+1:]...)
                }
            }
        },
        OnMessage: func(conn *wsev.Conn, msg []byte) {
            // a message has been recevied, broadcast it to the other connections
            lock.Lock()
            defer lock.Unlock()

            _, err := io.MultiWriter(connections...).Write(msg)
            if err != nil {
            	log.Printf("failed to write to connections: %s", err.Error())
            }
        },
    }

    err := wsev.New(
        h, 
    ).Serve(8000)

    if err != nil {
        log.Fatal(err)
    }

    runtime.Goexit()
}

Development

Running tests:

go test -v -race

Running with autobahn testsuite (requires Docker)

AUTOBAHN=1 go test -v -race

About

An ergonomic epoll based websocket server library in Go

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages