~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
60 lines · 1.4 KB Raw History
//go:build !js

package wsconn

import (
	"context"
	"fmt"
	"time"

	"github.com/gorilla/websocket"
)

type Conn struct {
	conn *websocket.Conn
}

func DialConfig(ctx context.Context, target string, cfg Config) (*Conn, error) {
	dialer := &websocket.Dialer{
		HandshakeTimeout: cfg.handshakeTimeout(),
		TLSClientConfig:  cfg.tlsConfig(),
	}
	if cfg.Dial != nil {
		dialer.NetDialContext = cfg.Dial
	}
	conn, response, err := dialer.DialContext(ctx, target, nil)
	if err != nil {
		if response != nil {
			return nil, &HandshakeError{StatusCode: response.StatusCode}
		}
		return nil, fmt.Errorf("wsconn: websocket dial: %w", err)
	}
	conn.SetReadLimit(MaxFrameBytes)
	conn.SetPingHandler(func(data string) error {
		_ = conn.SetReadDeadline(time.Now().Add(ReadTimeout))
		return conn.WriteControl(websocket.PongMessage, []byte(data), time.Now().Add(PongWriteTimeout))
	})
	_ = conn.SetReadDeadline(time.Now().Add(ReadTimeout))
	return &Conn{conn: conn}, nil
}

func (c *Conn) Read(ctx context.Context) ([]byte, error) {
	if err := ctx.Err(); err != nil {
		return nil, err
	}
	_ = c.conn.SetReadDeadline(time.Now().Add(ReadTimeout))
	stop := context.AfterFunc(ctx, func() { _ = c.conn.SetReadDeadline(time.Now()) })
	defer stop()
	_, data, err := c.conn.ReadMessage()
	if err != nil {
		if ctxErr := ctx.Err(); ctxErr != nil {
			return nil, ctxErr
		}
		return nil, err
	}
	return data, nil
}

func (c *Conn) Close() error {
	return c.conn.Close()
}