forked from mikhailv/graphql-transport-ws
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebsocket_graphqlws.go
171 lines (148 loc) · 4.15 KB
/
websocket_graphqlws.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
package transport
import (
"encoding/json"
"fmt"
"github.com/gorilla/websocket"
)
// https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md
const (
graphqlwsSubprotocol = "graphql-ws"
graphqlwsConnectionInitMsg = graphqlwsMessageType("connection_init")
graphqlwsConnectionTerminateMsg = graphqlwsMessageType("connection_terminate")
graphqlwsStartMsg = graphqlwsMessageType("start")
graphqlwsStopMsg = graphqlwsMessageType("stop")
graphqlwsConnectionAckMsg = graphqlwsMessageType("connection_ack")
graphqlwsConnectionErrorMsg = graphqlwsMessageType("connection_error")
graphqlwsDataMsg = graphqlwsMessageType("data")
graphqlwsErrorMsg = graphqlwsMessageType("error")
graphqlwsCompleteMsg = graphqlwsMessageType("complete")
graphqlwsConnectionKeepAliveMsg = graphqlwsMessageType("ka")
)
var allGraphqlwsMessageTypes = []graphqlwsMessageType{
graphqlwsConnectionInitMsg,
graphqlwsConnectionTerminateMsg,
graphqlwsStartMsg,
graphqlwsStopMsg,
graphqlwsConnectionAckMsg,
graphqlwsConnectionErrorMsg,
graphqlwsDataMsg,
graphqlwsErrorMsg,
graphqlwsCompleteMsg,
graphqlwsConnectionKeepAliveMsg,
}
type (
graphqlwsMessageExchanger struct {
c *websocket.Conn
}
graphqlwsMessage struct {
Payload json.RawMessage `json:"payload,omitempty"`
ID string `json:"id,omitempty"`
Type graphqlwsMessageType `json:"type"`
noOp bool
}
graphqlwsMessageType string
)
func (me graphqlwsMessageExchanger) NextMessage() (message, error) {
_, r, err := me.c.NextReader()
if err != nil {
return message{}, handleNextReaderError(err)
}
var graphqlwsMessage graphqlwsMessage
if err := jsonDecodeReader(r, &graphqlwsMessage); err != nil {
return message{}, errInvalidMsg
}
return graphqlwsMessage.toMessage()
}
func (me graphqlwsMessageExchanger) Send(m *message) error {
msg := &graphqlwsMessage{}
if err := msg.fromMessage(m); err != nil {
return err
}
if msg.noOp {
return nil
}
return me.c.WriteJSON(msg)
}
func (t *graphqlwsMessageType) UnmarshalText(text []byte) (err error) {
var found bool
for _, candidate := range allGraphqlwsMessageTypes {
if string(candidate) == string(text) {
*t = candidate
found = true
break
}
}
if !found {
err = fmt.Errorf("invalid message type %s", string(text))
}
return err
}
func (t graphqlwsMessageType) MarshalText() ([]byte, error) {
return []byte(string(t)), nil
}
func (m graphqlwsMessage) toMessage() (message, error) {
var t messageType
var err error
switch m.Type {
default:
err = fmt.Errorf("invalid client->server message type %s", m.Type)
case graphqlwsConnectionInitMsg:
t = initMessageType
case graphqlwsConnectionTerminateMsg:
t = connectionCloseMessageType
case graphqlwsStartMsg:
t = startMessageType
case graphqlwsStopMsg:
t = stopMessageType
case graphqlwsConnectionAckMsg:
t = connectionAckMessageType
case graphqlwsConnectionErrorMsg:
t = connectionErrorMessageType
case graphqlwsDataMsg:
t = dataMessageType
case graphqlwsErrorMsg:
t = errorMessageType
case graphqlwsCompleteMsg:
t = completeMessageType
case graphqlwsConnectionKeepAliveMsg:
t = keepAliveMessageType
}
return message{
payload: m.Payload,
id: m.ID,
t: t,
}, err
}
func (m *graphqlwsMessage) fromMessage(msg *message) (err error) {
m.ID = msg.id
m.Payload = msg.payload
switch msg.t {
default:
err = fmt.Errorf("invalid server->client message type %s", msg.t)
case initMessageType:
m.Type = graphqlwsConnectionInitMsg
case connectionAckMessageType:
m.Type = graphqlwsConnectionAckMsg
case keepAliveMessageType:
m.Type = graphqlwsConnectionKeepAliveMsg
case connectionErrorMessageType:
m.Type = graphqlwsConnectionErrorMsg
case connectionCloseMessageType:
m.Type = graphqlwsConnectionTerminateMsg
case startMessageType:
m.Type = graphqlwsStartMsg
case stopMessageType:
m.Type = graphqlwsStopMsg
case dataMessageType:
m.Type = graphqlwsDataMsg
case completeMessageType:
m.Type = graphqlwsCompleteMsg
case errorMessageType:
m.Type = graphqlwsErrorMsg
case pingMessageType:
m.noOp = true
case pongMessageType:
m.noOp = true
}
return err
}