diff options
author | Luke "Jared" Bennett <lbennett@gitlab.com> | 2017-05-20 20:05:31 +0100 |
---|---|---|
committer | Luke "Jared" Bennett <lbennett@gitlab.com> | 2017-05-20 20:56:10 +0100 |
commit | 71c859616524a5af903d3c736e93d7655e8a144d (patch) | |
tree | b09dbfcf20fe8230fb5e9b38e206ce0a5abb7623 /app/assets/javascripts/lib/utils/socket | |
parent | f5f99c9037e52392ca388b6e839d93df88421c31 (diff) | |
download | gitlab-ce-sockets-frontend.tar.gz |
Added SocketManager, SubscriptionStore, Subscription, VisibilitySocketManager and refactored currently instances of Pollsockets-frontend
Diffstat (limited to 'app/assets/javascripts/lib/utils/socket')
4 files changed, 227 insertions, 0 deletions
diff --git a/app/assets/javascripts/lib/utils/socket/socket_manager.js b/app/assets/javascripts/lib/utils/socket/socket_manager.js new file mode 100644 index 00000000000..2f4f428ebee --- /dev/null +++ b/app/assets/javascripts/lib/utils/socket/socket_manager.js @@ -0,0 +1,108 @@ +import socketIO from 'socket.io-client'; +import Socket from 'socket.io-client/lib/socket'; +import Subscription from './subscription'; +import SubscriptionStore from './subscription_store'; + +const SocketManager = { + socketPath: '', + socket: {}, + store: SubscriptionStore, + subscriptionsCount: 0, + + init(socketPath) { + this.socketPath = socketPath; + + this.removeAll(); + }, + + connect() { + if (this.socket instanceof Socket) return Promise.resolve(); + + return new Promise((resolve, reject) => { + this.socket = socketIO(this.socketPath); + + this.socket.on('connect', resolve); + this.socket.on('connect_error', reject); + this.socket.on('connect_timeout', reject); + }); + }, + + subscribe(endpointOrSubscription, data, callbacks) { + this.connect().then(() => { + const subscription = this.getSubscription(endpointOrSubscription, data, callbacks); + + subscription.subscribe(); + + return subscription; + }).catch((error) => { + // temporary + // eslint-disable-next-line no-console + console.log('connect error', error); + }); + }, + + remove(subscription) { + subscription.unsubscribe(); + + this.store.remove(subscription); + }, + + unsubscribeAll() { + const subscriptions = this.store.getAll(); + + if (!subscriptions) return; + + subscriptions.forEach(subscription => subscription.unsubscribe()); + }, + + subscribeAll() { + const subscriptions = this.store.getAll(); + + if (!subscriptions) return; + + subscriptions.forEach(subscription => subscription.subscribe()); + }, + + removeAll() { + this.unsubscribeAll(); + this.store.removeAll(); + }, + + getSubscription(endpointOrSubscription, data, callbacks) { + let subscription; + + if (endpointOrSubscription instanceof Subscription) { + subscription = endpointOrSubscription; + } else { + subscription = this.createSubscription({ + endpoint: endpointOrSubscription, + data, + callbacks, + }); + } + + return subscription; + }, + + createSubscription({ + endpoint, + data, + callbacks, + }) { + this.subscriptionsCount += 1; + + const subscription = new Subscription({ + endpoint, + data, + callbacks, + socket: this.socket, + id: this.subscriptionsCount, + }); + + this.store.add(subscription); + + return subscription; + }, +}; + +export default SocketManager; diff --git a/app/assets/javascripts/lib/utils/socket/subscription.js b/app/assets/javascripts/lib/utils/socket/subscription.js new file mode 100644 index 00000000000..46373a78acb --- /dev/null +++ b/app/assets/javascripts/lib/utils/socket/subscription.js @@ -0,0 +1,68 @@ +class Subscription { + constructor({ + id, + endpoint, + data, + socket, + callbacks, + }) { + this.id = id; + this.endpoint = endpoint; + this.data = data; + this.socket = socket; + this.updateCallback = callbacks.updateCallback; + this.errorCallback = callbacks.errorCallback; + + this.setPayload(); + this.setEventNames(); + } + + subscribe() { + this.socket.emit(this.eventNames.subscribe, this.payload, this.acknowledge); + + this.bindListeners(); + } + + unsubscribe() { + this.socket.emit(this.eventNames.unsubscribe, this.payload, this.acknowledge); + + this.unbindListeners(); + } + + bindListeners() { + this.socket.on(this.eventNames.update, this.updateCallback); + this.socket.on(this.eventNames.error, this.errorCallback); + } + + unbindListeners() { + this.socket.removeListener(this.eventNames.update, this.updateCallback); + this.socket.removeListener(this.eventNames.error, this.errorCallback); + } + + setPayload() { + this.payload = { + id: this.id, + endpoint: this.endpoint, + data: this.data, + }; + } + + setEventNames() { + this.eventNames = { + subscribe: `subscribe:${this.endpoint}`, + unsubscribe: `unsubscribe:${this.endpoint}`, + update: `update:${this.id}`, + error: `error:${this.id}`, + }; + } + + acknowledge(response, ...args) { + if (response.error) this.errorCallback(response.error, ...args); + + // temporary + // eslint-disable-next-line no-console + console.log('ACK', ...args); + } +} + +export default Subscription; diff --git a/app/assets/javascripts/lib/utils/socket/subscription_store.js b/app/assets/javascripts/lib/utils/socket/subscription_store.js new file mode 100644 index 00000000000..06b43da1360 --- /dev/null +++ b/app/assets/javascripts/lib/utils/socket/subscription_store.js @@ -0,0 +1,27 @@ +const SocketStore = { + subscriptions: {}, + + add(subscription) { + this.subscriptions[subscription.id] = subscription; + + return subscription; + }, + + remove(subscription) { + delete this.subscriptions[subscription.id]; + }, + + get(subscriptionID) { + return this.subscriptions[subscriptionID]; + }, + + getAll() { + Object.values(this.subscriptions); + }, + + removeAll() { + this.subscriptions = {}; + }, +}; + +export default SocketStore; diff --git a/app/assets/javascripts/lib/utils/socket/visibility_socket_manager.js b/app/assets/javascripts/lib/utils/socket/visibility_socket_manager.js new file mode 100644 index 00000000000..d363ae4bd44 --- /dev/null +++ b/app/assets/javascripts/lib/utils/socket/visibility_socket_manager.js @@ -0,0 +1,24 @@ +import SocketManager from './socket_manager'; + +const VisibilitySocketManager = { + init(socketPath) { + super.init(socketPath); + + document.addEventListener('visibilitychange', () => this.toggleAllSockets()); + }, + + toggleAllSockets() { + if (document.hidden) { + super.unsubscribeAll(); + } else { + super.subscribeAll(); + } + }, +}; + +Object.setPrototypeOf(VisibilitySocketManager, SocketManager); + +// temporary +VisibilitySocketManager.init('/broker'); + +export default VisibilitySocketManager; |