odataserver2
Version:
OData server on top of MySQL and LeveDb
179 lines (144 loc) • 4.47 kB
JavaScript
// Imports
// =======
var Update = require('odparser').json2sql.Update;
var Insert = require('odparser').json2sql.Insert;
var tosql = require('od2mysql');
var MysqlStream = require('mysqlstream');
var CheckHashStream = require('checkhashstream');
// Setup logging
// =============
var log = console.log.bind(console);
var info = console.info.bind(console, 'INFO');
var error = console.error.bind(console, 'ERROR');
var DEV_MODE = true;
var debug, debugStream;
if (DEV_MODE) {
debug = console.log.bind(console, 'DEBUG');
debugStream = process.stdout;
} else {
debugStream = new require('stream').Writable();
ws.write = function (d) {};
debug = function () {};
}
var OD = function () {}
OD.prototype.handleRequest = function () {
return function (req, res, next) {
var handleError = function (err) {
res.writeHead(406, {
"Content-Type": "application/json"
});
res.write(err);
error(err);
};
var parseJSON = function (j) {
try {
if (j && typeof j === 'string' && j.length) return JSON.parse(j);
else return null;
} catch (err) {
handleError('Error parsing json: ' + err);
}
};
var contentLength = parseInt(req.headers['content-length']);
contentLength = (!isNaN(contentLength)) ? contentLength : 0;
var ast = req.ast;
var options = {
host: process.env.DB_HOST
};
if (ast.adminOp) {
options.user = process.env.ADMIN_USER;
options.password = process.env.ADMIN_PASSWORD;
} else {
options.user = ast.user;
options.password = ast.password;
options.database = ast.user;
}
// setup mysqlstream
if (ast.etagCols) ast.etagCols.push('queryType');
var etagOptions = (ast.etagCols) ? {
etagAlg: 'md5',
etagDigest: 'hex',
etagCols: ast.etagCols
} : null;
var mysql = new MysqlStream(etagOptions, options);
debug('mysql options', options, 'etag options', etagOptions);
mysql.on('error', handleError);
if (ast.queryType === 'insert' && !ast.bucketOp) {
var ins = new Insert(null, ast.schema, ast.table);
ins.on('error', handleError);
req.pipe(ins).pipe(mysql).pipe(res);
//debug
req.pipe(debugStream);
ins.pipe(debugStream);
mysql.pipe(debugStream);
} else if (ast.queryType === 'update' && !ast.bucketOp) {
var upd = new Update(null, ast.schema, ast.table);
upd.on('error', handleError);
req.pipe(upd).pipe(mysql).pipe(res);
// debug
req.pipe(debugStream);
upd.pipe(debugStream);
mysql.pipe(debugStream);
} else if (!ast.bucketOp) {
var buffer = '';
req.on('data', function (chunk) {
chunk = chunk.toString();
buffer += chunk;
});
req.on('end', function () {
try {
var json = parseJSON(buffer);
var sql = tosql(ast, json, DEV_MODE, process.env.CONNECT_FROM_HOST);
debug('sql', sql);
debug('json data:', json);
debug('options:', options);
if (buffer.length !== contentLength) info('WARNING: data received less that indicated content length');
// Answer with 304 if the etag matches
if (req.headers['if-none-match']) {
var ws = new CheckHashStream({
hashAlg: 'md5',
hashDigest: 'hex'
}, req.headers['if-none-match']);
mysql.pipe(ws
/*, {
end: false
}*/
);
mysql.write(sql);
mysql.end();
if (!ws.get()) {
debug('NOT MODIFIED')
res.writeHead(304);
res.end();
return;
}
res.end(ws.get());
}
// Do not check against etag
else {
mysql.pipe(debugStream);
mysql.pipe(res);
mysql.write(sql);
mysql.end();
}
} catch (err) {
var result = {
error: 'ERROR parsing input, likely malformed/missing JSON: ' + err
};
res.write(JSON.stringify(result));
res.end();
}
});
} else {
if (next) next();
}
req.on('close', function () {
log('close in request')
});
res.on('finish', function () {
log('finish in response')
});
}
};
// exports
// =======
module.exports = OD;