io.rsocket.frame.SetupFrameCodec Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rsocket-core Show documentation
Show all versions of rsocket-core Show documentation
Core functionality for the RSocket library
The newest version!
package io.rsocket.frame;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.rsocket.Payload;
import java.nio.charset.StandardCharsets;
import reactor.util.annotation.Nullable;
public class SetupFrameCodec {
/**
* A flag used to indicate that the client requires connection resumption, if possible (the frame
* contains a Resume Identification Token)
*/
public static final int FLAGS_RESUME_ENABLE = 0b00_1000_0000;
/** A flag used to indicate that the client will honor LEASE sent by the server */
public static final int FLAGS_WILL_HONOR_LEASE = 0b00_0100_0000;
public static final int CURRENT_VERSION = VersionCodec.encode(1, 0);
private static final int VERSION_FIELD_OFFSET = FrameHeaderCodec.size();
private static final int KEEPALIVE_INTERVAL_FIELD_OFFSET = VERSION_FIELD_OFFSET + Integer.BYTES;
private static final int KEEPALIVE_MAX_LIFETIME_FIELD_OFFSET =
KEEPALIVE_INTERVAL_FIELD_OFFSET + Integer.BYTES;
private static final int VARIABLE_DATA_OFFSET =
KEEPALIVE_MAX_LIFETIME_FIELD_OFFSET + Integer.BYTES;
public static ByteBuf encode(
final ByteBufAllocator allocator,
final boolean lease,
final int keepaliveInterval,
final int maxLifetime,
final String metadataMimeType,
final String dataMimeType,
final Payload setupPayload) {
return encode(
allocator,
lease,
keepaliveInterval,
maxLifetime,
Unpooled.EMPTY_BUFFER,
metadataMimeType,
dataMimeType,
setupPayload);
}
public static ByteBuf encode(
final ByteBufAllocator allocator,
final boolean lease,
final int keepaliveInterval,
final int maxLifetime,
final ByteBuf resumeToken,
final String metadataMimeType,
final String dataMimeType,
final Payload setupPayload) {
final ByteBuf data = setupPayload.sliceData();
final boolean hasMetadata = setupPayload.hasMetadata();
final ByteBuf metadata = hasMetadata ? setupPayload.sliceMetadata() : null;
int flags = 0;
if (resumeToken.readableBytes() > 0) {
flags |= FLAGS_RESUME_ENABLE;
}
if (lease) {
flags |= FLAGS_WILL_HONOR_LEASE;
}
if (hasMetadata) {
flags |= FrameHeaderCodec.FLAGS_M;
}
final ByteBuf header = FrameHeaderCodec.encodeStreamZero(allocator, FrameType.SETUP, flags);
header.writeInt(CURRENT_VERSION).writeInt(keepaliveInterval).writeInt(maxLifetime);
if ((flags & FLAGS_RESUME_ENABLE) != 0) {
resumeToken.markReaderIndex();
header.writeShort(resumeToken.readableBytes()).writeBytes(resumeToken);
resumeToken.resetReaderIndex();
}
// Write metadata mime-type
int length = ByteBufUtil.utf8Bytes(metadataMimeType);
header.writeByte(length);
ByteBufUtil.writeUtf8(header, metadataMimeType);
// Write data mime-type
length = ByteBufUtil.utf8Bytes(dataMimeType);
header.writeByte(length);
ByteBufUtil.writeUtf8(header, dataMimeType);
return FrameBodyCodec.encode(allocator, header, metadata, hasMetadata, data);
}
public static int version(ByteBuf byteBuf) {
FrameHeaderCodec.ensureFrameType(FrameType.SETUP, byteBuf);
byteBuf.markReaderIndex();
int version = byteBuf.skipBytes(VERSION_FIELD_OFFSET).readInt();
byteBuf.resetReaderIndex();
return version;
}
public static String humanReadableVersion(ByteBuf byteBuf) {
int encodedVersion = version(byteBuf);
return VersionCodec.major(encodedVersion) + "." + VersionCodec.minor(encodedVersion);
}
public static boolean isSupportedVersion(ByteBuf byteBuf) {
return CURRENT_VERSION == version(byteBuf);
}
public static int resumeTokenLength(ByteBuf byteBuf) {
byteBuf.markReaderIndex();
int tokenLength = byteBuf.skipBytes(VARIABLE_DATA_OFFSET).readShort() & 0xFFFF;
byteBuf.resetReaderIndex();
return tokenLength;
}
public static int keepAliveInterval(ByteBuf byteBuf) {
byteBuf.markReaderIndex();
int keepAliveInterval = byteBuf.skipBytes(KEEPALIVE_INTERVAL_FIELD_OFFSET).readInt();
byteBuf.resetReaderIndex();
return keepAliveInterval;
}
public static int keepAliveMaxLifetime(ByteBuf byteBuf) {
byteBuf.markReaderIndex();
int keepAliveMaxLifetime = byteBuf.skipBytes(KEEPALIVE_MAX_LIFETIME_FIELD_OFFSET).readInt();
byteBuf.resetReaderIndex();
return keepAliveMaxLifetime;
}
public static boolean honorLease(ByteBuf byteBuf) {
return (FLAGS_WILL_HONOR_LEASE & FrameHeaderCodec.flags(byteBuf)) == FLAGS_WILL_HONOR_LEASE;
}
public static boolean resumeEnabled(ByteBuf byteBuf) {
return (FLAGS_RESUME_ENABLE & FrameHeaderCodec.flags(byteBuf)) == FLAGS_RESUME_ENABLE;
}
public static ByteBuf resumeToken(ByteBuf byteBuf) {
if (resumeEnabled(byteBuf)) {
byteBuf.markReaderIndex();
// header
int resumePos =
FrameHeaderCodec.size()
+
// version
Integer.BYTES
+
// keep-alive interval
Integer.BYTES
+
// keep-alive maxLifeTime
Integer.BYTES;
int tokenLength = byteBuf.skipBytes(resumePos).readShort() & 0xFFFF;
ByteBuf resumeToken = byteBuf.readSlice(tokenLength);
byteBuf.resetReaderIndex();
return resumeToken;
} else {
return Unpooled.EMPTY_BUFFER;
}
}
public static String metadataMimeType(ByteBuf byteBuf) {
int skip = bytesToSkipToMimeType(byteBuf);
byteBuf.markReaderIndex();
int length = byteBuf.skipBytes(skip).readUnsignedByte();
String mimeType = byteBuf.slice(byteBuf.readerIndex(), length).toString(StandardCharsets.UTF_8);
byteBuf.resetReaderIndex();
return mimeType;
}
public static String dataMimeType(ByteBuf byteBuf) {
int skip = bytesToSkipToMimeType(byteBuf);
byteBuf.markReaderIndex();
int metadataLength = byteBuf.skipBytes(skip).readByte();
int dataLength = byteBuf.skipBytes(metadataLength).readByte();
String mimeType = byteBuf.readSlice(dataLength).toString(StandardCharsets.UTF_8);
byteBuf.resetReaderIndex();
return mimeType;
}
@Nullable
public static ByteBuf metadata(ByteBuf byteBuf) {
boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf);
if (!hasMetadata) {
return null;
}
byteBuf.markReaderIndex();
skipToPayload(byteBuf);
ByteBuf metadata = FrameBodyCodec.metadataWithoutMarking(byteBuf);
byteBuf.resetReaderIndex();
return metadata;
}
public static ByteBuf data(ByteBuf byteBuf) {
boolean hasMetadata = FrameHeaderCodec.hasMetadata(byteBuf);
byteBuf.markReaderIndex();
skipToPayload(byteBuf);
ByteBuf data = FrameBodyCodec.dataWithoutMarking(byteBuf, hasMetadata);
byteBuf.resetReaderIndex();
return data;
}
private static int bytesToSkipToMimeType(ByteBuf byteBuf) {
int bytesToSkip = VARIABLE_DATA_OFFSET;
if ((FLAGS_RESUME_ENABLE & FrameHeaderCodec.flags(byteBuf)) == FLAGS_RESUME_ENABLE) {
bytesToSkip += resumeTokenLength(byteBuf) + Short.BYTES;
}
return bytesToSkip;
}
private static void skipToPayload(ByteBuf byteBuf) {
int skip = bytesToSkipToMimeType(byteBuf);
byte length = byteBuf.skipBytes(skip).readByte();
length = byteBuf.skipBytes(length).readByte();
byteBuf.skipBytes(length);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy