Skip to content

Instantly share code, notes, and snippets.

@taion
Last active February 26, 2018 22:50
Show Gist options
  • Save taion/9e88be32d915321ce1dad757323a353d to your computer and use it in GitHub Desktop.
Save taion/9e88be32d915321ce1dad757323a353d to your computer and use it in GitHub Desktop.
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