Skip to content

Commit

Permalink
[FEATURE] Create tokens associated with contracts.
Browse files Browse the repository at this point in the history
Switched to using Bookshelf.js as the ORM.
  • Loading branch information
justmoon committed Aug 3, 2014
1 parent 3bf32e4 commit 818c8d4
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 37 deletions.
33 changes: 16 additions & 17 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
var express = require('express');
var morgan = require('morgan');
var winston = require('winston');
var knex = require('knex');

var nconf = require('./lib/config');
var config = require('./lib/config');
var db = require('./lib/db');

var app = express();

Expand All @@ -14,34 +14,33 @@ var FileManager = codiusEngine.FileManager;
var FileHash = codiusEngine.FileHash;
var Engine = codiusEngine.Engine;

var engineConfig = new EngineConfig(config.get('engine'));
var compiler = new Compiler(engineConfig);
var fileManager = new FileManager(engineConfig);

var routePostContract = require('./routes/post_contract');
var routePostToken = require('./routes/post_token');

// Put winston into CLI mode (prettier)
winston.cli();
winston.default.transports.console.level = 'debug';

var engineConfig = new EngineConfig(nconf.get('engine'));
var compiler = new Compiler(engineConfig);
var fileManager = new FileManager(engineConfig);

app.set('compiler', compiler);
app.set('fileManager', fileManager);

var winstonStream = {write: function (data) {
winston.info(data.replace(/\n$/, ''));
}};
app.use(morgan(nconf.get('log_format'), {stream: winstonStream}))
app.use(morgan(config.get('log_format'), {stream: winstonStream}))

app.set('config', config);
app.set('knex', db.knex);
app.set('bookshelf', db.bookshelf);
app.set('compiler', compiler);
app.set('fileManager', fileManager);

app.post('/contract', routePostContract);
app.post('/token', routePostToken);

var db = knex.initialize(nconf.get('db'));

app.set('db', db);

db.migrate.latest().then(function () {
app.listen(nconf.get('http').port);
db.knex.migrate.latest().then(function () {
app.listen(config.get('http').port);

winston.info('Codius host running on port '+nconf.get('http').port);
winston.info('Codius host running on port '+config.get('http').port);
}).done();
9 changes: 8 additions & 1 deletion lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ nconf.defaults({
'log_format': 'dev',
'engine': {

}
},

// Size of a token in bytes
//
// The token will be base64 encoded and stored in the database as a string.
// Note that the database schema is hardcoded to allow 16 characters which is
// enough for a 12-byte token. (Base64 has a 33% overhead.)
'token_size': 12
});

if (nconf.get('NODE_ENV') === 'fig') {
Expand Down
7 changes: 7 additions & 0 deletions lib/db.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var nconf = require('./config');

var knex = require('knex').initialize(nconf.get('db'));
var bookshelf = require('bookshelf').initialize(knex);

exports.knex = knex;
exports.bookshelf = bookshelf;
2 changes: 2 additions & 0 deletions migrations/20140802170601_add_tokens.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
exports.up = function(knex, Promise) {
return knex.schema.createTable('tokens', function (t) {
t.increments().primary();
t.string('token', 16).unique();
t.integer('contract').unsigned().index().references('id').inTable('contracts');
t.integer('balance').unsigned().index().references('id').inTable('balances');
t.integer('parent').unsigned().index().references('id').inTable('tokens');
});
Expand Down
12 changes: 12 additions & 0 deletions models/balance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var bookshelf = require('../lib/db').bookshelf;

var Token = require('./token').model;

var Balance = bookshelf.Model.extend({
tableName: 'balances',
tokens: function () {
return this.hasMany(Token);
}
});

exports.model = Balance;
12 changes: 12 additions & 0 deletions models/contract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var bookshelf = require('../lib/db').bookshelf;

var Token = require('./token').model;

var Contract = bookshelf.Model.extend({
tableName: 'contracts',
tokens: function () {
return this.hasMany(Token);
}
});

exports.model = Contract;
18 changes: 18 additions & 0 deletions models/token.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
var bookshelf = require('../lib/db').bookshelf;

var Balance = require('./balance').model;

var Token = bookshelf.Model.extend({
tableName: 'tokens',
balance: function () {
return this.belongsTo(Balance);
},
parent: function () {
return this.belongsTo(Token);
},
children: function () {
return this.hasMany(Token);
}
});

exports.model = Token;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
},
"dependencies": {
"base64url": "0.0.6",
"bookshelf": "^0.7.7",
"codius-engine": "git+ssh://[email protected]:codius/codius-engine.git#master",
"concat-stream": "^1.4.6",
"express": "^4.5.1",
Expand Down
29 changes: 15 additions & 14 deletions routes/post_contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ var concat = require('concat-stream');
var winston = require('winston');
var path = require('path');

var Contract = require('../models/contract').model;

/**
* Upload a contract.
*/
Expand Down Expand Up @@ -71,22 +73,21 @@ module.exports = function (req, res, next) {

var contractHash = compiler.compileModule('codius-example-require');

var db = req.app.get('db');
db('contracts').where({hash: contractHash}).count('*').then(function (count) {
count = count.shift()['count(*)'];
if (!count) {
return db.insert({hash: contractHash}).into('contracts');
} else {
return false;
}
}).then(function (val) {
if (val) {
winston.debug('stored contract', contractHash);
res.send(204);
var knex = req.app.get('knex');
new Contract({hash: contractHash}).fetch().then(function (contract) {
if (contract) {
return contract;
} else {
winston.debug('already have contract', contractHash);
res.send(204);
return Contract.forge({
hash: contractHash
}).save();
}
}).then(function (contract) {
winston.debug('stored contract', contract.get('hash'));
res.json(200, {
hash: contract.get('hash'),
expires: contract.get('expires')
});
}).catch(function (error) {
next(error);
});
Expand Down
34 changes: 29 additions & 5 deletions routes/post_token.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
var crypto = require('crypto');
var base64url = require('base64url');

var Token = require('../models/token').model;
var Contract = require('../models/contract').model;

/**
* Request a token.
*
* A token is a multi-use endpoint for interacting with a contract via HTTP.
*/
module.exports = function (req, res) {
var token = base64url(crypto.pseudoRandomBytes(8));
var config = req.app.get('config');

// TODO: Token uniqueness should be checked
function getUniqueToken() {
var token = base64url(crypto.pseudoRandomBytes(config.get('token_size')));

// TODO: Token needs to be associated with a contract
return new Token({token: token}).fetch().then(function (model) {
if (model !== null) {
return getUniqueToken();
} else return token;
});
}

res.json(200, {
token: token
// First we check if the contract actually exists
new Contract({hash: req.query.contract}).fetch().then(function (contract) {
if (!contract) {
// Contract doesn't exist
res.json(400, {
message: "Unknown contract hash"
});
} else {
return getUniqueToken().then(function (token) {
return Token.forge({token: token, contract: contract.get('id')}).save();
}).then(function (token) {
// All done!
res.json(200, {
token: token.get('token')
});
});
}
});
};

0 comments on commit 818c8d4

Please sign in to comment.