Last active
December 7, 2017 21:45
-
-
Save Schnodderbalken/40114a2e500ae27864c6b4ae9688d3f2 to your computer and use it in GitHub Desktop.
Socket.io adapter for Ember.js - tested with ember 2.16.2, node 6.4.0 and npm 5.5.1. This is based on this gist https://gist.github.com/carlwoodward/8659793. The `websocket-connection-service` is nothing but a wrapper around socket.io. So in order to make it work: `npm install socket.io-client --save`. Can easily be adapted to websocket adapter.
This file contains 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 { Promise as EmberPromise } from 'rsvp'; | |
import { inject as service } from '@ember/service'; | |
import DS from 'ember-data'; | |
import Ember from 'ember'; | |
const {Logger} = Ember; | |
export default DS.Adapter.extend({ | |
websocketConnectionService: service('websocket-connection-service'), | |
callbacks: {}, | |
initializeSocket: function(callback) { | |
if(this.get('websocketConnectionService').connected()) { | |
callback(); | |
return; | |
} | |
this.registerEventHandlerForWebsocket(callback); | |
}, | |
registerEventHandlerForWebsocket(callback) { | |
var connectionService = this.get('websocketConnectionService'); | |
var adapter = this; | |
connectionService.on('connect', function() { | |
adapter.reactOnConnection(); | |
callback(); | |
}); | |
connectionService.on('connect_error', function(data) {adapter.reactOnDisconnection.call(adapter, data)}); | |
connectionService.on('response', function(data) {adapter.onMessage.call(adapter, data)}); | |
}, | |
reactOnDisconnection: function() { | |
Logger.info('disconnected'); | |
// Once the user should see the connection status this becomes important | |
}, | |
reactOnConnection: function() { | |
Logger.info('connected'); | |
// Once the user should see the connection status this becomes important | |
}, | |
buildRequestObject: function(requestType, query, uuid) { | |
var request_object = { | |
meta: { | |
'request-method': requestType, | |
'data-type': query.type, | |
'uuid': uuid | |
} | |
}; | |
if(query.data) { | |
request_object.content = query.data; | |
} | |
return request_object; | |
}, | |
doSocketRequest: function (store, requestType, query) { | |
var adapter = this; | |
return new EmberPromise(function (resolve, reject) { | |
adapter.get('initializeSocket').call(adapter, function() { | |
if(requestType === null) { | |
reject({message: 'No type specified in the request.'}); | |
} | |
if(adapter.get('websocketConnectionService').connected() === false) { | |
reject({ message : 'websocket is not available for requests'}); | |
} | |
try { | |
var uuid = adapter.generateUuid(); | |
var request_object = adapter.buildRequestObject(requestType, query, uuid); | |
var success = function(data) { | |
resolve(data); | |
}; | |
var error = function(data) { | |
reject(data); | |
}; | |
var callback = { success: success, error: error }; | |
adapter.callbacks[uuid] = callback; | |
adapter.get('websocketConnectionService').emit('request', request_object); | |
} catch (e) { | |
Logger.error(e); | |
reject({ message : 'websocket is not available for requests. Exception: ' + e}); | |
} | |
}); | |
}); | |
}, | |
createRecord: function(store, type, snapshot) { | |
var data = this.serialize(snapshot); | |
if(snapshot.id) { | |
data.id = snapshot.id; | |
} | |
var requestData = { type : type.modelName, data: data }; | |
return this.doSocketRequest(store, 'post', requestData); | |
}, | |
findRecord: function (store, type, id) { | |
return this.doSocketRequest(store, 'get', { | |
type : type.modelName, | |
data : { id : id } | |
}); | |
}, | |
findAll: function (store, type) { | |
var result = this.doSocketRequest(store, 'get', { | |
type : type.modelName | |
}); | |
return result; | |
}, | |
query: function (store, type, query) { | |
return this.doSocketRequest(store, 'get', { | |
type : type.modelName, | |
data : query | |
}); | |
}, | |
updateRecord: function(store, type, snapshot) { | |
if(!snapshot.record.hasOwnProperty('_changedProperties')) { | |
return this.doPatch(store, type, snapshot); | |
} | |
return this.doPut(store, type, snapshot); | |
}, | |
doPatch: function(store, type, snapshot) { | |
var data = this.serialize(snapshot); | |
data.id = snapshot.id; | |
var requestData = { type : type.modelName, data: data }; | |
return this.doSocketRequest(store, 'patch', requestData); | |
}, | |
doPut: function(store, type, snapshot) { | |
// This does not work for relationships but hopefully ember will support it in the future: | |
/*for (var key in snapshot._changedAttributes) { | |
data[key] = snapshot._changedAttributes[key][1]; | |
}*/ | |
var data = { | |
id: snapshot.id | |
} | |
if(snapshot.record._changedProperties.length === 0) { | |
return snapshot; | |
} | |
var serializedSnapshot = this.serialize(snapshot); | |
snapshot.record._changedProperties.forEach(function(propertyName) { | |
data[propertyName] = serializedSnapshot[propertyName]; | |
}); | |
var requestData = { type : type.modelName, data: data }; | |
return this.doSocketRequest(store, 'patch', requestData); | |
}, | |
deleteRecord: function(store, type, snapshot) { | |
var data = this.serialize(snapshot); | |
if(snapshot.id) { | |
data.id = snapshot.id; | |
} | |
var requestData = { type : type.modelName, data: data }; | |
return this.doSocketRequest(store, 'delete' ,requestData); | |
}, | |
generateUuid: function() { | |
var date = new Date().getTime(); | |
var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(character) { | |
var random = (date + Math.random() * 16) % 16 | 0; | |
date = Math.floor(date/16); | |
return (character === "x" ? random : (random & 0x7 | 0x8)).toString(16); | |
}); | |
if(!(uuid in this.callbacks)) { | |
return uuid; | |
} | |
return this.generateUuid(); | |
}, | |
onMessage: function(data) { | |
var data_object = {}; | |
try{ | |
data_object = JSON.parse(data); | |
} | |
catch(e) { | |
Logger.error(e); | |
return; | |
} | |
if(!('meta' in data_object)) { | |
return; | |
} | |
if(!('uuid' in data_object.meta)) { | |
return; | |
} | |
if(!(data_object.meta.uuid in this.callbacks)) { | |
return; | |
} | |
if(data_object.meta.code !== 200) { | |
var message = data_object.meta.message; | |
var error_log = 'Problem with ' + data_object.meta.request_method; | |
if(data_object.meta['data-type']) { | |
error_log += ' ' + data_object.meta['data-type']; | |
} | |
if (message) { | |
error_log += ': "' + message + '"'; | |
} | |
var error_callback = this.callbacks[data_object.meta.uuid].error; | |
delete this.callbacks[data_object.meta.uuid]; | |
Logger.error(error_log); | |
error_callback(new Error(error_log)); | |
return; | |
} | |
var success_callback = this.callbacks[data_object.meta.uuid].success; | |
delete this.callbacks[data_object.meta.uuid]; | |
success_callback(data_object.content); | |
} | |
}); |
This file contains 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 Service from '@ember/service'; | |
import config from '../config/environment'; | |
import io from 'npm:socket.io-client'; | |
export default Service.extend({ | |
socketConnection: null, | |
init() { | |
this.getConnection(); | |
}, | |
getConnection: function() { | |
if(this.socketConnection === null) { | |
this.set('socketConnection', io.connect(config.APP.websocketHost + ':' + config.APP.websocketPort + '/')); | |
} | |
return this.socketConnection; | |
}, | |
on: function(eventType, callback, context) { | |
this.get('socketConnection').on(eventType, callback, context); | |
}, | |
emit: function(eventType, data) { | |
this.get('socketConnection').emit(eventType, data); | |
}, | |
connected: function() { | |
return this.get('socketConnection').connected; | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment