ws

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Mar 10, 2024 License: MIT Imports: 6 Imported by: 0

README

Websocket

JSON-RPC client/server over Websocket protocol.

This package contains Webscoket server based on golang.org/x/net/websocket package. And contains Websocket full client that you can use to send notification from server.

See Server+Notification example in _examples/websocket directory.

Documentation

Overview

Package ws contains JSON-RPC server over Websocket protocol.

Example

Example about websocket server and notifications from server.

package main

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

	"nhooyr.io/websocket"

	"gitlab.com/pjrpc/pjrpc/v2/client"
	"gitlab.com/pjrpc/pjrpc/ws"
)

func main() {
	ctx := context.Background()
	address := "localhost:8080"
	endpoint := fmt.Sprintf("ws://%s/ws", address)

	conf := &ws.Config{
		Accept: func(w http.ResponseWriter, r *http.Request) (accepted bool) {
			return true // You can validate http request here.
		},
	}

	wsServer := ws.NewServerWebsocket(conf)

	clients := make(chan *client.AsyncClient)

	wsServer.OnNewConnection = func(_ context.Context, conn net.Conn) bool {
		fmt.Println("Got a new connection")

		cl := client.NewAsyncClient(conn)

		// Don't call cl.Listen() when your server already listens this connection.

		clients <- cl

		// You can return false if you don't want to accept this connection.
		return true
	}

	wsServer.OnCloseConnection = func(_ context.Context, conn net.Conn) {
		// Just remove client from your notification logic.
		// You don't need close notification client here (cl.Close).
	}

	mux := http.NewServeMux()
	mux.Handle("/ws", wsServer)

	go func() {
		err := http.ListenAndServe(address, mux)
		if err != nil {
			fmt.Println("http.ListenAndServe:", err)
		}
	}()

	clientGotMessage := make(chan string)

	go func() {
		c, _, err := websocket.Dial(ctx, endpoint, nil)
		if err != nil {
			fmt.Println("websocket.Dial:", err)
			return
		}

		mt, message, err := c.Read(ctx)
		if err != nil {
			fmt.Println("c.Read:", err)
			return
		}

		if mt != websocket.MessageText {
			fmt.Println("wrong message type:", mt)
			return
		}

		clientGotMessage <- string(message)
	}()

	// Waiting for a new client.
	cl := <-clients

	err := cl.Invoke(ctx, "", "notify", "string as parameter", nil)
	if err != nil {
		fmt.Println("client.Invoke:", err)
		return
	}

	// Waiting for a message that got the client.
	fmt.Println(<-clientGotMessage)

}
Output:

Got a new connection
{"jsonrpc":"2.0","method":"notify","params":"string as parameter"}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewClient added in v0.1.0

func NewClient(ctx context.Context, endpoint string, options *websocket.DialOptions) (*client.AsyncClient, error)

NewClient returns new async client based on websocket connection.

Example
// Create client and dial to the server.
wsClient, err := ws.NewClient(context.Background(), "ws://websocket-echo.com", nil)
if err != nil {
	fmt.Println("client.New:", err)
	return
}

// Optional: set unexpected handlers.
wsClient.OnParseMessageError = func(err error) error {
	fmt.Println("failed to parse message:", err)
	return nil // Return nil if you don't want to stop listener.
}

wsClient.OnUnknownResponse = func(resp *pjrpc.Response) error {
	fmt.Println("unknown response:", resp.GetID())
	return nil // Return nil if you don't want to stop listener.
}

// Run response listener.
go func() {
	err = wsClient.Listen()
	if err != nil {
		fmt.Println("wsClient.Listen:", err)
	}

	wsClient.Close() // Don't worry about error here.
}()

// Invoke the method.
var res any

ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()

err = wsClient.Invoke(ctx, "123", "test", "params", &res)
if err != nil {
	fmt.Println("wsClient.Invoke:", err)
	return
}

fmt.Println(res) // You will got <nil> as result because it's echo server.
Output:

Types

type Config

type Config struct {
	// Optional config of the Websocket accepter.
	AcceptOptions *websocket.AcceptOptions

	// Accept is the first HTTP handler.
	// You can refuse connection here.
	Accept func(w http.ResponseWriter, r *http.Request) (accepted bool)

	// OnErrorWebsocketAccept optional handler to debug failed websocket connect accept.
	OnErrorWebsocketAccept func(r *http.Request, err error)
}

Config is optional parameter to create websocket server. AcceptOptions is required field, feel free to set nil on others.

type ServerWebsocket

type ServerWebsocket struct {
	*pjrpc.ServerListener
	// contains filtered or unexported fields
}

ServerWebsocket JSON-RPC server over WebSocket protocol.

func NewServerWebsocket

func NewServerWebsocket(config *Config) *ServerWebsocket

NewServerWebsocket returns new Websocket Server based on your config.

func (*ServerWebsocket) ServeHTTP

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

ServeHTTP implements the http.Handler interface for a WebSocket server.

Jump to

Keyboard shortcuts

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