1
1
import { ApolloLink , execute } from 'apollo-link'
2
2
import { parseHeaders } from '../../components/Playground/util/parseHeaders'
3
- import { SubscriptionClient } from 'subscriptions-transport-ws'
4
3
import { HttpLink } from 'apollo-link-http'
5
- import { WebSocketLink } from 'apollo-link-ws'
6
4
import { isSubscription } from '../../components/Playground/util/hasSubscription'
7
5
import {
8
6
takeLatest ,
@@ -38,6 +36,10 @@ import { Session, ResponseRecord } from './reducers'
38
36
import { addHistoryItem } from '../history/actions'
39
37
import { safely } from '../../utils'
40
38
import { set } from 'immutable'
39
+ import { SubscriptionClient as SubscriptionClientSTWS } from 'subscriptions-transport-ws'
40
+ import { WebSocketLink as WebSocketLinkALW } from 'apollo-link-ws'
41
+ import { createClient as createSubscriptionClient , Client as SubscriptionClientGWS } from 'graphql-ws'
42
+ import { WebSocketLink as WebSocketLinkGW } from './WebSocketLink'
41
43
42
44
// tslint:disable
43
45
let subscriptionEndpoint
@@ -50,18 +52,22 @@ export interface LinkCreatorProps {
50
52
endpoint : string
51
53
headers ?: Headers
52
54
credentials ?: string
55
+ subscriptionTransport ?: string
53
56
}
54
57
55
58
export interface Headers {
56
59
[ key : string ] : string | number | null
57
60
}
58
61
62
+ const isWSEndpoint = ( endpoint : string ) : boolean => ! ! endpoint . match ( / w s s ? / ) ;
63
+
59
64
export const defaultLinkCreator = (
60
65
session : LinkCreatorProps ,
61
66
subscriptionEndpoint ?: string ,
62
- ) : { link : ApolloLink ; subscriptionClient ?: SubscriptionClient } => {
67
+ ) : { link : ApolloLink ; subscriptionClient ?: SubscriptionClientGWS | SubscriptionClientSTWS } => {
68
+
63
69
let connectionParams = { }
64
- const { headers, credentials } = session
70
+ const { headers, credentials, subscriptionTransport } = session
65
71
66
72
if ( headers ) {
67
73
connectionParams = { ...headers }
@@ -73,21 +79,53 @@ export const defaultLinkCreator = (
73
79
credentials,
74
80
} )
75
81
76
- if ( ! subscriptionEndpoint ) {
77
- return { link : httpLink }
82
+ // ws endpoint => graphql-ws default link
83
+ if ( isWSEndpoint ( session . endpoint ) ) {
84
+ const subscriptionClient = createSubscriptionClient ( {
85
+ retryAttempts : 1000 ,
86
+ retryWait : ( ) => new Promise ( resolve => setTimeout ( resolve , 20000 ) ) ,
87
+ lazy : true ,
88
+ connectionParams,
89
+ url : session . endpoint ,
90
+ } )
91
+
92
+ return {
93
+ link : new WebSocketLinkGW ( subscriptionClient ) ,
94
+ subscriptionClient,
95
+ }
96
+ }
97
+
98
+ // http endpoint & graphql-ws => default link = http + graphql-ws subscriptions
99
+ if ( subscriptionTransport === 'graphql-ws' ) {
100
+ const subscriptionClient = createSubscriptionClient ( {
101
+ retryWait : ( ) => new Promise ( resolve => setTimeout ( resolve , 20000 ) ) ,
102
+ lazy : true ,
103
+ connectionParams,
104
+ url : subscriptionEndpoint || session . endpoint . replace ( 'http' , 'ws' ) ,
105
+ } )
106
+
107
+ return {
108
+ subscriptionClient,
109
+ link : new WebSocketLinkGW ( subscriptionClient )
110
+ }
78
111
}
79
112
80
- const subscriptionClient = new SubscriptionClient ( subscriptionEndpoint , {
81
- timeout : 20000 ,
82
- lazy : true ,
83
- connectionParams,
84
- } )
113
+ // http endpoint => default link = http + subscriptions-transport-ws subscriptions
114
+ const subscriptionClient = new SubscriptionClientSTWS (
115
+ subscriptionEndpoint || session . endpoint . replace ( 'http' , 'ws' ) ,
116
+ {
117
+ timeout : 20000 ,
118
+ lazy : true ,
119
+ connectionParams,
120
+ }
121
+ )
122
+
123
+ const webSocketLink = new WebSocketLinkALW ( subscriptionClient ) ;
85
124
86
- const webSocketLink = new WebSocketLink ( subscriptionClient )
87
125
return {
88
126
link : ApolloLink . split (
89
127
operation => isSubscription ( operation ) ,
90
- webSocketLink as any ,
128
+ webSocketLink ,
91
129
httpLink ,
92
130
) ,
93
131
subscriptionClient,
@@ -107,6 +145,12 @@ export function setLinkCreator(newLinkCreator) {
107
145
108
146
const subscriptions = { }
109
147
148
+ const isSubscriptionClientSTWS = (
149
+ client : SubscriptionClientGWS | SubscriptionClientSTWS
150
+ ) : client is SubscriptionClientSTWS => {
151
+ return ! ! ( client as SubscriptionClientSTWS ) . onDisconnected
152
+ }
153
+
110
154
function * runQuerySaga ( action ) {
111
155
// run the query
112
156
const { operationName } = action . payload
@@ -127,12 +171,14 @@ function* runQuerySaga(action) {
127
171
if ( session . tracingSupported && session . responseTracingOpen ) {
128
172
headers = set ( headers , 'X-Apollo-Tracing' , '1' )
129
173
}
174
+
130
175
const lol = {
131
176
endpoint : session . endpoint ,
132
177
headers : {
133
178
...settings [ 'request.globalHeaders' ] ,
134
179
...headers ,
135
180
} ,
181
+ subscriptionTransport : settings [ 'subscriptions.protocol' ] ,
136
182
credentials : settings [ 'request.credentials' ] ,
137
183
}
138
184
@@ -143,15 +189,20 @@ function* runQuerySaga(action) {
143
189
const channel = eventChannel ( emitter => {
144
190
let closed = false
145
191
if ( subscriptionClient && operationIsSubscription ) {
146
- subscriptionClient . onDisconnected ( ( ) => {
192
+ const onDisconnect = ( ) => {
147
193
closed = true
148
194
emitter ( {
149
195
error : new Error (
150
196
`Could not connect to websocket endpoint ${ subscriptionEndpoint } . Please check if the endpoint url is correct.` ,
151
197
) ,
152
198
} )
153
199
emitter ( END )
154
- } )
200
+ }
201
+ if ( isSubscriptionClientSTWS ( subscriptionClient ) ) {
202
+ subscriptionClient . onDisconnected ( onDisconnect )
203
+ } else {
204
+ subscriptionClient . on ( 'closed' , onDisconnect )
205
+ }
155
206
}
156
207
const subscription = execute ( link , operation ) . subscribe ( {
157
208
next : function ( value ) {
0 commit comments