github.com/99designs/gqlgen@v0.17.45/graphql/handler/transport/websocket_subprotocol.go (about) 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 }