Various updates.
This commit is contained in:
parent
22ce37c0cd
commit
ddf259f8b7
|
@ -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"
|
||||||
},
|
},
|
||||||
|
|
103
src/api.js
103
src/api.js
|
@ -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 = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
160
src/main.js
160
src/main.js
|
@ -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
|
||||||
})
|
|
||||||
;
|
|
||||||
|
|
13
src/xo.js
13
src/xo.js
|
@ -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,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue