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

com.twitter.finagle.mysql.transport.Netty3.scala Maven / Gradle / Ivy

package com.twitter.finagle.exp.mysql.transport

import com.twitter.finagle.exp.mysql.{Request, Result}
import com.twitter.finagle.netty3.{ChannelSnooper, Netty3Transporter}
import com.twitter.util.NonFatal
import java.util.logging.{Level, Logger}
import org.jboss.netty.buffer.ChannelBuffer
import org.jboss.netty.channel._
import org.jboss.netty.channel.{Channels, ChannelPipelineFactory}
import org.jboss.netty.handler.codec.frame.FrameDecoder

/**
 * Decodes logical MySQL packets that could be fragmented across
 * frames. MySQL packets are a length encoded set of bytes written
 * in little endian byte order.
 */
class PacketFrameDecoder extends FrameDecoder {
  override def decode(ctx: ChannelHandlerContext, channel: Channel, buffer: ChannelBuffer): Packet = {
    if (buffer.readableBytes < Packet.HeaderSize)
      return null

    buffer.markReaderIndex()

    val header = new Array[Byte](Packet.HeaderSize)
    buffer.readBytes(header)
    val br = BufferReader(header)

    val length = br.readInt24()
    val seq  = br.readUnsignedByte()

    if (buffer.readableBytes < length) {
      buffer.resetReaderIndex()
      return null
    }

    val body = new Array[Byte](length)
    buffer.readBytes(body)

    Packet(seq, Buffer(body))
  }
}

class PacketEncoder extends SimpleChannelDownstreamHandler {
  override def writeRequested(ctx: ChannelHandlerContext, evt: MessageEvent) =
    evt.getMessage match {
      case p: Packet =>
        try {
          val cb = p.toChannelBuffer
          Channels.write(ctx, evt.getFuture, cb, evt.getRemoteAddress)
        } catch {
          case NonFatal(e) =>
            evt.getFuture.setFailure(new ChannelException(e.getMessage))
        }

      case unknown =>
        evt.getFuture.setFailure(new ChannelException(
          "Unsupported request type %s".format(unknown.getClass.getName)))
    }
}

/**
 * A Netty3 pipeline that is responsible for framing network
 * traffic in terms of mysql logical packets.
 */
object MysqlClientPipelineFactory extends ChannelPipelineFactory {
  def getPipeline = {
    val pipeline = Channels.pipeline()
    pipeline.addLast("packetDecoder", new PacketFrameDecoder)
    pipeline.addLast("packetEncoder", new PacketEncoder)
    pipeline
  }
}

/**
 * Responsible for the transport layer plumbing required to produce
 * a Transport[Packet, Packet]. The current implementation uses
 * Netty3.
 */
object MysqlTransporter extends Netty3Transporter[Packet, Packet](
  name = "mysql",
  pipelineFactory = MysqlClientPipelineFactory
)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy