Last active
February 26, 2018 22:50
-
-
Save taion/9e88be32d915321ce1dad757323a353d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import io from 'socket.io-client'; | |
import RelayNetworkLayer from '@taion/relay-network-layer'; | |
const MAX_SUBSCRIPTIONS = 200; | |
const EMPTY_SUBSCRIPTION = { | |
dispose() {}, | |
}; | |
/** | |
* A react-relay NetworkLayer implementation that supports query batching | |
* and subscriptions | |
*/ | |
export default class NetworkLayer extends RelayNetworkLayer { | |
constructor(origin, ...args) { | |
super(`${origin}/graphql`, ...args); | |
this.socket = io({ | |
path: `${origin}/socket.io/graphql`, | |
transports: ['websocket'], | |
}); | |
this.token = null; | |
this.requests = new Map(); | |
this.socket.on('connect', () => { | |
this.authenticate(); | |
Object.entries(this.requests).forEach(([id, request]) => { | |
this.subscribe(id, request); | |
}); | |
}); | |
this.socket.on('subscription update', ({ id, data, errors }) => { | |
const request = this.requests.get(id); | |
if (!request) { | |
return; | |
} | |
if (errors) { | |
request.onError(errors); | |
} else { | |
request.onNext(data); | |
} | |
}); | |
} | |
setToken(token) { | |
this.token = token; | |
if (token) { | |
this._init.headers = { | |
...this._init.headers, | |
Authorization: `Bearer ${token}`, | |
}; | |
} else if (this._init.headers) { | |
delete this._init.headers.Authorization; | |
} | |
this.authenticate(); | |
} | |
sendSubscription(request) { | |
const id = request.getClientSubscriptionId(); | |
if (this.requests.size >= MAX_SUBSCRIPTIONS) { | |
if (__DEV__) { | |
console.warn('subscription limit reached'); // eslint-disable-line no-console | |
} | |
return EMPTY_SUBSCRIPTION; | |
} | |
this.requests.set(id, request); | |
this.subscribe(id, request); | |
return { | |
dispose: () => { | |
this.emitTransient('unsubscribe', id); | |
this.requests.delete(id); | |
request.onCompleted(); | |
}, | |
}; | |
} | |
authenticate() { | |
if (this.token) { | |
this.emitTransient('authenticate', this.token); | |
} | |
} | |
subscribe(id, request) { | |
this.emitTransient('subscribe', { | |
id, | |
query: request.getQueryString(), | |
variables: request.getVariables(), | |
}); | |
} | |
emitTransient(...args) { | |
// For transient state management, we re-emit on reconnect anyway, so no | |
// need to use the send buffer. | |
if (!this.socket.connected) { | |
return; | |
} | |
this.socket.emit(...args); | |
} | |
disconnect() { | |
this.socket.disconnect(); | |
this.requests.forEach(request => { | |
request.onCompleted(); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment