Files
DirtSimpleP2P/common/src/main/java/me/proxylink/common/FrameCodec.java
T
2026-06-21 12:44:51 -04:00

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();
}
}
}