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