...

Source file src/github.com/99designs/gqlgen/graphql/handler/transport/websocket_subprotocol.go

Documentation: github.com/99designs/gqlgen/graphql/handler/transport

     1  package transport
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  
     7  	"github.com/gorilla/websocket"
     8  )
     9  
    10  const (
    11  	initMessageType messageType = iota
    12  	connectionAckMessageType
    13  	keepAliveMessageType
    14  	connectionErrorMessageType
    15  	connectionCloseMessageType
    16  	startMessageType
    17  	stopMessageType
    18  	dataMessageType
    19  	completeMessageType
    20  	errorMessageType
    21  	pingMessageType
    22  	pongMessageType
    23  )
    24  
    25  var (
    26  	supportedSubprotocols = []string{
    27  		graphqlwsSubprotocol,
    28  		graphqltransportwsSubprotocol,
    29  	}
    30  
    31  	errWsConnClosed = errors.New("websocket connection closed")
    32  	errInvalidMsg   = errors.New("invalid message received")
    33  )
    34  
    35  type (
    36  	messageType int
    37  	message     struct {
    38  		payload json.RawMessage
    39  		id      string
    40  		t       messageType
    41  	}
    42  	messageExchanger interface {
    43  		NextMessage() (message, error)
    44  		Send(m *message) error
    45  	}
    46  )
    47  
    48  func (t messageType) String() string {
    49  	var text string
    50  	switch t {
    51  	default:
    52  		text = "unknown"
    53  	case initMessageType:
    54  		text = "init"
    55  	case connectionAckMessageType:
    56  		text = "connection ack"
    57  	case keepAliveMessageType:
    58  		text = "keep alive"
    59  	case connectionErrorMessageType:
    60  		text = "connection error"
    61  	case connectionCloseMessageType:
    62  		text = "connection close"
    63  	case startMessageType:
    64  		text = "start"
    65  	case stopMessageType:
    66  		text = "stop subscription"
    67  	case dataMessageType:
    68  		text = "data"
    69  	case completeMessageType:
    70  		text = "complete"
    71  	case errorMessageType:
    72  		text = "error"
    73  	case pingMessageType:
    74  		text = "ping"
    75  	case pongMessageType:
    76  		text = "pong"
    77  	}
    78  	return text
    79  }
    80  
    81  func contains(list []string, elem string) bool {
    82  	for _, e := range list {
    83  		if e == elem {
    84  			return true
    85  		}
    86  	}
    87  
    88  	return false
    89  }
    90  
    91  func (t *Websocket) injectGraphQLWSSubprotocols() {
    92  	// the list of subprotocols is specified by the consumer of the Websocket struct,
    93  	// in order to preserve backward compatibility, we inject the graphql specific subprotocols
    94  	// at runtime
    95  	if !t.didInjectSubprotocols {
    96  		defer func() {
    97  			t.didInjectSubprotocols = true
    98  		}()
    99  
   100  		for _, subprotocol := range supportedSubprotocols {
   101  			if !contains(t.Upgrader.Subprotocols, subprotocol) {
   102  				t.Upgrader.Subprotocols = append(t.Upgrader.Subprotocols, subprotocol)
   103  			}
   104  		}
   105  	}
   106  }
   107  
   108  func handleNextReaderError(err error) error {
   109  	// TODO: should we consider all closure scenarios here for the ws connection?
   110  	// for now we only list the error codes from the previous implementation
   111  	if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
   112  		return errWsConnClosed
   113  	}
   114  
   115  	return err
   116  }
   117  

View as plain text