Various updates.

This commit is contained in:
Julien Fontanet 2013-07-05 13:09:20 +02:00
parent 22ce37c0cd
commit ddf259f8b7
4 changed files with 170 additions and 108 deletions

View File

@ -13,7 +13,7 @@
}, },
"main": "src/main.js", "main": "src/main.js",
"dependencies": { "dependencies": {
"backbone": ">=1.0.0", "extendable": ">=0.0.3",
"hashy": ">=0.1.0", "hashy": ">=0.1.0",
"underscore": ">=1.4.4" "underscore": ">=1.4.4"
}, },

View File

@ -2,6 +2,17 @@ var _ = require('underscore');
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
function deprecated(fn)
{
return function (session, req, res) {
console.warn(req.method +' is deprecated!');
return fn.call(this, session, req, res);
};
}
//////////////////////////////////////////////////////////////////////
function Api(xo) function Api(xo)
{ {
this.xo = xo; this.xo = xo;
@ -41,9 +52,19 @@ Api.prototype.get = function (name) {
) )
{} {}
return _.isFunction(current) // Method found.
? current if (_.isFunction(current))
: undefined {
return current;
}
// It's a (deprecated) alias.
if (_.isString(current))
{
return deprecated(this.get(current));
}
return undefined;
; ;
}; };
@ -64,14 +85,14 @@ function err(code, message)
Api.err = { Api.err = {
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// JSON errors. // JSON-RPC errors.
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
'INVALID_JSON': err(-32700, 'invalid JSON'), 'INVALID_JSON': err(-32700, 'invalid JSON'),
'INVALID_REQUEST': err(-32600, 'invalid JSON-RPC request'), 'INVALID_REQUEST': err(-32600, 'invalid JSON-RPC request'),
'INVALID_METHOD': err(-326001, 'method not found'), 'INVALID_METHOD': err(-32601, 'method not found'),
'INVALID_PARAMS': err(-32602, 'invalid parameter(s)'), 'INVALID_PARAMS': err(-32602, 'invalid parameter(s)'),
@ -100,6 +121,7 @@ Api.fn.api = {
}, },
}; };
// Session management
Api.fn.session = { Api.fn.session = {
'signInWithPassword': function (session, req, res) { 'signInWithPassword': function (session, req, res) {
var p_email = req.params.email; var p_email = req.params.email;
@ -161,7 +183,7 @@ Api.fn.session = {
return true; return true;
}, },
'getUser': function (session, req, res) { 'getUser': deprecated(function (session, req, res) {
var user_id = session.get('user_id'); var user_id = session.get('user_id');
if (undefined === user_id) if (undefined === user_id)
{ {
@ -169,36 +191,18 @@ Api.fn.session = {
} }
return _.pick(users.get(user_id), 'id', 'email'); return _.pick(users.get(user_id), 'id', 'email');
});
'getUserId': function (session, req, res) {
return session.get('user_id', null);
}; };
'createToken': function (session, req, res) { 'createToken': 'token.create'
var user_id = session.get('user_id');
if ((undefined === user_id)
|| session.has('token_id'))
{
throw Api.err.UNAUTHORIZED;
}
// @todo Ugly. 'destroyToken': 'token.delete',
var token = this.tokens.model.generate(user_id);
this.tokens.add(token);
return token.id;
},
'destroyToken': function (session, req, res) {
var p_token = req.params.token;
if (!this.tokens.get(p_token))
{
throw Api.err.INVALID_PARAMS;
}
this.tokens.remove(p_token);
return true;
},
}; };
// User management.
Api.fn.user = { Api.fn.user = {
'create': function (session, req, res) { 'create': function (session, req, res) {
var p_email = req.params.email; var p_email = req.params.email;
@ -220,7 +224,9 @@ Api.fn.user = {
}, },
'delete': function (session, req, res) { 'delete': function (session, req, res) {
var p_id = req.params.id;
var user
}, },
'changePassword': function (session, req, res) { 'changePassword': function (session, req, res) {
@ -235,3 +241,38 @@ Api.fn.user = {
}, },
}; };
// Token management.
Api.fn.token = {
'create': function (session, req, res) {
var user_id = session.get('user_id');
if ((undefined === user_id)
|| session.has('token_id'))
{
throw Api.err.UNAUTHORIZED;
}
// @todo Ugly.
var token = this.tokens.model.generate(user_id);
this.tokens.add(token);
return token.id;
},
'delete': function (session, req, res) {
var p_token = req.params.token;
if (!this.tokens.get(p_token))
{
throw Api.err.INVALID_PARAMS;
}
this.tokens.remove(p_token);
return true;
},
};
// VM
Api.fn.vm = {
};

View File

@ -1,5 +1,6 @@
var events = require('events'); var EventEmitter = require('events').EventEmitter;
var util = require('util'); var util = require('util');
var Session = require('session');
//-------------------------------------- //--------------------------------------
@ -8,34 +9,6 @@ var api = require('./api')(xo);
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
function Session()
{
this.data = {};
}
util.inherits(Session, events.EventEmitter);
Session.prototype.close = function () {
session.emit('close');
};
Session.prototype.get = function (name, def) {
if (undefined !== this.data[name])
{
return this.data[name];
}
return def;
};
Session.prototype.has = function (name) {
return (undefined !== this.data[name]);
};
Session.prototype.set = function (name, value) {
this.data[name] = value;
};
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
function Response(transport, id) function Response(transport, id)
@ -70,53 +43,98 @@ Response.prototype.sendError = function (error)
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
require('socket.io') function json_api_call(session, transport, message)
.listen(8080) {
.sockets.on('connection', function (socket) { try
{
var req = JSON.parse(message.toString());
}
catch (e if e instanceof SyntaxError)
{
new Response(transport, null).sendError(
api.err
);
return;
}
// @todo comment if (!req.method || !req.params
var transport = function (message) { || (undefined === req.id)
socket.send(data); || ('2.0' !== req.jsonrpc))
}; {
new Response(transport, null).sendError(
-32600,
'the JSON sent is not a valid request object'
);
return;
}
var session = new Session(); api.exec(
session.on('close', function () { session,
socket.disconnect(); {
}); 'method': req.method,
'params': req.params,
},
new Response(transport, req.id)
);
}
// When a message is received. //////////////////////////////////////////////////////////////////////
socket.on('message', function (message) { // JSON-RPC over WebSocket.
try //////////////////////////////////////////////////////////////////////
require('socket.io').listen(8080).sockets.on('connection', function (socket) {
var transport = function (message) {
socket.send(data);
};
var session = new Session();
session.on('close', function () {
socket.disconnect();
});
socket.on('message', function (message) {
json_api_call(session, transport, message);
});
});
//////////////////////////////////////////////////////////////////////
// JSON-RPC over TCP.
//////////////////////////////////////////////////////////////////////
require('net').createServer(function (socket) {
var transport = function (message) {
socket.write(message); // @todo Handle long messages.
};
var session = new Session();
session.on('close', function () {
socket.end(); // @todo Check it is enough.
});
var length = null; // Expected message length.
var buffer = new Buffer();
socket.on('data', function (data) {
data.copy(buffer);
// Read the message length.
if (!length)
{
var i = _.indexOf(buffer, 10);
if (-1 === i)
{ {
var req = JSON.parse(message.toString());
}
catch (e if e instanceof SyntaxError)
{
new Response(transport, null).sendError(
api.err
);
return; return;
} }
if (!req.method || !req.params length = +buffer.toString('ascii', 0, i); // @todo Handle NaN.
|| (undefined === req.id) buffer = buffer.slice(i + 1);
|| ('2.0' !== req.jsonrpc)) }
{
new Response(transport, null).sendError(
-32600,
'the JSON sent is not a valid request object'
);
return;
}
api.exec( // We do not have received everything.
session, if (buffer.length < length)
{ {
'method': req.method, return;
'params': req.params, }
},
new Response(transport, req.id) json_api_call(session, transport, buffer.toString());
); });
}); }).listen('<path>'); // @todo
})
;

View File

@ -1,8 +1,9 @@
var _ = require('underscore'); var _ = require('underscore');
var Backbone = require('backbone');
var crypto = require('crypto'); var crypto = require('crypto');
var hashy = require('hashy'); var hashy = require('hashy');
var Q = require('q'); var Q = require('q');
var Collection = require('collection');
var Model = require('model');
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
@ -33,7 +34,7 @@ var check = function () {
// @todo We could also give a permission level to tokens (<= // @todo We could also give a permission level to tokens (<=
// user.permission). // user.permission).
var Token = Backbone.Model.extend({ var Token = Model.extend({
// Validates model attributes. // Validates model attributes.
'validate': function (attr) { 'validate': function (attr) {
check(attr.id).len(10); check(attr.id).len(10);
@ -52,7 +53,9 @@ var Token = Backbone.Model.extend({
}, },
}); });
var User = Backbone.Model.extend({ user.set('password', '123');
var User = Model.extend({
'default': { 'default': {
'permission': 'none', 'permission': 'none',
}, },
@ -102,11 +105,11 @@ var User = Backbone.Model.extend({
// Collections // Collections
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
var Tokens = Backbone.Collection.extend({ var Tokens = Collection.extend({
'model': Token, 'model': Token,
}); });
var Users = Backbone.Collection.extend({ var Users = Collection.extend({
'model': User, 'model': User,
}); });