@@ -44,7 +44,7 @@ class MiddlewareApp extends React.Component<Props, State> {
44
44
subscriptionEndpoint :
45
45
props . subscriptionEndpoint ||
46
46
getParameterByName ( 'subscriptionEndpoint' ) ||
47
- getSubscriptionsUrl ( endpoint ) ,
47
+ '' ,
48
48
}
49
49
}
50
50
@@ -56,14 +56,18 @@ class MiddlewareApp extends React.Component<Props, State> {
56
56
}
57
57
}
58
58
59
+ componentDidMount ( ) {
60
+ if ( this . state . subscriptionEndpoint === '' ) {
61
+ this . updateSubscriptionsUrl ( )
62
+ }
63
+ }
64
+
59
65
render ( ) {
60
- const title = this . props . setTitle
61
- ? < Helmet >
62
- < title >
63
- { this . getTitle ( ) }
64
- </ title >
65
- </ Helmet >
66
- : null
66
+ const title = this . props . setTitle ? (
67
+ < Helmet >
68
+ < title > { this . getTitle ( ) } </ title >
69
+ </ Helmet >
70
+ ) : null
67
71
68
72
return (
69
73
< div >
@@ -134,7 +138,7 @@ class MiddlewareApp extends React.Component<Props, State> {
134
138
this . state . platformToken ||
135
139
this . state . endpoint . includes ( 'api.graph.cool' )
136
140
) {
137
- const projectId = getProjectId ( this . state . endpoint )
141
+ const projectId = this . getProjectId ( this . state . endpoint )
138
142
const cluster = this . state . endpoint . includes ( 'api.graph.cool' )
139
143
? 'shared'
140
144
: 'local'
@@ -143,22 +147,76 @@ class MiddlewareApp extends React.Component<Props, State> {
143
147
144
148
return `Playground - ${ this . state . endpoint } `
145
149
}
146
- }
147
150
148
- export default MiddlewareApp
151
+ private async updateSubscriptionsUrl ( ) {
152
+ const candidates = this . getSubscriptionsUrlCandidated ( this . state . endpoint )
153
+ const validCandidate = await find ( candidates , candidate =>
154
+ this . wsEndpointValid ( candidate ) ,
155
+ )
156
+ if ( validCandidate ) {
157
+ this . setState ( { subscriptionEndpoint : validCandidate } )
158
+ }
159
+ }
160
+
161
+ private getSubscriptionsUrlCandidated ( endpoint ) : string [ ] {
162
+ const candidates : string [ ] = [ ]
163
+ candidates . push ( endpoint . replace ( 'https' , 'wss' ) . replace ( 'http' , 'ws' ) )
164
+ if ( endpoint . includes ( 'graph.cool' ) ) {
165
+ candidates . push (
166
+ `wss://subscriptions.graph.cool/v1/${ this . getProjectId ( endpoint ) } ` ,
167
+ )
168
+ }
169
+ if ( endpoint . includes ( '/simple/v1/' ) ) {
170
+ // it's a graphcool local endpoint
171
+ const host = endpoint . match ( / h t t p s ? : \/ \/ ( .* ?) \/ / )
172
+ candidates . push (
173
+ `ws://${ host ! [ 1 ] } /subscriptions/v1/${ this . getProjectId ( endpoint ) } ` ,
174
+ )
175
+ }
176
+ return candidates
177
+ }
149
178
150
- function getSubscriptionsUrl ( endpoint ) : string | undefined {
151
- if ( endpoint . includes ( 'graph.cool' ) ) {
152
- return `wss://subscriptions.graph.cool/v1/${ getProjectId ( endpoint ) } `
179
+ private wsEndpointValid ( url ) : Promise < boolean > {
180
+ return new Promise ( resolve => {
181
+ const socket = new WebSocket (
182
+ 'wss://subscriptions.graph.cool/v1/cirs1ufsg02b101619ru0bx5r' ,
183
+ 'graphql-ws' ,
184
+ )
185
+ socket . addEventListener ( 'open' , event => {
186
+ socket . send ( JSON . stringify ( { type : 'connection_init' } ) )
187
+ } )
188
+ socket . addEventListener ( 'message' , event => {
189
+ const data = JSON . parse ( event . data )
190
+ if ( data . type === 'connection_ack' ) {
191
+ resolve ( true )
192
+ }
193
+ } )
194
+ socket . addEventListener ( 'error' , event => {
195
+ resolve ( false )
196
+ } )
197
+ setTimeout ( ( ) => {
198
+ resolve ( false )
199
+ } , 1000 )
200
+ } )
153
201
}
154
- if ( endpoint . includes ( '/simple/v1/' ) ) {
155
- // it's a graphcool local endpoint
156
- const host = endpoint . match ( / h t t p s ? : \/ \/ ( .* ?) \/ / )
157
- return `ws://${ host ! [ 1 ] } /subscriptions/v1/${ getProjectId ( endpoint ) } `
202
+
203
+ private getProjectId ( endpoint ) {
204
+ return endpoint . split ( '/' ) . slice ( - 1 ) [ 0 ]
158
205
}
159
- return undefined
160
206
}
161
207
162
- function getProjectId ( endpoint ) {
163
- return endpoint . split ( '/' ) . slice ( - 1 ) [ 0 ]
208
+ async function find (
209
+ iterable : any [ ] ,
210
+ predicate : ( item ?: any , index ?: number ) => Promise < boolean > ,
211
+ ) : Promise < any | null > {
212
+ for ( let i = 0 ; i < iterable . length ; i ++ ) {
213
+ const element = iterable [ i ]
214
+ const result = await predicate ( element , i )
215
+ if ( result ) {
216
+ return element
217
+ }
218
+ }
219
+ return null
164
220
}
221
+
222
+ export default MiddlewareApp
0 commit comments