websocket

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Sep 16, 2021 License: MIT Imports: 17 Imported by: 0

README

Custom WebSocket implementation library

ci Go Reference go-version code-size total-lines

Alt text

Motivation

The main purpose of this developed package is education. I hold the rule which means if you want to figure out or understand something, you should to try to implement it. In the process of implementation I kept to this article and RFC 6455.

Description

This package is a custom WebSocket implementation library. It includes set of types, functions and methods using which you can easily create both client-side and server-side applications which can communicate on the WebSocket protocol.

Features that have already been done:
  • ✅ Framing
  • ✅ Pings/Pongs
  • ✅ Reserved Bits
  • ✅ Opcodes
  • ✅ Fragmentation
  • ✅ UTF-8 Handling
  • ✅ Limits/Performance
  • ✅ Opening and Closing Handshake
What's not done:
  • ❌ Compression

Testing

For testing package I used Autobahn library. If you want to look at the Autobahn's report you should clone this repository and run test suites (make test) being in the folder with the project.

Installation

$ go get github.com/Mort4lis/websocket

How to use

Simple server
package main

import (
	"log"
	"net/http"

	"github.com/Mort4lis/websocket"
)

func handler(w http.ResponseWriter, req *http.Request) {
	conn, err := websocket.Upgrade(w, req)
	if err != nil {
		return
	}

	defer func() {
		_ = conn.Close()
	}()

	for {
		typ, payload, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}

		if err = conn.WriteMessage(typ, payload); err != nil {
			log.Println(err)
			return
		}
	}
}
Simple client
package main

import (
	"log"
	"time"

	"github.com/Mort4lis/websocket"
)

func main() {
	dialer := &websocket.Dialer{
		HandshakeTimeout: 10 * time.Second,
	}

	conn, err := dialer.Dial("ws://127.0.0.1:8080")
	if err != nil {
		log.Fatal(err)
	}
	defer func() {
		_ = conn.Close()
	}()

	typ, payload, err := conn.ReadMessage()
	if err != nil {
		log.Fatal(err)
	}
	
	if err = conn.WriteMessage(typ, payload); err != nil {
		log.Fatal(err)
	}
}

For more detailed information please visit documentation.

Documentation

Overview

Package websocket implements the WebSocket protocol defined in RFC 6455.

Usage

The Conn type represents the WebSocket connection. if you are developing a server application you should use Upgrade function in your http handler to switching protocol to WebSocket.

func handler(w http.ResponseWriter, req *http.Request) {
    conn, err := websocket.Upgrade(w, req)
    if err != nil {
        log.Println(err)
        return
    }
    ...
}

Otherwise, if you are interesting to use websocket package as a client you should invoke Dialer.Dial at first (or Dialer.DialContext). For example:

func main() {
   dialer := &websocket.Dialer{
       HandshakeTimeout: 10 * time.Second,
   }
   conn, err := dialer.Dial("ws://localhost:8080")
   if err != nil {
       log.Fatal(err)
   }
   ...
}

Having Conn instance you can send and receive message due WebSocket protocol, calling Conn.WriteMessage and Conn.ReadMessage.

typ, payload, err := conn.ReadMessage()
if err != nil {
    log.Println(err)
    return
}
if err = conn.WriteMessage(typ, payload); err != nil {
    log.Println(err)
    return
}

Also you can use Conn.NextWriter and Conn.NextReader for fragmented sending and receiving.

Index

Constants

View Source
const (
	CloseNormalClosure           = 1000
	CloseGoingAway               = 1001
	CloseProtocolError           = 1002
	CloseUnsupportedData         = 1003
	CloseNoStatusReceived        = 1005
	CloseAbnormalClosure         = 1006
	CloseInvalidFramePayloadData = 1007
	ClosePolicyViolation         = 1008
	CloseMessageTooBig           = 1009
	CloseMandatoryExtension      = 1010
	CloseInternalServerErr       = 1011
	CloseServiceRestart          = 1012
	CloseTryAgainLater           = 1013
	CloseTLSHandshake            = 1015
)

Close codes defined in RFC 6455.

View Source
const (
	ContinuationOpcode = 0x00
	TextOpcode         = 0x01
	BinaryOpcode       = 0x02
	CloseOpcode        = 0x08
	PingOpcode         = 0x09
	PongOpcode         = 0xA
)

Type of frames which defines in RFC 6455.

Variables

This section is empty.

Functions

This section is empty.

Types

type CloseError

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

CloseError is a type which represents closure WebSocket error.

func (*CloseError) Error

func (e *CloseError) Error() string

type Conn

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

Conn is a type which represents the WebSocket connection.

func Upgrade

func Upgrade(w http.ResponseWriter, req *http.Request) (*Conn, error)

Upgrade upgrades the HTTP connection protocol to WebSocket protocol.

func (*Conn) Close

func (c *Conn) Close() error

Close sends control normal close frame if wasn't any errors. After that the tcp connection will be closed. Otherwise, it sends close frame with status code depending on happened error.

func (*Conn) NextReader

func (c *Conn) NextReader() (frameType byte, r io.Reader, err error)

NextReader returns the message type of the first fragmented frame (either TextOpcode or BinaryOpcode) and reader, using which you can receive other frame bytes.

It discards the previous reader if it's not empty. There can be at most one open reader on a connection.

func (*Conn) NextWriter

func (c *Conn) NextWriter(messageType byte) (io.WriteCloser, error)

NextWriter returns a writer using which you can send message partially. The writer's Close method flushes the complete message to the network.

It discards the previous writer if it's not empty. There can be at most one open writer on a connection.

func (*Conn) ReadMessage

func (c *Conn) ReadMessage() (messageType byte, payload []byte, err error)

ReadMessage is a helper method for getting all fragmented frames in one message. It uses NextReader under the hood.

func (*Conn) WriteMessage

func (c *Conn) WriteMessage(messageType byte, payload []byte) error

WriteMessage is a helper method to send message entire. It uses a NextWriter under the hood.

type Dialer

type Dialer struct {
	HandshakeTimeout time.Duration
	TLSConfig        *tls.Config
	// contains filtered or unexported fields
}

Dialer is a type which represents the client settings to establish a WebSocket connection.

func (*Dialer) Dial

func (d *Dialer) Dial(urlStr string) (*Conn, error)

Dial creates a new client WebSocket connection using DialContext with a background context.

func (*Dialer) DialContext

func (d *Dialer) DialContext(ctx context.Context, urlStr string) (*Conn, error)

DialContext creates a new client WebSocket connection.

At first, it opens a new tcp connection over which it sends http handshake request for switching protocol to WebSocket. If handshake fails, DialContext returns HandshakeError with detailed reason about error.

type HandshakeError

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

HandshakeError is a type which represents an error occurs in process handshake to establish WebSocket connection.

func (HandshakeError) Error

func (e HandshakeError) Error() string

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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