home /
connvers /
src /
main /
java /
avividi /
connvers /
protocol /
BasicMessageEncoder.java
BasicMessageEncoder.java
package avividi.connvers.protocol;
import java.time.Instant;
import static avividi.connvers.Connvers.MAX_LENGTH_USER_NAME;
import static avividi.connvers.Connvers.MAX_MESSAGE_LENGTH;
import static avividi.connvers.Connvers.SERVER_USER;
import static avividi.connvers.Connvers.SYSTEM_USER;
public class BasicMessageEncoder implements MessageEncoder {
public static String PROTOCOL_NAME = "connvers-protocol-v1";
@Override
public String encode(Message message) {
String template = """
%s
user=%s
time=%s
topic=%s
%s""";
return String.format(
template,
PROTOCOL_NAME,
message.user(),
message.time(),
message.topic(),
message.content() == null ? "" : message.content());
}
@Override
public Message decode(String raw) throws ValidationException {
String[] lines = raw.split("\n");
if (lines.length < 4) {
throw new ValidationException();
}
String protocolLine = lines[0];
ValidationException.require(protocolLine.equals(PROTOCOL_NAME), () -> "invalid protocol");
String userLine = lines[1];
ValidationException.require(userLine.startsWith("user="), () -> "invalid user");
String user = userLine.substring("user=".length());
String timestampLine = lines[2];
ValidationException.require(timestampLine.startsWith("time="), () -> "invalid time");
Instant time;
try {
time =Instant.parse(timestampLine.substring("time=".length()));
} catch (Exception e) {
throw new ValidationException("invalid time");
}
String topicLine = lines[3];
ValidationException.require(topicLine.startsWith("topic="), () -> "invalid topic");
String topicString = lines[3].substring("topic=".length());
MessageTopic topic;
try {
topic = MessageTopic.valueOf(topicString);
} catch (Exception e) {
throw new ValidationException("invalid topic");
}
if (topic == MessageTopic.welcome || topic == MessageTopic.error) {
ValidationException.require(user.equals(SERVER_USER), () -> String.format("invalid user name <%s>", user));
} else if (topic == MessageTopic.join || topic == MessageTopic.heartbeat) {
ValidationException.require(!user.equals(SERVER_USER), () -> "invalid user name");
ValidationException.require(!user.equals(SYSTEM_USER), () -> "invalid user name");
}
String content = null;
if (topic == MessageTopic.say || topic == MessageTopic.error) {
ValidationException.require(lines.length >= 5, () -> "missing content ");
content = lines[4];
ValidationException.require(content.length() <= MAX_MESSAGE_LENGTH,
() -> String.format("invalid message (longer than %d)", MAX_MESSAGE_LENGTH));
}
return new Message(user, time, topic, content);
}
public static void validateUserName(String user) throws ValidationException {
ValidationException.require(user.replaceAll("\\w","").isEmpty(),
() -> "invalid user name (only alphanumerics allowed)");
ValidationException.require(user.length() <= MAX_LENGTH_USER_NAME,
() -> String.format("invalid user name (longer than %d)", MAX_LENGTH_USER_NAME));
ValidationException.require(user.length() > 1,
() -> "invalid user name (too short)");
}
}