redis.clients.jedis.Protocol Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jedis_preview Show documentation
Show all versions of jedis_preview Show documentation
Jedis is a blazingly small and sane Redis java client.
The newest version!
package redis.clients.jedis;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import redis.clients.jedis.exceptions.*;
import redis.clients.jedis.args.Rawable;
import redis.clients.jedis.commands.ProtocolCommand;
import redis.clients.jedis.util.KeyValue;
import redis.clients.jedis.util.RedisInputStream;
import redis.clients.jedis.util.RedisOutputStream;
import redis.clients.jedis.util.SafeEncoder;
public final class Protocol {
public static final String DEFAULT_HOST = "127.0.0.1";
public static final int DEFAULT_PORT = 6379;
public static final int DEFAULT_SENTINEL_PORT = 26379;
public static final int DEFAULT_TIMEOUT = 2000;
public static final int DEFAULT_DATABASE = 0;
public static final int CLUSTER_HASHSLOTS = 16384;
public static final Charset CHARSET = StandardCharsets.UTF_8;
public static final byte ASTERISK_BYTE = '*';
public static final byte COLON_BYTE = ':';
public static final byte COMMA_BYTE = ',';
public static final byte DOLLAR_BYTE = '$';
public static final byte EQUAL_BYTE = '=';
public static final byte GREATER_THAN_BYTE = '>';
public static final byte HASH_BYTE = '#';
public static final byte LEFT_BRACE_BYTE = '(';
public static final byte MINUS_BYTE = '-';
public static final byte PERCENT_BYTE = '%';
public static final byte PLUS_BYTE = '+';
public static final byte TILDE_BYTE = '~';
public static final byte UNDERSCORE_BYTE = '_';
public static final byte[] BYTES_TRUE = toByteArray(1);
public static final byte[] BYTES_FALSE = toByteArray(0);
public static final byte[] BYTES_TILDE = SafeEncoder.encode("~");
public static final byte[] BYTES_EQUAL = SafeEncoder.encode("=");
public static final byte[] BYTES_ASTERISK = SafeEncoder.encode("*");
public static final byte[] POSITIVE_INFINITY_BYTES = "+inf".getBytes();
public static final byte[] NEGATIVE_INFINITY_BYTES = "-inf".getBytes();
private static final String ASK_PREFIX = "ASK ";
private static final String MOVED_PREFIX = "MOVED ";
private static final String CLUSTERDOWN_PREFIX = "CLUSTERDOWN ";
private static final String BUSY_PREFIX = "BUSY ";
private static final String NOSCRIPT_PREFIX = "NOSCRIPT ";
private static final String NOAUTH_PREFIX = "NOAUTH";
private static final String WRONGPASS_PREFIX = "WRONGPASS";
private static final String NOPERM_PREFIX = "NOPERM";
private static final byte[] INVALIDATE_BYTES = SafeEncoder.encode("invalidate");
private Protocol() {
throw new InstantiationError("Must not instantiate this class");
}
public static void sendCommand(final RedisOutputStream os, CommandArguments args) {
try {
os.write(ASTERISK_BYTE);
os.writeIntCrLf(args.size());
for (Rawable arg : args) {
os.write(DOLLAR_BYTE);
final byte[] bin = arg.getRaw();
os.writeIntCrLf(bin.length);
os.write(bin);
os.writeCrLf();
}
} catch (IOException e) {
throw new JedisConnectionException(e);
}
}
private static void processError(final RedisInputStream is) {
String message = is.readLine();
// TODO: I'm not sure if this is the best way to do this.
// Maybe Read only first 5 bytes instead?
if (message.startsWith(MOVED_PREFIX)) {
String[] movedInfo = parseTargetHostAndSlot(message);
// throw new JedisMovedDataException(message, new HostAndPort(movedInfo[1],
// Integer.parseInt(movedInfo[2])), Integer.parseInt(movedInfo[0]));
throw new JedisMovedDataException(message, HostAndPort.from(movedInfo[1]), Integer.parseInt(movedInfo[0]));
} else if (message.startsWith(ASK_PREFIX)) {
String[] askInfo = parseTargetHostAndSlot(message);
// throw new JedisAskDataException(message, new HostAndPort(askInfo[1],
// Integer.parseInt(askInfo[2])), Integer.parseInt(askInfo[0]));
throw new JedisAskDataException(message, HostAndPort.from(askInfo[1]), Integer.parseInt(askInfo[0]));
} else if (message.startsWith(CLUSTERDOWN_PREFIX)) {
throw new JedisClusterException(message);
} else if (message.startsWith(BUSY_PREFIX)) {
throw new JedisBusyException(message);
} else if (message.startsWith(NOSCRIPT_PREFIX)) {
throw new JedisNoScriptException(message);
} else if (message.startsWith(NOAUTH_PREFIX)
|| message.startsWith(WRONGPASS_PREFIX)
|| message.startsWith(NOPERM_PREFIX)) {
throw new JedisAccessControlException(message);
}
throw new JedisDataException(message);
}
public static String readErrorLineIfPossible(RedisInputStream is) {
final byte b = is.readByte();
// if buffer contains other type of response, just ignore.
if (b != MINUS_BYTE) {
return null;
}
return is.readLine();
}
// private static String[] parseTargetHostAndSlot(String clusterRedirectResponse) {
// String[] response = new String[3];
// String[] messageInfo = clusterRedirectResponse.split(" ");
// String[] targetHostAndPort = HostAndPort.extractParts(messageInfo[2]);
// response[0] = messageInfo[1];
// response[1] = targetHostAndPort[0];
// response[2] = targetHostAndPort[1];
// return response;
// }
private static String[] parseTargetHostAndSlot(String clusterRedirectResponse) {
String[] response = new String[2];
String[] messageInfo = clusterRedirectResponse.split(" ");
response[0] = messageInfo[1];
response[1] = messageInfo[2];
return response;
}
private static Object process(final RedisInputStream is) {
final byte b = is.readByte();
//System.out.println("BYTE: " + (char) b);
switch (b) {
case PLUS_BYTE:
return is.readLineBytes();
case DOLLAR_BYTE:
case EQUAL_BYTE:
return processBulkReply(is);
case ASTERISK_BYTE:
return processMultiBulkReply(is);
case UNDERSCORE_BYTE:
return is.readNullCrLf();
case HASH_BYTE:
return is.readBooleanCrLf();
case COLON_BYTE:
return is.readLongCrLf();
case COMMA_BYTE:
return is.readDoubleCrLf();
case LEFT_BRACE_BYTE:
return is.readBigIntegerCrLf();
case PERCENT_BYTE: // TODO: currently just to start working with HELLO
return processMapKeyValueReply(is);
case TILDE_BYTE: // TODO:
return processMultiBulkReply(is);
case GREATER_THAN_BYTE:
return processMultiBulkReply(is);
case MINUS_BYTE:
processError(is);
return null;
// TODO: Blob error '!'
default:
throw new JedisConnectionException("Unknown reply: " + (char) b);
}
}
private static byte[] processBulkReply(final RedisInputStream is) {
final int len = is.readIntCrLf();
if (len == -1) {
return null;
}
final byte[] read = new byte[len];
int offset = 0;
while (offset < len) {
final int size = is.read(read, offset, (len - offset));
if (size == -1) {
throw new JedisConnectionException("It seems like server has closed the connection.");
}
offset += size;
}
// read 2 more bytes for the command delimiter
is.readByte();
is.readByte();
return read;
}
private static List