All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finagle.memcached.protocol.text.server.Decoder.scala Maven / Gradle / Ivy

There is a newer version: 21.2.0
Show newest version
package com.twitter.finagle.memcached.protocol.text.server

import com.twitter.finagle.memcached.protocol.ClientError
import com.twitter.finagle.memcached.protocol.text._
import com.twitter.finagle.memcached.util.ChannelBufferUtils._
import com.twitter.finagle.memcached.util.ParserUtils
import com.twitter.finagle.netty3.ChannelBufferBuf
import com.twitter.util.StateMachine
import org.jboss.netty.buffer.ChannelBuffer
import org.jboss.netty.channel._

class Decoder(storageCommands: collection.Set[ChannelBuffer]) extends AbstractDecoder with StateMachine {

  case class AwaitingCommand() extends State
  case class AwaitingData(tokens: Seq[ChannelBuffer], bytesNeeded: Int) extends State

  final protected[memcached] def start() {
    state = AwaitingCommand()
  }

  override def exceptionCaught(ctx: ChannelHandlerContext, e: ExceptionEvent) {
    super.exceptionCaught(ctx, e)
  }

  def decode(ctx: ChannelHandlerContext, channel: Channel, buffer: ChannelBuffer): Decoding = {
    state match {
      case AwaitingCommand() =>
        decodeLine(buffer, needsData) { tokens =>
          Tokens(tokens.map { ChannelBufferBuf.Owned(_) })
        }
      case AwaitingData(tokens, bytesNeeded) =>
        decodeData(bytesNeeded, buffer) { data =>
          TokensWithData(tokens.map { ChannelBufferBuf.Owned(_) }, ChannelBufferBuf.Owned(data))
        }
    }
  }

  final protected[memcached] def awaitData(tokens: Seq[ChannelBuffer], bytesNeeded: Int) {
    state = AwaitingData(tokens, bytesNeeded)
  }

  private[this] def needsData(tokens: Seq[ChannelBuffer]): Int = {
    val commandName = tokens.head
    if (storageCommands.contains(commandName)) {
      validateStorageCommand(tokens)
      val bytesNeeded = tokens(4).toInt
      bytesNeeded
    } else -1
  }

  private[this] def validateStorageCommand(tokens: Seq[ChannelBuffer]) = {
    if (tokens.size < 5) throw new ClientError("Too few arguments")
    if (tokens.size > 6) throw new ClientError("Too many arguments")
    if (!ParserUtils.isDigits(tokens(4))) throw new ClientError("Bad frame length")
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy