/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.zdemo.cache_; import org.redkale.convert.Convert; import org.redkale.convert.json.JsonConvert; import org.redkale.convert.json.JsonFactory; import org.redkale.net.AsyncConnection; import org.redkale.net.Transport; import org.redkale.net.TransportFactory; import org.redkale.service.AbstractService; import org.redkale.service.Local; import org.redkale.service.Service; import org.redkale.source.CacheSource; import org.redkale.source.Flipper; import org.redkale.util.*; import org.redkale.util.AnyValue.DefaultAnyValue; import javax.annotation.Resource; import java.io.IOException; import java.io.Serializable; import java.lang.reflect.Type; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.CompletionHandler; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Semaphore; import java.util.logging.Level; import java.util.logging.Logger; import static org.redkale.boot.Application.RESNAME_APP_GROUP; /** * 详情见: https://redkale.org * * @param Value * @author zhangjx */ @Local @AutoLoad(false) @ResourceType(CacheSource.class) public class RedisCacheSource extends AbstractService implements CacheSource, Service, AutoCloseable, Resourcable { protected static final byte DOLLAR_BYTE = '$'; protected static final byte ASTERISK_BYTE = '*'; protected static final byte PLUS_BYTE = '+'; protected static final byte MINUS_BYTE = '-'; protected static final byte COLON_BYTE = ':'; private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); @Resource(name = RESNAME_APP_GROUP) protected AsyncGroup asyncGroup; @Resource public JsonConvert defaultConvert; @Resource(name = "$_convert") public JsonConvert convert; protected Type objValueType = String.class; protected Map passwords; protected List nodeAddrs; protected int db; protected Transport transport; @Override public void init(AnyValue conf) { if (this.convert == null) this.convert = this.defaultConvert; if (conf == null) conf = new DefaultAnyValue(); final int readTimeoutSeconds = conf.getIntValue("readTimeoutSeconds", TransportFactory.DEFAULT_READTIMEOUTSECONDS); final int writeTimeoutSeconds = conf.getIntValue("writeTimeoutSeconds", TransportFactory.DEFAULT_WRITETIMEOUTSECONDS); final List addresses = new ArrayList<>(); Map passwords0 = new HashMap<>(); for (AnyValue node : conf.getAnyValues("node")) { String addrstr = node.getValue("addr"); InetSocketAddress addr = null; if (addrstr.startsWith("redis://")) { addrstr = addrstr.substring("redis://".length()); int pos = addrstr.indexOf(':'); addr = new InetSocketAddress(addrstr.substring(0, pos), Integer.parseInt(addrstr.substring(pos + 1))); addresses.add(addr); } else { addr = new InetSocketAddress(addrstr, node.getIntValue("port")); addresses.add(addr); } String password = node.getValue("password", "").trim(); if (!password.isEmpty()) passwords0.put(addr, password.getBytes(StandardCharsets.UTF_8)); String db0 = node.getValue("db", "").trim(); if (!db0.isEmpty()) this.db = Integer.valueOf(db0); } if (!passwords0.isEmpty()) this.passwords = passwords0; this.nodeAddrs = addresses; TransportFactory transportFactory = TransportFactory.create(asyncGroup, readTimeoutSeconds, writeTimeoutSeconds); this.transport = transportFactory.createTransportTCP("Redis-Transport", null, addresses); this.transport.setSemaphore(new Semaphore(conf.getIntValue("maxconns", 1000))); if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, RedisCacheSource.class.getSimpleName() + ": addrs=" + addresses + ", db=" + db); } @Override //ServiceLoader时判断配置是否符合当前实现类 public boolean match(AnyValue config) { if (config == null) return false; AnyValue[] nodes = config.getAnyValues("node"); if (nodes == null || nodes.length == 0) return false; for (AnyValue node : nodes) { if (node.getValue("addr") != null && node.getValue("port") != null) return true; if (node.getValue("addr") != null && node.getValue("addr").startsWith("redis://")) return true; } return false; } public void updateRemoteAddresses(final Collection addresses) { this.transport.updateRemoteAddresses(addresses); } @Override @Deprecated public final void initValueType(Type valueType) { this.objValueType = valueType == null ? String.class : valueType; } @Override @Deprecated public final void initTransient(boolean flag) { } @Override public final String getType() { return "redis"; } public static void main(String[] args) throws Exception { DefaultAnyValue conf = new DefaultAnyValue().addValue("maxconns", "1"); conf.addValue("node", new DefaultAnyValue().addValue("addr", "127.0.0.1").addValue("port", "6363")); final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); asyncGroup.start(); ResourceFactory.root().register(RESNAME_APP_GROUP, asyncGroup); RedisCacheSource source = new RedisCacheSource(); ResourceFactory.root().inject(source); source.init(null); source.defaultConvert = JsonFactory.root().getConvert(); source.init(conf); InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 7788); try { System.out.println("------------------------------------"); source.removeAsync("stritem1"); source.removeAsync("stritem2"); source.setStringAsync("stritem1", "value1"); source.setStringAsync("stritem2", "value2"); System.out.println("stritem开头的key有两个: " + source.queryKeysStartsWith("stritem")); System.out.println("[有值] MGET : " + source.getStringMap("stritem1", "stritem2")); System.out.println("[有值] MGET : " + Arrays.toString(source.getStringArray("stritem1", "stritem2"))); source.remove("intitem1"); source.remove("intitem2"); source.setLong("intitem1", 333); source.setLong("intitem2", 444); System.out.println("[有值] MGET : " + source.getStringMap("intitem1", "intitem22", "intitem2")); System.out.println("[有值] MGET : " + Arrays.toString(source.getStringArray("intitem1", "intitem22", "intitem2"))); source.remove("objitem1"); source.remove("objitem2"); source.set("objitem1", Flipper.class, new Flipper(10)); source.set("objitem2", Flipper.class, new Flipper(20)); System.out.println("[有值] MGET : " + source.getMap(Flipper.class, "objitem1", "objitem2")); source.remove("key1"); source.remove("key2"); source.remove("300"); source.set(1000, "key1", String.class, "value1"); source.set("key1", String.class, "value1"); source.setString("keystr1", "strvalue1"); source.setLong("keylong1", 333L); source.set("300", String.class, "4000"); source.getAndRefresh("key1", 3500, String.class); System.out.println("[有值] 300 GET : " + source.get("300", String.class)); System.out.println("[有值] key1 GET : " + source.get("key1", String.class)); System.out.println("[无值] key2 GET : " + source.get("key2", String.class)); System.out.println("[有值] keystr1 GET : " + source.getString("keystr1")); System.out.println("[有值] keylong1 GET : " + source.getLong("keylong1", 0L)); System.out.println("[有值] key1 EXISTS : " + source.exists("key1")); System.out.println("[无值] key2 EXISTS : " + source.exists("key2")); source.remove("keys3"); source.appendListItem("keys3", String.class, "vals1"); source.appendListItem("keys3", String.class, "vals2"); System.out.println("-------- keys3 追加了两个值 --------"); System.out.println("[两值] keys3 VALUES : " + source.getCollection("keys3", String.class)); System.out.println("[有值] keys3 EXISTS : " + source.exists("keys3")); source.removeListItem("keys3", String.class, "vals1"); System.out.println("[一值] keys3 VALUES : " + source.getCollection("keys3", String.class)); source.getCollectionAndRefresh("keys3", 3000, String.class); source.remove("stringmap"); source.appendSetItem("stringmap", JsonConvert.TYPE_MAP_STRING_STRING, Utility.ofMap("a", "aa", "b", "bb")); source.appendSetItem("stringmap", JsonConvert.TYPE_MAP_STRING_STRING, Utility.ofMap("c", "cc", "d", "dd")); System.out.println("[两值] stringmap VALUES : " + source.getCollectionAsync("stringmap", JsonConvert.TYPE_MAP_STRING_STRING).join()); source.remove("sets3"); source.remove("sets4"); source.appendSetItem("sets3", String.class, "setvals1"); source.appendSetItem("sets3", String.class, "setvals2"); source.appendSetItem("sets3", String.class, "setvals1"); source.appendSetItem("sets4", String.class, "setvals2"); source.appendSetItem("sets4", String.class, "setvals1"); System.out.println("[两值] sets3 VALUES : " + source.getCollection("sets3", String.class)); System.out.println("[有值] sets3 EXISTS : " + source.exists("sets3")); System.out.println("[有值] sets3-setvals2 EXISTSITEM : " + source.existsSetItem("sets3", String.class, "setvals2")); System.out.println("[有值] sets3-setvals3 EXISTSITEM : " + source.existsSetItem("sets3", String.class, "setvals3")); source.removeSetItem("sets3", String.class, "setvals1"); System.out.println("[一值] sets3 VALUES : " + source.getCollection("sets3", String.class)); System.out.println("sets3 大小 : " + source.getCollectionSize("sets3")); System.out.println("all keys: " + source.queryKeys()); System.out.println("key startkeys: " + source.queryKeysStartsWith("key")); System.out.println("newnum 值 : " + source.incr("newnum")); System.out.println("newnum 值 : " + source.decr("newnum")); System.out.println("sets3&sets4: " + source.getStringCollectionMap(true, "sets3", "sets4")); System.out.println("------------------------------------"); source.set("myaddr", InetSocketAddress.class, addr); System.out.println("myaddrstr: " + source.getString("myaddr")); System.out.println("myaddr: " + source.get("myaddr", InetSocketAddress.class)); source.remove("myaddrs"); source.remove("myaddrs2"); source.appendSetItem("myaddrs", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7788)); source.appendSetItem("myaddrs", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7799)); System.out.println("myaddrs: " + source.getCollection("myaddrs", InetSocketAddress.class)); source.removeSetItem("myaddrs", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7788)); System.out.println("myaddrs: " + source.getCollection("myaddrs", InetSocketAddress.class)); source.appendSetItem("myaddrs2", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7788)); source.appendSetItem("myaddrs2", InetSocketAddress.class, new InetSocketAddress("127.0.0.1", 7799)); System.out.println("myaddrs&myaddrs2: " + source.getCollectionMap(true, InetSocketAddress.class, "myaddrs", "myaddrs2")); System.out.println("------------------------------------"); source.remove("myaddrs"); Type mapType = new TypeToken>() { }.getType(); Map map = new HashMap<>(); map.put("a", 1); map.put("b", 2); source.set("mapvals", mapType, map); System.out.println("mapvals: " + source.get("mapvals", mapType)); source.remove("byteskey"); source.setBytes("byteskey", new byte[]{1, 2, 3}); System.out.println("byteskey 值 : " + Arrays.toString(source.getBytes("byteskey"))); //h source.remove("hmap"); source.hincr("hmap", "key1"); System.out.println("hmap.key1 值 : " + source.hgetLong("hmap", "key1", -1)); source.hmset("hmap", "key2", "haha", "key3", 333); source.hmset("hmap", "sm", (HashMap) Utility.ofMap("a", "aa", "b", "bb")); System.out.println("hmap.sm 值 : " + source.hget("hmap", "sm", JsonConvert.TYPE_MAP_STRING_STRING)); System.out.println("hmap.[key1,key2,key3] 值 : " + source.hmget("hmap", String.class, "key1", "key2", "key3")); System.out.println("hmap.keys 四值 : " + source.hkeys("hmap")); source.hremove("hmap", "key1", "key3"); System.out.println("hmap.keys 两值 : " + source.hkeys("hmap")); System.out.println("hmap.key2 值 : " + source.hgetString("hmap", "key2")); System.out.println("hmap列表(2)大小 : " + source.hsize("hmap")); source.remove("hmaplong"); source.hincr("hmaplong", "key1", 10); source.hsetLong("hmaplong", "key2", 30); System.out.println("hmaplong.所有两值 : " + source.hmap("hmaplong", long.class, 0, 10)); source.remove("hmapstr"); source.hsetString("hmapstr", "key1", "str10"); source.hsetString("hmapstr", "key2", null); System.out.println("hmapstr.所有一值 : " + source.hmap("hmapstr", String.class, 0, 10)); source.remove("hmapstrmap"); source.hset("hmapstrmap", "key1", JsonConvert.TYPE_MAP_STRING_STRING, (HashMap) Utility.ofMap("ks11", "vv11")); source.hset("hmapstrmap", "key2", JsonConvert.TYPE_MAP_STRING_STRING, null); System.out.println("hmapstrmap.无值 : " + source.hmap("hmapstrmap", JsonConvert.TYPE_MAP_STRING_STRING, 0, 10, "key2*")); source.remove("popset"); source.appendStringSetItem("popset", "111"); source.appendStringSetItem("popset", "222"); source.appendStringSetItem("popset", "333"); source.appendStringSetItem("popset", "444"); source.appendStringSetItem("popset", "555"); System.out.println("SPOP一个元素:" + source.spopStringSetItem("popset")); System.out.println("SPOP两个元素:" + source.spopStringSetItem("popset", 2)); System.out.println("SPOP五个元素:" + source.spopStringSetItem("popset", 5)); source.appendLongSetItem("popset", 111); source.appendLongSetItem("popset", 222); source.appendLongSetItem("popset", 333); source.appendLongSetItem("popset", 444); source.appendLongSetItem("popset", 555); System.out.println("SPOP一个元素:" + source.spopLongSetItem("popset")); System.out.println("SPOP两个元素:" + source.spopLongSetItem("popset", 2)); System.out.println("SPOP五个元素:" + source.spopLongSetItem("popset", 5)); System.out.println("SPOP一个元素:" + source.spopLongSetItem("popset")); //清除 int rs = source.remove("stritem1"); System.out.println("删除stritem1个数: " + rs); source.remove("popset"); source.remove("stritem2"); source.remove("intitem1"); source.remove("intitem2"); source.remove("keylong1"); source.remove("keystr1"); source.remove("mapvals"); source.remove("myaddr"); source.remove("myaddrs2"); source.remove("newnum"); source.remove("objitem1"); source.remove("objitem2"); source.remove("key1"); source.remove("key2"); source.remove("keys3"); source.remove("sets3"); source.remove("sets4"); source.remove("myaddrs"); source.remove("300"); source.remove("stringmap"); source.remove("hmap"); source.remove("hmaplong"); source.remove("hmapstr"); source.remove("hmapstrmap"); source.remove("byteskey"); System.out.println("------------------------------------"); // System.out.println("--------------测试大文本---------------"); // HashMap bigmap = new HashMap<>(); // StringBuilder sb = new StringBuilder(); // sb.append("起始"); // for (int i = 0; i < 1024 * 1024; i++) { // sb.append("abcde"); // } // sb.append("结束"); // bigmap.put("val", sb.toString()); // System.out.println("文本长度: " + sb.length()); // source.set("bigmap", JsonConvert.TYPE_MAP_STRING_STRING, bigmap); // System.out.println("写入完成"); // for (int i = 0; i < 1; i++) { // HashMap fs = (HashMap) source.get("bigmap", JsonConvert.TYPE_MAP_STRING_STRING); // System.out.println("内容长度: " + fs.get("val").length()); // } source.remove("bigmap"); } finally { source.close(); } } @Override public void close() throws Exception { //在 Application 关闭时调用 destroy(null); } @Override public String resourceName() { Resource res = this.getClass().getAnnotation(Resource.class); return res == null ? "" : res.name(); } @Override public String toString() { return getClass().getSimpleName() + "{addrs = " + this.nodeAddrs + ", db=" + this.db + "}"; } @Override public void destroy(AnyValue conf) { if (transport != null) transport.close(); } //--------------------- exists ------------------------------ @Override public CompletableFuture existsAsync(String key) { return (CompletableFuture) send("EXISTS", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public boolean exists(String key) { return existsAsync(key).join(); } //--------------------- get ------------------------------ @Override @Deprecated public CompletableFuture getAsync(String key) { return (CompletableFuture) send("GET", CacheEntryType.OBJECT, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture getAsync(String key, Type type) { return (CompletableFuture) send("GET", CacheEntryType.OBJECT, type, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture getStringAsync(String key) { return (CompletableFuture) send("GET", CacheEntryType.STRING, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture getLongAsync(String key, long defValue) { return ((CompletableFuture) send("GET", CacheEntryType.LONG, (Type) null, key, key.getBytes(StandardCharsets.UTF_8))).thenApplyAsync(v -> v == null ? defValue : v); } @Override @Deprecated public V get(String key) { return getAsync(key).join(); } @Override public T get(String key, final Type type) { return (T) getAsync(key, type).join(); } @Override public String getString(String key) { return getStringAsync(key).join(); } @Override public long getLong(String key, long defValue) { return getLongAsync(key, defValue).join(); } //--------------------- getAndRefresh ------------------------------ @Override @Deprecated public CompletableFuture getAndRefreshAsync(String key, int expireSeconds) { return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getAsync(key)); } @Override public CompletableFuture getAndRefreshAsync(String key, int expireSeconds, final Type type) { return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getAsync(key, type)); } @Override @Deprecated public V getAndRefresh(String key, final int expireSeconds) { return getAndRefreshAsync(key, expireSeconds).join(); } @Override public T getAndRefresh(String key, final int expireSeconds, final Type type) { return (T) getAndRefreshAsync(key, expireSeconds, type).join(); } @Override public CompletableFuture getStringAndRefreshAsync(String key, int expireSeconds) { return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getStringAsync(key)); } @Override public String getStringAndRefresh(String key, final int expireSeconds) { return getStringAndRefreshAsync(key, expireSeconds).join(); } @Override public CompletableFuture getLongAndRefreshAsync(String key, int expireSeconds, long defValue) { return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getLongAsync(key, defValue)); } @Override public long getLongAndRefresh(String key, final int expireSeconds, long defValue) { return getLongAndRefreshAsync(key, expireSeconds, defValue).join(); } //--------------------- refresh ------------------------------ @Override public CompletableFuture refreshAsync(String key, int expireSeconds) { return setExpireSecondsAsync(key, expireSeconds); } @Override public void refresh(String key, final int expireSeconds) { setExpireSeconds(key, expireSeconds); } //--------------------- set ------------------------------ @Override @Deprecated public CompletableFuture setAsync(String key, V value) { CacheEntryType cet = this.objValueType == String.class ? CacheEntryType.STRING : CacheEntryType.OBJECT; return (CompletableFuture) send("SET", cet, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(cet, (Convert) null, (Type) null, value)); } @Override public CompletableFuture setAsync(String key, Convert convert, T value) { CacheEntryType cet = value instanceof CharSequence ? CacheEntryType.STRING : CacheEntryType.OBJECT; return (CompletableFuture) send("SET", cet, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(cet, convert, (Type) null, value)); } @Override public CompletableFuture setAsync(String key, final Type type, T value) { CacheEntryType cet = type == String.class ? CacheEntryType.STRING : CacheEntryType.OBJECT; return (CompletableFuture) send("SET", cet, type, key, key.getBytes(StandardCharsets.UTF_8), formatValue(cet, (Convert) null, type, value)); } @Override public CompletableFuture setAsync(String key, Convert convert, final Type type, T value) { CacheEntryType cet = type == String.class ? CacheEntryType.STRING : CacheEntryType.OBJECT; return (CompletableFuture) send("SET", cet, type, key, key.getBytes(StandardCharsets.UTF_8), formatValue(cet, convert, type, value)); } @Override @Deprecated public void set(final String key, V value) { setAsync(key, value).join(); } @Override public void set(final String key, final Convert convert, T value) { setAsync(key, convert, value).join(); } @Override public void set(final String key, final Type type, T value) { setAsync(key, type, value).join(); } @Override public void set(String key, final Convert convert, final Type type, T value) { setAsync(key, convert, type, value).join(); } @Override public CompletableFuture setStringAsync(String key, String value) { return (CompletableFuture) send("SET", CacheEntryType.STRING, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); } @Override public void setString(String key, String value) { setStringAsync(key, value).join(); } @Override public CompletableFuture setLongAsync(String key, long value) { return (CompletableFuture) send("SET", CacheEntryType.LONG, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); } @Override public void setLong(String key, long value) { setLongAsync(key, value).join(); } //--------------------- set ------------------------------ @Override @Deprecated public CompletableFuture setAsync(int expireSeconds, String key, V value) { return (CompletableFuture) setAsync(key, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); } @Override public CompletableFuture setAsync(int expireSeconds, String key, Convert convert, T value) { return (CompletableFuture) setAsync(key, convert, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); } @Override public CompletableFuture setAsync(int expireSeconds, String key, final Type type, T value) { return (CompletableFuture) setAsync(key, type, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); } @Override public CompletableFuture setAsync(int expireSeconds, String key, Convert convert, final Type type, T value) { return (CompletableFuture) setAsync(key, convert, type, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); } @Override @Deprecated public void set(int expireSeconds, String key, V value) { setAsync(expireSeconds, key, value).join(); } @Override public void set(int expireSeconds, String key, Convert convert, T value) { setAsync(expireSeconds, key, convert, value).join(); } @Override public void set(int expireSeconds, String key, final Type type, T value) { setAsync(expireSeconds, key, type, value).join(); } @Override public void set(int expireSeconds, String key, Convert convert, final Type type, T value) { setAsync(expireSeconds, key, convert, type, value).join(); } @Override public CompletableFuture setStringAsync(int expireSeconds, String key, String value) { return (CompletableFuture) setStringAsync(key, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); } @Override public void setString(int expireSeconds, String key, String value) { setStringAsync(expireSeconds, key, value).join(); } @Override public CompletableFuture setLongAsync(int expireSeconds, String key, long value) { return (CompletableFuture) setLongAsync(key, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); } @Override public void setLong(int expireSeconds, String key, long value) { setLongAsync(expireSeconds, key, value).join(); } //--------------------- setExpireSeconds ------------------------------ @Override public CompletableFuture setExpireSecondsAsync(String key, int expireSeconds) { return (CompletableFuture) send("EXPIRE", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)); } @Override public void setExpireSeconds(String key, int expireSeconds) { setExpireSecondsAsync(key, expireSeconds).join(); } //--------------------- remove ------------------------------ @Override public CompletableFuture removeAsync(String key) { return (CompletableFuture) send("DEL", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public int remove(String key) { return removeAsync(key).join(); } //--------------------- incr ------------------------------ @Override public long incr(final String key) { return incrAsync(key).join(); } @Override public CompletableFuture incrAsync(final String key) { return (CompletableFuture) send("INCR", CacheEntryType.ATOMIC, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public long incr(final String key, long num) { return incrAsync(key, num).join(); } @Override public CompletableFuture incrAsync(final String key, long num) { return (CompletableFuture) send("INCRBY", CacheEntryType.ATOMIC, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)); } //--------------------- decr ------------------------------ @Override public long decr(final String key) { return decrAsync(key).join(); } @Override public CompletableFuture decrAsync(final String key) { return (CompletableFuture) send("DECR", CacheEntryType.ATOMIC, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public long decr(final String key, long num) { return decrAsync(key, num).join(); } @Override public CompletableFuture decrAsync(final String key, long num) { return (CompletableFuture) send("DECRBY", CacheEntryType.ATOMIC, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)); } @Override public int hremove(final String key, String... fields) { return hremoveAsync(key, fields).join(); } @Override public int hsize(final String key) { return hsizeAsync(key).join(); } @Override public List hkeys(final String key) { return hkeysAsync(key).join(); } @Override public long hincr(final String key, String field) { return hincrAsync(key, field).join(); } @Override public long hincr(final String key, String field, long num) { return hincrAsync(key, field, num).join(); } @Override public long hdecr(final String key, String field) { return hdecrAsync(key, field).join(); } @Override public long hdecr(final String key, String field, long num) { return hdecrAsync(key, field, num).join(); } @Override public boolean hexists(final String key, String field) { return hexistsAsync(key, field).join(); } @Override public void hset(final String key, final String field, final Convert convert, final T value) { hsetAsync(key, field, convert, value).join(); } @Override public void hset(final String key, final String field, final Type type, final T value) { hsetAsync(key, field, type, value).join(); } @Override public void hset(final String key, final String field, final Convert convert, final Type type, final T value) { hsetAsync(key, field, convert, type, value).join(); } @Override public void hsetString(final String key, final String field, final String value) { hsetStringAsync(key, field, value).join(); } @Override public void hsetLong(final String key, final String field, final long value) { hsetLongAsync(key, field, value).join(); } @Override public void hmset(final String key, final Serializable... values) { hmsetAsync(key, values).join(); } @Override public List hmget(final String key, final Type type, final String... fields) { return hmgetAsync(key, type, fields).join(); } @Override public Map hmap(final String key, final Type type, int offset, int limit, String pattern) { return (Map) hmapAsync(key, type, offset, limit, pattern).join(); } @Override public Map hmap(final String key, final Type type, int offset, int limit) { return (Map) hmapAsync(key, type, offset, limit).join(); } @Override public T hget(final String key, final String field, final Type type) { return (T) hgetAsync(key, field, type).join(); } @Override public String hgetString(final String key, final String field) { return hgetStringAsync(key, field).join(); } @Override public long hgetLong(final String key, final String field, long defValue) { return hgetLongAsync(key, field, defValue).join(); } @Override public CompletableFuture hremoveAsync(final String key, String... fields) { byte[][] bs = new byte[fields.length + 1][]; bs[0] = key.getBytes(StandardCharsets.UTF_8); for (int i = 0; i < fields.length; i++) { bs[i + 1] = fields[i].getBytes(StandardCharsets.UTF_8); } return (CompletableFuture) send("HDEL", CacheEntryType.MAP, (Type) null, key, bs); } @Override public CompletableFuture hsizeAsync(final String key) { return (CompletableFuture) send("HLEN", CacheEntryType.LONG, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture> hkeysAsync(final String key) { return (CompletableFuture) send("HKEYS", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture hincrAsync(final String key, String field) { return hincrAsync(key, field, 1); } @Override public CompletableFuture hincrAsync(final String key, String field, long num) { return (CompletableFuture) send("HINCRBY", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture hdecrAsync(final String key, String field) { return hincrAsync(key, field, -1); } @Override public CompletableFuture hdecrAsync(final String key, String field, long num) { return hincrAsync(key, field, -num); } @Override public CompletableFuture hexistsAsync(final String key, String field) { return (CompletableFuture) send("HEXISTS", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final T value) { return (CompletableFuture) send("HSET", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.MAP, convert, null, value)); } @Override public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value) { return (CompletableFuture) send("HSET", CacheEntryType.MAP, type, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.MAP, null, type, value)); } @Override public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final Type type, final T value) { return (CompletableFuture) send("HSET", CacheEntryType.MAP, type, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.MAP, convert, type, value)); } @Override public CompletableFuture hsetStringAsync(final String key, final String field, final String value) { return (CompletableFuture) send("HSET", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, null, null, value)); } @Override public CompletableFuture hsetLongAsync(final String key, final String field, final long value) { return (CompletableFuture) send("HSET", CacheEntryType.MAP, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, null, null, value)); } @Override public CompletableFuture hmsetAsync(final String key, final Serializable... values) { byte[][] bs = new byte[values.length + 1][]; bs[0] = key.getBytes(StandardCharsets.UTF_8); for (int i = 0; i < values.length; i += 2) { bs[i + 1] = String.valueOf(values[i]).getBytes(StandardCharsets.UTF_8); bs[i + 2] = formatValue(CacheEntryType.MAP, null, null, values[i + 1]); } return (CompletableFuture) send("HMSET", CacheEntryType.MAP, (Type) null, key, bs); } @Override public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields) { byte[][] bs = new byte[fields.length + 1][]; bs[0] = key.getBytes(StandardCharsets.UTF_8); for (int i = 0; i < fields.length; i++) { bs[i + 1] = fields[i].getBytes(StandardCharsets.UTF_8); } return (CompletableFuture) send("HMGET", CacheEntryType.MAP, type, key, bs); } @Override public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit) { return hmapAsync(key, type, offset, limit, null); } @Override public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit, String pattern) { byte[][] bs = new byte[pattern == null || pattern.isEmpty() ? 4 : 6][limit]; int index = -1; bs[++index] = key.getBytes(StandardCharsets.UTF_8); bs[++index] = String.valueOf(offset).getBytes(StandardCharsets.UTF_8); if (pattern != null && !pattern.isEmpty()) { bs[++index] = "MATCH".getBytes(StandardCharsets.UTF_8); bs[++index] = pattern.getBytes(StandardCharsets.UTF_8); } bs[++index] = "COUNT".getBytes(StandardCharsets.UTF_8); bs[++index] = String.valueOf(limit).getBytes(StandardCharsets.UTF_8); return (CompletableFuture) send("HSCAN", CacheEntryType.MAP, type, key, bs); } @Override public CompletableFuture hgetAsync(final String key, final String field, final Type type) { return (CompletableFuture) send("HGET", CacheEntryType.OBJECT, type, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture hgetStringAsync(final String key, final String field) { return (CompletableFuture) send("HGET", CacheEntryType.STRING, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture hgetLongAsync(final String key, final String field, long defValue) { return (CompletableFuture) send("HGET", CacheEntryType.LONG, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)).thenApplyAsync(v -> v == null ? defValue : v); } //--------------------- collection ------------------------------ @Override public CompletableFuture getCollectionSizeAsync(String key) { return (CompletableFuture) send("TYPE", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { if (t == null) return CompletableFuture.completedFuture(0); String rs = new String((byte[]) t); if (rs.contains("zset")) { // ziplist return send("ZCARD", null, int.class, key, key.getBytes(StandardCharsets.UTF_8)); } else if (rs.contains("list")) { //list return send("LLEN", null, int.class, key, key.getBytes(StandardCharsets.UTF_8)); } else if (rs.contains("hash")) { return send("HLEN", null, int.class, key, key.getBytes(StandardCharsets.UTF_8)); } else { return send("SCARD", null, int.class, key, key.getBytes(StandardCharsets.UTF_8)); } }); } @Override public int getCollectionSize(String key) { return getCollectionSizeAsync(key).join(); } @Override @Deprecated public CompletableFuture> getCollectionAsync(String key) { return (CompletableFuture) send("TYPE", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { if (t == null) return CompletableFuture.completedFuture(null); String str = new String((byte[]) t); if (str.contains("list")) { //list return send("LRANGE", CacheEntryType.OBJECT, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}); } else if (str.contains("none")) { return CompletableFuture.completedFuture(new ArrayList<>()); } else { return send("SMEMBERS", CacheEntryType.OBJECT, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)); } }); } @Override public CompletableFuture> getCollectionAsync(String key, final Type componentType) { return (CompletableFuture) send("TYPE", null, componentType, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { if (t == null) return CompletableFuture.completedFuture(null); if (new String((byte[]) t).contains("list")) { //list return send("LRANGE", CacheEntryType.OBJECT, componentType, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}); } else { return send("SMEMBERS", CacheEntryType.OBJECT, componentType, true, key, key.getBytes(StandardCharsets.UTF_8)); } }); } @Override public CompletableFuture> getLongMapAsync(String... keys) { byte[][] bs = new byte[keys.length][]; for (int i = 0; i < bs.length; i++) { bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); } return (CompletableFuture) send("MGET", CacheEntryType.LONG, null, false, keys[0], bs).thenApply(r -> { List list = (List) r; Map map = new LinkedHashMap<>(); for (int i = 0; i < keys.length; i++) { Object obj = list.get(i); if (obj != null) map.put(keys[i], list.get(i)); } return map; }); } @Override public CompletableFuture getLongArrayAsync(String... keys) { byte[][] bs = new byte[keys.length][]; for (int i = 0; i < bs.length; i++) { bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); } return (CompletableFuture) send("MGET", CacheEntryType.LONG, null, false, keys[0], bs).thenApply(r -> { List list = (List) r; Long[] rs = new Long[keys.length]; for (int i = 0; i < keys.length; i++) { Number obj = (Number) list.get(i); rs[i] = obj == null ? null : obj.longValue(); } return rs; }); } @Override public CompletableFuture getStringArrayAsync(String... keys) { byte[][] bs = new byte[keys.length][]; for (int i = 0; i < bs.length; i++) { bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); } return (CompletableFuture) send("MGET", CacheEntryType.STRING, null, false, keys[0], bs).thenApply(r -> { List list = (List) r; String[] rs = new String[keys.length]; for (int i = 0; i < keys.length; i++) { Object obj = list.get(i); rs[i] = obj == null ? null : obj.toString(); } return rs; }); } @Override public CompletableFuture> getStringMapAsync(String... keys) { byte[][] bs = new byte[keys.length][]; for (int i = 0; i < bs.length; i++) { bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); } return (CompletableFuture) send("MGET", CacheEntryType.STRING, null, false, keys[0], bs).thenApply(r -> { List list = (List) r; Map map = new LinkedHashMap<>(); for (int i = 0; i < keys.length; i++) { Object obj = list.get(i); if (obj != null) map.put(keys[i], list.get(i)); } return map; }); } @Override public CompletableFuture> getMapAsync(final Type componentType, String... keys) { byte[][] bs = new byte[keys.length][]; for (int i = 0; i < bs.length; i++) { bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); } return (CompletableFuture) send("MGET", CacheEntryType.OBJECT, componentType, false, keys[0], bs).thenApply(r -> { List list = (List) r; Map map = new LinkedHashMap<>(); for (int i = 0; i < keys.length; i++) { Object obj = list.get(i); if (obj != null) map.put(keys[i], list.get(i)); } return map; }); } @Override public CompletableFuture>> getCollectionMapAsync(final boolean set, final Type componentType, final String... keys) { final CompletableFuture>> rsFuture = new CompletableFuture<>(); final Map> map = new HashMap<>(); final CompletableFuture[] futures = new CompletableFuture[keys.length]; if (!set) { //list for (int i = 0; i < keys.length; i++) { final String key = keys[i]; futures[i] = send("LRANGE", CacheEntryType.OBJECT, componentType, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}).thenAccept(c -> { if (c != null) { synchronized (map) { map.put(key, (Collection) c); } } }); } } else { for (int i = 0; i < keys.length; i++) { final String key = keys[i]; futures[i] = send("SMEMBERS", CacheEntryType.OBJECT, componentType, true, key, key.getBytes(StandardCharsets.UTF_8)).thenAccept(c -> { if (c != null) { synchronized (map) { map.put(key, (Collection) c); } } }); } } CompletableFuture.allOf(futures).whenComplete((w, e) -> { if (e != null) { rsFuture.completeExceptionally(e); } else { rsFuture.complete(map); } }); return rsFuture; } @Override @Deprecated public Collection getCollection(String key) { return getCollectionAsync(key).join(); } @Override public Collection getCollection(String key, final Type componentType) { return (Collection) getCollectionAsync(key, componentType).join(); } @Override public Map getLongMap(final String... keys) { return getLongMapAsync(keys).join(); } @Override public Long[] getLongArray(final String... keys) { return getLongArrayAsync(keys).join(); } @Override public Map getStringMap(final String... keys) { return getStringMapAsync(keys).join(); } @Override public String[] getStringArray(final String... keys) { return getStringArrayAsync(keys).join(); } @Override public Map getMap(final Type componentType, final String... keys) { return (Map) getMapAsync(componentType, keys).join(); } @Override public Map> getCollectionMap(final boolean set, final Type componentType, String... keys) { return (Map) getCollectionMapAsync(set, componentType, keys).join(); } @Override public CompletableFuture> getStringCollectionAsync(String key) { return (CompletableFuture) send("TYPE", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { if (t == null) return CompletableFuture.completedFuture(null); if (new String((byte[]) t).contains("list")) { //list return send("LRANGE", CacheEntryType.STRING, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}); } else { return send("SMEMBERS", CacheEntryType.STRING, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)); } }); } @Override public CompletableFuture>> getStringCollectionMapAsync(final boolean set, String... keys) { final CompletableFuture>> rsFuture = new CompletableFuture<>(); final Map> map = new HashMap<>(); final CompletableFuture[] futures = new CompletableFuture[keys.length]; if (!set) { //list for (int i = 0; i < keys.length; i++) { final String key = keys[i]; futures[i] = send("LRANGE", CacheEntryType.STRING, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}).thenAccept(c -> { if (c != null) { synchronized (map) { map.put(key, (Collection) c); } } }); } } else { for (int i = 0; i < keys.length; i++) { final String key = keys[i]; futures[i] = send("SMEMBERS", CacheEntryType.STRING, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)).thenAccept(c -> { if (c != null) { synchronized (map) { map.put(key, (Collection) c); } } }); } } CompletableFuture.allOf(futures).whenComplete((w, e) -> { if (e != null) { rsFuture.completeExceptionally(e); } else { rsFuture.complete(map); } }); return rsFuture; } @Override public Collection getStringCollection(String key) { return getStringCollectionAsync(key).join(); } @Override public Map> getStringCollectionMap(final boolean set, String... keys) { return getStringCollectionMapAsync(set, keys).join(); } @Override public CompletableFuture> getLongCollectionAsync(String key) { return (CompletableFuture) send("TYPE", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { if (t == null) return CompletableFuture.completedFuture(null); if (new String((byte[]) t).contains("list")) { //list return send("LRANGE", CacheEntryType.LONG, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}); } else { return send("SMEMBERS", CacheEntryType.LONG, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)); } }); } @Override public CompletableFuture>> getLongCollectionMapAsync(final boolean set, String... keys) { final CompletableFuture>> rsFuture = new CompletableFuture<>(); final Map> map = new HashMap<>(); final CompletableFuture[] futures = new CompletableFuture[keys.length]; if (!set) { //list for (int i = 0; i < keys.length; i++) { final String key = keys[i]; futures[i] = send("LRANGE", CacheEntryType.LONG, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}).thenAccept(c -> { if (c != null) { synchronized (map) { map.put(key, (Collection) c); } } }); } } else { for (int i = 0; i < keys.length; i++) { final String key = keys[i]; futures[i] = send("SMEMBERS", CacheEntryType.LONG, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)).thenAccept(c -> { if (c != null) { synchronized (map) { map.put(key, (Collection) c); } } }); } } CompletableFuture.allOf(futures).whenComplete((w, e) -> { if (e != null) { rsFuture.completeExceptionally(e); } else { rsFuture.complete(map); } }); return rsFuture; } @Override public Collection getLongCollection(String key) { return getLongCollectionAsync(key).join(); } @Override public Map> getLongCollectionMap(final boolean set, String... keys) { return getLongCollectionMapAsync(set, keys).join(); } //--------------------- getCollectionAndRefresh ------------------------------ @Override @Deprecated public CompletableFuture> getCollectionAndRefreshAsync(String key, int expireSeconds) { return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getCollectionAsync(key)); } @Override public CompletableFuture> getCollectionAndRefreshAsync(String key, int expireSeconds, final Type componentType) { return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getCollectionAsync(key, componentType)); } @Override @Deprecated public Collection getCollectionAndRefresh(String key, final int expireSeconds) { return getCollectionAndRefreshAsync(key, expireSeconds).join(); } @Override public Collection getCollectionAndRefresh(String key, final int expireSeconds, final Type componentType) { return (Collection) getCollectionAndRefreshAsync(key, expireSeconds, componentType).join(); } @Override public CompletableFuture> getStringCollectionAndRefreshAsync(String key, int expireSeconds) { return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getStringCollectionAsync(key)); } @Override public Collection getStringCollectionAndRefresh(String key, final int expireSeconds) { return getStringCollectionAndRefreshAsync(key, expireSeconds).join(); } @Override public CompletableFuture> getLongCollectionAndRefreshAsync(String key, int expireSeconds) { return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getLongCollectionAsync(key)); } @Override public Collection getLongCollectionAndRefresh(String key, final int expireSeconds) { return getLongCollectionAndRefreshAsync(key, expireSeconds).join(); } //--------------------- existsItem ------------------------------ @Override @Deprecated public boolean existsSetItem(String key, V value) { return existsSetItemAsync(key, value).join(); } @Override public boolean existsSetItem(String key, final Type componentType, T value) { return existsSetItemAsync(key, componentType, value).join(); } @Override @Deprecated public CompletableFuture existsSetItemAsync(String key, V value) { return (CompletableFuture) send("SISMEMBER", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); } @Override public CompletableFuture existsSetItemAsync(String key, final Type componentType, T value) { return (CompletableFuture) send("SISMEMBER", null, componentType, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, componentType, value)); } @Override public boolean existsStringSetItem(String key, String value) { return existsStringSetItemAsync(key, value).join(); } @Override public CompletableFuture existsStringSetItemAsync(String key, String value) { return (CompletableFuture) send("SISMEMBER", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); } @Override public boolean existsLongSetItem(String key, long value) { return existsLongSetItemAsync(key, value).join(); } @Override public CompletableFuture existsLongSetItemAsync(String key, long value) { return (CompletableFuture) send("SISMEMBER", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); } //--------------------- appendListItem ------------------------------ @Override @Deprecated public CompletableFuture appendListItemAsync(String key, V value) { return (CompletableFuture) send("RPUSH", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); } @Override public CompletableFuture appendListItemAsync(String key, final Type componentType, T value) { return (CompletableFuture) send("RPUSH", null, componentType, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, componentType, value)); } @Override @Deprecated public void appendListItem(String key, V value) { appendListItemAsync(key, value).join(); } @Override public void appendListItem(String key, final Type componentType, T value) { appendListItemAsync(key, componentType, value).join(); } @Override public CompletableFuture appendStringListItemAsync(String key, String value) { return (CompletableFuture) send("RPUSH", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); } @Override public void appendStringListItem(String key, String value) { appendStringListItemAsync(key, value).join(); } @Override public CompletableFuture appendLongListItemAsync(String key, long value) { return (CompletableFuture) send("RPUSH", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); } @Override public void appendLongListItem(String key, long value) { appendLongListItemAsync(key, value).join(); } //--------------------- removeListItem ------------------------------ @Override @Deprecated public CompletableFuture removeListItemAsync(String key, V value) { return (CompletableFuture) send("LREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); } @Override public CompletableFuture removeListItemAsync(String key, final Type componentType, T value) { return (CompletableFuture) send("LREM", null, componentType, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(CacheEntryType.OBJECT, (Convert) null, componentType, value)); } @Override @Deprecated public int removeListItem(String key, V value) { return removeListItemAsync(key, value).join(); } @Override public int removeListItem(String key, final Type componentType, T value) { return removeListItemAsync(key, componentType, value).join(); } @Override public CompletableFuture removeStringListItemAsync(String key, String value) { return (CompletableFuture) send("LREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); } @Override public int removeStringListItem(String key, String value) { return removeStringListItemAsync(key, value).join(); } @Override public CompletableFuture removeLongListItemAsync(String key, long value) { return (CompletableFuture) send("LREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); } @Override public int removeLongListItem(String key, long value) { return removeLongListItemAsync(key, value).join(); } //--------------------- appendSetItem ------------------------------ @Override @Deprecated public CompletableFuture appendSetItemAsync(String key, V value) { return (CompletableFuture) send("SADD", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); } @Override public CompletableFuture appendSetItemAsync(String key, Type componentType, T value) { return (CompletableFuture) send("SADD", null, componentType, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, componentType, value)); } @Override public CompletableFuture spopSetItemAsync(String key, Type componentType) { return (CompletableFuture) send("SPOP", CacheEntryType.OBJECT, componentType, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture> spopSetItemAsync(String key, int count, Type componentType) { return (CompletableFuture) send("SPOP", CacheEntryType.OBJECT, componentType, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(count).getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture spopStringSetItemAsync(String key) { return (CompletableFuture) send("SPOP", CacheEntryType.STRING, String.class, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture> spopStringSetItemAsync(String key, int count) { return (CompletableFuture) send("SPOP", CacheEntryType.STRING, String.class, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(count).getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture spopLongSetItemAsync(String key) { return (CompletableFuture) send("SPOP", CacheEntryType.LONG, long.class, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture> spopLongSetItemAsync(String key, int count) { return (CompletableFuture) send("SPOP", CacheEntryType.LONG, long.class, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(count).getBytes(StandardCharsets.UTF_8)); } @Override @Deprecated public void appendSetItem(String key, V value) { appendSetItemAsync(key, value).join(); } @Override public void appendSetItem(String key, final Type componentType, T value) { appendSetItemAsync(key, componentType, value).join(); } @Override public T spopSetItem(String key, final Type componentType) { return (T) spopSetItemAsync(key, componentType).join(); } @Override public List spopSetItem(String key, int count, final Type componentType) { return (List) spopSetItemAsync(key, count, componentType).join(); } @Override public String spopStringSetItem(String key) { return spopStringSetItemAsync(key).join(); } @Override public List spopStringSetItem(String key, int count) { return spopStringSetItemAsync(key, count).join(); } @Override public Long spopLongSetItem(String key) { return spopLongSetItemAsync(key).join(); } @Override public List spopLongSetItem(String key, int count) { return spopLongSetItemAsync(key, count).join(); } @Override public CompletableFuture appendStringSetItemAsync(String key, String value) { return (CompletableFuture) send("SADD", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); } @Override public void appendStringSetItem(String key, String value) { appendStringSetItemAsync(key, value).join(); } @Override public CompletableFuture appendLongSetItemAsync(String key, long value) { return (CompletableFuture) send("SADD", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); } @Override public void appendLongSetItem(String key, long value) { appendLongSetItemAsync(key, value).join(); } //--------------------- removeSetItem ------------------------------ @Override @Deprecated public CompletableFuture removeSetItemAsync(String key, V value) { return (CompletableFuture) send("SREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); } @Override public CompletableFuture removeSetItemAsync(String key, final Type componentType, T value) { return (CompletableFuture) send("SREM", null, componentType, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, componentType, value)); } @Override @Deprecated public int removeSetItem(String key, V value) { return removeSetItemAsync(key, value).join(); } @Override public int removeSetItem(String key, final Type componentType, T value) { return removeSetItemAsync(key, componentType, value).join(); } @Override public CompletableFuture removeStringSetItemAsync(String key, String value) { return (CompletableFuture) send("SREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.STRING, (Convert) null, (Type) null, value)); } @Override public int removeStringSetItem(String key, String value) { return removeStringSetItemAsync(key, value).join(); } @Override public CompletableFuture removeLongSetItemAsync(String key, long value) { return (CompletableFuture) send("SREM", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.LONG, (Convert) null, (Type) null, value)); } @Override public int removeLongSetItem(String key, long value) { return removeLongSetItemAsync(key, value).join(); } //--------------------- queryKeys ------------------------------ @Override public List queryKeys() { return queryKeysAsync().join(); } @Override public List queryKeysStartsWith(String startsWith) { return queryKeysStartsWithAsync(startsWith).join(); } @Override public List queryKeysEndsWith(String endsWith) { return queryKeysEndsWithAsync(endsWith).join(); } @Override public byte[] getBytes(final String key) { return getBytesAsync(key).join(); } @Override public byte[] getBytesAndRefresh(final String key, final int expireSeconds) { return getBytesAndRefreshAsync(key, expireSeconds).join(); } @Override public void setBytes(final String key, final byte[] value) { setBytesAsync(key, value).join(); } @Override public void setBytes(final int expireSeconds, final String key, final byte[] value) { setBytesAsync(expireSeconds, key, value).join(); } @Override public void setBytes(final String key, final Convert convert, final Type type, final T value) { setBytesAsync(key, convert, type, value).join(); } @Override public void setBytes(final int expireSeconds, final String key, final Convert convert, final Type type, final T value) { setBytesAsync(expireSeconds, key, convert, type, value).join(); } @Override public CompletableFuture getBytesAsync(final String key) { return (CompletableFuture) send("GET", CacheEntryType.BYTES, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture getBytesAndRefreshAsync(final String key, final int expireSeconds) { return (CompletableFuture) refreshAsync(key, expireSeconds).thenCompose(v -> getBytesAsync(key)); } @Override public CompletableFuture setBytesAsync(final String key, final byte[] value) { return (CompletableFuture) send("SET", CacheEntryType.BYTES, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), value); } @Override public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final byte[] value) { return (CompletableFuture) setBytesAsync(key, value).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); } @Override public CompletableFuture setBytesAsync(final String key, final Convert convert, final Type type, final T value) { return (CompletableFuture) send("SET", CacheEntryType.BYTES, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), convert.convertToBytes(type, value)); } @Override public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final Convert convert, final Type type, final T value) { return (CompletableFuture) setBytesAsync(key, convert.convertToBytes(type, value)).thenCompose(v -> setExpireSecondsAsync(key, expireSeconds)); } @Override public CompletableFuture> queryKeysAsync() { return (CompletableFuture) send("KEYS", null, (Type) null, "*", new byte[]{(byte) '*'}); } @Override public CompletableFuture> queryKeysStartsWithAsync(String startsWith) { if (startsWith == null) return queryKeysAsync(); String key = startsWith + "*"; return (CompletableFuture) send("KEYS", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } @Override public CompletableFuture> queryKeysEndsWithAsync(String endsWith) { if (endsWith == null) return queryKeysAsync(); String key = "*" + endsWith; return (CompletableFuture) send("KEYS", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)); } //--------------------- getKeySize ------------------------------ @Override public int getKeySize() { return getKeySizeAsync().join(); } @Override public CompletableFuture getKeySizeAsync() { return (CompletableFuture) send("DBSIZE", null, (Type) null, null); } //--------------------- queryList ------------------------------ @Override public List> queryList() { return queryListAsync().join(); } @Override public CompletableFuture>> queryListAsync() { return CompletableFuture.completedFuture(new ArrayList<>()); //不返回数据 } //--------------------- send ------------------------------ private byte[] formatValue(CacheEntryType cacheType, Convert convert0, Type resultType, Object value) { if (value == null) return "null".getBytes(StandardCharsets.UTF_8); if (value instanceof byte[]) return (byte[]) value; if (convert0 == null) convert0 = convert; if (cacheType == CacheEntryType.MAP) { if ((value instanceof CharSequence) || (value instanceof Number)) { return String.valueOf(value).getBytes(StandardCharsets.UTF_8); } if (objValueType == String.class && !(value instanceof CharSequence)) resultType = value.getClass(); return convert0.convertToBytes(resultType == null ? objValueType : resultType, value); } if (value instanceof Number || cacheType == CacheEntryType.LONG || cacheType == CacheEntryType.ATOMIC || value.getClass() == String.class) return String.valueOf(value).getBytes(StandardCharsets.UTF_8); if (cacheType == CacheEntryType.STRING) return convert0.convertToBytes(String.class, value); return convert0.convertToBytes(resultType == null ? objValueType : resultType, value); } protected CompletableFuture send(final String command, final CacheEntryType cacheType, final Type resultType, final String key, final byte[]... args) { return send(command, cacheType, resultType, false, key, args); } protected CompletableFuture send(final String command, final CacheEntryType cacheType, final Type resultType, final boolean set, final String key, final byte[]... args) { return send(null, command, cacheType, resultType, set, key, args); } private CompletableFuture send(final CompletionHandler callback, final String command, final CacheEntryType cacheType, final Type resultType, final boolean set, final String key, final byte[]... args) { final ByteArray writer = new ByteArray(); writer.put(ASTERISK_BYTE); writer.put(String.valueOf(args.length + 1).getBytes(StandardCharsets.UTF_8)); writer.put((byte) '\r', (byte) '\n'); writer.put(DOLLAR_BYTE); writer.put(String.valueOf(command.length()).getBytes(StandardCharsets.UTF_8)); writer.put((byte) '\r', (byte) '\n'); writer.put(command.getBytes(StandardCharsets.UTF_8)); writer.put((byte) '\r', (byte) '\n'); for (final byte[] arg : args) { writer.put(DOLLAR_BYTE); writer.put(String.valueOf(arg.length).getBytes(StandardCharsets.UTF_8)); writer.put((byte) '\r', (byte) '\n'); writer.put(arg); writer.put((byte) '\r', (byte) '\n'); } final CompletableFuture future = callback == null ? new CompletableFuture<>() : null; CompletableFuture connFuture = this.transport.pollConnection(null); if (passwords != null) { connFuture = connFuture.thenCompose(conn -> { if (conn.getSubobject() != null) return CompletableFuture.completedFuture(conn); byte[] password = passwords.get(conn.getRemoteAddress()); if (password == null) return CompletableFuture.completedFuture(conn); CompletableFuture rs = auth(conn, password, command); if (db > 0) { rs = rs.thenCompose(conn2 -> { if (conn2.getSubobject() != null) return CompletableFuture.completedFuture(conn2); return selectdb(conn2, db, command); }); } return rs; }); } else if (db > 0) { connFuture = connFuture.thenCompose(conn2 -> { if (conn2.getSubobject() != null) return CompletableFuture.completedFuture(conn2); return selectdb(conn2, db, command); }); } connFuture.whenComplete((conn, ex) -> { if (ex != null) { if (future == null) { callback.failed(ex, null); } else { future.completeExceptionally(ex); } return; } conn.write(writer, new CompletionHandler() { @Override public void completed(Integer result, Void attachment0) { try { //----------------------- 读取返回结果 ------------------------------------- conn.read(new ReplyCompletionHandler(conn) { @Override public void completed(Integer result, ByteBuffer buffer) { buffer.flip(); try { final byte sign = buffer.get(); if (sign == PLUS_BYTE) { // + byte[] bs = readBytes(buffer); if (future == null) { transport.offerConnection(false, conn); //必须在complete之前,防止并发是conn还没回收完毕 callback.completed(null, key); } else { transport.offerConnection(false, conn); future.complete(("SET".equals(command) || "HSET".equals(command)) ? null : bs); } } else if (sign == MINUS_BYTE) { // - String bs = readString(buffer); if (future == null) { transport.offerConnection(false, conn); callback.failed(new RuntimeException(bs), key); } else { transport.offerConnection(false, conn); future.completeExceptionally(new RuntimeException("command : " + command + ", error: " + bs)); } } else if (sign == COLON_BYTE) { // : long rs = readLong(buffer); if (future == null) { if (command.startsWith("INCR") || command.startsWith("DECR") || command.startsWith("HINCR")) { transport.offerConnection(false, conn); callback.completed(rs, key); } else { transport.offerConnection(false, conn); callback.completed((command.endsWith("EXISTS") || "SISMEMBER".equals(command)) ? (rs > 0) : (("LLEN".equals(command) || "SCARD".equals(command) || "SREM".equals(command) || "LREM".equals(command) || "DEL".equals(command) || "HDEL".equals(command) || "HLEN".equals(command) || "DBSIZE".equals(command)) ? (int) rs : null), key); } } else { if (command.startsWith("INCR") || command.startsWith("DECR") || command.startsWith("HINCR") || command.startsWith("HGET")) { transport.offerConnection(false, conn); future.complete(rs); } else if (command.equals("ZRANK") || command.equals("ZREVRANK")) { transport.offerConnection(false, conn); future.complete(rs); } else if (command.equals("GETBIT")) { transport.offerConnection(false, conn); future.complete(rs); } else if (command.equals("TTL") || command.equals("PTTL")) { transport.offerConnection(false, conn); future.complete(rs); } else if (command.equals("SETNX")) { transport.offerConnection(false, conn); future.complete(rs); } else { transport.offerConnection(false, conn); future.complete((command.endsWith("EXISTS") || "SISMEMBER".equals(command)) ? (rs > 0) : (("LLEN".equals(command) || "SCARD".equals(command) || "SREM".equals(command) || "LREM".equals(command) || "DEL".equals(command) || "HDEL".equals(command) || "HLEN".equals(command) || "DBSIZE".equals(command) || "ZCARD".equals(command) || "EVAL".equals(command)) ? (int) rs : null)); } } } else if (sign == DOLLAR_BYTE) { // $ long val = readLong(buffer); byte[] rs = val <= 0 ? null : readBytes(buffer); Type ct = cacheType == CacheEntryType.LONG ? long.class : (cacheType == CacheEntryType.STRING ? String.class : (resultType == null ? objValueType : resultType)); if (future == null) { transport.offerConnection(false, conn); callback.completed((("SPOP".equals(command) || command.endsWith("GET") || rs == null) ? (ct == String.class && rs != null ? new String(rs, StandardCharsets.UTF_8) : convert.convertFrom(ct, new String(rs, StandardCharsets.UTF_8))) : null), key); } else { transport.offerConnection(false, conn); if ("ZSCORE".equals(command)) { future.complete(ct == String.class && rs != null ? new String(rs, StandardCharsets.UTF_8) : convert.convertFrom(ct, rs == null ? null : new String(rs, StandardCharsets.UTF_8))); } else if (command.equals("HINCRBYFLOAT")) { future.complete(new String(rs, StandardCharsets.UTF_8)); } else { future.complete("SPOP".equals(command) || command.endsWith("GET") || command.endsWith("ZINCRBY") ? (ct == String.class && rs != null ? new String(rs, StandardCharsets.UTF_8) : convert.convertFrom(ct, rs == null ? null : new String(rs, StandardCharsets.UTF_8))) : rs); } } } else if (sign == ASTERISK_BYTE) { // * final int len = readInt(buffer); if (len < 0) { if (future == null) { transport.offerConnection(false, conn); callback.completed(null, key); } else { transport.offerConnection(false, conn); future.complete((byte[]) null); } } else { Object rsobj; if (command.endsWith("SCAN")) { LinkedHashMap rs = new LinkedHashMap(); rsobj = rs; for (int i = 0; i < len; i++) { int l = readInt(buffer); if (l > 0) { readBytes(buffer); } else { while (buffer.hasRemaining()) { readBytes(buffer); String field = new String(readBytes(buffer), StandardCharsets.UTF_8); String value = null; if (readInt(buffer) > 0) { value = new String(readBytes(buffer), StandardCharsets.UTF_8); } Type ct = cacheType == CacheEntryType.LONG ? long.class : (cacheType == CacheEntryType.STRING ? String.class : (resultType == null ? objValueType : resultType)); try { rs.put(field, value == null ? null : (ct == String.class ? value : convert.convertFrom(ct, value))); } catch (RuntimeException e) { buffer.flip(); byte[] bsss = new byte[buffer.remaining()]; buffer.get(bsss); logger.log(Level.SEVERE, "异常: " + new String(bsss)); throw e; } } } } } else { Collection rs = set ? new HashSet() : new ArrayList(); rsobj = rs; boolean keys = "KEYS".equals(command) || "HKEYS".equals(command); boolean mget = !keys && ("MGET".equals(command) || "HMGET".equals(command)); boolean zsetscore = !keys && ("ZREVRANGE".equals(command) || "ZRANGE".equals(command)); boolean hgetall = !keys && "HGETALL".equals(command); boolean lpop = !keys && "BRPOP".equals(command); Type ct = cacheType == CacheEntryType.LONG ? long.class : (cacheType == CacheEntryType.STRING ? String.class : (resultType == null ? objValueType : resultType)); for (int i = 0; i < len; i++) { int l = readInt(buffer); if (l > 0) { // 1、zsetscore 查询 偶数元素统一返回 string 方法内自定义转换 // 2、hgetall 基数元素返回 string if ((zsetscore && rs.size() % 2 == 1) || (hgetall && rs.size() % 2 == 0)) { rs.add(readString(buffer)); } else if (lpop && i == 1) { rsobj = convert.convertFrom(ct, new String(readBytes(buffer), StandardCharsets.UTF_8)); } else { rs.add(keys ? new String(readBytes(buffer), StandardCharsets.UTF_8) : (ct == String.class ? new String(readBytes(buffer), StandardCharsets.UTF_8) : convert.convertFrom(ct, new String(readBytes(buffer), StandardCharsets.UTF_8)))); } } else if (mget) { rs.add(null); } } } if (future == null) { transport.offerConnection(false, conn); callback.completed(rsobj, key); } else { transport.offerConnection(false, conn); future.complete((Serializable) rsobj); } } } else { String exstr = "Unknown reply: " + (char) sign; if (future == null) { transport.offerConnection(false, conn); callback.failed(new RuntimeException(exstr), key); } else { transport.offerConnection(false, conn); future.completeExceptionally(new RuntimeException(exstr)); } } } catch (Exception e) { failed(e, buffer); } } @Override public void failed(Throwable exc, ByteBuffer attachment) { conn.offerBuffer(attachment); transport.offerConnection(true, conn); if (future == null) { callback.failed(exc, attachment0); } else { future.completeExceptionally(exc); } } }); } catch (Exception e) { failed(e, attachment0); } } @Override public void failed(Throwable exc, Void attachment0) { transport.offerConnection(true, conn); if (future == null) { callback.failed(exc, attachment0); } else { future.completeExceptionally(exc); } } }); }); return future; //.orTimeout(3, TimeUnit.SECONDS) JDK9以上才支持 } private CompletableFuture selectdb(final AsyncConnection conn, final int db, final String command) { final CompletableFuture rsfuture = new CompletableFuture(); try { final ByteArray dbwriter = new ByteArray(); dbwriter.put(ASTERISK_BYTE); dbwriter.put((byte) '2'); dbwriter.put((byte) '\r', (byte) '\n'); dbwriter.put(DOLLAR_BYTE); dbwriter.put((byte) '6'); dbwriter.put((byte) '\r', (byte) '\n'); dbwriter.put("SELECT".getBytes(StandardCharsets.UTF_8)); dbwriter.put((byte) '\r', (byte) '\n'); dbwriter.put(DOLLAR_BYTE); dbwriter.put(String.valueOf(String.valueOf(db).length()).getBytes(StandardCharsets.UTF_8)); dbwriter.put((byte) '\r', (byte) '\n'); dbwriter.put(String.valueOf(db).getBytes(StandardCharsets.UTF_8)); dbwriter.put((byte) '\r', (byte) '\n'); conn.write(dbwriter, new CompletionHandler() { @Override public void completed(Integer result, Void attachments) { try { //----------------------- 读取返回结果 ------------------------------------- conn.read(new ReplyCompletionHandler(conn) { @Override public void completed(Integer result, ByteBuffer buffer) { buffer.flip(); try { final byte sign = buffer.get(); if (sign == PLUS_BYTE) { // + byte[] bs = readBytes(buffer); if ("OK".equalsIgnoreCase(new String(bs))) { conn.setSubobject("authed+db"); rsfuture.complete(conn); } else { transport.offerConnection(false, conn); rsfuture.completeExceptionally(new RuntimeException("command : " + command + ", error: " + bs)); } } else if (sign == MINUS_BYTE) { // - 异常 String bs = readString(buffer); transport.offerConnection(false, conn); rsfuture.completeExceptionally(new RuntimeException("command : " + command + ", error: " + bs)); } else { String exstr = "Unknown reply: " + (char) sign; transport.offerConnection(false, conn); rsfuture.completeExceptionally(new RuntimeException(exstr)); } } catch (Exception e) { failed(e, buffer); } } @Override public void failed(Throwable exc, ByteBuffer buffer) { conn.offerBuffer(buffer); transport.offerConnection(true, conn); rsfuture.completeExceptionally(exc); } }); } catch (Exception e) { failed(e, attachments); } } @Override public void failed(Throwable exc, Void attachments) { transport.offerConnection(true, conn); rsfuture.completeExceptionally(exc); } }); } catch (Exception e) { rsfuture.completeExceptionally(e); } return rsfuture; } private CompletableFuture auth(final AsyncConnection conn, final byte[] password, final String command) { final CompletableFuture rsfuture = new CompletableFuture(); try { final ByteArray authwriter = new ByteArray(); authwriter.put(ASTERISK_BYTE); authwriter.put((byte) '2'); authwriter.put((byte) '\r', (byte) '\n'); authwriter.put(DOLLAR_BYTE); authwriter.put((byte) '4'); authwriter.put((byte) '\r', (byte) '\n'); authwriter.put("AUTH".getBytes(StandardCharsets.UTF_8)); authwriter.put((byte) '\r', (byte) '\n'); authwriter.put(DOLLAR_BYTE); authwriter.put(String.valueOf(password.length).getBytes(StandardCharsets.UTF_8)); authwriter.put((byte) '\r', (byte) '\n'); authwriter.put(password); authwriter.put((byte) '\r', (byte) '\n'); conn.write(authwriter, new CompletionHandler() { @Override public void completed(Integer result, Void attachments) { try { //----------------------- 读取返回结果 ------------------------------------- conn.read(new ReplyCompletionHandler(conn) { @Override public void completed(Integer result, ByteBuffer buffer) { buffer.flip(); try { final byte sign = buffer.get(); if (sign == PLUS_BYTE) { // + byte[] bs = readBytes(buffer); if ("OK".equalsIgnoreCase(new String(bs))) { conn.setSubobject("authed"); rsfuture.complete(conn); } else { transport.offerConnection(false, conn); rsfuture.completeExceptionally(new RuntimeException("command : " + command + ", error: " + bs)); } } else if (sign == MINUS_BYTE) { // - 异常 String bs = readString(buffer); transport.offerConnection(false, conn); rsfuture.completeExceptionally(new RuntimeException("command : " + command + ", error: " + bs)); } else { String exstr = "Unknown reply: " + (char) sign; transport.offerConnection(false, conn); rsfuture.completeExceptionally(new RuntimeException(exstr)); } } catch (Exception e) { failed(e, buffer); } } @Override public void failed(Throwable exc, ByteBuffer buffer) { conn.offerBuffer(buffer); transport.offerConnection(true, conn); rsfuture.completeExceptionally(exc); } }); } catch (Exception e) { failed(e, attachments); } } @Override public void failed(Throwable exc, Void attachments) { transport.offerConnection(true, conn); rsfuture.completeExceptionally(exc); } }); } catch (Exception e) { rsfuture.completeExceptionally(e); } return rsfuture; } } abstract class ReplyCompletionHandler implements CompletionHandler { protected final ByteArray out = new ByteArray(); protected final AsyncConnection conn; public ReplyCompletionHandler(AsyncConnection conn) { this.conn = conn; } protected byte[] readBytes(ByteBuffer buffer) throws IOException { readLine(buffer); return out.getBytesAndClear(); } protected String readString(ByteBuffer buffer) throws IOException { readLine(buffer); return out.toStringAndClear(null);//传null则表示使用StandardCharsets.UTF_8 } protected int readInt(ByteBuffer buffer) throws IOException { return (int) readLong(buffer); } protected long readLong(ByteBuffer buffer) throws IOException { readLine(buffer); int start = 0; if (out.get(0) == '$') start = 1; boolean negative = out.get(start) == '-'; long value = negative ? 0 : (out.get(start) - '0'); for (int i = 1 + start; i < out.length(); i++) { value = value * 10 + (out.get(i) - '0'); } out.clear(); return negative ? -value : value; } private void readLine(ByteBuffer buffer) throws IOException { boolean has = buffer.hasRemaining(); byte lasted = has ? buffer.get() : 0; if (lasted == '\n' && !out.isEmpty() && out.getLastByte() == '\r') { out.removeLastByte();//读掉 \r buffer.get();//读掉 \n return;//传null则表示使用StandardCharsets.UTF_8 } if (has) out.put(lasted); while (buffer.hasRemaining()) { byte b = buffer.get(); if (b == '\n' && lasted == '\r') { out.removeLastByte(); return; } out.put(lasted = b); } //说明数据还没读取完 buffer.clear(); conn.readableByteChannel().read(buffer); buffer.flip(); readLine(buffer); } }