etp

package module
v4.1.3 Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 11 Imported by: 2

README

etp

GoDoc Build and test codecov Go Report Card

ETP - event transport protocol on WebSocket, simple and powerful.

Highly inspired by socket.io. But there is no good implementation in Go, that is why etp exists.

The package based on github.com/nhooyr/websocket.

Install

go get -u github.com/txix-open/etp/v4

Features:

  • Rooms for server
  • Javascript client
  • Concurrent event emitting
  • Context based API
  • Event acknowledgment (for sync communication)

Internals

  • WebSocket message
    • websocket.MessageText (not binary)
    • <eventName>||<ackId>||<eventData>
    • can be overridden by custom msg.Codec
  • Each event is handled concurrently in separated goroutine
  • Message limit is 1MB by default

Complete example

package main

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

	"github.com/txix-open/etp/v4"
	"github.com/txix-open/etp/v4/msg"
)

func main() {
	srv := etp.NewServer(etp.WithServerAcceptOptions(&etp.AcceptOptions{
		InsecureSkipVerify: true, //completely ignore CORS checks, enable only for dev purposes
	}))

	//callback to handle new connection
	srv.OnConnect(func(conn *etp.Conn) {
		//you have access to original HTTP request
		fmt.Printf("id: %d, url: %s, connected\n", conn.Id(), conn.HttpRequest().URL)
		srv.Rooms().Join(conn, "goodClients") //leave automatically then disconnected

		conn.Data().Set("key", "value") //put any data associative with connection
	})

	//callback to handle disconnection
	srv.OnDisconnect(func(conn *etp.Conn, err error) {
		fmt.Println("disconnected", conn.Id(), err, etp.IsNormalClose(err))
	})

	//callback to handle any error during serving
	srv.OnError(func(conn *etp.Conn, err error) {
		connId := uint64(0)
		// be careful, conn can be nil on upgrading protocol error (before success WebSocket connection)
		if conn != nil {
			connId = conn.Id()
		}
		fmt.Println("error", connId, err)
	})

	//your business event handler
	//each event is handled in separated goroutine
	srv.On("hello", etp.HandlerFunc(func(ctx context.Context, conn *etp.Conn, event msg.Event) []byte {
		fmt.Printf("hello event received: %s, %s\n", event.Name, event.Data)
		return []byte("hello handled")
	}))

	//fallback handler
	srv.OnUnknownEvent(etp.HandlerFunc(func(ctx context.Context, conn *etp.Conn, event msg.Event) []byte {
		fmt.Printf("unknown event received, %s, %s\n", event.Name, event.Data)
		_ = conn.Close() //you may close a connection whenever you want
		return nil
	}))

	mux := http.NewServeMux()
	mux.Handle("GET /ws", srv)
	go func() {
		err := http.ListenAndServe(":8080", mux)
		if err != nil {
			panic(err)
		}
	}()
	time.Sleep(1 * time.Second)

	cli := etp.NewClient().
		OnDisconnect(func(conn *etp.Conn, err error) { //basically you have all handlers like a server here
			fmt.Println("client disconnected", conn.Id(), err)
		})
	err := cli.Dial(context.Background(), "ws://localhost:8080/ws")
	if err != nil {
		panic(err)
	}

	//to check connection is still alive
	err = cli.Ping(context.Background())
	if err != nil {
		panic(err)
	}

	//simply emit event
	err = cli.Emit(context.Background(), "hello", []byte("fire and forget"))
	if err != nil {
		panic(err)
	}

	//emit event and wait server response
	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) //highly recommended to set up timeout for waiting acknowledgment
	defer cancel()
	resp, err := cli.EmitWithAck(ctx, "hello", []byte("wait acknowledgment"))
	if err != nil {
		panic(err)
	}
	fmt.Printf("hello resposne: '%s'\n", resp)

	//data can be empty
	err = cli.Emit(ctx, "unknown event", nil)
	if err != nil {
		panic(err)
	}

	time.Sleep(15 * time.Second)

	//call to disconnect all clients
	srv.Shutdown()
}

V4 Migration

  • Internal message format is the same as v2
  • Each event now is handled in separated goroutine (completely async)
  • Significantly reduce code base, removed redundant interfaces
  • Fixed some memory leaks and potential deadlocks
  • Main package github.com/txix-open/isp-etp-go/v2 -> github.com/txix-open/etp/v4
  • OnDefault -> OnUnknownEvent
  • On* API are the same either etp.Client and etp.Server
  • WAS
srv.On("event", func (conn etp.Conn, data []byte) {
    log.Println("Received " + testEvent + ":" + string(data))
}).
  • BECOME
srv.On("hello", etp.HandlerFunc(func(ctx context.Context, conn *etp.Conn, event msg.Event) []byte {
    fmt.Printf("hello event received: %s, %s\n", event.Name, event.Data)
    return []byte("hello handled")
}))

The second param now is an interface.

Documentation

Overview

Package etp provides a client-server communication library using WebSockets. It supports event-based messaging, acknowledgments, and room-based broadcasting.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrClientClosed is returned when the client is closed or not connected.
	ErrClientClosed = errors.New("client closed")
)

Functions

func IsNormalClose

func IsNormalClose(err error) bool

IsNormalClose checks if the error is a WebSocket normal closure.

Types

type AcceptOptions

type AcceptOptions = websocket.AcceptOptions

AcceptOptions is an alias for websocket.AcceptOptions.

type Client

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

Client represents a WebSocket client for event-based communication. It is safe for concurrent use.

func NewClient

func NewClient(opts ...ClientOption) *Client

NewClient creates a new Client instance with the provided options.

func (*Client) Close

func (c *Client) Close() error

Close closes the client connection. It returns ErrClientClosed if the client is already closed.

func (*Client) Dial

func (c *Client) Dial(ctx context.Context, url string) error

Dial establishes a WebSocket connection to the specified URL. It returns an error if already connected or if the WebSocket dial fails.

func (*Client) Emit

func (c *Client) Emit(ctx context.Context, event string, data []byte) error

Emit sends an event with the specified data to the server. It returns ErrClientClosed if the client is not connected.

func (*Client) EmitWithAck

func (c *Client) EmitWithAck(ctx context.Context, event string, data []byte) ([]byte, error)

EmitWithAck sends an event with the specified data to the server and waits for an acknowledgment. It returns ErrClientClosed if the client is not connected. The response data from the server is returned on success.

func (*Client) On

func (c *Client) On(event string, handler Handler) *Client

On registers an event handler for the specified event name. It returns the Client to allow method chaining.

func (*Client) OnConnect

func (c *Client) OnConnect(handler ConnectHandler) *Client

OnConnect registers a handler to be called when the client connects. It returns the Client to allow method chaining.

func (*Client) OnDisconnect

func (c *Client) OnDisconnect(handler DisconnectHandler) *Client

OnDisconnect registers a handler to be called when the client disconnects. It returns the Client to allow method chaining.

func (*Client) OnError

func (c *Client) OnError(handler ErrorHandler) *Client

OnError registers a handler to be called when an error occurs. It returns the Client to allow method chaining.

func (*Client) OnUnknownEvent

func (c *Client) OnUnknownEvent(handler Handler) *Client

OnUnknownEvent registers a handler to be called when an unknown event is received. It returns the Client to allow method chaining.

func (*Client) Ping

func (c *Client) Ping(ctx context.Context) error

Ping sends a ping to the server to check the connection health. It returns ErrClientClosed if the client is not connected.

type ClientOption

type ClientOption func(*clientOptions)

ClientOption is a function that configures a clientOptions struct.

func WithClientCodec added in v4.1.0

func WithClientCodec(codec msg.Codec) ClientOption

WithClientCodec sets the codec for encoding and decoding events.

func WithClientDialOptions

func WithClientDialOptions(opts *DialOptions) ClientOption

WithClientDialOptions sets the WebSocket dial options for the client.

func WithClientReadLimit

func WithClientReadLimit(limit int64) ClientOption

WithClientReadLimit sets the maximum message size in bytes that the client can read.

type Conn

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

Conn represents a WebSocket connection associated with a client or server.

func (*Conn) Close

func (c *Conn) Close() error

Close closes the WebSocket connection with a normal closure status.

func (*Conn) Data

func (c *Conn) Data() *store.Store

Data returns the key-value store for connection-specific data.

func (*Conn) Emit

func (c *Conn) Emit(ctx context.Context, event string, data []byte) error

Emit sends an event with the specified data over the connection.

func (*Conn) EmitWithAck

func (c *Conn) EmitWithAck(ctx context.Context, event string, data []byte) ([]byte, error)

EmitWithAck sends an event with the specified data and waits for an acknowledgment. It returns the response data from the receiver on success.

func (*Conn) HttpRequest

func (c *Conn) HttpRequest() *http.Request

HttpRequest returns the underlying HTTP request associated with the connection.

func (*Conn) Id

func (c *Conn) Id() string

Id returns the unique identifier for the connection.

func (*Conn) Ping

func (c *Conn) Ping(ctx context.Context) error

Ping sends a WebSocket ping to check connection health.

type ConnectHandler

type ConnectHandler func(conn *Conn)

ConnectHandler is a function type called when a connection is established.

type DialOptions

type DialOptions = websocket.DialOptions

DialOptions is an alias for websocket.DialOptions.

type DisconnectHandler

type DisconnectHandler func(conn *Conn, err error)

DisconnectHandler is a function type called when a connection is closed.

type ErrorHandler

type ErrorHandler func(conn *Conn, err error)

ErrorHandler is a function type called when an error occurs.

type Handler

type Handler interface {
	Handle(ctx context.Context, conn *Conn, event msg.Event) []byte
}

Handler is an interface for handling events. The Handle method processes an event and returns a response.

type HandlerFunc

type HandlerFunc func(ctx context.Context, conn *Conn, event msg.Event) []byte

HandlerFunc is a function type that implements the Handler interface.

func (HandlerFunc) Handle

func (h HandlerFunc) Handle(ctx context.Context, conn *Conn, event msg.Event) []byte

Handle calls the underlying function.

type Rooms

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

Rooms manages groups of connections for broadcasting. It is safe for concurrent use.

func (*Rooms) AllConns

func (s *Rooms) AllConns() []*Conn

AllConns returns all connections managed by the server.

func (*Rooms) Clear

func (s *Rooms) Clear(rooms ...string)

Clear removes the specified rooms.

func (*Rooms) Get

func (s *Rooms) Get(connId string) (*Conn, bool)

Get retrieves a connection by its ID from the internal room. It returns the connection and a boolean indicating whether it exists.

func (*Rooms) Join

func (s *Rooms) Join(conn *Conn, rooms ...string)

Join adds a connection to the specified rooms. New rooms are created if they do not exist.

func (*Rooms) LeaveByConnId

func (s *Rooms) LeaveByConnId(id string, rooms ...string)

LeaveByConnId removes a connection from the specified rooms. Empty rooms are automatically deleted.

func (*Rooms) Len

func (s *Rooms) Len(room string) int

Len returns the number of connections in the specified room.

func (*Rooms) Rooms

func (s *Rooms) Rooms() []string

Rooms returns a slice of all room names, excluding the internal room.

func (*Rooms) ToBroadcast

func (s *Rooms) ToBroadcast(rooms ...string) []*Conn

ToBroadcast returns all connections in the specified rooms for broadcasting. Duplicate connections are included multiple times if they belong to multiple rooms.

type Server

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

Server represents a WebSocket server for event-based communication. It is safe for concurrent use.

func NewServer

func NewServer(opts ...ServerOption) *Server

NewServer creates a new Server instance with the provided options.

func (*Server) On

func (s *Server) On(event string, handler Handler) *Server

On registers an event handler for the specified event name. It returns the Server to allow method chaining.

func (*Server) OnConnect

func (s *Server) OnConnect(handler ConnectHandler) *Server

OnConnect registers a handler to be called when a client connects. It returns the Server to allow method chaining.

func (*Server) OnDisconnect

func (s *Server) OnDisconnect(handler DisconnectHandler) *Server

OnDisconnect registers a handler to be called when a client disconnects. It returns the Server to allow method chaining.

func (*Server) OnError

func (s *Server) OnError(handler ErrorHandler) *Server

OnError registers a handler to be called when an error occurs. It returns the Server to allow method chaining.

func (*Server) OnUnknownEvent

func (s *Server) OnUnknownEvent(handler Handler) *Server

OnUnknownEvent registers a handler to be called when an unknown event is received. It returns the Server to allow method chaining.

func (*Server) Rooms

func (s *Server) Rooms() *Rooms

Rooms returns the Rooms instance for managing connection groups.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP handles HTTP requests by upgrading them to WebSocket connections. It implements the http.Handler interface.

func (*Server) Shutdown

func (s *Server) Shutdown()

Shutdown closes all active connections on the server.

type ServerOption

type ServerOption func(*serverOptions)

ServerOption is a function that configures a serverOptions struct.

func WithServerAcceptOptions

func WithServerAcceptOptions(opts *AcceptOptions) ServerOption

WithServerAcceptOptions sets the WebSocket accept options for the server.

func WithServerCodec added in v4.1.0

func WithServerCodec(codec msg.Codec) ServerOption

WithServerCodec sets the codec for encoding and decoding events.

func WithServerReadLimit

func WithServerReadLimit(limit int64) ServerOption

WithServerReadLimit sets the maximum message size in bytes that the server can read.

Directories

Path Synopsis
Package bpool provides a buffer pool for reusing *bytes.Buffer instances.
Package bpool provides a buffer pool for reusing *bytes.Buffer instances.
Package msg provides message types and codecs for event-based communication.
Package msg provides message types and codecs for event-based communication.
Package store provides a thread-safe key-value store for arbitrary data.
Package store provides a thread-safe key-value store for arbitrary data.

Jump to

Keyboard shortcuts

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