PluginProbe
WebTotem Security / 2.2.2
WebTotem Security v2.2.2
3.0.1 3.0.0 trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 2.0 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.1 2.2.2 2.2.3 2.2.4 All 109 releases
wt-security / htdocs / js / subscriber.js

subscriber.js in WebTotem Security 2.2.2, at htdocs/js/subscriber.js

144 lines 4.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1
2
3 const GQL = {
4 CONNECTION_INIT: 'connection_init',
5 CONNECTION_ACK: 'connection_ack',
6 CONNECTION_ERROR: 'connection_error',
7 CONNECTION_KEEP_ALIVE: 'ka',
8 START: 'start',
9 STOP: 'stop',
10 CONNECTION_TERMINATE: 'connection_terminate',
11 DATA: 'data',
12 ERROR: 'error',
13 COMPLETE: 'complete'
14 }
15
16 class Subscriber {
17 constructor (url, options, callback, protocols = 'graphql-ws') {
18 this.callback = callback
19
20 this.nextId = 1
21 this.subscriptions = new Map()
22 this.webSocket = new WebSocket(url, protocols)
23
24 this.webSocket.onopen = event => {
25 // Initiate the connection
26 this.webSocket.send(JSON.stringify({
27 type: GQL.CONNECTION_INIT,
28 payload: options
29 }))
30
31 setInterval(function () {
32 this.webSocket.send(JSON.stringify({
33 type: GQL.CONNECTION_KEEP_ALIVE
34 }))
35 }.bind(this), 5000);
36 }
37
38
39 this.webSocket.onclose = event => {
40 // The code 1000 (Normal Closure) is special, and results in no error or payload.
41 const error = event.code === 1000 ? null : new Error(event)
42 // Notify the subscriber.
43 this.callback(error)
44 // Notify the subscriptions.
45 const callbacks = Array.from(this.subscriptions.values())
46 this.subscriptions.clear()
47 for (const callback of callbacks) {
48 callback(error, null)
49 }
50 }
51
52 this.webSocket.onmessage = this.onMessage.bind(this)
53 }
54
55 subscribe (query, variables, operationName, callback) {
56 const id = (this.nextId++).toString()
57 this.subscriptions.set(id, callback)
58
59 this.webSocket.send(JSON.stringify({
60 type: GQL.START,
61 id,
62 payload: { query, variables, operationName }
63 }))
64
65 // Return the unsubscriber.
66 return () => {
67 this.subscriptions.delete(id)
68
69 this.webSocket.send(JSON.stringify({
70 type: GQL.STOP,
71 id
72 }))
73 }
74 }
75
76 shutdown () {
77 this.webSocket.send(JSON.stringify({
78 type: GQL.CONNECTION_TERMINATE
79 }))
80 this.webSocket.close()
81 }
82
83 onMessage (event) {
84 const data = JSON.parse(event.data)
85
86 switch (data.type) {
87 case GQL.CONNECTION_ACK: {
88 // This is the successful response to GQL.CONNECTION_INIT
89 if (this.callback) {
90 this.callback(null, this.subscribe.bind(this))
91 }
92 break
93 }
94 case GQL.CONNECTION_ERROR: {
95 // This may occur:
96 // 1. In response to GQL.CONNECTION_INIT
97 // 2. In case of parsing errors in the client which will not disconnect.
98 if (this.callback) {
99 this.callback(new Error(data.payload), this)
100 }
101 break
102 }
103 case GQL.CONNECTION_KEEP_ALIVE: {
104 // This may occur:
105 // 1. After GQL.CONNECTION_ACK,
106 // 2. Periodically to keep the connection alive.
107 break
108 }
109 case GQL.DATA: {
110 // This message is sent after GQL.START to transfer the result of the GraphQL subscription.
111 const callback = this.subscriptions.get(data.id)
112 if (callback) {
113 const error = data.payload.errors ? new Error(data.payload.errors) : null
114 callback(error, data.payload.data)
115 }
116 break
117 }
118 case GQL.ERROR: {
119 // This method is sent when a subscription fails. This is usually dues to validation errors
120 // as resolver errors are returned in GQL.DATA messages.
121 const callback = this.subscriptions.get(data.id)
122 if (callback) {
123 callback(new Error(data.payload), null)
124 }
125 break
126 }
127 case GQL.COMPLETE: {
128 // This is sent when the operation is done and no more dta will be sent.
129 const callback = this.subscriptions.get(data.id)
130 if (callback) {
131 this.subscriptions.delete(data.id)
132 // Return a null error and payload to indicate the subscription is closed.
133 callback(null, null)
134 }
135 break
136 }
137 }
138 }
139 }
140
141 function graphQLSubscriber (url, options, callback, protocols = 'graphql-ws') {
142 const subscriber = new Subscriber(url, options, callback, protocols)
143 return subscriber.shutdown.bind(subscriber)
144 }