2
\$\begingroup\$

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.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Apr 11, 2016 at 14:12
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

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.

answered Apr 20, 2016 at 5:40
\$\endgroup\$
2
  • \$\begingroup\$ how do you recommend to rewrite the code? \$\endgroup\$ Commented 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\$ Commented Apr 20, 2016 at 9:40
1
\$\begingroup\$

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).

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
answered May 10, 2016 at 15:56
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.