Skip to content

Commit

Permalink
WRITER: Basic writing of (short) strings
Browse files Browse the repository at this point in the history
  • Loading branch information
codeaholics committed Jul 27, 2013
1 parent e7e576f commit f8f0ec1
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 11 deletions.
80 changes: 74 additions & 6 deletions lib/writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,12 @@ function Writer(options) {
options = options || {};

var self = this;
var currentDatabase = 0;
var currentDatabase = undefined;
var encoding = options.encoding || 'utf8';
var crc = new Crc64();
var emptyCrc = new Buffer(8);
var outputBuffers = [];
var expectedNext = ['header'];

emptyCrc.fill(0);
var handlers = {};

self._transform = function(obj, encoding, cb) {
try {
Expand All @@ -50,7 +49,76 @@ function Writer(options) {
}

function handleObject(obj, cb) {
if (!obj || !obj.type || expectedNext.indexOf(obj.type) == -1) throw new Error('Unexpected object received');
cb();
if (!obj || !obj.type) throw new Error('Unexpected object received');
if (expectedNext.indexOf(obj.type) == -1) throw new Error('Unexpected object received: ' + obj.type + '; was expecting one of: ' + expectedNext);

handlers[obj.type](obj, function() {
if (outputBuffers.length) {
self.push(Buffer.concat(outputBuffers));
outputBuffers = [];
}
expectedNext = Array.prototype.slice.call(arguments, 0);
cb();
});
}

handlers.header = function(obj, next) {
var header = 'REDIS' + ('000' + obj.version).slice(-4);
output(header);
next('database', 'end');
}

handlers.database = function(obj, next) {
// don't do anything explicit with database objects; switch databases based on the key objects
next('database', 'key', 'end');
}

handlers.key = function(obj, next) {
if (obj.database != currentDatabase) {
switchDatabase(obj.database);
}

handlers[obj.rtype + 'Key'](obj);

next('database', 'key', 'end');
}

handlers.end = function(obj, next) {
output(new Buffer([0xFF]));
// TODO: CRC
next();
}

handlers.stringKey = function(obj) {
output(new Buffer([0x00]));
outputBytes(new Buffer(obj.key, encoding));
outputBytes(new Buffer(obj.value, encoding));
}

function switchDatabase(n) {
output(new Buffer([0xFE]));
outputLengthEncoding(n, false);
currentDatabase = n;
}

function outputLengthEncoding(n, special) {
if (n < 0) throw new Error('Cannot write negative length encoding: ' + n);

if (!special && n <= 0x3F) {
return output(new Buffer([n]));
} else {
throw new Error('Failed to write length encoding: ' + n);
}
}

function outputBytes(buffer) {
outputLengthEncoding(buffer.length, false);
output(buffer);
}

function output(data) {
if (data instanceof Buffer) return outputBuffers.push(data);
if (typeof(data) == 'string') return outputBuffers.push(new Buffer(data, 'ascii'));
throw new Error('Unknown output data type');
}
}
13 changes: 8 additions & 5 deletions test/writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ var Parser = require('../rdb-tools').Parser,

describe('Writer', function() {
describe('should round-trip', function() {
_.each(fs.readdirSync('test/dumps'), function(f) {
it.skip(f, roundTripTest.bind(null, f));
_.each(fs.readdirSync('test/dumps'), function(f, i) {
if (['empty_database.rdb', 'multiple_databases.rdb'].indexOf(f) != -1) it(f, roundTripTest.bind(null, f));
});
});

Expand All @@ -32,7 +32,8 @@ describe('Writer', function() {
['string', 'hello world'],
['null', null],
['undefined', undefined],
['object without type', {}]], function(data) {
['object without type', {}],
['wrong type of object', {type: 'database'}]], function(data) {
it(data[0], simpleErrorTest.bind(null, data[1]));
});
});
Expand Down Expand Up @@ -62,19 +63,21 @@ function roundTripTest(f, done) {
outputCaptives = [];

inputCaptor._transform = function(obj, encoding, cb) {
delete obj.offset;
inputCaptives.push(obj);
this.push(obj);
cb();
}

outputCaptor._write = function(obj, encoding, cb) {
delete obj.offset;
outputCaptives.push(obj);
cb();
}

outputCaptor.on('finish', function() {
// TODO: check the input and output captive match
done('not yet testing');
assert.deepEqual(outputCaptives, inputCaptives);
done();
});

inputStream.pipe(parser).pipe(inputCaptor).pipe(writer).pipe(reparser).pipe(outputCaptor);
Expand Down

0 comments on commit f8f0ec1

Please sign in to comment.