Skip to content

Commit

Permalink
Merge pull request #52 from damienlevin/master
Browse files Browse the repository at this point in the history
Build multi-bulk reply with List prepend to maintain compatibility
  • Loading branch information
gramk committed Apr 9, 2015
2 parents 188e4d2 + ed59039 commit d8e0e66
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 41 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ In your build.sbt

resolvers += "http://chrisdinn.github.io/releases/"

libraryDependencies += "com.digital-achiever" %% "brando" % "2.1.1"
libraryDependencies += "com.digital-achiever" %% "brando" % "2.1.2"

### Getting started

Expand Down Expand Up @@ -159,7 +159,7 @@ The `ShardManager` will send a `ShardStateChange(shard, state)` message when a s

## Documentation

Read the API documentation here: [http://chrisdinn.github.io/api/brando-2.1.1/](http://chrisdinn.github.io/api/brando-2.1.1/)
Read the API documentation here: [http://chrisdinn.github.io/api/brando-2.1.2/](http://chrisdinn.github.io/api/brando-2.1.2/)

## Mailing list

Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name := "brando"

organization := "com.digital-achiever"

version := "2.1.1"
version := "2.1.2"

scalaVersion := "2.11.4"

Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/Brando.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ private class Connection(
case Tcp.Received(data)
parseReply(data) { reply
reply match {
case Some(Vector(Some(x: ByteString), Some(channel: ByteString), Some(message: ByteString))) if (x.utf8String == "message")
case Some(List(Some(x: ByteString), Some(channel: ByteString), Some(message: ByteString))) if (x.utf8String == "message")

val pubSubMessage = PubSubMessage(channel.utf8String, message.utf8String)
getSubscribers(channel).map { x
Expand Down
38 changes: 18 additions & 20 deletions src/main/scala/ReplyParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private[brando] trait ReplyParser {
case _ Failure(buffer)
}

def readStatusReply(buffer: ByteString) = splitLine(buffer) match {
def readSimpleStringReply(buffer: ByteString) = splitLine(buffer) match {
case Some((status, rest))
Success(StatusReply.fromString(status), rest)
case _ Failure(buffer)
Expand All @@ -80,7 +80,7 @@ private[brando] trait ReplyParser {
case x Failure(buffer)
}

def readBulkReply(buffer: ByteString): Result = splitLine(buffer) match {
def readBulkStringReply(buffer: ByteString): Result = splitLine(buffer) match {
case Some((length, rest))
val dataLength = length.toInt

Expand All @@ -94,28 +94,26 @@ private[brando] trait ReplyParser {
case _ Failure(buffer)
}

def readMultiBulkReply(buffer: ByteString): Result = splitLine(buffer) match {

def readArrayReply(buffer: ByteString): Result = splitLine(buffer) match {
case Some((count, rest))
val itemCount = count.toInt

@tailrec def readComponents(remaining: Int, result: Result): Result = remaining match {
@tailrec def readElements(remaining: Int, result: Result): Result = remaining match {
case 0 result
case _ if result.next.isEmpty Failure(buffer)
case i
parse(result.next) match {
case failure: Failure Failure(buffer)

case Success(newReply, next)
val replyList =
result.reply.map(_.asInstanceOf[Vector[Option[Any]]])
val newReplyList = replyList map (_ :+ newReply)

readComponents(i - 1, Success(newReplyList, next))
case _
(parse(result.next), result.reply) match {
case (failure: Failure, _)
Failure(buffer)
case (Success(element, next), Some(elements: List[_]))
if (remaining == 1) //Add last element to the array reply and reorder
readElements(0, Success(Some((element +: elements).reverse), next))
else
readElements(remaining - 1, Success(Some(element +: elements), next))
}
}

readComponents(itemCount, Success(Some(Vector.empty[Option[Any]]), rest))
readElements(itemCount, Success(Some(List.empty[Option[Any]]), rest))

case _ Failure(buffer)
}
Expand All @@ -126,11 +124,11 @@ private[brando] trait ReplyParser {
}

def parse(reply: ByteString) = reply(0) match {
case '+' readStatusReply(reply)
case ':' readIntegerReply(reply)
case '$' readBulkReply(reply)
case '*' readMultiBulkReply(reply)
case '+' readSimpleStringReply(reply)
case '-' readErrorReply(reply)
case ':' readIntegerReply(reply)
case '$' readBulkStringReply(reply)
case '*' readArrayReply(reply)
}

@tailrec final def parseReply(bytes: ByteString)(withReply: Any Unit) {
Expand Down
34 changes: 17 additions & 17 deletions src/test/scala/ReplyParserTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
remainingBuffer = ByteString.empty
}

describe("Status reply") {
describe("Simple String reply") {
it("should decode Ok") {
val result = parse(ByteString("+OK\r\n"))

Expand Down Expand Up @@ -46,7 +46,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
}
}

describe("Bulk reply") {
describe("Bulk String reply") {
it("should decode as ByteString option") {
val result = parse(ByteString("$6\r\nfoobar\r\n"))

Expand All @@ -60,8 +60,8 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
}
}

describe("Multi Bulk reply") {
it("should decode list of bulk reply values") {
describe("Array reply") {
it("should decode list of bulk string reply values") {
val result = parse(ByteString("*4\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$4\r\nfoob\r\n$6\r\nfoobar\r\n"))

val expected = Some(List(Some(ByteString("foo")), Some(ByteString("bar")),
Expand All @@ -70,7 +70,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
assert(result === Success(expected))
}

it("should decode list of with nil values") {
it("should decode list with nil values") {
val result = parse(ByteString("*3\r\n$-1\r\n$3\r\nbar\r\n$6\r\nfoobar\r\n"))

val expected = Some(List(None, Some(ByteString("bar")),
Expand All @@ -79,7 +79,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
assert(result === Success(expected))
}

it("should decode list of with integer values") {
it("should decode list with integer values") {
val result = parse(ByteString("*3\r\n$3\r\nbar\r\n:37282\r\n$6\r\nfoobar\r\n"))

val expected = Some(List(Some(ByteString("bar")), Some(37282),
Expand All @@ -88,7 +88,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
assert(result === Success(expected))
}

it("should decode list of with nested multi bulk reply") {
it("should decode list with nested array reply") {
val result = parse(ByteString("*3\r\n$3\r\nbar\r\n*4\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$4\r\nfoob\r\n$6\r\nfoobar\r\n$6\r\nfoobaz\r\n"))

val expected = Some(List(Some(ByteString("bar")),
Expand All @@ -110,7 +110,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
describe("parsing incomplete replies") {

var parsed = false
it("should handle a multi-bulk reply split into two parts") {
it("should handle an array reply split into two parts") {
parseReply(ByteString("*")) { _ fail("nothing to parse yet") }

parseReply(ByteString("1\r\n$3\r\nfoo\r\n")) { result
Expand All @@ -121,7 +121,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
if (!parsed) fail("Did not parse anything")
}

it("should handle a multi-bulk reply split before an entry") {
it("should handle an array reply split before an entry") {
parseReply(ByteString("*1\r\n")) { _ fail("nothing to parse yet") }

var parsed = false
Expand All @@ -133,7 +133,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
if (!parsed) fail("Did not parse anything")
}

it("should handle a multi-bulk reply split in an entry") {
it("should handle an array reply split in an entry") {
parseReply(ByteString("*1\r\n$3\r\n")) { _ fail("nothing to parse yet") }

var parsed = false
Expand All @@ -145,7 +145,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
if (!parsed) fail("Did not parse anything")
}

it("should handle a multi-bulk reply split between entries") {
it("should handle an array reply split between entries") {
parseReply(ByteString("*2\r\n$3\r\nfoo\r\n")) { _ fail("nothing to parse yet") }

var parsed = false
Expand All @@ -158,7 +158,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
assert(remainingBuffer === ByteString.empty)
}

it("should handle a status reply split into two parts") {
it("should handle a string reply split into two parts") {
parseReply(ByteString("+")) { _ fail("nothing to parse yet") }

var parsed = false
Expand All @@ -171,7 +171,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
assert(remainingBuffer === ByteString.empty)
}

it("should handle a status reply split after the \\r") {
it("should handle a string reply split after the \\r") {
parseReply(ByteString("+OK\r")) { _ fail("nothing to parse yet") }

var parsed = false
Expand All @@ -184,7 +184,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
assert(remainingBuffer === ByteString.empty)
}

it("should handle an int reply split into two parts") {
it("should handle an integer reply split into two parts") {
parseReply(ByteString(":")) { _ fail("nothing to parse yet") }

var parsed = false
Expand All @@ -197,7 +197,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
assert(remainingBuffer === ByteString.empty)
}

it("should handle a bulk reply split into two parts") {
it("should handle a bulk string reply split into two parts") {
parseReply(ByteString("$")) { _ fail("nothing to parse yet") }

var parsed = false
Expand All @@ -210,7 +210,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
assert(remainingBuffer === ByteString.empty)
}

it("should handle a bulk reply split after the number") {
it("should handle a bulk string reply split after the number") {
parseReply(ByteString("$3")) { _ fail("nothing to parse yet") }

var parsed = false
Expand All @@ -223,7 +223,7 @@ class ReplyParserTest extends FunSpec with BeforeAndAfterEach {
assert(remainingBuffer === ByteString.empty)
}

it("should handle a bulk reply split after the first line") {
it("should handle a bulk string reply split after the first line") {
parseReply(ByteString("$3\r\n")) { _ fail("nothing to parse yet") }

var parsed = false
Expand Down

0 comments on commit d8e0e66

Please sign in to comment.