package org.springframework.boot.devtools.livereload;
import java.io.IOException;
import java.io.OutputStream;
import org.springframework.util.Assert;
class Frame {
private static final byte[] NO_BYTES = new byte[0];
private final Type type;
private final byte[] payload;
Frame(String payload) {
Assert.notNull(payload, "Payload must not be null");
this.type = Type.TEXT;
this.payload = payload.getBytes();
}
Frame(Type type) {
Assert.notNull(type, "Type must not be null");
this.type = type;
this.payload = NO_BYTES;
}
Frame(Type type, byte[] payload) {
this.type = type;
this.payload = payload;
}
Type getType() {
return this.type;
}
byte[] getPayload() {
return this.payload;
}
@Override
public String toString() {
return new String(this.payload);
}
void write(OutputStream outputStream) throws IOException {
outputStream.write(0x80 | this.type.code);
if (this.payload.length < 126) {
outputStream.write(0x00 | (this.payload.length & 0x7F));
}
else {
outputStream.write(0x7E);
outputStream.write(this.payload.length >> 8 & 0xFF);
outputStream.write(this.payload.length >> 0 & 0xFF);
}
outputStream.write(this.payload);
outputStream.flush();
}
static Frame read(ConnectionInputStream inputStream) throws IOException {
int firstByte = inputStream.checkedRead();
Assert.state((firstByte & 0x80) != 0, "Fragmented frames are not supported");
int maskAndLength = inputStream.checkedRead();
boolean hasMask = (maskAndLength & 0x80) != 0;
int length = (maskAndLength & 0x7F);
Assert.state(length != 127, "Large frames are not supported");
if (length == 126) {
length = ((inputStream.checkedRead()) << 8 | inputStream.checkedRead());
}
byte[] mask = new byte[4];
if (hasMask) {
inputStream.readFully(mask, 0, mask.length);
}
byte[] payload = new byte[length];
inputStream.readFully(payload, 0, length);
if (hasMask) {
for (int i = 0; i < payload.length; i++) {
payload[i] ^= mask[i % 4];
}
}
return new Frame(Type.forCode(firstByte & 0x0F), payload);
}
enum Type {
CONTINUATION(0x00),
TEXT(0x01),
BINARY(0x02),
CLOSE(0x08),
PING(0x09),
PONG(0x0A);
private final int code;
Type(int code) {
this.code = code;
}
static Type forCode(int code) {
for (Type type : values()) {
if (type.code == code) {
return type;
}
}
throw new IllegalStateException("Unknown code " + code);
}
}
}