71 lines
2.3 KiB
Java
71 lines
2.3 KiB
Java
package me.proxylink.common;
|
|
|
|
import java.io.DataInputStream;
|
|
import java.io.DataOutputStream;
|
|
import java.io.EOFException;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
|
|
public final class FrameCodec {
|
|
private final DataInputStream input;
|
|
private final DataOutputStream output;
|
|
|
|
public FrameCodec(InputStream input, OutputStream output) {
|
|
this.input = new DataInputStream(input);
|
|
this.output = new DataOutputStream(output);
|
|
}
|
|
|
|
public Frame readFrame() throws IOException {
|
|
int magic;
|
|
try {
|
|
magic = input.readInt();
|
|
} catch (EOFException eof) {
|
|
return null;
|
|
}
|
|
|
|
if (magic != ProtocolConstants.MAGIC) {
|
|
throw new ProtocolException("Invalid frame magic");
|
|
}
|
|
|
|
int version = Short.toUnsignedInt(input.readShort());
|
|
if (version != ProtocolConstants.PROTOCOL_VERSION) {
|
|
throw new ProtocolException("Unsupported protocol version: " + version);
|
|
}
|
|
|
|
int typeCode = Byte.toUnsignedInt(input.readByte());
|
|
input.readByte();
|
|
long streamId = input.readLong();
|
|
int payloadLength = input.readInt();
|
|
|
|
if (payloadLength < 0 || payloadLength > ProtocolConstants.MAX_FRAME_PAYLOAD_BYTES) {
|
|
throw new ProtocolException("Invalid frame payload length: " + payloadLength);
|
|
}
|
|
|
|
byte[] payload = input.readNBytes(payloadLength);
|
|
if (payload.length != payloadLength) {
|
|
throw new EOFException("Unexpected end of stream while reading frame payload");
|
|
}
|
|
|
|
return new Frame(FrameType.fromCode(typeCode), streamId, payload);
|
|
}
|
|
|
|
public void writeFrame(Frame frame) throws IOException {
|
|
byte[] payload = frame.payload();
|
|
if (payload.length > ProtocolConstants.MAX_FRAME_PAYLOAD_BYTES) {
|
|
throw new ProtocolException("Frame payload is too large: " + payload.length);
|
|
}
|
|
|
|
synchronized (output) {
|
|
output.writeInt(ProtocolConstants.MAGIC);
|
|
output.writeShort(ProtocolConstants.PROTOCOL_VERSION);
|
|
output.writeByte(frame.type().code());
|
|
output.writeByte(0);
|
|
output.writeLong(frame.streamId());
|
|
output.writeInt(payload.length);
|
|
output.write(payload);
|
|
output.flush();
|
|
}
|
|
}
|
|
}
|