private void handleHTTP(OutPacketMessage msg, ChannelHandlerContext ctx, ChannelPromise promise)
      throws IOException {
    Channel channel = ctx.channel();
    Attribute<Boolean> attr = channel.attr(WRITE_ONCE);

    Queue<Packet> queue = msg.getClientHead().getPacketsQueue(msg.getTransport());

    if (!channel.isActive() || queue.isEmpty() || !attr.compareAndSet(null, true)) {
      promise.setSuccess();
      return;
    }

    ByteBuf out = encoder.allocateBuffer(ctx.alloc());
    Boolean b64 = ctx.channel().attr(EncoderHandler.B64).get();
    if (b64 != null && b64) {
      Integer jsonpIndex = ctx.channel().attr(EncoderHandler.JSONP_INDEX).get();
      encoder.encodeJsonP(jsonpIndex, queue, out, ctx.alloc(), 50);
      String type = "application/javascript";
      if (jsonpIndex == null) {
        type = "text/plain";
      }
      sendMessage(msg, channel, out, type, promise);
    } else {
      encoder.encodePackets(queue, out, ctx.alloc(), 50);
      sendMessage(msg, channel, out, "application/octet-stream", promise);
    }
  }
  private void handleWebsocket(
      final OutPacketMessage msg, ChannelHandlerContext ctx, ChannelPromise promise)
      throws IOException {
    while (true) {
      Queue<Packet> queue = msg.getClientHead().getPacketsQueue(msg.getTransport());
      Packet packet = queue.poll();
      if (packet == null) {
        promise.setSuccess();
        break;
      }

      final ByteBuf out = encoder.allocateBuffer(ctx.alloc());
      encoder.encodePacket(packet, out, ctx.alloc(), true);

      WebSocketFrame res = new TextWebSocketFrame(out);
      if (log.isTraceEnabled()) {
        log.trace(
            "Out message: {} sessionId: {}", out.toString(CharsetUtil.UTF_8), msg.getSessionId());
      }

      if (out.isReadable()) {
        ctx.channel().writeAndFlush(res, promise);
      } else {
        promise.setSuccess();
        out.release();
      }

      for (ByteBuf buf : packet.getAttachments()) {
        ByteBuf outBuf = encoder.allocateBuffer(ctx.alloc());
        outBuf.writeByte(4);
        outBuf.writeBytes(buf);
        if (log.isTraceEnabled()) {
          log.trace(
              "Out attachment: {} sessionId: {}", ByteBufUtil.hexDump(outBuf), msg.getSessionId());
        }
        ctx.channel().writeAndFlush(new BinaryWebSocketFrame(outBuf));
      }
    }
  }
  @Override
  public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
      throws Exception {
    if (!(msg instanceof BaseMessage)) {
      super.write(ctx, msg, promise);
      return;
    }

    if (msg instanceof OutPacketMessage) {
      OutPacketMessage m = (OutPacketMessage) msg;
      if (m.getTransport() == Transport.WEBSOCKET) {
        handleWebsocket((OutPacketMessage) msg, ctx, promise);
      }
      if (m.getTransport() == Transport.POLLING) {
        handleHTTP((OutPacketMessage) msg, ctx, promise);
      }
    } else if (msg instanceof XHROptionsMessage) {
      write((XHROptionsMessage) msg, ctx, promise);
    } else if (msg instanceof XHRPostMessage) {
      write((XHRPostMessage) msg, ctx, promise);
    }
  }