forked from andreyk0/redis-client-scala-netty
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #31 from yarosman/master
Netty 4.1 support
- Loading branch information
Showing
30 changed files
with
1,369 additions
and
581 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
sbt.version=0.13.13 | ||
sbt.version=1.1.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
addSbtPlugin("me.lessis" % "bintray-sbt" % "0.3.0") | ||
|
||
addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.1") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package com.fotolog.redis | ||
|
||
import com.fotolog.redis.connections.BulkDataResult | ||
import io.netty.util.CharsetUtil | ||
|
||
/** | ||
* @author Yaroslav Derman <[email protected]>. | ||
* created on 12.03.2017. | ||
*/ | ||
sealed trait RedisMessage | ||
|
||
trait SimpleMessage extends RedisMessage { | ||
def asOptBin: Option[Array[Byte]] = None | ||
} | ||
|
||
trait ComplexMessage extends RedisMessage | ||
|
||
case object NullRedisMessage extends SimpleMessage | ||
|
||
case object EmptyArrayRedisMessage extends SimpleMessage | ||
|
||
case class StringRedisMessage(content: String) extends SimpleMessage { | ||
override def asOptBin: Option[Array[Byte]] = Option(content).map(_.getBytes(CharsetUtil.UTF_8)) | ||
} | ||
|
||
case class RawRedisMessage(content: Array[Byte]) extends SimpleMessage { | ||
override def toString: String = new String(content) | ||
|
||
override def asOptBin: Option[Array[Byte]] = Some(content) | ||
} | ||
|
||
case class IntRedisMessage(number: Int) extends SimpleMessage { | ||
override def asOptBin: Option[Array[Byte]] = Some(number.toString.getBytes) | ||
} | ||
|
||
case class ErrorRedisMessage(error: String) extends SimpleMessage { | ||
override def asOptBin: Option[Array[Byte]] = Option(error).map(_.getBytes(CharsetUtil.UTF_8)) | ||
} | ||
|
||
case class ArrayHeaderRedisMessage(length: Int) extends SimpleMessage { | ||
override def asOptBin: Option[Array[Byte]] = None | ||
} | ||
|
||
case class ArrayRedisMessage(children: List[RedisMessage]) extends ComplexMessage { | ||
|
||
//TODO: fixme | ||
def asBulk: Seq[BulkDataResult] = children.flatMap { | ||
case s: SimpleMessage => Seq(BulkDataResult(s.asOptBin)) | ||
case c: ArrayRedisMessage => c.asBulk | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
src/main/scala/com/fotolog/redis/codecs/ChannelExceptionHandler.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package com.fotolog.redis.codecs | ||
|
||
import io.netty.channel.ChannelHandlerContext | ||
|
||
/** | ||
* @author Yaroslav Derman <[email protected]>. | ||
* created on 02.03.2017. | ||
*/ | ||
private[codecs] trait ChannelExceptionHandler { | ||
def handleException(ctx: ChannelHandlerContext, ex: Throwable) { | ||
ctx.close() | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
src/main/scala/com/fotolog/redis/codecs/RedisArrayAgregator.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package com.fotolog.redis.codecs | ||
|
||
import java.util | ||
|
||
|
||
import com.fotolog.redis.codecs.RedisArrayAgregator.AggregateState | ||
import com.fotolog.redis._ | ||
import io.netty.channel.ChannelHandlerContext | ||
import io.netty.handler.codec.MessageToMessageDecoder | ||
|
||
import scala.collection.mutable.ArrayBuffer | ||
|
||
/** | ||
* @author Yaroslav Derman <[email protected]>. | ||
* created on 13.03.2017. | ||
*/ | ||
class RedisArrayAgregator extends MessageToMessageDecoder[RedisMessage] { | ||
|
||
val queue: util.Deque[AggregateState] = new util.ArrayDeque[AggregateState] | ||
|
||
override def decode(ctx: ChannelHandlerContext, msg: RedisMessage, out: util.List[AnyRef]): Unit = { | ||
msg match { | ||
case header: ArrayHeaderRedisMessage if header.length == 0 => | ||
out.add(EmptyArrayRedisMessage) | ||
|
||
case header: ArrayHeaderRedisMessage if header.length == -1 => | ||
out.add(NullRedisMessage) | ||
|
||
case ArrayHeaderRedisMessage(length) if queue.isEmpty => | ||
queue.push(new AggregateState(length)) | ||
|
||
case ArrayHeaderRedisMessage(length) if !queue.isEmpty => | ||
queue.push(new AggregateState(length)) | ||
|
||
case proxyMsg if queue.isEmpty => | ||
out.add(proxyMsg) | ||
|
||
case partMsg if !queue.isEmpty => | ||
|
||
var promMsg: RedisMessage = partMsg | ||
|
||
while (!queue.isEmpty) { | ||
val current = queue.peekFirst() | ||
current.add(promMsg) | ||
|
||
if (current.isFull) { | ||
promMsg = ArrayRedisMessage(current.msgs.toList) | ||
queue.pop() | ||
} else { | ||
promMsg = null | ||
return | ||
} | ||
} | ||
|
||
Option(promMsg).foreach(msg => out.add(msg)) | ||
} | ||
} | ||
|
||
} | ||
|
||
object RedisArrayAgregator { | ||
|
||
case class AggregateState(length: Int, msgs: ArrayBuffer[RedisMessage]) { | ||
|
||
def isFull: Boolean = length == msgs.size | ||
|
||
def this(length: Int) = this(length, new ArrayBuffer[RedisMessage](length)) | ||
|
||
def add(msg: RedisMessage): Unit = msgs.append(msg) | ||
} | ||
|
||
} |
35 changes: 35 additions & 0 deletions
35
src/main/scala/com/fotolog/redis/codecs/RedisCommandEncoder.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.fotolog.redis.codecs | ||
|
||
import com.fotolog.redis.connections.ResultFuture | ||
import io.netty.buffer.ByteBuf | ||
import io.netty.channel.ChannelHandler.Sharable | ||
import io.netty.channel.ChannelHandlerContext | ||
import io.netty.handler.codec.MessageToByteEncoder | ||
|
||
/** | ||
* @author Yaroslav Derman <[email protected]>. | ||
* created on 02.03.2017. | ||
*/ | ||
@Sharable | ||
private[redis] class RedisCommandEncoder extends MessageToByteEncoder[ResultFuture] { | ||
|
||
import com.fotolog.redis.connections.Cmd._ | ||
|
||
override def encode(ctx: ChannelHandlerContext, msg: ResultFuture, out: ByteBuf): Unit = { | ||
binaryCmd(msg.cmd.asBin, out) | ||
} | ||
|
||
private def binaryCmd(cmdParts: Seq[Array[Byte]], out: ByteBuf) = { | ||
out.writeBytes(ARRAY_START) | ||
out.writeBytes(cmdParts.length.toString.getBytes) | ||
out.writeBytes(EOL) | ||
|
||
for (p <- cmdParts) { | ||
out.writeBytes(STRING_START) | ||
out.writeBytes(p.length.toString.getBytes) | ||
out.writeBytes(EOL) | ||
out.writeBytes(p) | ||
out.writeBytes(EOL) | ||
} | ||
} | ||
} |
93 changes: 93 additions & 0 deletions
93
src/main/scala/com/fotolog/redis/codecs/RedisResponseDecoder.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package com.fotolog.redis.codecs | ||
|
||
import java.nio.charset.Charset | ||
import java.util | ||
|
||
import com.fotolog.redis._ | ||
import io.netty.buffer.ByteBuf | ||
import io.netty.channel.ChannelHandlerContext | ||
import io.netty.handler.codec.ByteToMessageDecoder | ||
import io.netty.util.{ByteProcessor, CharsetUtil} | ||
|
||
/** | ||
* @author Yaroslav Derman <[email protected]>. | ||
* created on 02.03.2017. | ||
*/ | ||
private[redis] class RedisResponseDecoder extends ByteToMessageDecoder with ChannelExceptionHandler { | ||
|
||
val charset: Charset = CharsetUtil.UTF_8 | ||
var responseType: ResponseType = Unknown | ||
|
||
//TODO: split into frame without '/r/n' | ||
override def decode(ctx: ChannelHandlerContext, in: ByteBuf, out: util.List[AnyRef]): Unit = { | ||
responseType match { | ||
case Unknown if in.isReadable => | ||
responseType = ResponseType(in.readByte) | ||
|
||
case Unknown if !in.isReadable => | ||
|
||
case BulkData => readAsciiLine(in).foreach { line => | ||
line.toInt match { | ||
case -1 => | ||
responseType = Unknown | ||
out.add(NullRedisMessage) | ||
case n => | ||
responseType = BinaryData(n) | ||
} | ||
} | ||
|
||
case BinaryData(len) => | ||
if (in.readableBytes >= (len + 2)) { | ||
// +2 for eol | ||
responseType = Unknown | ||
val bytes = new Array[Byte](len) | ||
in.readBytes(bytes) | ||
in.skipBytes(2) | ||
out.add(RawRedisMessage(bytes)) | ||
} | ||
|
||
case MultiBulkData => | ||
readAsciiLine(in).map { line => | ||
responseType = Unknown | ||
out.add(ArrayHeaderRedisMessage(line.toInt)) | ||
} | ||
|
||
case Integer => | ||
readAsciiLine(in).map { line => | ||
responseType = Unknown | ||
out.add(IntRedisMessage(line.toInt)) | ||
} | ||
|
||
case Error => | ||
readAsciiLine(in).map { line => | ||
responseType = Unknown | ||
out.add(ErrorRedisMessage(line)) | ||
} | ||
|
||
case SingleLine => | ||
readAsciiLine(in).map { line => | ||
responseType = Unknown | ||
out.add(StringRedisMessage(line)) | ||
} | ||
} | ||
} | ||
|
||
private def findEndOfLine(buffer: ByteBuf): Int = { | ||
val i = buffer.forEachByte(ByteProcessor.FIND_LF) | ||
if (i > 0 && buffer.getByte(i - 1) == '\r') i - 1 else -1 | ||
} | ||
|
||
private def readAsciiLine(buf: ByteBuf): Option[String] = if (!buf.isReadable) None else { | ||
findEndOfLine(buf) match { | ||
case -1 => None | ||
case n => | ||
val line = buf.toString(buf.readerIndex, n - buf.readerIndex, charset) | ||
buf.skipBytes(line.length + 2) | ||
Some(line) | ||
} | ||
} | ||
|
||
override def exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable) { | ||
handleException(ctx, cause) | ||
} | ||
} |
Oops, something went wrong.