Skip to content

Commit 642e2d1

Browse files
committed
Added smart subscription url detection
1 parent 86759ba commit 642e2d1

File tree

1 file changed

+79
-21
lines changed

1 file changed

+79
-21
lines changed

packages/graphql-playground/src/components/MiddlewareApp.tsx

Lines changed: 79 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class MiddlewareApp extends React.Component<Props, State> {
4444
subscriptionEndpoint:
4545
props.subscriptionEndpoint ||
4646
getParameterByName('subscriptionEndpoint') ||
47-
getSubscriptionsUrl(endpoint),
47+
'',
4848
}
4949
}
5050

@@ -56,14 +56,18 @@ class MiddlewareApp extends React.Component<Props, State> {
5656
}
5757
}
5858

59+
componentDidMount() {
60+
if (this.state.subscriptionEndpoint === '') {
61+
this.updateSubscriptionsUrl()
62+
}
63+
}
64+
5965
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
6771

6872
return (
6973
<div>
@@ -134,7 +138,7 @@ class MiddlewareApp extends React.Component<Props, State> {
134138
this.state.platformToken ||
135139
this.state.endpoint.includes('api.graph.cool')
136140
) {
137-
const projectId = getProjectId(this.state.endpoint)
141+
const projectId = this.getProjectId(this.state.endpoint)
138142
const cluster = this.state.endpoint.includes('api.graph.cool')
139143
? 'shared'
140144
: 'local'
@@ -143,22 +147,76 @@ class MiddlewareApp extends React.Component<Props, State> {
143147

144148
return `Playground - ${this.state.endpoint}`
145149
}
146-
}
147150

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(/https?:\/\/(.*?)\//)
172+
candidates.push(
173+
`ws://${host![1]}/subscriptions/v1/${this.getProjectId(endpoint)}`,
174+
)
175+
}
176+
return candidates
177+
}
149178

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+
})
153201
}
154-
if (endpoint.includes('/simple/v1/')) {
155-
// it's a graphcool local endpoint
156-
const host = endpoint.match(/https?:\/\/(.*?)\//)
157-
return `ws://${host![1]}/subscriptions/v1/${getProjectId(endpoint)}`
202+
203+
private getProjectId(endpoint) {
204+
return endpoint.split('/').slice(-1)[0]
158205
}
159-
return undefined
160206
}
161207

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
164220
}
221+
222+
export default MiddlewareApp

0 commit comments

Comments
 (0)