This is a silly Redis implementation that handles only three commands: INFO, ECHO, PING.
The implementation is based on streams:
var _ = require('lodash')
var expect = require('chai').expect;
var assert = require('chai').assert;
var redis = require('redis')
var split = require('split')
var net = require('net');
var util = require('util');
var Transform = require('stream').Transform;
function makeCommand(parts) {
var parts = _.filter(parts, (_, i) => i % 2 === 1)
return {
command: _.first(parts),
args: _.drop(parts)
}
}
function CommandParser(options) {
if (!(this instanceof CommandParser)) {
return new CommandParser(options)
}
Transform.call(this, {readableObjectMode: true})
this.__counter = 0
this.__parts = []
}
util.inherits(CommandParser, Transform);
CommandParser.prototype._transform = function(chunk, encoding, done) {
var str = chunk.toString('utf-8')
if(this.__counter == 0) {
assert(str[0] == '*')
this.__counter = Number(_.drop(str)) * 2
} else {
console.log(this.__counter, str)
this.__parts.push(str)
this.__counter--
}
if(this.__counter === 0 && !_.isEmpty(this.__parts)) {
console.log('here')
var command = makeCommand(this.__parts)
console.log(command)
this.push(command)
this.__parts = []
}
done()
};
function CommandProcessor(options) {
if (!(this instanceof CommandProcessor)) {
return new CommandProcessor(options)
}
Transform.call(this, {writableObjectMode: true})
}
util.inherits(CommandProcessor, Transform);
CommandProcessor.prototype._transform = function(command, encoding, done) {
switch (command.command) {
case 'ping':
done(null, '+pong\r\n')
break;
case 'info':
done(null, '9ドル\r\nsome info\r\n')
break;
case 'echo':
done(null, `\$${command.args[0].length}\r\n${command.args[0]}\r\n`)
break;
default:
console.log(command)
assert.fail()
}
};
var TEST_PORT = 6380
var server = net.createServer(function(socket) {
var commandParser = new CommandParser()
var commandProcessor = new CommandProcessor()
socket
.pipe(split())
.pipe(commandParser)
.pipe(commandProcessor)
.pipe(socket)
});
server.listen(6380, '127.0.0.1')
You can use the standard redis client to work with it. I'm mostly interested in any advice about node streams, but any other ideas are welcome too.
2 Answers 2
var parts = _.filter(parts, (_, i) => i % 2 === 1)
this looks like a habit from python. I do not recommend shadowing lodash
in any part of the code, it is harder to read.
-
\$\begingroup\$ how do you recommend to rewrite the code? \$\endgroup\$kharandziuk– kharandziuk2016年04月20日 09:18:20 +00:00Commented Apr 20, 2016 at 9:18
-
\$\begingroup\$ anything that does not shadow
_
the lodash variable, try:var parts = _.filter(parts, (e, i) => i % 2 === 1)
\$\endgroup\$Jan Grz– Jan Grz2016年04月20日 09:40:48 +00:00Commented Apr 20, 2016 at 9:40
You can simplify the whole thing by using a library such as this.
Your stream, I believe, should be a duplex, one onto which you write command into redis, and read output from redis. For example, sockets are duplex (net.Socket
).