phoenix

package module
v0.0.0-...-c9718f5 Latest Latest
Warning

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

Go to latest
Published: Aug 30, 2024 License: Apache-2.0 Imports: 20 Imported by: 0

README

Phoenix Channels WebSocket Transport for Golang

This package provides a WebSocket transport with Phoenix Channels subprotocol support for the 99designs/gqlgen package. This is very much a work in progress and does not claim to be a complete implementation of the Phoenix Channels protocol, but merely enough to support the needs of the project for which it was created.

Why?

The project for which this was created has a frontend that was built using Phoenix LiveView, which uses Phoenix Channels for its WebSocket transport. The backend for the project is being reimplemented in Go with the goal of being a drop-in replacement for the existing Elixir backend. This package was created to allow the Go backend to support the existing Phoenix Channels-based WebSocket transport without requiring any changes to the frontend.

You're Doing What Now?

The Phoenix Channels protocol is not a standard WebSocket subprotocol, so this package is not a standard WebSocket transport for gqlgen. It is a bespoke implementation of the Phoenix Channels protocol that is intended to be used with the gqlgen package. It should support the basic needs of the project.

You're crazy

I know. But it's working so far, so I'm going to keep going with it. Maybe one day we'll revamp the UI to use a standard WebSocket subprotocol and I can throw this away. But for now, it's what we've got.

Ok, how do I use it?

If you're using gqlgen, you can add this package to your project and use it as a transport for your subscriptions. Here's an example of how you might do that:

// Add the WSS transport to the server.
// In this excerpt, gqlSrv is an instance of a gqlgen server
// and opts is a struct that contains configuration options.
if opts.WSSUsePhoenix {
    // Use our custom Phoenix transport
    gqlSrv.AddTransport(&phoenix.Websocket{
        Upgrader: websocket.Upgrader{
            EnableCompression: opts.WSSEnableCompression,
        },
    })
} else {
    // Fallback to the default ws transport that has graphql-ws support
    gqlSrv.AddTransport(&transport.Websocket{
        KeepAlivePingInterval: opts.WSSKeepAlivePingInterval,
        Upgrader: websocket.Upgrader{
            EnableCompression: opts.WSSEnableCompression,
        },
    })
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddSubscriptionError

func AddSubscriptionError(ctx context.Context, err *gqlerror.Error)

AddSubscriptionError is used to let websocket return an error message after subscription resolver returns a channel. for example:

func (r *subscriptionResolver) Method(ctx context.Context) (<-chan *model.Message, error) {
	ch := make(chan *model.Message)
	go func() {
     defer func() {
			close(ch)
     }
		// some kind of block processing (e.g.: gRPC client streaming)
		stream, err := gRPCClientStreamRequest(ctx)
		if err != nil {
			   transport.AddSubscriptionError(ctx, err)
            return // must return and close channel so websocket can send error back
     }
		for {
			m, err := stream.Recv()
			if err == io.EOF {
				return
			}
			if err != nil {
			   transport.AddSubscriptionError(ctx, err)
            return // must return and close channel so websocket can send error back
			}
			ch <- m
		}
	}()

	return ch, nil
}

see https://github.com/99designs/gqlgen/pull/2506 for more details

func AppendCloseReason

func AppendCloseReason(ctx context.Context, reason string) context.Context

Types

type InitPayload

type InitPayload map[string]interface{}

InitPayload is a structure that is parsed from the websocket init message payload. TO use request headers for non-websocket, instead wrap the graphql handler in a middleware.

type Message

type Message struct {
	Ref     *string         `json:"ref"`
	JoinRef *string         `json:"join_ref"`
	Topic   *string         `json:"topic"`
	Event   string          `json:"event"`
	Payload json.RawMessage `json:"payload"`
}

func (Message) MarshalJSON

func (m Message) MarshalJSON() ([]byte, error)

MarshalJSON overrides the default JSON marshalling

func (Message) Type

func (m Message) Type() messageType

type MessageExchanger

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

func (MessageExchanger) NextMessage

func (me MessageExchanger) NextMessage() (Message, error)

func (MessageExchanger) Send

func (me MessageExchanger) Send(m *Message) error

type Websocket

type Websocket struct {
	Upgrader    websocket.Upgrader
	InitFunc    WebsocketInitFunc
	InitTimeout time.Duration
	ErrorFunc   WebsocketErrorFunc
	CloseFunc   WebsocketCloseFunc
}

Websocket is a custom websocket transport that extends the default transport with Phoenix-specific functionality. Phoenix is a web framework for Elixir that uses websockets for real-time communication; the goal of this transport is to provide a way for the GraphQL server to communicate with Phoenix clients.

func (Websocket) Do

func (Websocket) Supports

func (t Websocket) Supports(r *http.Request) bool

type WebsocketCloseFunc

type WebsocketCloseFunc func(ctx context.Context, closeCode int)

Callback called when websocket is closed.

type WebsocketErrorFunc

type WebsocketErrorFunc func(ctx context.Context, err error)

type WebsocketInitFunc

type WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, *InitPayload, error)

Jump to

Keyboard shortcuts

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