package com.gmail.woodyc40.common.protocol;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import javax.annotation.concurrent.ThreadSafe;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Wraps a bytebuffer which is used by the pipeline internally to send or decode bytes
*
* <p>Each segment is written individually</p>
*
* @author Pierre C
*/
@ThreadSafe
public class ByteAppender {
/** The underlying bytebuf to append to */
private final ConcurrentLinkedQueue<ByteBuf> bufs = new ConcurrentLinkedQueue<>();
/**
* Creates a new byte appender
*
* @param buf the buffer to wrap
*/
private ByteAppender(ByteBuf buf) {
bufs.add(buf);
}
/**
* Wraps a bytebuf with a new appender
*
* @param buf the buffer to wrap
* @return the new byte appender
*/
public static ByteAppender wrap(ByteBuf buf) {
return new ByteAppender(buf);
}
/**
* Creates a new empty byte appender
*
* @return the new byte appender
*/
public static ByteAppender empty() {
return wrap(Unpooled.directBuffer());
}
/**
* Separates the last byte entries and creates a new entry for subsequent bytes
*/
public void segment() {
bufs.add(Unpooled.directBuffer());
}
//////////////////////////////// APPENDING ////////////////////////////////
/**
* Appends a byte array to the buffer
*
* @param bytes the bytes to append
*/
public void append(byte[] bytes) {
bufs.peek().writeBytes(bytes);
}
/**
* Appends a byte to the buffer
*
* @param by the byte to append
*/
public void append(byte by) {
bufs.peek().writeByte(by);
}
/**
* Appends a byte buffer to the buffer
*
* @param buf the bytes to append
*/
public void append(ByteBuf buf) {
bufs.peek().writeBytes(buf);
}
/**
* Appends a byte array to the buffer
*
* @param stream the bytes to append
*/
public void append(ByteArrayOutputStream stream) {
bufs.peek().writeBytes(stream.toByteArray());
}
/**
* Appends the btyes from the given appender to this appender
*
* @param appender the appender to grab the bytes from
*/
public void append(ByteAppender appender) {
for (ByteBuf byteBuf : appender.bufs) {
segment();
append(byteBuf);
}
}
//////////////////////////////// WRITING TO ////////////////////////////////
/**
* Writes the buffer to another buffer
*
* @param buf the buffer to write to
*/
public void writeTo(ByteBuf buf) {
for (ByteBuf b : bufs) {
buf.writeBytes(b);
}
}
/**
* Writes the buffer to the stream
*
* @param stream the stream to write to
*/
public void writeTo(ByteArrayOutputStream stream) {
try {
for (ByteBuf b : bufs) {
stream.write(b.array());
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Writes and flushes the buffer's array to the channel
*
* @param ctx the channel to write to
*/
public void writeTo(Channel ctx) {
for (ByteBuf b : bufs) {
ctx.writeAndFlush(b.array());
}
}
//////////////////////////////// COPYING ////////////////////////////////
/**
* Returns the original internal buffer (non-array)
*
* @return the original buffer that was wrapped
*/
public Queue<ByteBuf> wrapped() {
return bufs;
}
/**
* Copies the internal bytes to an array
*
* @return the copy of the byte array
*/
public byte[] copy() {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
writeTo(stream);
return stream.toByteArray();
}
}