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

reactor.tcp.encoding.FrameCodec Maven / Gradle / Ivy

The newest version!
package reactor.tcp.encoding;

import reactor.function.Consumer;
import reactor.function.Function;
import reactor.io.Buffer;

/**
 * @author Jon Brisbin
 */
public class FrameCodec implements Codec {

	public enum LengthField {
		SHORT, INT, LONG
	}

	private final FrameEncoder encoder = new FrameEncoder();

	private final LengthField lengthField;
	private final int         prefixLength;
	private final int         minRequiredLen;

	public FrameCodec(int prefixLength, LengthField lengthField) {
		this.prefixLength = prefixLength;
		this.lengthField = lengthField;
		this.minRequiredLen = lengthFieldLength(lengthField) + prefixLength;
	}

	@Override
	public Function decoder(Consumer next) {
		return new FrameDecoder(next);
	}

	@Override
	public Function encoder() {
		return encoder;
	}

	private class FrameDecoder implements Function {
		private final Consumer next;

		private FrameDecoder(Consumer next) {
			this.next = next;
		}

		@Override
		public Frame apply(Buffer buffer) {
			while (buffer.remaining() > minRequiredLen) {
				int pos = buffer.position();
				int limit = buffer.limit();

				Buffer.View prefix = readPrefix(buffer);
				if (null == prefix) {
					// insufficient data
					buffer.limit(limit);
					buffer.position(pos);
					return null;
				}

				Buffer.View data = readData(buffer);
				if (null == data) {
					// insufficient data
					buffer.limit(limit);
					buffer.position(pos);
					return null;
				}

				Buffer prefixBuff = new Buffer(prefixLength, true).append(prefix.get()).flip();
				Buffer dataBuff = new Buffer(data.getEnd() - data.getStart(), true).append(data.get()).flip();

				buffer.limit(limit);

				Frame f = new Frame(prefixBuff, dataBuff);
				if (null != next) {
					next.accept(f);
				} else {
					return f;
				}
			}
			return null;
		}

		private Buffer.View readPrefix(Buffer buffer) {
			if (buffer.remaining() < prefixLength) {
				return null;
			}

			int pos = buffer.position();
			Buffer.View prefix = buffer.createView(pos, pos + prefixLength);
			buffer.position(pos + prefixLength);

			return prefix;
		}

		private int readLen(Buffer buffer) {
			switch (lengthField) {
				case SHORT:
					if (buffer.remaining() > 2) {
						return buffer.readShort();
					}
					break;
				case INT:
					if (buffer.remaining() > 4) {
						return buffer.readInt();
					}
					break;
				case LONG:
					if (buffer.remaining() > 8) {
						return (int) buffer.readLong();
					}
					break;
			}

			return -1;
		}

		private Buffer.View readData(Buffer buffer) {
			int pos = buffer.position();
			int limit = buffer.limit();

			int len = readLen(buffer);
			if (len == -1 || buffer.remaining() < len) {
				buffer.limit(limit);
				buffer.position(pos);
				return null;
			}

			pos = buffer.position();
			Buffer.View data = buffer.createView(pos, pos + len);
			buffer.position(pos + len);

			return data;
		}
	}

	private class FrameEncoder implements Function {
		@Override
		public Buffer apply(Frame frame) {
			return null;
		}
	}


	private static int lengthFieldLength(LengthField lf) {
		switch (lf) {
			case SHORT:
				return 2;
			case INT:
				return 4;
			default:
				return 8;
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy