io.netty.buffer.ByteBuf Scala Examples

The following examples show how to use io.netty.buffer.ByteBuf. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: Packet.scala    From finagle-postgres   with Apache License 2.0 6 votes vote down vote up
package com.twitter.finagle.postgres.messages

import com.twitter.finagle.postgres.values.Charsets

import io.netty.buffer.{ByteBuf, Unpooled}

object Packet {
  val INT_SIZE = 4
}


class PacketBuilder(val code: Option[Char]) {
  private val underlying = Unpooled.buffer()

  def writeByte(byte: Byte) = {
    underlying.writeByte(byte)
    this
  }

  def writeBytes(bytes: Array[Byte]) = {
	  underlying.writeBytes(bytes)
	  this
  }

  def writeBuf(bytes: ByteBuf) = {
	  underlying.writeBytes(bytes)
	  this
  }

  def writeChar(char: Char) = {
    underlying.writeByte(char)
    this
  }
  def writeInt(int: Int) = {
    underlying.writeInt(int)
    this
  }

  def writeShort(short: Short) = {
    underlying.writeShort(short)
    this
  }

  def writeCString(str: String) = {
    underlying.writeBytes(str.getBytes(Charsets.Utf8))
    underlying.writeByte(0)
    this
  }

  def toPacket = new Packet(code, underlying.writerIndex(), underlying)
}

object PacketBuilder {
  def apply(): PacketBuilder = new PacketBuilder(None)

  def apply(code: Char): PacketBuilder = new PacketBuilder(Some(code))
} 
Example 2
Source File: OneWayMessage.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.transport.message

import com.google.common.base.{MoreObjects, Objects}
import io.netty.buffer.ByteBuf

class OneWayMessage(private val message: ByteBuf) extends RequestMessage {
  
  override def encode(buf: ByteBuf): Unit = {
    // See comment in encodedLength().
    buf.writeInt(body.readableBytes())
  }

  override def hashCode: Int = Objects.hashCode(body)

  override def equals(other: Any): Boolean = {
    other match {
      case o: OneWayMessage =>
        return super.equals(o)
      case _ =>
    }
    false
  }

  override def toString: String =
    MoreObjects.toStringHelper(this).add("body", body).toString
}

object OneWayMessage {
  def decode(buf: ByteBuf): OneWayMessage = {
    // See comment in encodedLength().
    buf.readInt
    new OneWayMessage(buf.retain)
  }
} 
Example 3
Source File: FinaglePostgresDecoders.scala    From quill   with Apache License 2.0 5 votes vote down vote up
package io.getquill.context.finagle.postgres

import java.nio.charset.Charset
import java.time.{ LocalDate, LocalDateTime, ZoneId }
import java.util.{ Date, UUID }

import com.twitter.finagle.postgres.values.ValueDecoder
import com.twitter.util.Return
import com.twitter.util.Throw
import com.twitter.util.Try
import io.getquill.FinaglePostgresContext
import io.getquill.util.Messages.fail
import io.netty.buffer.ByteBuf

trait FinaglePostgresDecoders {
  this: FinaglePostgresContext[_] =>

  import ValueDecoder._

  type Decoder[T] = FinaglePostgresDecoder[T]

  case class FinaglePostgresDecoder[T](
    vd:      ValueDecoder[T],
    default: Throwable => T  = (e: Throwable) => fail(e.getMessage)
  ) extends BaseDecoder[T] {
    override def apply(index: Index, row: ResultRow): T =
      row.getTry[T](index)(vd) match {
        case Return(r) => r
        case Throw(e)  => default(e)
      }

    def orElse[U](f: U => T)(implicit vdu: ValueDecoder[U]): FinaglePostgresDecoder[T] = {
      val mappedVd = vdu.map[T](f)
      FinaglePostgresDecoder[T](
        new ValueDecoder[T] {
          def decodeText(recv: String, text: String): Try[T] = {
            val t = vd.decodeText(recv, text)
            if (t.isReturn) t
            else mappedVd.decodeText(recv, text)
          }
          def decodeBinary(recv: String, bytes: ByteBuf, charset: Charset): Try[T] = {
            val t = vd.decodeBinary(recv, bytes, charset)
            if (t.isReturn) t
            else mappedVd.decodeBinary(recv, bytes, charset)
          }
        }
      )
    }
  }

  implicit def decoderDirectly[T](implicit vd: ValueDecoder[T]): Decoder[T] = FinaglePostgresDecoder(vd)
  def decoderMapped[U, T](f: U => T)(implicit vd: ValueDecoder[U]): Decoder[T] = FinaglePostgresDecoder(vd.map[T](f))

  implicit def optionDecoder[T](implicit d: Decoder[T]): Decoder[Option[T]] =
    FinaglePostgresDecoder[Option[T]](
      new ValueDecoder[Option[T]] {
        def decodeText(recv: String, text: String): Try[Option[T]] = Return(d.vd.decodeText(recv, text).toOption)
        def decodeBinary(recv: String, bytes: ByteBuf, charset: Charset): Try[Option[T]] = Return(d.vd.decodeBinary(recv, bytes, charset).toOption)
      },
      _ => None
    )

  implicit def mappedDecoder[I, O](implicit mapped: MappedEncoding[I, O], d: Decoder[I]): Decoder[O] =
    decoderMapped[I, O](mapped.f)(d.vd)

  implicit val stringDecoder: Decoder[String] = decoderDirectly[String]
  implicit val bigDecimalDecoder: Decoder[BigDecimal] = decoderDirectly[BigDecimal]
  implicit val booleanDecoder: Decoder[Boolean] = decoderDirectly[Boolean]
  implicit val shortDecoder: Decoder[Short] = decoderDirectly[Short]
  implicit val byteDecoder: Decoder[Byte] = decoderMapped[Short, Byte](_.toByte)
  implicit val intDecoder: Decoder[Int] = decoderDirectly[Int].orElse[Long](_.toInt)
  implicit val longDecoder: Decoder[Long] = decoderDirectly[Long].orElse[Int](_.toLong)
  implicit val floatDecoder: Decoder[Float] = decoderDirectly[Float].orElse[Double](_.toFloat)
  implicit val doubleDecoder: Decoder[Double] = decoderDirectly[Double]
  implicit val byteArrayDecoder: Decoder[Array[Byte]] = decoderDirectly[Array[Byte]]
  implicit val dateDecoder: Decoder[Date] = decoderMapped[LocalDateTime, Date](d => Date.from(d.atZone(ZoneId.systemDefault()).toInstant))
  implicit val localDateDecoder: Decoder[LocalDate] = decoderDirectly[LocalDate].orElse[LocalDateTime](_.toLocalDate)
  implicit val localDateTimeDecoder: Decoder[LocalDateTime] = decoderDirectly[LocalDateTime].orElse[LocalDate](_.atStartOfDay)
  implicit val uuidDecoder: Decoder[UUID] = decoderDirectly[UUID]
} 
Example 4
Source File: ChannelStatisticsHandler.scala    From Neutrino   with Apache License 2.0 5 votes vote down vote up
package com.ebay.neutrino.handler.ops

import java.util.concurrent.atomic.{AtomicInteger, AtomicLong}

import com.ebay.neutrino.metrics.Instrumented
import com.typesafe.scalalogging.slf4j.StrictLogging
import io.netty.buffer.{ByteBuf, ByteBufHolder}
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel._
import scala.concurrent.duration._



@Sharable
class ChannelStatisticsHandler(upstream: Boolean) extends ChannelDuplexHandler with StrictLogging with Instrumented
{
  import com.ebay.neutrino.util.AttributeSupport._
  import com.ebay.neutrino.util.Utilities.AtomicLongSupport
  import com.ebay.neutrino.metrics.Metrics._

  // Global statistics
  val readBytes    = if (upstream) UpstreamBytesRead else DownstreamBytesRead
  val writeBytes   = if (upstream) UpstreamBytesWrite else DownstreamBytesWrite
  val readPackets  = if (upstream) UpstreamPacketsRead else DownstreamPacketsRead
  val writePackets = if (upstream) UpstreamPacketsWrite else DownstreamPacketsWrite


  @inline def calculateSize(msg: AnyRef) = msg match {
    case data: ByteBuf => data.readableBytes()
    case data: ByteBufHolder => data.content.readableBytes
    case data => 0
  }


  // Log to global (and local) statistics
  override def channelRead(ctx: ChannelHandlerContext, msg: AnyRef): Unit = {
    val bytes = calculateSize(msg)

    readPackets.mark
    readBytes += bytes
    ctx.statistics.readPackets += 1
    ctx.statistics.readBytes += bytes

    ctx.fireChannelRead(msg)
  }


  override def write(ctx: ChannelHandlerContext, msg: AnyRef, promise: ChannelPromise): Unit = {
    val bytes = calculateSize(msg)

    writePackets.mark
    writeBytes += bytes
    ctx.statistics.writePackets += 1
    ctx.statistics.writeBytes += bytes

    ctx.write(msg, promise)
  }
}

class ChannelStatistics {

  // Collected traffic statistics
  val readBytes     = new AtomicLong()
  val writeBytes    = new AtomicLong()
  val readPackets   = new AtomicLong()
  val writePackets  = new AtomicLong()

  // Channel usage statistics
  val startTime     = System.nanoTime()
  val allocations   = new AtomicInteger()

  // Request statistics
  val requestCount  = new AtomicInteger()
  val responseCount = new AtomicInteger()

  // Helper methods
  def elapsed       = (System.nanoTime()-startTime).nanos
} 
Example 5
Source File: AsyncHttpClientScalazBackend.scala    From sttp   with Apache License 2.0 5 votes vote down vote up
package sttp.client.asynchttpclient.scalaz

import java.nio.ByteBuffer

import io.netty.buffer.ByteBuf
import org.asynchttpclient.{
  AsyncHttpClient,
  AsyncHttpClientConfig,
  BoundRequestBuilder,
  DefaultAsyncHttpClient,
  DefaultAsyncHttpClientConfig
}
import org.reactivestreams.Publisher
import scalaz.concurrent.Task
import sttp.client.asynchttpclient.{AsyncHttpClientBackend, WebSocketHandler}
import sttp.client.impl.scalaz.TaskMonadAsyncError
import sttp.client.testing.SttpBackendStub
import sttp.client.{FollowRedirectsBackend, SttpBackend, SttpBackendOptions}

class AsyncHttpClientScalazBackend private (
    asyncHttpClient: AsyncHttpClient,
    closeClient: Boolean,
    customizeRequest: BoundRequestBuilder => BoundRequestBuilder
) extends AsyncHttpClientBackend[Task, Nothing](asyncHttpClient, TaskMonadAsyncError, closeClient, customizeRequest) {
  override protected def streamBodyToPublisher(s: Nothing): Publisher[ByteBuf] =
    s // nothing is everything

  override protected def publisherToStreamBody(p: Publisher[ByteBuffer]): Nothing =
    throw new IllegalStateException("This backend does not support streaming")
}

object AsyncHttpClientScalazBackend {
  private def apply(
      asyncHttpClient: AsyncHttpClient,
      closeClient: Boolean,
      customizeRequest: BoundRequestBuilder => BoundRequestBuilder
  ): SttpBackend[Task, Nothing, WebSocketHandler] =
    new FollowRedirectsBackend[Task, Nothing, WebSocketHandler](
      new AsyncHttpClientScalazBackend(asyncHttpClient, closeClient, customizeRequest)
    )

  def apply(
      options: SttpBackendOptions = SttpBackendOptions.Default,
      customizeRequest: BoundRequestBuilder => BoundRequestBuilder = identity
  ): Task[SttpBackend[Task, Nothing, WebSocketHandler]] =
    Task.delay(
      AsyncHttpClientScalazBackend(AsyncHttpClientBackend.defaultClient(options), closeClient = true, customizeRequest)
    )

  def usingConfig(
      cfg: AsyncHttpClientConfig,
      customizeRequest: BoundRequestBuilder => BoundRequestBuilder = identity
  ): Task[SttpBackend[Task, Nothing, WebSocketHandler]] =
    Task.delay(AsyncHttpClientScalazBackend(new DefaultAsyncHttpClient(cfg), closeClient = true, customizeRequest))

  
  def stub: SttpBackendStub[Task, Nothing, WebSocketHandler] = SttpBackendStub(TaskMonadAsyncError)
} 
Example 6
Source File: AsyncHttpClientFs2Backend.scala    From sttp   with Apache License 2.0 5 votes vote down vote up
package sttp.client.asynchttpclient.fs2

import java.io.File
import java.nio.ByteBuffer

import cats.effect._
import cats.effect.implicits._
import cats.implicits._
import fs2.{Chunk, Stream}
import fs2.interop.reactivestreams._
import io.netty.buffer.{ByteBuf, Unpooled}
import org.asynchttpclient.{Request => _, Response => _, _}
import org.reactivestreams.Publisher
import sttp.client.asynchttpclient.{AsyncHttpClientBackend, WebSocketHandler}
import sttp.client.impl.cats.CatsMonadAsyncError
import sttp.client.internal._
import sttp.client.testing.SttpBackendStub
import sttp.client.ws.WebSocketResponse
import sttp.client.{FollowRedirectsBackend, SttpBackend, SttpBackendOptions, _}

import scala.concurrent.ExecutionContext
import scala.language.higherKinds

class AsyncHttpClientFs2Backend[F[_]: ConcurrentEffect: ContextShift] private (
    asyncHttpClient: AsyncHttpClient,
    closeClient: Boolean,
    customizeRequest: BoundRequestBuilder => BoundRequestBuilder
) extends AsyncHttpClientBackend[F, Stream[F, Byte]](
      asyncHttpClient,
      new CatsMonadAsyncError,
      closeClient,
      customizeRequest
    ) {
  override def send[T](r: Request[T, Stream[F, Byte]]): F[Response[T]] = {
    super.send(r).guarantee(implicitly[ContextShift[F]].shift)
  }

  override def openWebsocket[T, WS_RESULT](
      r: Request[T, Stream[F, Byte]],
      handler: WebSocketHandler[WS_RESULT]
  ): F[WebSocketResponse[WS_RESULT]] = super.openWebsocket(r, handler).guarantee(ContextShift[F].shift)

  override protected def streamBodyToPublisher(s: Stream[F, Byte]): Publisher[ByteBuf] =
    s.chunks.map(c => Unpooled.wrappedBuffer(c.toArray)).toUnicastPublisher

  override protected def publisherToStreamBody(p: Publisher[ByteBuffer]): Stream[F, Byte] =
    p.toStream[F].flatMap(buf => Stream.chunk(Chunk.byteBuffer(buf)))

  override protected def publisherToBytes(p: Publisher[ByteBuffer]): F[Array[Byte]] = {
    p.toStream[F]
      .compile
      .fold(ByteBuffer.allocate(0))(concatByteBuffers)
      .map(_.array())
  }

  override protected def publisherToFile(p: Publisher[ByteBuffer], f: File): F[Unit] = {
    p.toStream[F]
      .flatMap(b => Stream.emits(b.array()))
      .through(fs2.io.file.writeAll(f.toPath, Blocker.liftExecutionContext(ExecutionContext.global)))
      .compile
      .drain
  }
}

object AsyncHttpClientFs2Backend {
  private def apply[F[_]: ConcurrentEffect: ContextShift](
      asyncHttpClient: AsyncHttpClient,
      closeClient: Boolean,
      customizeRequest: BoundRequestBuilder => BoundRequestBuilder
  ): SttpBackend[F, Stream[F, Byte], WebSocketHandler] =
    new FollowRedirectsBackend(new AsyncHttpClientFs2Backend(asyncHttpClient, closeClient, customizeRequest))

  def apply[F[_]: ConcurrentEffect: ContextShift](
      options: SttpBackendOptions = SttpBackendOptions.Default,
      customizeRequest: BoundRequestBuilder => BoundRequestBuilder = identity
  ): F[SttpBackend[F, Stream[F, Byte], WebSocketHandler]] =
    implicitly[Sync[F]]
      .delay(apply[F](AsyncHttpClientBackend.defaultClient(options), closeClient = true, customizeRequest))

  
  def stub[F[_]: Concurrent]: SttpBackendStub[F, Stream[F, ByteBuffer], WebSocketHandler] =
    SttpBackendStub(new CatsMonadAsyncError())
} 
Example 7
Source File: AsyncHttpClientFutureBackend.scala    From sttp   with Apache License 2.0 5 votes vote down vote up
package sttp.client.asynchttpclient.future

import java.nio.ByteBuffer

import io.netty.buffer.ByteBuf
import org.asynchttpclient.{
  AsyncHttpClient,
  AsyncHttpClientConfig,
  BoundRequestBuilder,
  DefaultAsyncHttpClient,
  DefaultAsyncHttpClientConfig
}
import org.reactivestreams.Publisher
import sttp.client.asynchttpclient.{AsyncHttpClientBackend, WebSocketHandler}
import sttp.client.monad.FutureMonad
import sttp.client.testing.SttpBackendStub
import sttp.client.{FollowRedirectsBackend, SttpBackend, SttpBackendOptions}

import scala.concurrent.{ExecutionContext, Future}

class AsyncHttpClientFutureBackend private (
    asyncHttpClient: AsyncHttpClient,
    closeClient: Boolean,
    customizeRequest: BoundRequestBuilder => BoundRequestBuilder
)(implicit
    ec: ExecutionContext
) extends AsyncHttpClientBackend[Future, Nothing](asyncHttpClient, new FutureMonad, closeClient, customizeRequest) {
  override protected def streamBodyToPublisher(s: Nothing): Publisher[ByteBuf] =
    s // nothing is everything

  override protected def publisherToStreamBody(p: Publisher[ByteBuffer]): Nothing =
    throw new IllegalStateException("This backend does not support streaming")
}

object AsyncHttpClientFutureBackend {
  private def apply(
      asyncHttpClient: AsyncHttpClient,
      closeClient: Boolean,
      customizeRequest: BoundRequestBuilder => BoundRequestBuilder
  )(implicit
      ec: ExecutionContext
  ): SttpBackend[Future, Nothing, WebSocketHandler] =
    new FollowRedirectsBackend[Future, Nothing, WebSocketHandler](
      new AsyncHttpClientFutureBackend(asyncHttpClient, closeClient, customizeRequest)
    )

  
  def stub(implicit
      ec: ExecutionContext = ExecutionContext.global
  ): SttpBackendStub[Future, Nothing, WebSocketHandler] =
    SttpBackendStub(new FutureMonad())
} 
Example 8
Source File: Handshake.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.net.{InetAddress, InetSocketAddress}

import com.google.common.base.Charsets
import io.netty.buffer.ByteBuf
import com.wavesplatform.utils._

case class Handshake(applicationName: String,
                     applicationVersion: (Int, Int, Int),
                     nodeName: String,
                     nodeNonce: Long,
                     declaredAddress: Option[InetSocketAddress]) {
  def encode(out: ByteBuf): out.type = {
    val applicationNameBytes = applicationName.utf8Bytes
    require(applicationNameBytes.length <= Byte.MaxValue, "The application name is too long!")
    out.writeByte(applicationNameBytes.length)
    out.writeBytes(applicationNameBytes)

    out.writeInt(applicationVersion._1)
    out.writeInt(applicationVersion._2)
    out.writeInt(applicationVersion._3)

    val nodeNameBytes = nodeName.utf8Bytes
    require(nodeNameBytes.length <= Byte.MaxValue, "A node name is too long!")
    out.writeByte(nodeNameBytes.length)
    out.writeBytes(nodeNameBytes)

    out.writeLong(nodeNonce)

    val peer = for {
      inetAddress <- declaredAddress
      address     <- Option(inetAddress.getAddress)
    } yield (address.getAddress, inetAddress.getPort)

    peer match {
      case None => out.writeInt(0)
      case Some((addressBytes, peerPort)) =>
        out.writeInt(addressBytes.length + Integer.BYTES)
        out.writeBytes(addressBytes)
        out.writeInt(peerPort)
    }

    out.writeLong(System.currentTimeMillis() / 1000)
    out
  }
}

object Handshake {
  class InvalidHandshakeException(msg: String) extends IllegalArgumentException(msg)

  def decode(in: ByteBuf): Handshake = {
    val appNameSize = in.readByte()

    if (appNameSize < 0 || appNameSize > Byte.MaxValue) {
      throw new InvalidHandshakeException(s"An invalid application name's size: $appNameSize")
    }
    val appName    = in.readSlice(appNameSize).toString(Charsets.UTF_8)
    val appVersion = (in.readInt(), in.readInt(), in.readInt())

    val nodeNameSize = in.readByte()
    if (nodeNameSize < 0 || nodeNameSize > Byte.MaxValue) {
      throw new InvalidHandshakeException(s"An invalid node name's size: $nodeNameSize")
    }
    val nodeName = in.readSlice(nodeNameSize).toString(Charsets.UTF_8)

    val nonce = in.readLong()

    val declaredAddressLength = in.readInt()
    // 0 for no declared address, 8 for ipv4 address + port, 20 for ipv6 address + port
    if (declaredAddressLength != 0 && declaredAddressLength != 8 && declaredAddressLength != 20) {
      throw new InvalidHandshakeException(s"An invalid declared address length: $declaredAddressLength")
    }
    val isa =
      if (declaredAddressLength == 0) None
      else {
        val addressBytes = new Array[Byte](declaredAddressLength - Integer.BYTES)
        in.readBytes(addressBytes)
        val address = InetAddress.getByAddress(addressBytes)
        val port    = in.readInt()
        Some(new InetSocketAddress(address, port))
      }
    in.readLong() // time is ignored

    Handshake(appName, appVersion, nodeName, nonce, isa)
  }
} 
Example 9
Source File: LegacyFrameCodec.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.util

import com.google.common.cache.CacheBuilder
import com.wavesplatform.block.Block
import com.wavesplatform.common.utils.Base64
import com.wavesplatform.crypto
import com.wavesplatform.network.message.Message._
import com.wavesplatform.transaction.Transaction
import com.wavesplatform.utils.ScorexLogging
import io.netty.buffer.ByteBuf
import io.netty.buffer.Unpooled._
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.{ByteToMessageCodec, DecoderException}

import scala.concurrent.duration.FiniteDuration
import scala.util.control.NonFatal

class LegacyFrameCodec(peerDatabase: PeerDatabase, receivedTxsCacheTimeout: FiniteDuration) extends ByteToMessageCodec[Any] with ScorexLogging {

  import BasicMessagesRepo.specsByCodes
  import LegacyFrameCodec._

  private val receivedTxsCache = CacheBuilder
    .newBuilder()
    .expireAfterWrite(receivedTxsCacheTimeout.length, receivedTxsCacheTimeout.unit)
    .build[String, Object]()

  override def exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable): Unit = cause match {
    case e: DecoderException => peerDatabase.blacklistAndClose(ctx.channel(), s"Corrupted message frame: $e")
    case _                   => super.exceptionCaught(ctx, cause)
  }

  override def decode(ctx: ChannelHandlerContext, in: ByteBuf, out: util.List[AnyRef]): Unit =
    try {
      require(in.readInt() == Magic, "invalid magic number")

      val code = in.readByte()
      require(specsByCodes.contains(code), s"Unexpected message code $code")

      val spec   = specsByCodes(code)
      val length = in.readInt()
      require(length <= spec.maxLength, s"${spec.messageName} message length $length exceeds ${spec.maxLength}")

      val dataBytes = new Array[Byte](length)
      val pushToPipeline = length == 0 || {
        val declaredChecksum = in.readSlice(ChecksumLength)
        in.readBytes(dataBytes)
        val rawChecksum    = crypto.fastHash(dataBytes)
        val actualChecksum = wrappedBuffer(rawChecksum, 0, ChecksumLength)

        require(declaredChecksum.equals(actualChecksum), "invalid checksum")
        actualChecksum.release()

        spec != TransactionSpec || {
          val actualChecksumStr = Base64.encode(rawChecksum)
          if (receivedTxsCache.getIfPresent(actualChecksumStr) == null) {
            receivedTxsCache.put(actualChecksumStr, LegacyFrameCodec.dummy)
            true
          } else false
        }
      }

      if (pushToPipeline) out.add(RawBytes(code, dataBytes))
    } catch {
      case NonFatal(e) =>
        log.warn(s"${id(ctx)} Malformed network message", e)
        peerDatabase.blacklistAndClose(ctx.channel(), s"Malformed network message: $e")
        in.resetReaderIndex() // Cancels subsequent read tries, see Netty decode() documentation
    }

  override def encode(ctx: ChannelHandlerContext, msg1: Any, out: ByteBuf): Unit = {
    val msg = msg1 match {
      case rb: RawBytes           => rb
      case tx: Transaction        => RawBytes.fromTransaction(tx)
      case block: Block           => RawBytes.fromBlock(block)
      case mb: MicroBlockResponse => RawBytes.fromMicroBlock(mb)
    }

    out.writeInt(Magic)
    out.writeByte(msg.code)
    if (msg.data.length > 0) {
      out.writeInt(msg.data.length)
      out.writeBytes(crypto.fastHash(msg.data), 0, ChecksumLength)
      out.writeBytes(msg.data)
    } else {
      out.writeInt(0)
    }
  }
}

object LegacyFrameCodec {
  val Magic         = 0x12345678
  private val dummy = new Object()
} 
Example 10
Source File: ClientSpec.scala    From Waves   with MIT License 5 votes vote down vote up
package com.wavesplatform.network

import java.util.concurrent.ConcurrentHashMap

import com.wavesplatform.{TransactionGen, Version}
import io.netty.buffer.{ByteBuf, Unpooled}
import io.netty.channel.Channel
import io.netty.channel.embedded.EmbeddedChannel
import io.netty.channel.group.ChannelGroup
import org.scalamock.scalatest.MockFactory
import org.scalatest.{FreeSpec, Matchers}

import scala.concurrent.duration.DurationInt
import scala.util.Random

class ClientSpec extends FreeSpec with Matchers with MockFactory with TransactionGen {

  private val clientHandshake = new Handshake(
    applicationName = "wavesI",
    applicationVersion = Version.VersionTuple,
    nodeName = "test",
    nodeNonce = Random.nextInt(),
    declaredAddress = None
  )

  private val serverHandshake = clientHandshake.copy(nodeNonce = Random.nextInt())

  "should send only a local handshake on connection" in {
    val channel = createEmbeddedChannel(mock[ChannelGroup])

    val sentClientHandshakeBuff = channel.readOutbound[ByteBuf]()
    Handshake.decode(sentClientHandshakeBuff) shouldBe clientHandshake
    channel.outboundMessages() shouldBe empty
  }

  "should add a server's channel to all channels after the handshake only" in {
    var channelWasAdded = false
    val allChannels     = mock[ChannelGroup]
    (allChannels.add _).expects(*).onCall { _: Channel =>
      channelWasAdded = true
      true
    }

    val channel = createEmbeddedChannel(allChannels)

    // skip the client's handshake
    channel.readOutbound[ByteBuf]()
    channelWasAdded shouldBe false

    val replyServerHandshakeBuff = Unpooled.buffer()
    serverHandshake.encode(replyServerHandshakeBuff)
    channel.writeInbound(replyServerHandshakeBuff)
    channelWasAdded shouldBe true
  }

  private def createEmbeddedChannel(allChannels: ChannelGroup) = new EmbeddedChannel(
    new HandshakeDecoder(PeerDatabase.NoOp),
    new HandshakeTimeoutHandler(1.minute),
    new HandshakeHandler.Client(
      handshake = clientHandshake,
      establishedConnections = new ConcurrentHashMap(),
      peerConnections = new ConcurrentHashMap(),
      peerDatabase = PeerDatabase.NoOp,
      allChannels = allChannels
    )
  )

} 
Example 11
Source File: example.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.example

import com.google.common.base.Charsets
import io.netty.buffer.{ByteBuf, Unpooled}
import me.jrwang.aloha.common.{AlohaConf, Logging}
import me.jrwang.aloha.transport.client.{RpcResponseCallback, TransportClient}
import me.jrwang.aloha.transport.server.RpcHandler
import me.jrwang.aloha.transport.{AlohaTransportConf, TransportContext}

object SimpleAlohaServer extends Logging {
  def main(args: Array[String]): Unit = {
    val transportConf = AlohaTransportConf.fromAlohaConf(new AlohaConf(), "rpc")
    val rpcHandler = new RpcHandler {
      override def receive(client: TransportClient, message: ByteBuf, callback: RpcResponseCallback): Unit = {
        logInfo(s"server receive ${message.toString(Charsets.UTF_8)}")
        callback.onSuccess(Unpooled.wrappedBuffer("hello".getBytes))
      }

      override def channelActive(client: TransportClient): Unit = {
        logInfo("server channel active")
      }

      override def channelInactive(client: TransportClient): Unit = {
        logInfo("server channel inactive")
      }

      override def exceptionCaught(cause: Throwable, client: TransportClient): Unit = {
        logInfo(s"server exception$cause")
      }
    }

    new TransportContext(transportConf, rpcHandler)
      .createServer("localhost", 9999)
      .awaitTermination()
  }
}

object SimpleAlohaClient extends Logging {
  def main(args: Array[String]): Unit = {
    val transportConf = AlohaTransportConf.fromAlohaConf(new AlohaConf(), "rpc")
    val rpcHandler = new RpcHandler {
      override def receive(client: TransportClient, message: ByteBuf, callback: RpcResponseCallback): Unit = {
        logInfo(s"client receive ${message.toString(Charsets.UTF_8)}")
        callback.onSuccess(Unpooled.wrappedBuffer("hello".getBytes))
      }

      override def channelActive(client: TransportClient): Unit = {
        logInfo("client channel active")
      }

      override def channelInactive(client: TransportClient): Unit = {
        logInfo("client channel inactive")
      }

      override def exceptionCaught(cause: Throwable, client: TransportClient): Unit = {
        logInfo(s"client exception$cause")
      }
    }

    val client = new TransportContext(transportConf, rpcHandler).createClientFactory()
      .createClient("localhost", 9999)

    client.sendRpc(Unpooled.wrappedBuffer("hello world.".getBytes), new RpcResponseCallback {
      override def onSuccess(response: ByteBuf): Unit = {
        logInfo(s"rpc request success with ${response.toString(Charsets.UTF_8)}")
      }

      override def onFailure(e: Throwable): Unit = {
        logInfo(s"rpc request failed $e")
      }
    })

    client.channel.closeFuture().sync()
  }
} 
Example 12
Source File: RpcRequest.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.transport.message

import com.google.common.base.{MoreObjects, Objects}
import io.netty.buffer.ByteBuf
import me.jrwang.aloha.transport.server.RpcHandler


  override def isBodyInFrame: Boolean = true

  override def encodeLength: Int = {
    // The integer (a.k.a. the body size) is not really used, since that information is already
    // encoded in the frame length. But this maintains backwards compatibility with versions of
    // RpcRequest that use Encoders.ByteArrays.
    8 + 4
  }

  override def encode(buf: ByteBuf): Unit = {
    buf.writeLong(requestId)
    // See comment in encodedLength().
    buf.writeInt(body.readableBytes())
  }

  override def hashCode: Int = Objects.hashCode(requestId.asInstanceOf[AnyRef], body)

  override def equals(other: Any): Boolean = {
    other match {
      case o: RpcRequest =>
        return requestId == o.requestId && super.equals(o)
      case _ =>
    }
    false
  }

  override def toString: String = MoreObjects.toStringHelper(this)
    .add("requestId", requestId)
    .add("body", body)
    .toString
}

object RpcRequest {
  def decode(buf: ByteBuf): RpcRequest = {
    val requestId = buf.readLong()
    // See comment in encodedLength().
    buf.readInt()
    new RpcRequest(requestId, buf.retain())
  }
} 
Example 13
Source File: RpcResponse.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.transport.message

import com.google.common.base.{MoreObjects, Objects}
import io.netty.buffer.ByteBuf


class RpcResponse(val requestId: Long, private val message: ByteBuf) extends ResponseMessage  {
  
  override def isBodyInFrame: Boolean = true

  override def encodeLength: Int = {
    // The integer (a.k.a. the body size) is not really used, since that information is already
    // encoded in the frame length. But this maintains backwards compatibility with versions of
    // RpcRequest that use Encoders.ByteArrays.
    8 + 4
  }

  override def encode(buf: ByteBuf): Unit = {
    buf.writeLong(requestId)
    // See comment in encodedLength().
    buf.writeInt(body.readableBytes())
  }

  override def hashCode: Int = Objects.hashCode(requestId.asInstanceOf[AnyRef], body)

  override def equals(other: Any): Boolean = {
    other match {
      case o: RpcResponse =>
        return requestId == o.requestId && super.equals(o)
      case _ =>
    }
    false
  }

  override def toString: String = MoreObjects.toStringHelper(this)
    .add("requestId", requestId)
    .add("body", body)
    .toString
}

object RpcResponse {
  def decode(buf: ByteBuf): RpcResponse = {
    val requestId = buf.readLong()
    // See comment in encodedLength().
    buf.readInt()
    new RpcResponse(requestId, buf.retain())
  }
} 
Example 14
Source File: BootstrapClientWithOptionsAndAttrs.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.Bootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelOption
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioSocketChannel
import io.netty.util.AttributeKey
import java.net.InetSocketAddress
import java.lang.{ Boolean ⇒ JBoolean }


  def bootstrap(): Unit = { //创建一个 AttributeKey 以标识该属性
    val id: AttributeKey[Integer] = AttributeKey.newInstance("ID")
    //创建一个 Bootstrap 类的实例以创建客户端 Channel 并连接它们
    val bootstrap = new Bootstrap
    //设置 EventLoopGroup,其提供了用以处理 Channel 事件的 EventLoop
    bootstrap.group(new NioEventLoopGroup)
      .channel(classOf[NioSocketChannel])
      .handler(new SimpleChannelInboundHandler[ByteBuf]() {
        @throws[Exception]
        override def channelRegistered(ctx: ChannelHandlerContext): Unit = { //使用 AttributeKey 检索属性以及它的值
          val idValue = ctx.channel.attr(id).get
          // do something with the idValue
        }

        @throws[Exception]
        override protected def channelRead0(channelHandlerContext: ChannelHandlerContext, byteBuf: ByteBuf): Unit = {
          System.out.println("Received data")
        }
      })

    //设置 ChannelOption,其将在 connect()或者bind()方法被调用时被设置到已经创建的 Channel 上
    bootstrap
      .option[JBoolean](ChannelOption.SO_KEEPALIVE, true)
      .option[Integer](ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)

    //存储该 id 属性
    bootstrap.attr[Integer](id, 123456)

    //使用配置好的 Bootstrap 实例连接到远程主机
    val future = bootstrap.connect(new InetSocketAddress("www.manning.com", 80))
    future.syncUninterruptibly
  }
} 
Example 15
Source File: Encoders.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.transport.message

import java.nio.charset.StandardCharsets

import io.netty.buffer.ByteBuf


object Encoders {
  object Strings {
    def encodedLength(s: String): Int = 4 + s.getBytes(StandardCharsets.UTF_8).length

    def encode(buf: ByteBuf, s: String): Unit = {
      val bytes = s.getBytes(StandardCharsets.UTF_8)
      buf.writeInt(bytes.length)
      buf.writeBytes(bytes)
    }

    def decode(buf: ByteBuf): String = {
      val length = buf.readInt
      val bytes = new Array[Byte](length)
      buf.readBytes(bytes)
      new String(bytes, StandardCharsets.UTF_8)
    }
  }
} 
Example 16
Source File: MessageDecoder.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.transport.message

import java.util

import io.netty.buffer.ByteBuf
import io.netty.channel.{ChannelHandler, ChannelHandlerContext}
import io.netty.handler.codec.MessageToMessageDecoder
import me.jrwang.aloha.common.Logging

@ChannelHandler.Sharable
object MessageDecoder extends MessageToMessageDecoder[ByteBuf] with Logging {

  //Be aware that you need to call {@link ReferenceCounted#retain()} on messages
  //that are just passed through if they are of type {@link ReferenceCounted}.
  //This is needed as the {@link MessageToMessageDecoder} will call
  //{@link ReferenceCounted#release()} on decoded messages.
  override def decode(ctx: ChannelHandlerContext, msg: ByteBuf, out: util.List[AnyRef]): Unit = {
    val msgType = MessageType.decode(msg)
    val decodedMsg = decode(msgType, msg)
    require(msgType == decodedMsg.`type`)
    logTrace(s"Received message ${msgType}: ${decodedMsg}")
    out.add(decodedMsg)
  }

  private def decode(msgType: MessageType, in: ByteBuf) = msgType match {
    case MessageType.RpcRequest =>
      RpcRequest.decode(in)
    case MessageType.RpcResponse =>
      RpcResponse.decode(in)
    case MessageType.RpcFailure =>
      RpcFailure.decode(in)
    case MessageType.OneWayMessage =>
      OneWayMessage.decode(in)
    case _ =>
      throw new IllegalArgumentException("Unexpected message type: " + msgType)
  }
} 
Example 17
Source File: RpcFailure.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.transport.message

import com.google.common.base.{MoreObjects, Objects}
import io.netty.buffer.ByteBuf

class RpcFailure(val requestId: Long, val errorString: String) extends ResponseMessage {
  
  override def isBodyInFrame: Boolean = false

  override def encodeLength: Int = {
    8 + Encoders.Strings.encodedLength(errorString)
  }

  override def encode(buf: ByteBuf): Unit = {
    buf.writeLong(requestId)
    Encoders.Strings.encode(buf, errorString)
  }

  override def hashCode: Int =
    Objects.hashCode(requestId.asInstanceOf[AnyRef], errorString)

  override def equals(other: Any): Boolean = {
    other match {
      case o: RpcFailure =>
        return requestId == o.requestId && errorString == o.errorString
      case _ =>
    }
    false
  }

  override def toString: String = {
    MoreObjects.toStringHelper(this)
      .add("requestId", requestId)
      .add("errorString", errorString)
      .toString
  }
}

object RpcFailure {
  def decode(buf: ByteBuf): RpcFailure = {
    val requestId = buf.readLong
    val errorString = Encoders.Strings.decode(buf)
    new RpcFailure(requestId, errorString)
  }
} 
Example 18
Source File: Message.scala    From aloha   with Apache License 2.0 5 votes vote down vote up
package me.jrwang.aloha.transport.message

import io.netty.buffer.ByteBuf


trait Encodable {
  //Number of bytes encoding this object.
  def encodeLength: Int

  //Serializing this object by writing to ByteBuf.
  //This method must write exactly encodeLength bytes.
  def encode(buf: ByteBuf): Unit
}

trait Message extends Encodable {
  
  def isBodyInFrame: Boolean
}

sealed abstract class MessageType(val id: Byte)
    extends Encodable with Ordered[MessageType] {
  override def encodeLength: Int = 1

  override def encode(buf: ByteBuf): Unit = buf.writeByte(id)

  override def compare(that: MessageType): Int = this.id - that.id
}

object MessageType {
  def decode(buf: ByteBuf): MessageType = {
    buf.readByte() match {
      case 0 => RpcRequest
      case 1 => RpcResponse
      case 2 => RpcFailure
      case 3 => OneWayMessage
      case t => UnknownMessageType(t)
    }
  }

  case object RpcRequest extends MessageType(0)
  case object RpcResponse extends MessageType(1)
  case object RpcFailure extends MessageType(2)
  case object OneWayMessage extends MessageType(3)
  case class UnknownMessageType(override val id: Byte) extends MessageType(id)
}

trait RequestMessage extends Message {
}

trait ResponseMessage extends Message {
} 
Example 19
Source File: HandshakeResponse.scala    From asyncdb   with Apache License 2.0 5 votes vote down vote up
package io.asyncdb
package netty
package mysql
package protocol
package client

import io.netty.buffer.ByteBuf
import java.nio.charset.Charset
import shapeless._


case class HandshakeResponse(
  clientFlag: Int,
  maxPacketSize: Int,
  charset: Short,
  filter: Array[Byte],
  username: String,
  password: Array[Byte],
  database: Option[String],
  authMethod: String
) extends Message

object HandshakeResponse {

  def apply(init: server.HandshakeInit, config: MySQLSocketConfig) = {
    val cap = {
      val base = Cap.baseCap
      val withDatabase = config.database.fold(base)(_ => base + Cap.ConnectWithDB)
      withDatabase
    }
    val passBytes = config.password.fold(Array.empty[Byte])(p => Auth.nativePassword(init.authPluginData, p, CharsetMap.of(config.charset)))
    new HandshakeResponse(
      clientFlag = cap.mask,
      maxPacketSize = Packet.MaxSize,
      charset = config.charset,
      database = config.database,
      username = config.username,
      password = passBytes,
      authMethod = config.authMethod.getOrElse(init.authenticationMethod),
      filter = Array.fill(23)(0.toByte)
    )
  }

  import Encoder._

  implicit val handshakeResponseEncoder: Encoder[HandshakeResponse] =
    Encoder[HandshakeResponse] { data =>
      (intL4 :: intL4 :: uint1 :: bytes :: ntText :: lenencBytes :: ntText.? :: ntText).as[HandshakeResponse]
    }

} 
Example 20
Source File: OrError.scala    From asyncdb   with Apache License 2.0 5 votes vote down vote up
package io.asyncdb
package netty
package mysql
package protocol
package server

import io.netty.buffer.ByteBuf
import java.nio.charset.Charset

case class OrErr[R <: Message](value: Either[Err, R]) extends Message

object OrErr {
  implicit def resultOrErr[R <: Message](
    implicit ad: Decoder[R]
  ): Decoder[OrErr[R]] = new Decoder[OrErr[R]] {
    def decode(buf: ByteBuf, charset: Charset) = {
      val head = buf.getByte(buf.readerIndex())
      if (head.toByte == -1) {
        OrErr(Left(Err.errDecoder.decode(buf, charset)))
      } else {
        OrErr(Right(ad.decode(buf, charset)))
      }
    }
  }

} 
Example 21
Source File: package.scala    From asyncdb   with Apache License 2.0 5 votes vote down vote up
package io.asyncdb
package netty
package mysql

import io.netty.buffer.ByteBuf
import java.nio.charset.Charset
import shapeless._

package object protocol {
  implicit class ValueEncoderOps[A](val encoder: Encoder[A]) extends AnyVal {
    def ::[H](pre: Encoder[H]): Encoder[H :: A :: HNil] =
      new Encoder[H :: A :: HNil] {
        def encode(v: H :: A :: HNil, buf: ByteBuf, charset: Charset) = {
          val hv = v.head
          val av = v.tail.head
          pre.encode(hv, buf, charset)
          encoder.encode(av, buf, charset)
        }
      }
  }

  implicit class HListEncoderOps[L <: HList](val encoder: Encoder[L])
      extends AnyVal {
    def ::[H](pre: Encoder[H]): Encoder[H :: L] = new Encoder[H :: L] {
      def encode(v: H :: L, buf: ByteBuf, charset: Charset) = {
        pre.encode(v.head, buf, charset)
        encoder.encode(v.tail, buf, charset)
      }
    }
    def as[A](implicit gen: Generic.Aux[A, L]): Encoder[A] =
      encoder.contramap(l => gen.to(l))
  }

  implicit class ValueDecoderOps[A](val Decoder: Decoder[A]) extends AnyVal {
    def ::[H](pre: Decoder[H]): Decoder[H :: A :: HNil] =
      new Decoder[H :: A :: HNil] {
        def decode(buf: ByteBuf, charset: Charset) = {
          val h = pre.decode(buf, charset)
          val t = Decoder.decode(buf, charset)
          h :: t :: HNil
        }
      }
  }

  implicit class HListDecoderOps[L <: HList](val decoder: Decoder[L])
      extends AnyVal {
    def ::[H](pre: Decoder[H]): Decoder[H :: L] = new Decoder[H :: L] {
      def decode(buf: ByteBuf, charset: Charset) = {
        val h = pre.decode(buf, charset)
        val l = decoder.decode(buf, charset)
        h :: l
      }
    }
    def as[A](implicit gen: Generic.Aux[A, L]): Decoder[A] =
      decoder.map(l => gen.from(l))
  }
} 
Example 22
Source File: NEModelRandomize.scala    From sona   with Apache License 2.0 5 votes vote down vote up
package com.tencent.angel.sona.psf.embedding

import com.tencent.angel.PartitionKey
import com.tencent.angel.ml.math2.storage.IntFloatDenseVectorStorage
import com.tencent.angel.ml.matrix.psf.update.base.{PartitionUpdateParam, UpdateFunc, UpdateParam}
import com.tencent.angel.ps.storage.partition.RowBasedPartition
import com.tencent.angel.ps.storage.vector.ServerRowUtils
import com.tencent.angel.psagent.PSAgentContext
import io.netty.buffer.ByteBuf
import com.tencent.angel.sona.psf.embedding.NEModelRandomize.{RandomizePartitionUpdateParam, RandomizeUpdateParam}

import scala.collection.JavaConversions._
import scala.util.Random


class NEModelRandomize(param: RandomizeUpdateParam) extends UpdateFunc(param) {
  def this(matrixId: Int, partDim: Int, dimension: Int, order: Int, seed: Int) =
    this(new RandomizeUpdateParam(matrixId, partDim, dimension, order, seed))

  def this() = this(null)

  override def partitionUpdate(partParam: PartitionUpdateParam): Unit = {
    val part = psContext.getMatrixStorageManager.getPart(partParam.getMatrixId, partParam.getPartKey.getPartitionId).asInstanceOf[RowBasedPartition]
    if (part != null) {
      val ff = partParam.asInstanceOf[RandomizePartitionUpdateParam]
      update(part, partParam.getPartKey, ff.partDim, ff.dim, ff.order, ff.seed)
    }
  }

  private def update(part: RowBasedPartition, key: PartitionKey, partDim: Int, dim: Int, order: Int, seed: Int): Unit = {
    val startRow = key.getStartRow
    val endRow = key.getEndRow
    val rand = new Random(seed)
    (startRow until endRow).map(rowId =>
      (rowId, rand.nextInt)
    ).par.foreach { case (rowId, rowSeed) =>
      val rowRandom = new Random(rowSeed)
      val data = ServerRowUtils.getVector(part.getRow(rowId)).getStorage.asInstanceOf[IntFloatDenseVectorStorage].getValues
      if (order == 1)
        data.indices.foreach(data(_) = (rowRandom.nextFloat() - 0.5f) / dim)
      else {
        val nodeOccupied = 2 * partDim
        data.indices.foreach(i =>
          data(i) = if (i % nodeOccupied < partDim) (rowRandom.nextFloat() - 0.5f) / dim else 0.0f)
//          data(i) = if (i % nodeOccupied < partDim) 0.01f else 0.0f)
      }
    }
  }
}

object NEModelRandomize {

  class RandomizePartitionUpdateParam(matrixId: Int,
                                      partKey: PartitionKey,
                                      var partDim: Int,
                                      var dim: Int,
                                      var order: Int,
                                      var seed: Int)
    extends PartitionUpdateParam(matrixId, partKey) {
    def this() = this(-1, null, -1, -1, -1, -1)

    override def serialize(buf: ByteBuf): Unit = {
      super.serialize(buf)
      buf.writeInt(partDim)
      buf.writeInt(dim)
      buf.writeInt(order)
      buf.writeInt(seed)
    }

    override def deserialize(buf: ByteBuf): Unit = {
      super.deserialize(buf)
      this.partDim = buf.readInt()
      this.dim = buf.readInt()
      this.order = buf.readInt()
      this.seed = buf.readInt()
    }

    override def bufferLen: Int = super.bufferLen + 16
  }


  class RandomizeUpdateParam(matrixId: Int, partDim: Int, dim: Int, order: Int, seed: Int)
    extends UpdateParam(matrixId) {
    override def split: java.util.List[PartitionUpdateParam] = {
      PSAgentContext.get.getMatrixMetaManager.getPartitions(matrixId).map { part =>
        new RandomizePartitionUpdateParam(matrixId, part, partDim, dim, order, seed + part.getPartitionId)
      }
    }
  }

} 
Example 23
Source File: NEDot.scala    From sona   with Apache License 2.0 5 votes vote down vote up
package com.tencent.angel.sona.psf.embedding

import com.tencent.angel.ml.matrix.psf.get.base._
import com.tencent.angel.ps.storage.partition.RowBasedPartition
import io.netty.buffer.ByteBuf
import com.tencent.angel.sona.psf.embedding.NEDot.{DotPartitionResult, NEDotResult}

import scala.collection.JavaConversions._

abstract class NEDot(param: GetParam) extends GetFunc(param) {
  def this() = this(null)

  override def merge(partResults: java.util.List[PartitionGetResult]): GetResult = {
    if (partResults.size() == 0) null else {
      val arr = partResults.map(_.asInstanceOf[DotPartitionResult].getResult)
      val result: Array[Float] = arr.head
      arr.tail.foreach(other => other.indices.foreach(i => result(i) += other(i)))
      new NEDotResult(result)
    }
  }

  override def partitionGet(pParam: PartitionGetParam): PartitionGetResult = {
    val part = psContext.getMatrixStorageManager.getPart(pParam.getMatrixId, pParam.getPartKey.getPartitionId).asInstanceOf[RowBasedPartition]
    if (part == null) null else new DotPartitionResult(doProcess(part, pParam))
  }

  def doProcess(part: RowBasedPartition, pParam: PartitionGetParam): Array[Float]
}

object NEDot {

  class NEDotResult(val result: Array[Float]) extends GetResult

  class DotPartitionResult(private var result: Array[Float]) extends PartitionGetResult {
    def this() = this(null)

    def getResult: Array[Float] = result

    override def serialize(buf: ByteBuf) {
      buf.writeInt(result.length)
      result.foreach(buf.writeFloat)
    }

    override def deserialize(buf: ByteBuf) {
      val size = buf.readInt()
      result = new Array[Float](size)
      for (i <- result.indices) result(i) = buf.readFloat()
    }

    override def bufferLen(): Int = 4 + result.length * 4
  }

} 
Example 24
Source File: EmptyReSize.scala    From sona   with Apache License 2.0 5 votes vote down vote up
package com.tencent.angel.sona.psf.pagerank
import java.util

import com.tencent.angel.PartitionKey
import com.tencent.angel.ml.math2.vector.{IntFloatVector, LongFloatVector}
import com.tencent.angel.ml.matrix.psf.update.base.{PartitionUpdateParam, UpdateFunc, UpdateParam}
import com.tencent.angel.ps.storage.vector.{ServerLongFloatRow, ServerRowUtils}
import com.tencent.angel.psagent.PSAgentContext
import com.tencent.angel.sona.psf.pagerank.EmptyReSize.{EmptyReSizeParam, EmptyReSizePartParam}
import io.netty.buffer.ByteBuf

import scala.collection.JavaConversions._

class EmptyReSize(param: EmptyReSizeParam) extends UpdateFunc(param) {

  def this() = this(null)
  def this(matrixId: Int, rowId: Array[Int], sizes: Array[Int]) = this(new EmptyReSizeParam(matrixId, rowId, sizes))
  def this(matrixId: Int, rowId: Int, size: Int) = this(new EmptyReSizeParam(matrixId, Array(rowId), Array(size)))

  override def partitionUpdate(partParam: PartitionUpdateParam): Unit = {
    val param = partParam.asInstanceOf[EmptyReSizePartParam]
    param.rowIds.zip(param.sizes).foreach {
      case (rowId, size) =>
        val row = psContext.getMatrixStorageManager.getRow(param.getPartKey, rowId)
        val vector = ServerRowUtils.getVector(row.asInstanceOf[ServerLongFloatRow])
        println(s"rowId=${row.getRowId} vector.size()=${vector.getSize} size=${size}")
        vector match {
          case int: IntFloatVector =>
            int.setStorage(int.getStorage.emptySparse(size))
          case long: LongFloatVector =>
            long.setStorage(long.getStorage.emptySparse(size))
        }
        println(s"rowId=${row.getRowId} vector.size()=${vector.getSize} size=${size}")
    }
  }

}

object EmptyReSize {

  class EmptyReSizeParam(matrixId: Int, rowIds: Array[Int], sizes: Array[Int]) extends UpdateParam(matrixId) {
    override def split(): util.List[PartitionUpdateParam] = {
      val parts = PSAgentContext.get().getMatrixMetaManager.getPartitions(matrixId)
      parts.map(p => new EmptyReSizePartParam(matrixId, p, rowIds, sizes))
    }
  }

  class EmptyReSizePartParam(matrixId: Int, partKey: PartitionKey,
                             var rowIds: Array[Int], var sizes: Array[Int])
    extends PartitionUpdateParam(matrixId, partKey) {

    def this() = this(-1, null, null, null)

    override def serialize(buf: ByteBuf): Unit = {
      super.serialize(buf)
      buf.writeInt(rowIds.length)
      rowIds.foreach(buf.writeInt)
      sizes.foreach(buf.writeInt)
    }

    override def deserialize(buf: ByteBuf): Unit = {
      super.deserialize(buf)
      val len = buf.readInt()
      rowIds = Array.tabulate(len)(_ => buf.readInt)
      sizes = Array.tabulate(len)(_ => buf.readInt)
    }
  }

} 
Example 25
Source File: LINEInitFunc.scala    From sona   with Apache License 2.0 5 votes vote down vote up
package com.tencent.angel.sona.graph.embedding.line2

import java.util.UUID

import com.tencent.angel.ps.storage.matrix.{PSMatrixInit, ServerMatrix}
import com.tencent.angel.ps.storage.partition.RowBasedPartition
import com.tencent.angel.ps.storage.vector.ServerIntAnyRow
import io.netty.buffer.ByteBuf

import scala.collection.JavaConversions._
import scala.util.Random

class LINEInitFunc(var order:Int, var dim:Int) extends PSMatrixInit {

  def this() = this(-1, -1)

  override def init(psMatrix: ServerMatrix): Unit = {
    val parts = psMatrix.getPartitions.values()
    val seed = UUID.randomUUID().hashCode();
    val rand = new Random(seed)

    for(part <- parts) {
      val row: ServerIntAnyRow = part.asInstanceOf[RowBasedPartition].getRow(0).asInstanceOf[ServerIntAnyRow]
      println(s"random seed in init=${seed}")

      (row.getStartCol until row.getEndCol).map(colId => {
        val embedding = new Array[Float](dim)
        for (i <- 0 until dim) {
          embedding(i) = (rand.nextFloat() - 0.5f) / dim
        }
        if(order == 1) {
          row.set(colId.toInt, new LINENode(embedding, null))
        } else {
          row.set(colId.toInt, new LINENode(embedding, new Array[Float](dim)))
        }
      })
    }
  }

  override def serialize(output: ByteBuf): Unit = {
    output.writeInt(order)
    output.writeInt(dim)
  }

  override def deserialize(input: ByteBuf): Unit = {
    order = input.readInt()
    dim = input.readInt()
  }

  override def bufferLen(): Int = 8
} 
Example 26
Source File: GamePacketDecoderCataclysm.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import java.util.zip.Inflater

import io.netty.buffer.{ByteBuf, PooledByteBufAllocator}
import io.netty.channel.ChannelHandlerContext

class GamePacketDecoderCataclysm extends GamePacketDecoderWotLK with GamePacketsCataclysm15595 {

  protected val inflater: Inflater = new Inflater

  override def channelInactive(ctx: ChannelHandlerContext): Unit = {
    inflater.end()
    super.channelInactive(ctx)
  }

  override def decompress(id: Int, byteBuf: ByteBuf): (Int, ByteBuf) = {
    if (isCompressed(id)) {
      val decompressedSize = getDecompressedSize(byteBuf)

      val compressed = new Array[Byte](byteBuf.readableBytes)
      byteBuf.readBytes(compressed)
      byteBuf.release
      val decompressed = new Array[Byte](decompressedSize)

      inflater.setInput(compressed)
      inflater.inflate(decompressed)

      val ret = PooledByteBufAllocator.DEFAULT.buffer(decompressed.length, decompressed.length)
      ret.writeBytes(decompressed)
      (getDecompressedId(id, ret), ret)
    } else {
      (id, byteBuf)
    }
  }

  def getDecompressedSize(byteBuf: ByteBuf): Int = {
    byteBuf.readIntLE
  }

  def getDecompressedId(id: Int, buf: ByteBuf): Int = {
    id ^ COMPRESSED_DATA_MASK
  }

  def isCompressed(id: Int): Boolean = {
    (id & COMPRESSED_DATA_MASK) == COMPRESSED_DATA_MASK
  }
} 
Example 27
Source File: Responses.scala    From finagle-postgres   with Apache License 2.0 5 votes vote down vote up
package com.twitter.finagle.postgres

import java.nio.charset.Charset

import com.twitter.finagle.postgres.messages.{DataRow, Field}
import com.twitter.finagle.postgres.values.ValueDecoder
import com.twitter.util.Try
import Try._
import com.twitter.concurrent.AsyncStream
import com.twitter.finagle.postgres.PostgresClient.TypeSpecifier
import com.twitter.finagle.postgres.codec.NullValue
import io.netty.buffer.ByteBuf

import scala.language.existentials

// capture all common format data for a set of rows to reduce repeated references
case class RowFormat(
  indexMap: Map[String, Int],
  formats: Array[Short],
  oids: Array[Int],
  dataTypes: Map[Int, TypeSpecifier],
  receives: PartialFunction[String, ValueDecoder[T] forSome {type T}],
  charset: Charset
) {
  @inline final def recv(index: Int) = dataTypes(oids(index)).receiveFunction
  @inline final def defaultDecoder(index: Int) = receives.applyOrElse(recv(index), (_: String) => ValueDecoder.never)
}

trait Row {
  def getOption[T](name: String)(implicit decoder: ValueDecoder[T]): Option[T]
  def getOption[T](index: Int)(implicit decoder: ValueDecoder[T]): Option[T]
  def get[T](name: String)(implicit decoder: ValueDecoder[T]): T
  def get[T](index: Int)(implicit decoder: ValueDecoder[T]): T
  def getTry[T](name: String)(implicit decoder: ValueDecoder[T]): Try[T]
  def getTry[T](index: Int)(implicit decoder: ValueDecoder[T]): Try[T]
  def getOrElse[T](name: String, default: => T)(implicit decoder: ValueDecoder[T]): T
  def getOrElse[T](index: Int, default: => T)(implicit decoder: ValueDecoder[T]): T
  def getAnyOption(name: String): Option[Any]
  def getAnyOption(index: Int): Option[Any]
}

object Row {
  def apply(values: Array[Option[ByteBuf]], rowFormat: RowFormat): Row = RowImpl(values, rowFormat)
}


object ResultSet {
  def apply(
    fields: Array[Field],
    charset: Charset,
    dataRows: AsyncStream[DataRow],
    types: Map[Int, TypeSpecifier],
    receives: PartialFunction[String, ValueDecoder[T] forSome { type T }]
  ): ResultSet = {
    val (indexMap, formats, oids) = {
      val l = fields.length
      val stringIndex = new Array[(String, Int)](l)
      val formats = new Array[Short](l)
      val oids = new Array[Int](l)
      var i = 0
      while(i < l) {
        val Field(name, format, dataType) = fields(i)
        stringIndex(i) = (name, i)
        formats(i) = format
        oids(i) = dataType
        i += 1
      }
      (stringIndex.toMap, formats, oids)
    }

    val rowFormat = RowFormat(indexMap, formats, oids, types, receives, charset)

    val rows = dataRows.map {
      dataRow => Row(
        values = dataRow.data,
        rowFormat = rowFormat
      )
    }

    ResultSet(rows)
  }
} 
Example 28
Source File: HStores.scala    From finagle-postgres   with Apache License 2.0 5 votes vote down vote up
package com.twitter.finagle.postgres.values

import java.nio.charset.Charset

import scala.util.parsing.combinator.RegexParsers

import io.netty.buffer.{ByteBuf, Unpooled}

object HStores {
  object HStoreStringParser extends RegexParsers {
    def key:Parser[String] = "\"" ~ """([^"\\]*(\\.[^"\\]*)*)""".r ~ "\"" ^^ {
      case o~value~c => value.replace("\\\"", "\"").replace("\\\\", "\\")
    }

    def value = key | "NULL"

    def item:Parser[(String, Option[String])] = key ~ "=>" ~ value ^^ {
      case key~arrow~"NULL" => (key, None)
      case key~arrow~value => (key, Some(value))
    }

    def items:Parser[Map[String, Option[String]]] = repsep(item, ", ") ^^ { l => l.toMap }

    def apply(input:String):Option[Map[String, Option[String]]] = parseAll(items, input) match {
      case Success(result, _) => Some(result)
      case failure:NoSuccess => None
    }
  }

  def parseHStoreString(str: String) = HStoreStringParser(str)

  def formatHStoreString(hstore: Map[String, Option[String]]) = hstore.map {
    case (k, v) =>
      val key = s""""${k.replace("\"", "\\\"")}""""
      val value = v.map(str => s""""${str.replace("\"", "\\\"")}"""").getOrElse("NULL")
      s"""$key => $value"""
  }.mkString(",")

  def decodeHStoreBinary(buf: ByteBuf, charset: Charset) = {
    val count = buf.readInt()
    val pairs = Array.fill(count) {
      val keyLength = buf.readInt()
      val key = Array.fill(keyLength)(buf.readByte())
      val valueLength = buf.readInt()
      val value = valueLength match {
        case -1 => None
        case l =>
          val valueBytes = Array.fill(l)(buf.readByte())
          Some(valueBytes)
      }
      new String(key, charset) -> value.map(new String(_, charset))
    }
    pairs.toMap
  }

  def encodeHStoreBinary(hstore: Map[String, Option[String]], charset: Charset) = {
    val buf = Unpooled.buffer()
    buf.writeInt(hstore.size)
    hstore foreach {
      case (key, value) =>
        val keyBytes = key.getBytes(charset)
        buf.writeInt(keyBytes.length)
        buf.writeBytes(keyBytes)
        value match {
          case None => buf.writeInt(-1)
          case Some(v) =>
            val valueBytes = v.getBytes(charset)
            buf.writeInt(valueBytes.length)
            buf.writeBytes(valueBytes)
        }
    }
    buf
  }

} 
Example 29
Source File: Numerics.scala    From finagle-postgres   with Apache License 2.0 5 votes vote down vote up
package com.twitter.finagle.postgres.values

import java.math.BigInteger

import io.netty.buffer.{ByteBuf, Unpooled}

private object Numerics {
  private val NUMERIC_POS = 0x0000
  private val NUMERIC_NEG = 0x4000
  private val NUMERIC_NAN = 0xC000
  private val NUMERIC_NULL = 0xF000
  private val NumericDigitBaseExponent = 4
  val biBase = BigInteger.valueOf(10000)

  private def getUnsignedShort(buf: ByteBuf) = {
    val high = buf.readByte().toInt
    val low = buf.readByte()
    (high << 8) | low
  }

  private def base10exponent(in: java.math.BigDecimal) = {
     in.round(new java.math.MathContext(1)).scale() * -1
  }

  def readNumeric(buf: ByteBuf) = {
    val len = getUnsignedShort(buf)
    val weight = buf.readShort()
    val sign = getUnsignedShort(buf)
    val displayScale = getUnsignedShort(buf)

    //digits are actually unsigned base-10000 numbers (not straight up bytes)
    val digits = Array.fill(len)(buf.readShort())
    val bdDigits = digits.map(BigDecimal(_))

    if(bdDigits.length > 0) {
      val unscaled = bdDigits.foldLeft(BigDecimal(0)) {
        case (acc, n) => acc * 10000 + n
      }

      val scaleFactor = (weight  + 1 - len) * NumericDigitBaseExponent
      val unsigned = unscaled.bigDecimal.movePointRight(scaleFactor).setScale(displayScale)

      sign match {
        case NUMERIC_POS => BigDecimal(unsigned)
        case NUMERIC_NEG => BigDecimal(unsigned.negate())
        case NUMERIC_NAN => throw new NumberFormatException("Decimal is NaN")
        case NUMERIC_NULL => throw new NumberFormatException("Decimal is NUMERIC_NULL")
      }
    } else {
      BigDecimal(0)
    }
  }

  def writeNumeric(in: BigDecimal) = {
    val minimized = BigDecimal(in.bigDecimal.stripTrailingZeros())
    val unscaled = minimized.bigDecimal.unscaledValue().abs()
    val sign = minimized.signum

    def findDigits(i: BigInteger, current: List[Short] = Nil): List[Short] = if(i.signum() != 0) {
      val Array(q, r) = i.divideAndRemainder(biBase)
      findDigits(q, r.shortValue() :: current)
    } else current

    //the decimal point must align on a base-10000 digit
    val padZeroes = 4 - (minimized.scale % 4)
    val paddedUnscaled = Option(padZeroes)
      .filterNot(_ == 0)
      .map(a => BigInteger.valueOf(10).pow(a))
      .map(unscaled.multiply)
      .getOrElse(unscaled)

    val digits = findDigits(paddedUnscaled, Nil)

    val weight = {
      val powers10 = base10exponent(in.bigDecimal) - base10exponent(new java.math.BigDecimal(paddedUnscaled))
      val mod4 = if (powers10 % 4 >= 0) powers10 % 4 else 4 + powers10 % 4

      digits.length + (powers10 - mod4) / 4 - 1
    }
    val bufSize =
      2 + //digit length
      2 + //weight
      2 + //sign
      2 + //scale
      digits.length * 2 //a short for each digit

    val buf = Unpooled.wrappedBuffer(new Array[Byte](bufSize))
    val scale = if(in.scale < 0) 0 else in.scale
    buf.resetWriterIndex()
    buf.writeShort(digits.length)
    buf.writeShort(weight)
    buf.writeShort(if(sign < 0) NUMERIC_NEG else NUMERIC_POS)
    buf.writeShort(scale)
    digits foreach (d => buf.writeShort(d))
    buf
  }
} 
Example 30
Source File: Arrays.scala    From finagle-postgres   with Apache License 2.0 5 votes vote down vote up
package com.twitter.finagle.postgres.values

import scala.collection.immutable.Queue
import scala.util.parsing.combinator.RegexParsers

import com.twitter.util.{Return, Throw, Try}
import io.netty.buffer.ByteBuf
object Arrays {

  object ArrayStringParser extends RegexParsers {

    val value = """([^",}]|\")*""".r | """"([^"]|\")*"""".r
    val valueComma = "," ~ value ^^ { case "," ~ v => v }
    val values = (value ~ valueComma.*) ^^ { case first ~ rest => first :: rest } | value.? ^^ (_.toList)
    val array = "{" ~ values ~ "}" ^^ { case _ ~ vs ~ _ => vs }
    val maybeArrayValue = array | value ^^ (List(_))
    val maybeArrayValueComma = ("," ~ maybeArrayValue) ^^ { case _ ~ v => v}
    val maybeArrayValues =
      (maybeArrayValue ~ maybeArrayValueComma.*) ^^ { case first ~ rest => first ::: rest.flatten } |
        maybeArrayValue.* ^^ (_.flatten)
    val root = "{" ~ maybeArrayValues ~ "}" ^^ {
      case _ ~ vs ~ _ => vs
    }

    def apply(str: String) = parseAll(root, str) match {
      case Success(strings, _) => Return(strings)
      case Failure(_, _) | Error(_, _) => Throw(new Exception("Failed to parse array string"))
    }

  }

  // TODO: this isn't used anywhere, but it would need access to the type map and it would need to receive the elemoid
  def decodeArrayText[T](str: String, elemDecoder: ValueDecoder[T]) = {
    ArrayStringParser(str).flatMap {
      strings => strings.map(str => elemDecoder.decodeText("", str)).foldLeft[Try[Queue[T]]](Return(Queue.empty[T])) {
        (accum, next) => accum.flatMap {
          current => next.map(v => current enqueue v)
        }
      }
    }
  }

  def decodeArrayBinary[T](buf: ByteBuf, elemDecoder: ValueDecoder[T]) = {
    val ndims = buf.readInt()
    val flags = buf.readInt()
    val elemOid = buf.readInt()
  }

} 
Example 31
Source File: Utils.scala    From finagle-postgres   with Apache License 2.0 5 votes vote down vote up
package com.twitter.finagle.postgres.values

import java.nio.charset.Charset
import java.security.MessageDigest

import io.netty.buffer.ByteBuf

import scala.annotation.tailrec

object Charsets {
  val Utf8 = Charset.forName("UTF-8")
}

object Buffers {
  
  @throws(classOf[IllegalArgumentException])
  def encrypt(user: Array[Byte], password: Array[Byte], salt: Array[Byte]): Array[Byte] = {

    require(user != null && user.length > 0, "user should not be empty")
    require(password != null && password.length > 0, "password should not be empty")
    require(salt != null && salt.length > 0, "salt should not be empty")

    val inner = MessageDigest.getInstance("MD5")
    inner.update(password)
    inner.update(user)

    val outer = MessageDigest.getInstance("MD5")
    outer.update(Hex.valueOf(inner.digest).getBytes)
    outer.update(salt)

    ("md5" + Hex.valueOf(outer.digest)).getBytes
  }
}

object Hex {
  def valueOf(buf: Array[Byte]): String = buf.map("%02X" format _).mkString.toLowerCase
}

object Convert {
  def asShort(i : Int) = i.asInstanceOf[Short]
}

object Strings {
  val empty = new String
} 
Example 32
Source File: TileSieve.scala    From Electrodynamics   with GNU Lesser General Public License v3.0 5 votes vote down vote up
package com.calclavia.edx.basic.process.sifting

import java.util.ArrayList

import cpw.mods.fml.relauncher.{Side, SideOnly}
import edx.core.Reference
import edx.core.resource.content.ItemRubble
import io.netty.buffer.ByteBuf
import net.minecraft.block.Block
import net.minecraft.block.material.Material
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.util.ResourceLocation
import net.minecraftforge.client.IItemRenderer.ItemRenderType
import net.minecraftforge.client.model.AdvancedModelLoader
import org.lwjgl.opengl.GL11
import resonantengine.api.item.ISimpleItemRenderer
import resonantengine.core.network.discriminator.PacketType
import resonantengine.lib.content.prefab.TInventory
import resonantengine.lib.modcontent.block.ResonantTile
import resonantengine.lib.render.{RenderItemOverlayUtility, RenderUtility}
import resonantengine.lib.transform.region.Cuboid
import resonantengine.lib.transform.vector.Vector3
import resonantengine.lib.utility.inventory.InventoryUtility
import resonantengine.lib.wrapper.ByteBufWrapper._
import resonantengine.prefab.block.itemblock.ItemBlockSaved
import resonantengine.prefab.network.{TPacketReceiver, TPacketSender}

object TileSieve
{
  val model = AdvancedModelLoader.loadModel(new ResourceLocation(Reference.domain, Reference.modelPath + "sieve.tcn"))
}

class TileSieve extends ResonantTile(Material.wood) with TInventory with TPacketSender with TPacketReceiver with ISimpleItemRenderer
{
  //Constructor
  setTextureName("material_wood_top")
  bounds = new Cuboid(0, 0, 0, 1, 0.25, 1)
  normalRender = false
  isOpaqueCube = false
  itemBlock = classOf[ItemSieve]

  override def canUpdate: Boolean = false

  override def getSizeInventory: Int = 1

  override def use(player: EntityPlayer, hitSide: Int, hit: Vector3): Boolean =
  {
    val currentStack = player.inventory.getCurrentItem

    if (currentStack != null && currentStack.getItem.isInstanceOf[ItemRubble])
    {
      interactCurrentItem(this, 0, player)
    }
    else
    {
      extractItem(this, 0, player)
    }

    return true
  }

  override def isItemValidForSlot(i: Int, itemStack: ItemStack): Boolean = itemStack.getItem.isInstanceOf[ItemRubble]

  override def renderInventoryItem(renderType: ItemRenderType, itemStack: ItemStack, data: AnyRef*): Unit =
  {
    
  override def write(buf: ByteBuf, id: Int)
  {
    super.write(buf, id)
    buf <<<< writeToNBT
  }

  override def read(buf: ByteBuf, id: Int, packetType: PacketType)
  {
    super.read(buf, id, packetType)
    buf >>>> readFromNBT
  }
} 
Example 33
Source File: GamePacketEncoderMoP.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import wowchat.common.{ByteUtils, Packet}

import scala.collection.mutable.ArrayBuffer

class GamePacketEncoderMoP extends GamePacketEncoderCataclysm with GamePacketsMoP18414 {

  override def encode(ctx: ChannelHandlerContext, msg: Packet, out: ByteBuf): Unit = {
    val crypt = ctx.channel.attr(CRYPT).get
    val unencrypted = isUnencryptedPacket(msg.id)

    val headerSize = 4
    val size = msg.byteBuf.writerIndex

    val array = new ArrayBuffer[Byte](headerSize)
    val header = if (unencrypted) {
      array ++= ByteUtils.shortToBytesLE(size + 2)
      array ++= ByteUtils.shortToBytesLE(msg.id)
      array.toArray
    } else {
      array ++= ByteUtils.intToBytesLE((size << 13) | (msg.id & 0x1FFF))
      crypt.encrypt(array.toArray)
    }

    logger.debug(f"SEND PACKET: ${msg.id}%04X - ${ByteUtils.toHexString(msg.byteBuf, true, false)}")

    out.writeBytes(header)
    out.writeBytes(msg.byteBuf)
    msg.byteBuf.release
  }
} 
Example 34
Source File: GamePacketDecoderMoP.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import java.util.zip.Inflater

import io.netty.buffer.ByteBuf
import wowchat.common.ByteUtils

class GamePacketDecoderMoP extends GamePacketDecoderCataclysm with GamePacketsMoP18414 {

  // MoP compression does not have zlib header
  override protected val inflater: Inflater = new Inflater(true)

  override def parseGameHeader(in: ByteBuf): (Int, Int) = {
    val size = in.readShortLE - 2
    val id = in.readShortLE
    (id, size)
  }

  override def parseGameHeaderEncrypted(in: ByteBuf, crypt: GameHeaderCrypt): (Int, Int) = {
    val header = new Array[Byte](HEADER_LENGTH)
    in.readBytes(header)
    val decrypted = crypt.decrypt(header)
    val raw = ByteUtils.bytesToLongLE(decrypted).toInt
    val id = raw & 0x1FFF
    val size = raw >>> 13
    (id, size)
  }

  override def getDecompressedSize(byteBuf: ByteBuf): Int = {
    val size = byteBuf.readIntLE
    byteBuf.skipBytes(8) // skip adler checksums
    size
  }

  override def getDecompressedId(id: Int, buf: ByteBuf): Int = {
    val newId = buf.readShortLE
    buf.skipBytes(2)
    newId
  }

  override def isCompressed(id: Int): Boolean = {
    id == SMSG_COMPRESSED_DATA
  }
} 
Example 35
Source File: RC4.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import io.netty.buffer.{ByteBuf, PooledByteBufAllocator}

// used for warden and wotlk header encryption
class RC4(key: Array[Byte]) {
  private val SBOX_LENGTH = 256
  private var sbox = initSBox(key)
  private var i = 0
  private var j = 0

  def cryptToByteArray(msg: Array[Byte]): Array[Byte] = {
    val code = new Array[Byte](msg.length)
    msg.indices.foreach(n => {
      i = (i + 1) % SBOX_LENGTH
      j = (j + sbox(i)) % SBOX_LENGTH
      swap(i, j, sbox)
      val rand = sbox((sbox(i) + sbox(j)) % SBOX_LENGTH)
      code(n) = (rand ^ msg(n).toInt).toByte
    })
    code
  }

  def crypt(msg: Array[Byte]): ByteBuf = {
    val byteBuf = PooledByteBufAllocator.DEFAULT.buffer(msg.length, msg.length)
    byteBuf.writeBytes(cryptToByteArray(msg))
  }

  def crypt(msg: Byte): ByteBuf = {
    crypt(Array(msg))
  }

  def crypt(msg: ByteBuf, length: Int): ByteBuf = {
    val arr = new Array[Byte](length)
    msg.readBytes(arr)
    crypt(arr)
  }

  private def initSBox(key: Array[Byte]) = {
    val sbox = new Array[Int](SBOX_LENGTH)
    var j = 0
    (0 until SBOX_LENGTH).foreach(i => sbox(i) = i)
    (0 until SBOX_LENGTH).foreach(i => {
      j = (j + sbox(i) + key(i % key.length) + SBOX_LENGTH) % SBOX_LENGTH
      swap(i, j, sbox)
    })
    sbox
  }

  private def swap(i: Int, j: Int, sbox: Array[Int]): Unit = {
    val temp = sbox(i)
    sbox(i) = sbox(j)
    sbox(j) = temp
  }
} 
Example 36
Source File: WardenHandlerMoP18414.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game.warden

import java.security.MessageDigest

import io.netty.buffer.{ByteBuf, PooledByteBufAllocator}
import wowchat.common.Packet

class WardenHandlerMoP18414(sessionKey: Array[Byte]) extends WardenHandler(sessionKey) {

  override protected val WARDEN_MODULE_LENGTH = 32

  override protected def getEncryptedMessageLength(msg: Packet): Int = {
    msg.byteBuf.readIntLE
  }

  override protected def formResponse(out: ByteBuf): ByteBuf = {
    val newLength = out.readableBytes + 4
    val withHeader = PooledByteBufAllocator.DEFAULT.buffer(newLength, newLength)
    withHeader.writeIntLE(out.readableBytes)
    withHeader.writeBytes(out)
    out.release
    withHeader
  }

  override protected def formCheatChecksRequestDigest(ret: ByteBuf, key: Array[Byte]): Unit = {
    val mdSHA1 = MessageDigest.getInstance("SHA1")
    mdSHA1.update(key)
    ret.writeBytes(mdSHA1.digest)

    val mdSHA256 = MessageDigest.getInstance("SHA-256")
    mdSHA256.update(key)
    ret.writeBytes(mdSHA256.digest)
  }
} 
Example 37
Source File: GamePacketDecoderWotLK.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import io.netty.buffer.ByteBuf

class GamePacketDecoderWotLK extends GamePacketDecoder with GamePacketsWotLK {

  override def parseGameHeaderEncrypted(in: ByteBuf, crypt: GameHeaderCrypt): (Int, Int) = {
    val header = new Array[Byte](HEADER_LENGTH)
    in.readBytes(header)
    val decrypted = crypt.decrypt(header)

    // WotLK and later expansions have a variable size header. An extra byte is included if the size is > 0x7FFF
    if ((decrypted.head & 0x80) == 0x80) {
      val nextByte = crypt.decrypt(Array(in.readByte)).head
      val size = (((decrypted(0) & 0x7F) << 16) | ((decrypted(1) & 0xFF) << 8) | (decrypted(2) & 0xFF)) - 2
      val id = (nextByte & 0xFF) << 8 | decrypted(3) & 0xFF
      (id, size)
    } else {
      val size = ((decrypted(0) & 0xFF) << 8 | decrypted(1) & 0xFF) - 2
      val id = (decrypted(3) & 0xFF) << 8 | decrypted(2) & 0xFF
      (id, size)
    }
  }
} 
Example 38
Source File: BootstrapServer.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.ServerBootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelFuture
import io.netty.channel.ChannelFutureListener
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioServerSocketChannel
import java.net.InetSocketAddress


  def bootstrap(): Unit = {
    val group = new NioEventLoopGroup
    //创建 Server Bootstrap
    val bootstrap = new ServerBootstrap
    //设置 EventLoopGroup,其提供了用于处理 Channel 事件的EventLoop
    bootstrap.group(group)
      //指定要使用的 Channel 实现
      .channel(classOf[NioServerSocketChannel])
      //设置用于处理已被接受的子 Channel 的I/O及数据的 ChannelInboundHandler
      .childHandler {
        new SimpleChannelInboundHandler[ByteBuf]() {
          @throws[Exception]
          override protected def channelRead0(channelHandlerContext: ChannelHandlerContext, byteBuf: ByteBuf): Unit = {
            System.out.println("Received data")
          }
        }
      }

    //通过配置好的 ServerBootstrap 的实例绑定该 Channel
    val future = bootstrap.bind(new InetSocketAddress(8080))
    future.addListener(new ChannelFutureListener() {
      @throws[Exception]
      override def operationComplete(channelFuture: ChannelFuture): Unit = {
        if (channelFuture.isSuccess) System.out.println("Server bound")
        else {
          System.err.println("Bind attempt failed")
          channelFuture.cause.printStackTrace()
        }
      }
    })
  }
} 
Example 39
Source File: GamePacketDecoder.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import java.util

import wowchat.common.{ByteUtils, Packet}
import com.typesafe.scalalogging.StrictLogging
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.ByteToMessageDecoder

class GamePacketDecoder extends ByteToMessageDecoder with GamePackets with StrictLogging {

  protected val HEADER_LENGTH = 4

  private var size = 0
  private var id = 0

  override def decode(ctx: ChannelHandlerContext, in: ByteBuf, out: util.List[AnyRef]): Unit = {
    if (in.readableBytes < HEADER_LENGTH) {
      return
    }

    val crypt = ctx.channel.attr(CRYPT).get

    if (size == 0 && id == 0) {
      // decrypt if necessary
      val tuple = if (crypt.isInit) {
        parseGameHeaderEncrypted(in, crypt)
      } else {
        parseGameHeader(in)
      }
      id = tuple._1
      size = tuple._2
    }

    if (size > in.readableBytes) {
      return
    }

    val byteBuf = in.readBytes(size)

    // decompress if necessary
    val (newId, decompressed) = decompress(id, byteBuf)

    val packet = Packet(newId, decompressed)

    logger.debug(f"RECV PACKET: $newId%04X - ${ByteUtils.toHexString(decompressed, true, false)}")

    out.add(packet)
    size = 0
    id = 0
  }

  def parseGameHeader(in: ByteBuf): (Int, Int) = {
    val size = in.readShort - 2
    val id = in.readShortLE
    (id, size)
  }

  def parseGameHeaderEncrypted(in: ByteBuf, crypt: GameHeaderCrypt): (Int, Int) = {
    val header = new Array[Byte](HEADER_LENGTH)
    in.readBytes(header)
    val decrypted = crypt.decrypt(header)
    val size = ((decrypted(0) & 0xFF) << 8 | decrypted(1) & 0xFF) - 2
    val id = (decrypted(3) & 0xFF) << 8 | decrypted(2) & 0xFF
    (id, size)
  }

  // vanilla has no compression. starts in cata/mop
  def decompress(id: Int, in: ByteBuf): (Int, ByteBuf) = {
    (id, in)
  }
} 
Example 40
Source File: GamePacketEncoder.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.game

import wowchat.common.{ByteUtils, Packet}
import com.typesafe.scalalogging.StrictLogging
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.MessageToByteEncoder

import scala.collection.mutable.ArrayBuffer

class GamePacketEncoder extends MessageToByteEncoder[Packet] with GamePackets with StrictLogging {

  override def encode(ctx: ChannelHandlerContext, msg: Packet, out: ByteBuf): Unit = {
    val crypt = ctx.channel.attr(CRYPT).get
    val unencrypted = isUnencryptedPacket(msg.id)

    val headerSize = if (unencrypted) 4 else 6

    val array = new ArrayBuffer[Byte](headerSize)
    array ++= ByteUtils.shortToBytes(msg.byteBuf.writerIndex + headerSize - 2)
    array ++= ByteUtils.shortToBytesLE(msg.id)
    val header = if (unencrypted) {
      array.toArray
    } else {
      array.append(0, 0)
      crypt.encrypt(array.toArray)
    }

    logger.debug(f"SEND PACKET: ${msg.id}%04X - ${ByteUtils.toHexString(msg.byteBuf, true, false)}")

    out.writeBytes(header)
    out.writeBytes(msg.byteBuf)
    msg.byteBuf.release
  }

  protected def isUnencryptedPacket(id: Int): Boolean = {
    id == CMSG_AUTH_CHALLENGE
  }
} 
Example 41
Source File: RealmPacketDecoder.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.realm

import java.util

import wowchat.common.{ByteUtils, Packet, WowChatConfig, WowExpansion}
import com.typesafe.scalalogging.StrictLogging
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.ByteToMessageDecoder

class RealmPacketDecoder extends ByteToMessageDecoder with StrictLogging {

  private var size = 0
  private var id = 0

  override def decode(ctx: ChannelHandlerContext, in: ByteBuf, out: util.List[AnyRef]): Unit = {
    if (in.readableBytes == 0) {
      return
    }

    if (size == 0 && id == 0) {
      in.markReaderIndex
      id = in.readByte
      id match {
        case RealmPackets.CMD_AUTH_LOGON_CHALLENGE =>
          if (in.readableBytes < 2) {
            in.resetReaderIndex
            return
          }

          in.markReaderIndex
          in.skipBytes(1)
          val result = in.readByte
          size = if (RealmPackets.AuthResult.isSuccess(result)) {
            118
          } else {
            2
          }
          in.resetReaderIndex
        case RealmPackets.CMD_AUTH_LOGON_PROOF =>
          if (in.readableBytes < 1) {
            in.resetReaderIndex
            return
          }

          // size is error dependent
          in.markReaderIndex
          val result = in.readByte
          size = if (RealmPackets.AuthResult.isSuccess(result)) {
            if (WowChatConfig.getExpansion == WowExpansion.Vanilla) 25 else 31
          } else {
            if (WowChatConfig.getExpansion == WowExpansion.Vanilla) 1 else 3
          }
          in.resetReaderIndex
        case RealmPackets.CMD_REALM_LIST =>
          if (in.readableBytes < 2) {
            in.resetReaderIndex
            return
          }

          size = in.readShortLE
      }
    }

    if (size > in.readableBytes) {
      return
    }

    val byteBuf = in.readBytes(size)
    val packet = Packet(id, byteBuf)

    logger.debug(f"RECV REALM PACKET: $id%04X - ${ByteUtils.toHexString(byteBuf, true, false)}")

    out.add(packet)
    size = 0
    id = 0
  }
} 
Example 42
Source File: Packet.scala    From wowchat   with GNU General Public License v3.0 5 votes vote down vote up
package wowchat.common

import io.netty.buffer.{ByteBuf, ByteBufAllocator, EmptyByteBuf}

import scala.collection.mutable.ArrayBuffer
import scala.io.Source

case class Packet(
  id: Int,
  byteBuf: ByteBuf = new EmptyByteBuf(ByteBufAllocator.DEFAULT)
) {

  def readString: String = {
    import scala.util.control.Breaks._

    val ret = ArrayBuffer.newBuilder[Byte]
    breakable {
      while (byteBuf.readableBytes > 0) {
        val value = byteBuf.readByte
        if (value == 0) {
          break
        }
        ret += value
      }
    }

    Source.fromBytes(ret.result.toArray, "UTF-8").mkString
  }

  def skipString: Packet = {
    while (byteBuf.readableBytes > 0 && byteBuf.readByte != 0) {}
    this
  }

  // bit manipulation for cata+
  private var bitPosition = 7
  private var byte: Byte = 0

  def resetBitReader: Unit = {
    bitPosition = 7
    byte = 0
  }

  def readBit: Byte = {
    bitPosition += 1
    if (bitPosition > 7) {
      bitPosition = 0
      byte = byteBuf.readByte
    }

    (byte >> (7 - bitPosition) & 1).toByte
  }

  def readBits(length: Int): Int = {
    (length - 1 to 0 by -1).foldLeft(0) {
      case (result, i) => result | (readBit << i)
    }
  }

  def readBitSeq(mask: Array[Byte], indices: Int*): Unit = {
    indices.foreach(i => {
      mask(i) = readBit
    })
  }

  def readXorByte(mask: Byte): Byte = {
    if (mask != 0) {
      (mask ^ byteBuf.readByte).toByte
    } else {
      mask
    }
  }

  def readXorByteSeq(mask: Array[Byte], indices: Int*): Unit = {
    indices.foreach(i => {
      mask(i) = readXorByte(mask(i))
    })
  }
} 
Example 43
Source File: EchoClientHandler.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter2.echoclient

import io.netty.buffer.{ ByteBuf, Unpooled }
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ ChannelHandlerContext, SimpleChannelInboundHandler }
import io.netty.util.CharsetUtil

@Sharable //标记该类的实例可以被多个 Channel 共享
class EchoClientHandler extends SimpleChannelInboundHandler[ByteBuf] {
  override def channelActive(ctx: ChannelHandlerContext): Unit = {
    //当被通知 Channel是活跃的时候,发送一条消息
    ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8))
  }

  override def channelRead0(ctx: ChannelHandlerContext, in: ByteBuf): Unit = {
    //记录已接收消息的转储
    System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8))
  }

  override def exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable): Unit = {
    //在发生异常时,记录错误并关闭Channel
    cause.printStackTrace()
    ctx.close()
  }
} 
Example 44
Source File: EchoServerHandler.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter2.echoserver

import io.netty.buffer.{ ByteBuf, Unpooled }
import io.netty.channel.ChannelHandler.Sharable
import io.netty.channel.{ ChannelFutureListener, ChannelHandlerContext, ChannelInboundHandlerAdapter }
import io.netty.util.CharsetUtil

@Sharable
class EchoServerHandler extends ChannelInboundHandlerAdapter {
  override def channelRead(ctx: ChannelHandlerContext, msg: Any): Unit = {
    val in = msg.asInstanceOf[ByteBuf]
    //将消息记录到控制台
    System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8))
    //将接收到的消息写给发送者,而不冲刷出站消息
    ctx.write(in)
  }

  @throws[Exception]
  override def channelReadComplete(ctx: ChannelHandlerContext): Unit = {
    //将未决消息冲刷到远程节点,并且关闭该 Channel
    ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE)
  }

  override def exceptionCaught(ctx: ChannelHandlerContext, cause: Throwable): Unit = {
    //打印异常栈跟踪
    cause.printStackTrace()
    //关闭该Channel
    ctx.close()
  }
} 
Example 45
Source File: BootstrapClient.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.Bootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel._
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioSocketChannel
import java.net.InetSocketAddress


  def bootstrap(): Unit = {
    //设置 EventLoopGroup,提供用于处理 Channel 事件的 EventLoop
    val group: EventLoopGroup = new NioEventLoopGroup
    //创建一个Bootstrap类的实例以创建和连接新的客户端Channel
    val bootstrap = new Bootstrap
    bootstrap.group(group)
      //指定要使用的Channel 实现
      .channel(classOf[NioSocketChannel])
      //设置用于 Channel 事件和数据的ChannelInboundHandler
      .handler {
        new SimpleChannelInboundHandler[ByteBuf]() {
          @throws[Exception]
          override protected def channelRead0(
            channelHandlerContext: ChannelHandlerContext,
            byteBuf:               ByteBuf): Unit = {
            println("Received data")
          }
        }
      }
    //连接到远程主机
    val future = bootstrap.connect(new InetSocketAddress("www.manning.com", 80))
    future.addListener(new ChannelFutureListener() {
      @throws[Exception]
      override def operationComplete(channelFuture: ChannelFuture): Unit = {
        if (channelFuture.isSuccess)
          println("Connection established")
        else {
          System.err.println("Connection attempt failed")
          channelFuture.cause.printStackTrace()
        }
      }
    })
  }
} 
Example 46
Source File: InvalidBootstrapClient.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.Bootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.oio.OioSocketChannel
import java.net.InetSocketAddress


  def bootstrap(): Unit = {
    val group = new NioEventLoopGroup
    //创建一个新的 Bootstrap 类的实例,以创建新的客户端Channel
    val bootstrap = new Bootstrap
    //指定一个适用于 NIO 的 EventLoopGroup 实现
    bootstrap.group(group)
      //指定一个适用于 OIO 的 Channel 实现类
      .channel(classOf[OioSocketChannel])
      //设置一个用于处理 Channel的 I/O 事件和数据的 ChannelInboundHandler
      .handler {
        new SimpleChannelInboundHandler[ByteBuf]() {
          @throws[Exception]
          override protected def channelRead0(channelHandlerContext: ChannelHandlerContext, byteBuf: ByteBuf): Unit = {
            println("Received data")
          }
        }
      }
    //尝试连接到远程节点
    val future = bootstrap.connect(new InetSocketAddress("www.manning.com", 80))
    future.syncUninterruptibly
  }
} 
Example 47
Source File: GracefulShutdown.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.Bootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel._
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioSocketChannel
import io.netty.util.concurrent.Future
import java.net.InetSocketAddress


  def bootstrap(): Unit = {
    //创建处理 I/O 的EventLoopGroup
    val group = new NioEventLoopGroup

    //创建一个 Bootstrap 类的实例并配置它
    val bootstrap = new Bootstrap
    bootstrap.group(group)
      .channel(classOf[NioSocketChannel])
      .handler(
        new SimpleChannelInboundHandler[ByteBuf]() {
          @throws[Exception]
          override protected def channelRead0(channelHandlerContext: ChannelHandlerContext, byteBuf: ByteBuf): Unit = {
            System.out.println("Received data")
          }
        }
      )
    bootstrap.connect(new InetSocketAddress("www.manning.com", 80)).syncUninterruptibly()

    //shutdownGracefully()方法将释放所有的资源,并且关闭所有的当前正在使用中的 Channel
    val future = group.shutdownGracefully()
    // block until the group has shutdown
    future.syncUninterruptibly()
  }
} 
Example 48
Source File: BootstrapSharingEventLoopGroup.scala    From netty-in-action-scala   with Apache License 2.0 5 votes vote down vote up
package nia.chapter8

import io.netty.bootstrap.Bootstrap
import io.netty.bootstrap.ServerBootstrap
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelFuture
import io.netty.channel.ChannelFutureListener
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.SimpleChannelInboundHandler
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.nio.NioServerSocketChannel
import io.netty.channel.socket.nio.NioSocketChannel
import java.net.InetSocketAddress


  def bootstrap(): Unit = { //创建 ServerBootstrap 以创建 ServerSocketChannel,并绑定它
    val bootstrap = new ServerBootstrap
    //设置 EventLoopGroup,其将提供用以处理 Channel 事件的 EventLoop
    bootstrap.group(new NioEventLoopGroup, new NioEventLoopGroup)
      //指定要使用的 Channel 实现
      .channel(classOf[NioServerSocketChannel])
      //设置用于处理已被接受的子 Channel 的 I/O 和数据的 ChannelInboundHandler
      .childHandler {
        new SimpleChannelInboundHandler[ByteBuf]() {
          private[chapter8] var connectFuture: ChannelFuture = _

          @throws[Exception]
          override def channelActive(ctx: ChannelHandlerContext): Unit = {
            //创建一个 Bootstrap 类的实例以连接到远程主机
            val bootstrap = new Bootstrap
            //指定 Channel 的实现
            bootstrap.channel(classOf[NioSocketChannel])
              .handler(new SimpleChannelInboundHandler[ByteBuf]() {
                @throws[Exception]
                override protected def channelRead0(
                  ctx: ChannelHandlerContext,
                  in:  ByteBuf): Unit = {
                  println("Received data")
                }
              })
            //使用与分配给已被接受的子Channel相同的EventLoop
            bootstrap.group(ctx.channel.eventLoop)
            //连接到远程节点
            connectFuture = bootstrap.connect(new InetSocketAddress("www.manning.com", 80))
          }

          @throws[Exception]
          override protected def channelRead0(
            channelHandlerContext: ChannelHandlerContext,
            byteBuf:               ByteBuf): Unit = {
            if (connectFuture.isDone) {
              //当连接完成时,执行一些数据操作(如代理)
              // do something with the data
            }
          }
        }
      }

    //通过配置好的 ServerBootstrap 绑定该 ServerSocketChannel
    val future = bootstrap.bind(new InetSocketAddress(8080))
    future.addListener(new ChannelFutureListener() {
      @throws[Exception]
      override def operationComplete(channelFuture: ChannelFuture): Unit = {
        if (channelFuture.isSuccess) System.out.println("Server bound")
        else {
          System.err.println("Bind attempt failed")
          channelFuture.cause.printStackTrace()
        }
      }
    })
  }
}