-
-
Save cha0s/4369700 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
// Requires ember.js and ember-data.js, socket.io | |
// Initializer for Models | |
window.Models = {}; | |
var SOCKET = '/'; // Served off the root of our app | |
var ID = 'uuid'; | |
var FIND = 'find'; | |
var FIND_MANY = 'findMany'; | |
var FIND_QUERY = 'findQuery'; | |
var FIND_ALL = 'findAll'; | |
var CREATE = 'create'; | |
var CREATES = 'creates'; | |
var UPDATE = 'update'; | |
var UPDATES = 'updates'; | |
var DELETE = 'delete'; | |
var DELETES = 'deletes'; | |
/** | |
* Implementation of WebSocket for DS.Store | |
* Shamelessly derived from https://github.com/emberjs/data/blob/master/README.md#adapter-api and http://stackoverflow.com/a/10557122/704939 | |
*/ | |
DS.SocketAdapter = DS.Adapter.extend({ | |
socket: undefined, | |
requests: undefined, | |
generateUuid: function() { | |
var S4 = function (){ | |
return Math.floor( | |
Math.random() * 0x10000 // 65536 | |
).toString(16); | |
}; | |
return ( | |
S4() + S4() + "-" + | |
S4() + "-" + | |
S4() + "-" + | |
S4() + "-" + | |
S4() + S4() + S4() | |
); | |
}, | |
send: function(action, type, data, result) { | |
var dataSerialized = []; | |
if( Object.prototype.toString.call( data ) !== '[object Array]' ) { | |
data = [data]; | |
} | |
data.forEach(function(el) { | |
var obj = el.serialize(); | |
obj.id = el.id; | |
dataSerialized.pushObject(obj); | |
}); | |
var request = { | |
"uuid": this.generateUuid(), // This UUID is strictly for tracking requests within EmberJS. It does not serve to identify any objects except this particular adapter transaction, and is disposed of when the server replies. | |
"action": action, | |
"type": type.modelType, | |
"data": dataSerialized | |
}; | |
this.socket.emit('ember-data', request); | |
// Modify the request to store original hash of data | |
request.rawData = data; | |
request.rawType = type; | |
// So we have access to the original request upon a response from the server | |
this.get('requests')[request.uuid] = request; | |
return request; | |
}, | |
find: function (store, type, id) { | |
this.send(FIND, type, id); | |
}, | |
findMany: function (store, type, ids, query) { | |
this.send(FIND_MANY, type, ids); | |
}, | |
findQuery: function (store, type, query, modelArray) { | |
this.send(FIND_QUERY, type, query, modelArray).modelArray = modelArray; | |
}, | |
findAll: function (store, type) { | |
this.send(FIND_ALL, type); | |
}, | |
createRecord: function(store, type, model) { | |
this.send(CREATE, type, model); | |
}, | |
createRecords: function(store, type, array) { | |
this.send(CREATES, type, array.list); | |
}, | |
updateRecord: function(store, type, model) { | |
this.send(UPDATE, type, model); | |
}, | |
updateRecords: function(store, type, array) { | |
this.send(UPDATES, type, array.list); | |
}, | |
deleteRecord: function(store, type, model) { | |
this.send(DELETE, type, model); | |
}, | |
deleteRecords: function(store, type, array) { | |
this.send(DELETES, type, array.list); | |
}, | |
init: function () { | |
this._super(); | |
var context = this; | |
this.set('requests', {}); | |
var ws = io.connect(location.protocol + '//' + location.host); | |
// For all standard socket.io client events, see https://github.com/LearnBoost/socket.io-client | |
ws.on('ember-data', function(event) { | |
var response = event; | |
var request = context.get('requests')[response.uuid]; | |
var type = request.rawType; | |
var array = request.rawData; | |
var data = response.data; | |
var store = Models.store; | |
switch (request.action) { | |
case FIND: | |
App.store.load(type, response.data[0]); | |
break; | |
case FIND_MANY: | |
App.store.loadMany(type, response.data); | |
break; | |
case FIND_QUERY: | |
request.modelArray.load(response.data); | |
break; | |
case FIND_ALL: | |
App.store.loadMany(type, response.data); | |
break; | |
case CREATE: | |
store.didSaveRecord(model, data); | |
break; | |
case CREATES: | |
store.didSaveRecords(array, data); | |
break; | |
case UPDATE: | |
store.didSaveRecord(model, data); | |
break; | |
case UPDATES: | |
store.didSaveRecords(array); | |
break; | |
case DELETE: | |
store.didSaveRecord(model); | |
break; | |
case DELETES: | |
store.didSaveRecords(array); | |
break; | |
default: | |
throw('Unknown Request: ' + request.action); | |
} | |
// Cleanup | |
context.get('requests')[response.uuid] = undefined; | |
}); | |
ws.on('disconnect',function () { | |
}); | |
this.set('socket', ws); | |
} | |
}); | |
// Create ember-data datastore and define our adapter | |
Models.store = DS.Store.create({ | |
revision: 10, | |
adapter: DS.SocketAdapter.create({}) | |
}); |
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
/** | |
* Module dependencies. | |
*/ | |
var express = require('express') | |
, http = require('http') | |
, path = require('path'); | |
var app = express(); | |
app.configure(function(){ | |
app.set('port', process.env.PORT || 3000); | |
app.set('views', __dirname + '/views'); | |
app.set('view engine', 'jade'); | |
app.use(express.favicon()); | |
app.use(express.logger('dev')); | |
app.use(express.bodyParser()); | |
app.use(express.methodOverride()); | |
}); | |
app.configure('development', function(){ | |
app.use(express.errorHandler()); | |
}); | |
app.get('/', function(req, res) { | |
res.render('index'); | |
}); | |
var server = app.listen(app.get('port'), function(){ | |
console.log("Express server listening on port " + app.get('port')); | |
}); | |
/** Socket.IO server implementation **/ | |
var io = require('socket.io').listen(server); | |
var modelActions = function(data) { | |
var socketActions = { | |
FIND: 'find', | |
FIND_MANY: 'findMany', | |
FIND_QUERY: 'findQuery', | |
FIND_ALL: 'findAll', | |
CREATE: 'create', | |
CREATES: 'creates', | |
UPDATE: 'update', | |
UPDATES: 'updates', | |
DELETE: 'delete', | |
DELETES: 'deletes' | |
}; | |
var results = []; | |
for (var i = 0; i < data.data.length; i++) { | |
var obj = data.data[i]; | |
switch(data.action) { | |
case socketActions.CREATE: | |
case socketActions.CREATES: | |
results.push(function(callback) { | |
models[data.type].create(obj, function(err, newModel) { | |
if (err) { | |
callback(err,null); | |
} else { | |
callback(null,newModel); | |
} | |
}); | |
}); | |
break; | |
case socketActions.UPDATE: | |
case socketActions.UPDATES: | |
results.push(function(callback) { | |
models[data.type].update({_id: obj.id}, { $set: obj}, callback); | |
}); | |
break; | |
case socketActions.DELETE: | |
case socketActions.DELETES: | |
results.push(function(callback) { | |
models[data.type].remove({ _id: obj.id}, function(err) { | |
callback(err, null); | |
}); | |
}); | |
break; | |
case socketActions.FIND: | |
case socketActions.FIND_MANY: | |
case socketActions.FIND_QUERY: | |
case socketActions.FIND_ALL: | |
default: | |
throw "Unknown action " + data.action; | |
break; | |
} | |
} | |
return results; | |
} | |
var async = require('async'); | |
io.sockets.on('connection', function(socket) { | |
socket.on('ember-data', function(data) { | |
var actions = modelActions(data); | |
async.parallel(actions, function(err, results) { | |
console.log('Parallel processing complete'); | |
if (err) { | |
console.warn(err); | |
} | |
for (var i = 0; i < data.data.length; i++) { | |
if (results[i]) { | |
data.data[i].id = results[i]._id; | |
} | |
} | |
var response = { | |
uuid: data.uuid, | |
action: data.action, | |
type: data.type, | |
data: data.data | |
}; | |
socket.emit('ember-data', response); | |
}); | |
}); | |
}); |
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
{ | |
"name": "ember-socket.io-adapter", | |
"version": "0.0.1", | |
"private": false, | |
"scripts": { | |
"start": "node app" | |
}, | |
"dependencies": { | |
"socket.io": "*", | |
"express": "3.x", | |
"mongoose": "3.5.x", | |
"async": "0.1.22" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment