diff --git a/conf/application.properties b/conf/application.properties new file mode 100644 index 0000000..3987050 --- /dev/null +++ b/conf/application.properties @@ -0,0 +1,13 @@ +redkale.name=zhub-dev +redkale.port=6560 +redkale.server[0].protocol=HTTP +redkale.server[0].host=127.0.0.1 +redkale.server[0].port=80 +# redkale.server[0].root = root +redkale.server[0].rest.autoload=true +redkale.server[0].rest.path= +redkale.server[0].services[0].autoload=true +# zhub +redkale.cluster.zhub[hub].addr=47.111.150.118:6066 +redkale.cluster.zhub[hub].auth=zchd@123456 +redkale.cluster.zhub[hub].groupid=venue-zhub \ No newline at end of file diff --git a/conf/application.xml b/conf/application.xml deleted file mode 100644 index 3c2e3ed..0000000 --- a/conf/application.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/conf/kafak.properties b/conf/kafak.properties deleted file mode 100644 index 37bcd72..0000000 --- a/conf/kafak.properties +++ /dev/null @@ -1,19 +0,0 @@ -# Producer -#bootstrap.servers=47.111.150.118:6062 -#bootstrap.servers=121.196.17.55:6062 -bootstrap.servers=39.108.56.246:9092 -#bootstrap.servers=122.112.180.156:6062 -acks=all -retries=0 -batch.size=16384 -linger.ms=1 -buffer.memory=33554432 -key.serializer=org.apache.kafka.common.serialization.StringSerializer -value.serializer=org.apache.kafka.common.serialization.StringSerializer - -# Consumer -enable.auto.commit=true -auto.commit.interval.ms=1000 -group.id= -key.deserializer=org.apache.kafka.common.serialization.StringDeserializer -value.deserializer=org.apache.kafka.common.serialization.StringDeserializer \ No newline at end of file diff --git a/conf/logging.properties b/conf/logging.properties new file mode 100644 index 0000000..ab86219 --- /dev/null +++ b/conf/logging.properties @@ -0,0 +1,18 @@ +handlers=java.util.logging.ConsoleHandler +# handlers = java.util.logging.FileHandler +############################################################ +.level=FINEST +java.level=INFO +javax.level=INFO +com.sun.level=INFO +sun.level=INFO +jdk.level=INFO +java.util.logging.FileHandler.level=FINER +#10M +java.util.logging.FileHandler.limit=10M +java.util.logging.FileHandler.count=20 +java.util.logging.FileHandler.encoding=UTF-8 +java.util.logging.FileHandler.pattern=${APP_HOME}/logs-%tY%tm/log-%tY%tm%td.log +java.util.logging.FileHandler.unusual=${APP_HOME}/logs-%tY%tm/log-warnerr-%tY%tm%td.log +java.util.logging.FileHandler.append=true +java.util.logging.ConsoleHandler.level=FINEST diff --git a/conf/source.properties b/conf/source.properties new file mode 100644 index 0000000..741210c --- /dev/null +++ b/conf/source.properties @@ -0,0 +1,5 @@ +############ ClusterSource @Resource(name="hub") ############ +# redkale.cluster.zhub[hub].addr = 47.111.150.118:6066 +# redkale.cluster.zhub[hub].auth = zchd@123456 +# redkale.cluster.zhub[hub].groupid = venue-zhub + diff --git a/src/com/zdemo/AbstractConsumer.java b/src/com/zdemo/AbstractConsumer.java index db3e02b..b3a48a2 100644 --- a/src/com/zdemo/AbstractConsumer.java +++ b/src/com/zdemo/AbstractConsumer.java @@ -1,6 +1,7 @@ package com.zdemo; import org.redkale.convert.json.JsonConvert; +import org.redkale.util.Resourcable; import org.redkale.util.TypeToken; import javax.annotation.Resource; @@ -13,7 +14,7 @@ import java.util.function.Consumer; * @author Liang * @data 2020-09-05 23:18 */ -public abstract class AbstractConsumer implements IConsumer { +public abstract class AbstractConsumer extends ZhubAgentProvider implements IConsumer, Resourcable { protected JsonConvert convert = JsonConvert.root(); @@ -24,10 +25,6 @@ public abstract class AbstractConsumer implements IConsumer { protected abstract String getGroupid(); - protected boolean preInit() { - return true; - } - protected final Set getTopics() { if (!eventMap.isEmpty()) { return eventMap.keySet(); @@ -76,4 +73,10 @@ public abstract class AbstractConsumer implements IConsumer { } } + // -------------- + + @Override + public String resourceName() { + return super.getName(); + } } diff --git a/src/com/zdemo/ZhubAgentProvider.java b/src/com/zdemo/ZhubAgentProvider.java new file mode 100644 index 0000000..c122d4b --- /dev/null +++ b/src/com/zdemo/ZhubAgentProvider.java @@ -0,0 +1,69 @@ +package com.zdemo; + +import org.redkale.boot.Application; +import org.redkale.boot.NodeServer; +import org.redkale.cluster.CacheClusterAgent; +import org.redkale.cluster.ClusterAgent; +import org.redkale.service.Service; +import org.redkale.util.ResourceEvent; + +import java.net.InetSocketAddress; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +public abstract class ZhubAgentProvider extends ClusterAgent { + + @Override + public void onResourceChange(ResourceEvent[] events) { + + } + + @Override + public void register(Application application) { + + } + + @Override + public void deregister(Application application) { + + } + + @Override + public CompletableFuture>> queryMqtpAddress(String protocol, String module, String resname) { + return null; + } + + @Override + public CompletableFuture> queryHttpAddress(String protocol, String module, String resname) { + return null; + } + + @Override + public CompletableFuture> querySncpAddress(String protocol, String restype, String resname) { + return null; + } + + @Override + protected CompletableFuture> queryAddress(ClusterEntry entry) { + return null; + } + + @Override + protected ClusterEntry register(NodeServer ns, String protocol, Service service) { + deregister(ns, protocol, service); + ClusterEntry clusterEntry = new ClusterEntry(ns, protocol, service); + CacheClusterAgent.AddressEntry entry = new CacheClusterAgent.AddressEntry(); + entry.addr = clusterEntry.address; + entry.resname = clusterEntry.resourceName; + entry.nodeid = this.nodeid; + entry.time = System.currentTimeMillis(); + //source.hset(clusterEntry.serviceName, clusterEntry.serviceid, CacheClusterAgent.AddressEntry.class, entry); + return clusterEntry; + } + + @Override + protected void deregister(NodeServer ns, String protocol, Service service) { + + } +} diff --git a/src/com/zdemo/ZhubListener.java b/src/com/zdemo/ZhubListener.java index 7db44f7..8c17ebe 100644 --- a/src/com/zdemo/ZhubListener.java +++ b/src/com/zdemo/ZhubListener.java @@ -1,3 +1,4 @@ +/* package com.zdemo; import org.redkale.boot.Application; @@ -10,11 +11,14 @@ import org.redkale.util.ResourceFactory; import java.lang.reflect.InvocationTargetException; import java.util.concurrent.CompletableFuture; +*/ /** * 服务监听 * * @author: liangxy. - */ + *//* + +@Deprecated public class ZhubListener implements ApplicationListener { @Override @@ -47,3 +51,4 @@ public class ZhubListener implements ApplicationListener { } } +*/ diff --git a/src/com/zdemo/ZhubProvider.java b/src/com/zdemo/ZhubProvider.java new file mode 100644 index 0000000..fcb6e1c --- /dev/null +++ b/src/com/zdemo/ZhubProvider.java @@ -0,0 +1,21 @@ +package com.zdemo; + +import com.zdemo.zhub.ZHubClient; +import org.redkale.annotation.Priority; +import org.redkale.cluster.ClusterAgent; +import org.redkale.cluster.ClusterAgentProvider; +import org.redkale.util.AnyValue; + +@Priority(1) +public class ZhubProvider implements ClusterAgentProvider { + + @Override + public boolean acceptsConf(AnyValue config) { + return new ZHubClient().acceptsConf(config); + } + + @Override + public ClusterAgent createInstance() { + return new ZHubClient(); + } +} diff --git a/src/com/zdemo/cache_/RedisCacheSource.java b/src/com/zdemo/cache_/RedisCacheSource.java deleted file mode 100644 index 4bf837e..0000000 --- a/src/com/zdemo/cache_/RedisCacheSource.java +++ /dev/null @@ -1,2173 +0,0 @@ -/* - * 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); - } - -} diff --git a/src/com/zdemo/cache_/RedisTest.java b/src/com/zdemo/cache_/RedisTest.java deleted file mode 100644 index bf441a7..0000000 --- a/src/com/zdemo/cache_/RedisTest.java +++ /dev/null @@ -1,262 +0,0 @@ -package com.zdemo.cache_; - -import com.zdemo.cachex.MyRedisCacheSource; -import org.redkale.convert.json.JsonFactory; -import org.redkale.net.AsyncIOGroup; -import org.redkale.util.AnyValue; -import org.redkale.util.ResourceFactory; - -import java.util.Map; - -import static org.redkale.boot.Application.RESNAME_APP_GROUP; - -public class RedisTest { - - static MyRedisCacheSource source; - static MyRedisCacheSource sourceInt; - - static { - AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue().addValue("maxconns", "10"); - conf.addValue("node", new AnyValue.DefaultAnyValue().addValue("addr", "47.111.150.118").addValue("port", "6064").addValue("password", "*Zhong9307!").addValue("db", 1)); - - final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); - asyncGroup.start(); - ResourceFactory.root().register(RESNAME_APP_GROUP, asyncGroup); - - source = new MyRedisCacheSource(); - ResourceFactory.root().inject(source); - source.init(null); - source.defaultConvert = JsonFactory.root().getConvert(); - source.init(conf); - - // int - sourceInt = new MyRedisCacheSource(); - ResourceFactory.root().inject(sourceInt); - sourceInt.init(null); - sourceInt.defaultConvert = JsonFactory.root().getConvert(); - sourceInt.init(conf); - sourceInt.initValueType(Integer.class); - } - - public static void main(String[] args) { - - //System.out.println(source.remove("a", "b")); - - // bit - /*source.initValueType(Integer.class); - source.remove("a"); - boolean a = source.getBit("a", 1); - System.out.println(a); - - source.setBit("a", 1, true); - a = source.getBit("a", 1); - System.out.println("bit-a-1: " + a); - - source.setBit("a", 1, false); - a = source.getBit("a", 1); - System.out.println("bit-a-1: " + a);*/ - - /*source.remove("a"); - - // setnx - System.out.println(source.setnx("a", 1)); - source.remove("a"); - System.out.println(source.setnx("a", 1)); - - // set - source.remove("abx1"); - source.appendSetItems("abx1", "a", "b", "c"); - List list = source.srandomItems("abx1", 2); - String str = source.srandomItem("abx1"); //r - System.out.println(list);//[r1, r2] */ - - /*int[] arr = {0}; - ExecutorService executor = Executors.newFixedThreadPool(10); - CountDownLatch latch = new CountDownLatch(1000); - for (int i = 0; i < 1000; i++) { - executor.submit(() -> { - try { - source.lock("c", 1000); - arr[0]++; - // System.out.println("Thread: " + Thread.currentThread().getName()); - // Thread.sleep(10); - - } catch (Exception e) { - e.printStackTrace(); - } finally { - source.unlock("c"); - latch.countDown(); - } - }); - } - - try { - latch.await(); - System.out.println("n=" + arr[0]); - executor.shutdown(); - } catch (InterruptedException e) { - e.printStackTrace(); - }*/ - - - /*List list = (List) source.getCollection("gamerank-comment-stat"); - System.out.println(list);*/ - - /*for (int i = 0; i < 10; i++) { - String brpop = source.brpop("z", 2); - System.out.println(brpop); - }*/ - - // key 测试 - /*source.set("a", "123321"); - System.out.println(source.get("a")); // 123321 - System.out.println(source.getTtl("a")); // -1 - System.out.println(source.getPttl("a")); // -1 - System.out.println(source.getPttl("x")); // -2*/ - - // hashmap 测试 - /*source.remove("sk"); - source.setHm("sk", "a", "1"); - source.setHm("sk", "b", "2"); - System.out.println(source.getHm("sk", "a")); // 1 - source.remove("sk"); - - source.setHms("sk", Map.of("b", "5", "c", "3", "a", "1")); - source.hdel("sk", "a"); - - Map map = source.getHms("sk", "a", "x", "b", "c", "f"); // {b=5, c=3} - System.out.println(map); - System.out.println(source.getHmall("sk")); //{b=5, c=3} - System.out.println(source.incrHm("sk", "b", 1.1d)); // b = 6.1 - System.out.println(source.incrHm("sk", "c", 1)); // c = 4 - System.out.println(source.getHmall("sk")); //{b=6.1, c=4} - - System.out.println("--------------"); - System.out.println(source.hexists("sk", "b")); // true - System.out.println(source.getCollectionSize("sk")); // 2*/ - - - Map hms = source.getHms("supportusers", "5-kfeu0f", "xxxx", "3-0kbt7u8t", "95q- "); - hms.forEach((k, v) -> { - System.out.println(k + " : " + v); - }); - - - /*MyRedisCacheSource source2 = new MyRedisCacheSource(); - source2.defaultConvert = JsonFactory.root().getConvert(); - source2.initValueType(String.class); //value用String类型 - source2.init(conf);*/ - - /*Map gcMap = source.getHmall("hot-gamecomment"); - gcMap.forEach((k,v) -> { - System.out.println(k + " : " + v); - });*/ - - - //Map gameinfo = source.getHms("gameinfo", "22759", "22838", "10097", "22751", "22632", "22711", "22195", "15821", "10099", "16313", "11345", "10534", "22768", "22647", "22924", "18461", "15871", "17099", "22640", "22644", "10744", "10264", "18032", "22815", "13584", "10031", "22818", "22452", "22810", "10513", "10557", "15848", "11923", "15920", "22808", "20073", "22809", "15840", "12332", "15803", "10597", "22624", "17113", "19578", "22664", "22621", "20722", "16226", "10523", "12304", "10597","11923","10031"); - //Map gameinfo = source.getHms("gameinfo", "22759","22838","10097","22751","22632","22711","22195","15821","10099","16313","11345","10534","22768","22647","22924","18461","15871","17099","22363","22640","22644","10744","10264","18032","22815","13584","22818","22452","22810","10513","10557","15848","15920","22808","20073","22809","15840","12332","15803","10597","22624","17113","19578","22627","22664","22621","20722","16226","10523","12304"); - - /*gameinfo.forEach((k,v ) -> { - System.out.println(v); - });*/ - - - /*source.queryKeysStartsWith("articlebean:").forEach(x -> { - System.out.println(x); - //source.remove(x); - //System.out.println(source.getHmall(x)); - });*/ - - // list 测试 - /*sourceInt.remove("list"); - Collection list = sourceInt.getCollection("list"); - System.out.println(list); - for (int i = 1; i <= 10; i++) { - sourceInt.appendListItem("list", i); - } - System.out.println(sourceInt.getCollection("list")); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - - sourceInt.appendListItems("list", 11, 12, 13); - System.out.println(sourceInt.getCollection("list")); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] - System.out.println(sourceInt.getCollection("list", 0, 5)); // [1, 2, 3, 4, 5] - System.out.println(sourceInt.getCollectionSize("list")); // 13 - - List ids = new ArrayList<>(100); - for (int i = 0; i < 2000; i++) { - ids.add(i); - } - sourceInt.remove("abx"); - sourceInt.appendListItems("abx", ids.toArray(Integer[]::new)); - System.out.println(sourceInt.getCollection("abx")); - */ - - /*System.out.println(sourceInt.getCollectionSize("recommend-user-quality")); - Collection uid = sourceInt.getCollection("recommend-user-quality"); - System.out.println(uid);*/ - - // zset 测试 - /*source.initValueType(String.class); //value用Integer类型 - source.remove("zx"); - source.zadd("zx", Map.of("a", 1, "b", 2)); - - source.zadd("zx", Map.of("a", 1, "c", 5L)); - source.zadd("zx", Map.of("x", 20, "j", 3.5)); - source.zadd("zx", Map.of("f", System.currentTimeMillis(), "c", 5L)); - source.zadd("zx", Map.of("a", 1, "c", 5L)); - - System.out.println(source.zincr("zx", "a", 1.34)); // 2.34 - System.out.println(source.getZsetDoubleScore("zx")); // {f=1592924555704, x=20, c=5, j=3, b=2.34, a=1} - source.zrem("zx", "b", "c", "e", "x"); - System.out.println(source.getZsetLongScore("zx")); // {f=1592924555704, j=3, a=2} - - System.out.println("--------------"); - System.out.println(source.getZsetLongScore("zx", "f")); - - System.out.println(source.getZrevrank("zx", "f")); // 0 - System.out.println(source.getZrank("zx", "f")); // 2 - System.out.println(source.getZrank("zx", "Y")); // -1 - System.out.println(source.getCollectionSize("zx")); // 3 - - System.out.println(source.getZset("zx")); - System.out.println(source.zexists("zx", "f", "x", "a"));*/ - - /*LocalDate date = LocalDate.of(2019, 12, 31); - for (int i = 0; i < 60; i++) { - LocalDate localDate = date.plusDays(-i); - String day = localDate.format(DateTimeFormatter.ISO_LOCAL_DATE); - System.out.println(String.format("mkdir %s; mv *%s*.zip %s", day, day, day)); - }*/ - - - /*MyRedisCacheSource source = new MyRedisCacheSource(); - source.defaultConvert = JsonFactory.root().getConvert(); - source.initValueType(UserDetail.class); - source.init(conf); - - - Map map = source.getHmall("user-detail"); - - Integer[] array = map.values().stream().map(x -> x.getUserid()).toArray(Integer[]::new); - - System.out.println(JsonConvert.root().convertTo(array)); - - Map hms = source.getHms("user-detail", 11746, 11988, 11504, 11987, 11745, 11503, 11748, 11506, 11747, 11989, 11505, 11508, 11507, 11509, 11980, 11740, 11982, 11981, 11984, 11742, 11500, 11983, 11741, 11502, 11744, 11986, 11985, 11501, 11743, 11999, 11757, 11515, 1, 11514, 11998, 11756, 2, 11517, 11516, 11758, 3, 11519, 4, 5, 11518, 6, 7, 11991, 8, 11990, 9, 11993, 11751, 11750, 11992, 11753, 11511, 11995, 11994, 11510, 11752, 11755, 11513, 11997, 11512, 11996, 11754, 11724, 11966, 11965, 11723, 11968, 11726, 11967, 11725, 11728, 11969, 11727, 11729, 11960, 11720, 11962, 11961, 11722, 11964, 11721); - - System.out.println(hms.size());*/ - - /*source.getCollection("article-comment-list", 19, 1).forEach(x -> System.out.println(x)); - - - while (true) { - System.out.println("---" + Utility.now() + "---"); - source.getHmall("ck").forEach((k, v) -> { - System.out.println(k + ":" + v); - }); - try { - Thread.sleep(60 * 1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - }*/ - } -} diff --git a/src/com/zdemo/cachex/MyRedisCacheSource.java b/src/com/zdemo/cachex/MyRedisCacheSource.java deleted file mode 100644 index f08f311..0000000 --- a/src/com/zdemo/cachex/MyRedisCacheSource.java +++ /dev/null @@ -1,430 +0,0 @@ -package com.zdemo.cachex; - - -import org.redkale.convert.Convert; -import org.redkale.service.Local; -import org.redkale.source.CacheSource; -import org.redkale.util.AutoLoad; -import org.redkale.util.ResourceType; - -import java.io.Serializable; -import java.lang.reflect.Type; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Stream; - -@Local -@AutoLoad(false) -@ResourceType(CacheSource.class) -public class MyRedisCacheSource extends RedisCacheSource { - //--------------------- oth ------------------------------ - public boolean setnx(String key, Object v) { - byte[][] bytes = Stream.of(key, v).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - Serializable rs = send("SETNX", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - return rs == null ? false : (long) rs == 1; - } - //--------------------- oth ------------------------------ - - //--------------------- bit ------------------------------ - public boolean getBit(String key, int offset) { - byte[][] bytes = Stream.of(key, offset).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - Serializable v = send("GETBIT", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - return v == null ? false : (long) v == 1; - } - - public void setBit(String key, int offset, boolean bool) { - byte[][] bytes = Stream.of(key, offset, bool ? 1 : 0).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - send("SETBIT", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - } - - //--------------------- bit ------------------------------ - //--------------------- lock ------------------------------ - // 尝试加锁,成功返回0,否则返回上一锁剩余毫秒值 - public int tryLock(String key, int millis) { - byte[][] bytes = Stream.of("" + - "if (redis.call('exists',KEYS[1]) == 0) then " + - "redis.call('psetex', KEYS[1], ARGV[1], 1) " + - "return 0; " + - "else " + - "return redis.call('PTTL', KEYS[1]); " + - "end; ", 1, key, millis).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - int n = (int) send("EVAL", CacheEntryType.OBJECT, (Type) null, null, bytes).join(); - return n; - } - - // 加锁 - public void lock(String key, int millis) { - int i; - do { - i = tryLock(key, millis); - try { - Thread.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } while (i > 0); - } - - // 解锁 - public void unlock(String key) { - remove(key); - } - - - //--------------------- key ------------------------------ - - public long getTtl(String key) { - return (long) send("TTL", CacheEntryType.OBJECT, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).join(); - } - - public long getPttl(String key) { - return (long) send("PTTL", CacheEntryType.OBJECT, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).join(); - } - - public int remove(String... keys) { - if (keys == null || keys.length == 0) { - return 0; - } - List para = new ArrayList<>(); - para.add("" + - " local args = ARGV;" + - " local x = 0;" + - " for i,v in ipairs(args) do" + - " local inx = redis.call('del', v);" + - " if(inx > 0) then" + - " x = x + 1;" + - " end" + - " end" + - " return x;"); - - para.add("0"); - for (Object field : keys) { - para.add(String.valueOf(field)); - } - byte[][] bytes = para.stream().map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - return (int) send("EVAL", CacheEntryType.OBJECT, (Type) null, null, bytes).join(); - } - - //--------------------- hmget ------------------------------ - public V getHm(String key, T field) { - // return (V) send("HMGET", CacheEntryType.OBJECT, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)).join(); - Map map = getHms(key, field); - return map.get(field); - } - - public Map getHms(String key, T... field) { - if (field == null || field.length == 0) { - return new HashMap<>(); - } - byte[][] bytes = Stream.concat(Stream.of(key), Stream.of(field)).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - Map result = new HashMap<>(); - - List vs = (List) send("HMGET", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - for (int i = 0; i < field.length; i++) { // /*vs != null && vs.size() > i &&*/ - if (vs.get(i) == null) { - continue; - } - result.put(field[i], vs.get(i)); - } - - return result; - } - - public Map getHmall(String key) { - List vs = (List) send("HGETALL", CacheEntryType.OBJECT, (Type) null, key, key.getBytes(StandardCharsets.UTF_8)).join(); - Map result = new HashMap<>(vs.size() / 2); - for (int i = 0; i < vs.size(); i += 2) { - result.put(String.valueOf(vs.get(i)), vs.get(i + 1)); - } - - return result; - } - - //--------------------- hmset、hmdel、incr ------------------------------ - public void setHm(String key, T field, V value) { - byte[][] bytes = Stream.of(key, field, value).map(x -> x.toString().getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - send("HMSET", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - } - - public void setHms(String key, Map kv) { - List args = new ArrayList(); - args.add(key); - - kv.forEach((k, v) -> { - args.add(String.valueOf(k)); - args.add(String.valueOf(v)); - }); - - byte[][] bytes = args.stream().map(x -> x.getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - send("HMSET", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - } - - public Long incrHm(String key, T field, long n) { - byte[][] bytes = Stream.of(key, String.valueOf(field), String.valueOf(n)).map(x -> x.getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - return (Long) send("HINCRBY", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - } - - public Double incrHm(String key, T field, double n) { - byte[][] bytes = Stream.of(key, String.valueOf(field), String.valueOf(n)).map(x -> x.getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - Serializable v = send("HINCRBYFLOAT", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - if (v == null) { - return null; - } - return Double.parseDouble(String.valueOf(v)); - } - - public void hdel(String key, T... field) { - byte[][] bytes = Stream.concat(Stream.of(key), Stream.of(field)).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - send("HDEL", null, (Type) null, key, bytes).join(); - } - - public List zexists(String key, T... fields) { - if (fields == null || fields.length == 0) { - return new ArrayList<>(); - } - List para = new ArrayList<>(); - para.add("" + - " local key = KEYS[1];" + - " local args = ARGV;" + - " local result = {};" + - " for i,v in ipairs(args) do" + - " local inx = redis.call('ZREVRANK', key, v);" + - " if(inx) then" + - " table.insert(result,1,v);" + - " end" + - " end" + - " return result;"); - para.add("1"); - para.add(key); - for (Object field : fields) { - para.add(String.valueOf(field)); - } - byte[][] bytes = para.stream().map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - return (List) send("EVAL", CacheEntryType.OBJECT, (Type) null, null, bytes).join(); - } - - //--------------------- set ------------------------------ - public T srandomItem(String key) { - byte[][] bytes = Stream.of(key, 1).map(x -> formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, x)).toArray(byte[][]::new); - List list = (List) send("SRANDMEMBER", null, (Type) null, key, bytes).join(); - return list != null && !list.isEmpty() ? list.get(0) : null; - } - - public List srandomItems(String key, int n) { - byte[][] bytes = Stream.of(key, n).map(x -> formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, x)).toArray(byte[][]::new); - return (List) send("SRANDMEMBER", null, (Type) null, key, bytes).join(); - } - - //--------------------- list ------------------------------ - public CompletableFuture appendListItemsAsync(String key, V... values) { - byte[][] bytes = Stream.concat(Stream.of(key), Stream.of(values)).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - return (CompletableFuture) send("RPUSH", null, (Type) null, key, bytes); - } - - public CompletableFuture lpushListItemAsync(String key, V value) { - return (CompletableFuture) send("LPUSH", null, (Type) null, key, key.getBytes(StandardCharsets.UTF_8), formatValue(CacheEntryType.OBJECT, (Convert) null, (Type) null, value)); - } - - public void lpushListItem(String key, V value) { - lpushListItemAsync(key, value).join(); - } - - public void appendListItems(String key, V... values) { - appendListItemsAsync(key, values).join(); - } - - public void appendSetItems(String key, V... values) { - // todo: - for (V v : values) { - appendSetItem(key, v); - } - } - - // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - public CompletableFuture> getCollectionAsync(String key, int offset, int limit) { - return (CompletableFuture) send("OBJECT", null, (Type) null, key, "ENCODING".getBytes(StandardCharsets.UTF_8), 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, (Type) null, false, key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(offset).getBytes(StandardCharsets.UTF_8), String.valueOf(offset + limit - 1).getBytes(StandardCharsets.UTF_8)); - } else { - return send("SMEMBERS", CacheEntryType.OBJECT, (Type) null, true, key, key.getBytes(StandardCharsets.UTF_8)); - } - }); - } - - public Collection getCollection(String key, int offset, int limit) { - return getCollectionAsync(key, offset, limit).join(); - } - - public V brpop(String key, int seconds) { - byte[][] bytes = Stream.concat(Stream.of(key), Stream.of(seconds)).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - return (V) send("BRPOP", null, (Type) null, key, bytes).join(); - } - - //--------------------- zset ------------------------------ - public void zadd(String key, Map kv) { - if (kv == null || kv.isEmpty()) { - return; - } - List args = new ArrayList(); - args.add(key); - - kv.forEach((k, v) -> { - args.add(String.valueOf(v)); - args.add(String.valueOf(k)); - }); - - byte[][] bytes = args.stream().map(x -> x.getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - send("ZADD", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - } - - public double zincr(String key, Object number, N n) { - byte[][] bytes = Stream.of(key, n, number).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - Serializable v = send("ZINCRBY", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - return Double.parseDouble(String.valueOf(v)); - } - - public void zrem(String key, V... vs) { - List args = new ArrayList(); - args.add(key); - for (V v : vs) { - args.add(String.valueOf(v)); - } - byte[][] bytes = args.stream().map(x -> x.getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - send("ZREM", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - } - - public int getZrank(String key, V v) { - byte[][] bytes = Stream.of(key, v).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - Long t = (Long) send("ZRANK", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - - return t == null ? -1 : (int) (long) t; - } - - public int getZrevrank(String key, V v) { - byte[][] bytes = Stream.of(key, v).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - Long t = (Long) send("ZREVRANK", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - - return t == null ? -1 : (int) (long) t; - } - - //ZRANGE/ZREVRANGE key start stop - public List getZset(String key) { - byte[][] bytes = Stream.of(key, 0, -1).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - List vs = (List) send("ZREVRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - List vs2 = new ArrayList(vs.size()); - - for (int i = 0; i < vs.size(); ++i) { - if (i % 2 == 1) { - vs2.add(this.convert.convertFrom(this.objValueType, String.valueOf(vs.get(i)))); - } else { - vs2.add(vs.get(i)); - } - } - - return vs2; - } - - public List getZset(String key, int offset, int limit) { - byte[][] bytes = Stream.of(key, offset, offset + limit - 1).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - List vs = (List) send("ZREVRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - List vs2 = new ArrayList(vs.size()); - - for (int i = 0; i < vs.size(); ++i) { - if (i % 2 == 1) { - vs2.add(this.convert.convertFrom(this.objValueType, String.valueOf(vs.get(i)))); - } else { - vs2.add(vs.get(i)); - } - } - - return vs2; - } - - public LinkedHashMap getZsetLongScore(String key) { - LinkedHashMap map = getZsetDoubleScore(key); - if (map.isEmpty()) { - return new LinkedHashMap<>(); - } - - LinkedHashMap map2 = new LinkedHashMap<>(map.size()); - map.forEach((k, v) -> map2.put(k, (long) (double) v)); - return map2; - } - - public LinkedHashMap getZsetItemsLongScore(String key) { - byte[][] bytes = Stream.of(key, 0, -1, "WITHSCORES").map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - List vs = (List) send("ZRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - - LinkedHashMap map = new LinkedHashMap<>(); - for (int i = 0; i < vs.size(); i += 2) { - map.put((V) vs.get(i), (long) Double.parseDouble((String) vs.get(i + 1))); - } - return map; - } - - public Long getZsetLongScore(String key, V v) { - Double score = getZsetDoubleScore(key, v); - if (score == null) { - return null; - } - return (long) (double) score; - } - - public LinkedHashMap getZsetDoubleScore(String key) { - byte[][] bytes = Stream.of(key, 0, -1, "WITHSCORES").map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - List vs = (List) send("ZREVRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - - LinkedHashMap map = new LinkedHashMap<>(); - for (int i = 0; i < vs.size(); i += 2) { - map.put((V) vs.get(i), Double.parseDouble((String) vs.get(i + 1))); - } - return map; - } - - public Double getZsetDoubleScore(String key, V v) { - byte[][] bytes = Stream.of(key, v).map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - Serializable zscore = send("ZSCORE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - if (zscore == null) { - return null; - } - - return Double.parseDouble(String.valueOf(zscore)); - } - - public LinkedHashMap getZsetLongScore(String key, int offset, int limit) { - byte[][] bytes = Stream.of(key, offset, offset + limit - 1, "WITHSCORES").map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - List vs = (List) send("ZREVRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - - LinkedHashMap map = new LinkedHashMap<>(); - for (int i = 0; i < vs.size(); i += 2) { - map.put((V) vs.get(i), (long) Double.parseDouble((String) vs.get(i + 1))); - } - return map; - } - - public LinkedHashMap getZsetDoubleScore(String key, int offset, int limit) { - byte[][] bytes = Stream.of(key, offset, offset + limit - 1, "WITHSCORES").map(x -> String.valueOf(x).getBytes(StandardCharsets.UTF_8)).toArray(byte[][]::new); - List vs = (List) send("ZREVRANGE", CacheEntryType.OBJECT, (Type) null, key, bytes).join(); - - LinkedHashMap map = new LinkedHashMap<>(); - for (int i = 0; i < vs.size(); i += 2) { - map.put((V) vs.get(i), Double.parseDouble(vs.get(i + 1) + "")); - } - return map; - } - - // ---------- - protected byte[] formatValue(CacheEntryType cacheType, Convert convert0, Type resultType, Object value) { - if (value == null) return "null".getBytes(StandardCharsets.UTF_8); - if (convert0 == null) convert0 = convert; - if (cacheType == CacheEntryType.LONG || cacheType == CacheEntryType.ATOMIC) - return String.valueOf(value).getBytes(StandardCharsets.UTF_8); - if (cacheType == CacheEntryType.STRING) return convert0.convertToBytes(String.class, value); - - if (value instanceof String) return String.valueOf(value).getBytes(StandardCharsets.UTF_8); - if (value instanceof Number) return String.valueOf(value).getBytes(StandardCharsets.UTF_8); - return convert0.convertToBytes(resultType == null ? objValueType : resultType, value); - } -} diff --git a/src/com/zdemo/cachex/RedisCacheSource.java b/src/com/zdemo/cachex/RedisCacheSource.java deleted file mode 100644 index fcbe6a4..0000000 --- a/src/com/zdemo/cachex/RedisCacheSource.java +++ /dev/null @@ -1,2240 +0,0 @@ -/* - * 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.cachex; - -import org.redkale.convert.Convert; -import org.redkale.convert.bson.BsonByteBufferWriter; -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; - -/** - * 详情见: 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 - protected JsonConvert defaultConvert; - - @Resource(name = "$_convert") - protected 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 AnyValue.DefaultAnyValue(); - - AnyValue prop = conf.getAnyValue("properties"); - if (prop != null) { - String storeValueStr = prop.getValue("value-type"); - if (storeValueStr != null) { - try { - this.initValueType(Thread.currentThread().getContextClassLoader().loadClass(storeValueStr)); - } catch (Throwable e) { - logger.log(Level.SEVERE, this.getClass().getSimpleName() + " load key & value store class (" + storeValueStr + ") error", e); - } - } - } - final int bufferCapacity = conf.getIntValue("bufferCapacity", 8 * 1024); - final int bufferPoolSize = conf.getIntValue("bufferPoolSize", Runtime.getRuntime().availableProcessors() * 8); - final int threads = conf.getIntValue("threads", Runtime.getRuntime().availableProcessors() * 8); - 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(threads, bufferPoolSize, bufferCapacity, readTimeoutSeconds, writeTimeoutSeconds); - this.transport = transportFactory.createTransportTCP("Redis-Transport", null, addresses); - this.transport.setSemaphore(new Semaphore(conf.getIntValue("maxconns", threads))); - 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")); - - RedisCacheSource source = new RedisCacheSource(); - 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 (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 BsonByteBufferWriter writer = new BsonByteBufferWriter(transport.getBufferSupplier()); - writer.writeTo(ASTERISK_BYTE); - writer.writeTo(String.valueOf(args.length + 1).getBytes(StandardCharsets.UTF_8)); - writer.writeTo((byte) '\r', (byte) '\n'); - writer.writeTo(DOLLAR_BYTE); - writer.writeTo(String.valueOf(command.length()).getBytes(StandardCharsets.UTF_8)); - writer.writeTo((byte) '\r', (byte) '\n'); - writer.writeTo(command.getBytes(StandardCharsets.UTF_8)); - writer.writeTo((byte) '\r', (byte) '\n'); - - for (final byte[] arg : args) { - writer.writeTo(DOLLAR_BYTE); - writer.writeTo(String.valueOf(arg.length).getBytes(StandardCharsets.UTF_8)); - writer.writeTo((byte) '\r', (byte) '\n'); - writer.writeTo(arg); - writer.writeTo((byte) '\r', (byte) '\n'); - } - - final ByteBuffer[] buffers = writer.toBuffers(); - - 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) { - transport.offerBuffer(buffers); - if (future == null) { - callback.failed(ex, null); - } else { - future.completeExceptionally(ex); - } - return; - } - conn.write(buffers, buffers, new CompletionHandler() { - @Override - public void completed(Integer result, ByteBuffer[] attachments) { - int index = -1; - try { - for (int i = 0; i < attachments.length; i++) { - if (attachments[i].hasRemaining()) { - index = i; - break; - } else { - transport.offerBuffer(attachments[i]); - } - } - if (index == 0) { - conn.write(attachments, attachments, this); - return; - } else if (index > 0) { - ByteBuffer[] newattachs = new ByteBuffer[attachments.length - index]; - System.arraycopy(attachments, index, newattachs, 0, newattachs.length); - conn.write(newattachs, newattachs, this); - return; - } - //----------------------- 读取返回结果 ------------------------------------- - 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) { - logger.log(Level.WARNING, "", 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, attachments); - } else { - future.completeExceptionally(exc); - } - } - - }); - } catch (Exception e) { - failed(e, attachments); - } - } - - @Override - public void failed(Throwable exc, ByteBuffer[] attachments) { - transport.offerConnection(true, conn); - if (future == null) { - callback.failed(exc, attachments); - } 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 BsonByteBufferWriter dbwriter = new BsonByteBufferWriter(transport.getBufferSupplier()); - dbwriter.writeTo(ASTERISK_BYTE); - dbwriter.writeTo((byte) '2'); - dbwriter.writeTo((byte) '\r', (byte) '\n'); - dbwriter.writeTo(DOLLAR_BYTE); - dbwriter.writeTo((byte) '6'); - dbwriter.writeTo((byte) '\r', (byte) '\n'); - dbwriter.writeTo("SELECT".getBytes(StandardCharsets.UTF_8)); - dbwriter.writeTo((byte) '\r', (byte) '\n'); - - dbwriter.writeTo(DOLLAR_BYTE); - dbwriter.writeTo(String.valueOf(String.valueOf(db).length()).getBytes(StandardCharsets.UTF_8)); - dbwriter.writeTo((byte) '\r', (byte) '\n'); - dbwriter.writeTo(String.valueOf(db).getBytes(StandardCharsets.UTF_8)); - dbwriter.writeTo((byte) '\r', (byte) '\n'); - - final ByteBuffer[] authbuffers = dbwriter.toBuffers(); - conn.write(authbuffers, authbuffers, new CompletionHandler() { - @Override - public void completed(Integer result, ByteBuffer[] attachments) { - int index = -1; - try { - for (int i = 0; i < attachments.length; i++) { - if (attachments[i].hasRemaining()) { - index = i; - break; - } else { - transport.offerBuffer(attachments[i]); - } - } - if (index == 0) { - conn.write(attachments, attachments, this); - return; - } else if (index > 0) { - ByteBuffer[] newattachs = new ByteBuffer[attachments.length - index]; - System.arraycopy(attachments, index, newattachs, 0, newattachs.length); - conn.write(newattachs, newattachs, this); - return; - } - //----------------------- 读取返回结果 ------------------------------------- - 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, ByteBuffer[] 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 BsonByteBufferWriter authwriter = new BsonByteBufferWriter(transport.getBufferSupplier()); - authwriter.writeTo(ASTERISK_BYTE); - authwriter.writeTo((byte) '2'); - authwriter.writeTo((byte) '\r', (byte) '\n'); - authwriter.writeTo(DOLLAR_BYTE); - authwriter.writeTo((byte) '4'); - authwriter.writeTo((byte) '\r', (byte) '\n'); - authwriter.writeTo("AUTH".getBytes(StandardCharsets.UTF_8)); - authwriter.writeTo((byte) '\r', (byte) '\n'); - - authwriter.writeTo(DOLLAR_BYTE); - authwriter.writeTo(String.valueOf(password.length).getBytes(StandardCharsets.UTF_8)); - authwriter.writeTo((byte) '\r', (byte) '\n'); - authwriter.writeTo(password); - authwriter.writeTo((byte) '\r', (byte) '\n'); - - final ByteBuffer[] authbuffers = authwriter.toBuffers(); - conn.write(authbuffers, authbuffers, new CompletionHandler() { - @Override - public void completed(Integer result, ByteBuffer[] attachments) { - int index = -1; - try { - for (int i = 0; i < attachments.length; i++) { - if (attachments[i].hasRemaining()) { - index = i; - break; - } else { - transport.offerBuffer(attachments[i]); - } - } - if (index == 0) { - conn.write(attachments, attachments, this); - return; - } else if (index > 0) { - ByteBuffer[] newattachs = new ByteBuffer[attachments.length - index]; - System.arraycopy(attachments, index, newattachs, 0, newattachs.length); - conn.write(newattachs, newattachs, this); - return; - } - //----------------------- 读取返回结果 ------------------------------------- - 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, ByteBuffer[] attachments) { - transport.offerConnection(true, conn); - rsfuture.completeExceptionally(exc); - } - }); - } catch (Exception e) { - rsfuture.completeExceptionally(e); - } - return rsfuture; - } -} - -abstract class ReplyCompletionHandler implements CompletionHandler { - - private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - 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.size(); 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 - //logger.info("打印buffer.get()---> " + buffer.get()); - //logger.info("--- 打印buffer start --- "); - return;//传null则表示使用StandardCharsets.UTF_8 - } - if (has) out.write(lasted); - while (buffer.hasRemaining()) { - byte b = buffer.get(); - if (b == '\n' && lasted == '\r') { - out.removeLastByte(); - return; - } - out.write(lasted = b); - } - //说明数据还没读取完 - buffer.clear(); - conn.readableByteChannel().read(buffer); - buffer.flip(); - readLine(buffer); - } - -} diff --git a/src/com/zdemo/cachex/RedissionCacheSource.java b/src/com/zdemo/cachex/RedissionCacheSource.java deleted file mode 100644 index 59e0b9d..0000000 --- a/src/com/zdemo/cachex/RedissionCacheSource.java +++ /dev/null @@ -1,1944 +0,0 @@ -/* - * 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 org.redkalex.cache; - -import java.io.*; -import java.lang.reflect.Type; -import java.net.*; -import java.util.*; -import java.util.concurrent.*; -import java.util.logging.*; -import java.util.stream.Collectors; -import javax.annotation.Resource; -import org.redisson.Redisson; -import org.redisson.api.*; -import org.redisson.config.*; -import org.redkale.convert.Convert; -import org.redkale.convert.json.*; -import org.redkale.convert.json.JsonConvert; -import org.redkale.service.*; -import org.redkale.source.*; -import org.redkale.util.*; -import org.redkale.util.AnyValue.DefaultAnyValue; - -*/ -/** - * //https://www.cnblogs.com/xiami2046/p/13934146.html - * - * @author zhangjx - *//* - -@Local -@AutoLoad(false) -@ResourceType(CacheSource.class) -public class RedissionCacheSource extends AbstractService implements CacheSource, Service, AutoCloseable, Resourcable { - - private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - @Resource - protected JsonConvert defaultConvert; - - @Resource(name = "$_convert") - protected JsonConvert convert; - - protected Type objValueType = String.class; - - protected List nodeAddrs; - - protected int db; - - protected RedissonClient redisson; - - @Override - public void init(AnyValue conf) { - if (this.convert == null) this.convert = this.defaultConvert; - if (conf == null) conf = new AnyValue.DefaultAnyValue(); - - final List addresses = new ArrayList<>(); - Config config = new Config(); - AnyValue[] nodes = conf.getAnyValues("node"); - String type = conf.getOrDefault("type", ""); - BaseConfig baseConfig = null; - for (AnyValue node : nodes) { - String addr = node.getValue("addr"); - addresses.add(addr); - String db0 = node.getValue("db", "").trim(); - if (!db0.isEmpty()) this.db = Integer.valueOf(db0); - if (nodes.length == 1) { - baseConfig = config.useSingleServer(); - config.useSingleServer().setAddress(addr); - config.useSingleServer().setDatabase(this.db); - } else if ("masterslave".equalsIgnoreCase(type)) { //主从 - baseConfig = config.useMasterSlaveServers(); - if (node.get("master") != null) { - config.useMasterSlaveServers().setMasterAddress(addr); - } else { - config.useMasterSlaveServers().addSlaveAddress(addr); - } - config.useMasterSlaveServers().setDatabase(this.db); - } else if ("cluster".equalsIgnoreCase(type)) { //集群 - baseConfig = config.useClusterServers(); - config.useClusterServers().addNodeAddress(addr); - } else if ("replicated".equalsIgnoreCase(type)) { // - baseConfig = config.useReplicatedServers(); - config.useReplicatedServers().addNodeAddress(addr); - config.useReplicatedServers().setDatabase(this.db); - } else if ("sentinel".equalsIgnoreCase(type)) { // - baseConfig = config.useSentinelServers(); - config.useSentinelServers().addSentinelAddress(addr); - config.useSentinelServers().setDatabase(this.db); - } - } - if (baseConfig != null) { - String username = conf.getValue("username", "").trim(); - String password = conf.getValue("password", "").trim(); - String retryAttempts = conf.getValue("retryAttempts", "").trim(); - String retryInterval = conf.getValue("retryInterval", "").trim(); - if (!username.isEmpty()) baseConfig.setUsername(username); - if (!password.isEmpty()) baseConfig.setPassword(password); - if (!retryAttempts.isEmpty()) baseConfig.setRetryAttempts(Integer.parseInt(retryAttempts)); - if (!retryInterval.isEmpty()) baseConfig.setRetryInterval(Integer.parseInt(retryInterval)); - } - this.redisson = Redisson.create(config); - this.nodeAddrs = addresses; - 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) { - String val = node.getValue("addr"); - if (val != null && val.startsWith("redis://")) return true; - } - return false; - } - - @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"; - } - - protected CompletableFuture completableFuture(CompletionStage rf) { - CompletableFuture future = new CompletableFuture(); - rf.whenComplete((r, t) -> { - if (t != null) { - future.completeExceptionally(t); - } else { - future.complete(r); - } - }); - return future; - } - - public static void main(String[] args) throws Exception { - DefaultAnyValue conf = new DefaultAnyValue().addValue("maxconns", "1"); - conf.addValue("node", new DefaultAnyValue().addValue("addr", "redis://127.0.0.1:6363")); - - RedissionCacheSource source = new RedissionCacheSource(); - 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 (redisson != null) redisson.shutdown(); - } - - //--------------------- exists ------------------------------ - @Override - public CompletableFuture existsAsync(String key) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.isExistsAsync()); - } - - @Override - public boolean exists(String key) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return bucket.isExists(); - } - - //--------------------- get ------------------------------ - @Override - @Deprecated - public CompletableFuture getAsync(String key) { - return getAsync(key, objValueType); - } - - @Override - public CompletableFuture getAsync(String key, Type type) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.getAsync().thenApply(bs -> bs == null ? null : convert.convertFrom(type, bs))); - } - - @Override - public CompletableFuture getStringAsync(String key) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); - return completableFuture(bucket.getAsync()); - } - - @Override - public CompletableFuture getLongAsync(String key, long defValue) { - final RAtomicLong bucket = redisson.getAtomicLong(key); - return completableFuture(bucket.getAsync()); - } - - @Override - @Deprecated - public V get(String key) { - return get(key, objValueType); - } - - @Override - public T get(String key, final Type type) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - byte[] bs = bucket.get(); - return bs == null ? null : convert.convertFrom(type, bs); - } - - @Override - public String getString(String key) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); - return bucket.get(); - } - - @Override - public long getLong(String key, long defValue) { - final RAtomicLong bucket = redisson.getAtomicLong(key); - return bucket.get(); - } - - //--------------------- getAndRefresh ------------------------------ - @Override - @Deprecated - public CompletableFuture getAndRefreshAsync(String key, int expireSeconds) { - return getAndRefreshAsync(key, expireSeconds, objValueType); - } - - @Override - public CompletableFuture getAndRefreshAsync(String key, int expireSeconds, final Type type) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.getAsync().thenCompose(bs -> { - T rs = convert.convertFrom(type, bs); - if (rs == null) return CompletableFuture.completedFuture(null); - return bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> rs); - })); - } - - @Override - @Deprecated - public V getAndRefresh(String key, final int expireSeconds) { - return getAndRefresh(key, expireSeconds, objValueType); - } - - @Override - public T getAndRefresh(String key, final int expireSeconds, final Type type) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - T rs = convert.convertFrom(type, bucket.get()); - if (rs == null) return rs; - bucket.expire(expireSeconds, TimeUnit.SECONDS); - return rs; - } - - @Override - public CompletableFuture getStringAndRefreshAsync(String key, int expireSeconds) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); - return completableFuture(bucket.getAsync().thenCompose(rs -> { - if (rs == null) return CompletableFuture.completedFuture(null); - return bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> rs); - })); - } - - @Override - public String getStringAndRefresh(String key, final int expireSeconds) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); - String rs = bucket.get(); - if (rs == null) return rs; - bucket.expire(expireSeconds, TimeUnit.SECONDS); - return rs; - } - - @Override - public CompletableFuture getLongAndRefreshAsync(String key, int expireSeconds, long defValue) { - final RAtomicLong bucket = redisson.getAtomicLong(key); - return completableFuture(bucket.getAsync().thenCompose(rs -> { - if (rs == null) return CompletableFuture.completedFuture(defValue); - return bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> rs); - })); - } - - @Override - public long getLongAndRefresh(String key, final int expireSeconds, long defValue) { - final RAtomicLong bucket = redisson.getAtomicLong(key); - long rs = bucket.get(); - bucket.expire(expireSeconds, TimeUnit.SECONDS); - return rs; - } - - //--------------------- refresh ------------------------------ - @Override - public CompletableFuture refreshAsync(String key, int expireSeconds) { - final RBucket bucket = redisson.getBucket(key); - return completableFuture(bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(r -> null)); - } - - @Override - public void refresh(String key, final int expireSeconds) { - final RBucket bucket = redisson.getBucket(key); - bucket.expire(expireSeconds, TimeUnit.SECONDS); - } - - //--------------------- set ------------------------------ - @Override - @Deprecated - public CompletableFuture setAsync(String key, V value) { - return setAsync(key, objValueType, value); - } - - @Override - public CompletableFuture setAsync(String key, Convert convert0, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.setAsync((convert0 == null ? this.convert : convert0).convertToBytes(value))); - } - - @Override - public CompletableFuture setAsync(String key, final Type type, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.setAsync(this.convert.convertToBytes(type, value))); - } - - @Override - public CompletableFuture setAsync(String key, Convert convert0, final Type type, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.setAsync((convert0 == null ? this.convert : convert0).convertToBytes(type, value))); - } - - @Override - @Deprecated - public void set(final String key, V value) { - set(key, objValueType, value); - } - - @Override - public void set(final String key, final Convert convert0, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.set((convert0 == null ? this.convert : convert0).convertToBytes(value)); - } - - @Override - public void set(final String key, final Type type, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.set(this.convert.convertToBytes(type, value)); - } - - @Override - public void set(String key, final Convert convert0, final Type type, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.set((convert0 == null ? this.convert : convert0).convertToBytes(type, value)); - } - - @Override - public CompletableFuture setStringAsync(String key, String value) { - return completableFuture(redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE).setAsync(value)); - } - - @Override - public void setString(String key, String value) { - redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE).set(value); - } - - @Override - public CompletableFuture setLongAsync(String key, long value) { - return completableFuture(redisson.getAtomicLong(key).setAsync(value)); - } - - @Override - public void setLong(String key, long value) { - redisson.getAtomicLong(key).set(value); - } - - //--------------------- set ------------------------------ - @Override - @Deprecated - public CompletableFuture setAsync(int expireSeconds, String key, V value) { - return setAsync(expireSeconds, key, objValueType, value); - } - - @Override - public CompletableFuture setAsync(int expireSeconds, String key, Convert convert0, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.setAsync((convert0 == null ? convert : convert0).convertToBytes(value)).thenCompose(v -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS)).thenApply(r -> null)); - } - - @Override - public CompletableFuture setAsync(int expireSeconds, String key, final Type type, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.setAsync(convert.convertToBytes(type, value)).thenCompose(v -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS)).thenApply(r -> null)); - } - - @Override - public CompletableFuture setAsync(int expireSeconds, String key, Convert convert0, final Type type, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.setAsync((convert0 == null ? convert : convert0).convertToBytes(type, value)).thenCompose(v -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS)).thenApply(r -> null)); - } - - @Override - @Deprecated - public void set(int expireSeconds, String key, V value) { - set(expireSeconds, key, objValueType, value); - } - - @Override - public void set(int expireSeconds, String key, Convert convert0, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.set((convert0 == null ? convert : convert0).convertToBytes(value)); - bucket.expire(expireSeconds, TimeUnit.SECONDS); - } - - @Override - public void set(int expireSeconds, String key, final Type type, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.set(convert.convertToBytes(type, value)); - bucket.expire(expireSeconds, TimeUnit.SECONDS); - } - - @Override - public void set(int expireSeconds, String key, Convert convert0, final Type type, T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.set((convert0 == null ? convert : convert0).convertToBytes(type, value)); - bucket.expire(expireSeconds, TimeUnit.SECONDS); - } - - @Override - public CompletableFuture setStringAsync(int expireSeconds, String key, String value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); - return completableFuture(bucket.setAsync(value).thenCompose(v -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS)).thenApply(r -> null)); - } - - @Override - public void setString(int expireSeconds, String key, String value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.StringCodec.INSTANCE); - bucket.set(value); - bucket.expire(expireSeconds, TimeUnit.SECONDS); - } - - @Override - public CompletableFuture setLongAsync(int expireSeconds, String key, long value) { - final RAtomicLong bucket = redisson.getAtomicLong(key); - return completableFuture(bucket.setAsync(value).thenCompose(v -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS)).thenApply(r -> null)); - } - - @Override - public void setLong(int expireSeconds, String key, long value) { - final RAtomicLong bucket = redisson.getAtomicLong(key); - bucket.set(value); - bucket.expire(expireSeconds, TimeUnit.SECONDS); - } - - //--------------------- setExpireSeconds ------------------------------ - @Override - public CompletableFuture setExpireSecondsAsync(String key, int expireSeconds) { - return completableFuture(redisson.getBucket(key).expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(r -> null)); - } - - @Override - public void setExpireSeconds(String key, int expireSeconds) { - redisson.getBucket(key).expire(expireSeconds, TimeUnit.SECONDS); - } - - //--------------------- remove ------------------------------ - @Override - public CompletableFuture removeAsync(String key) { - return completableFuture(redisson.getBucket(key).deleteAsync().thenApply(rs -> rs ? 1 : 0)); - } - - @Override - public int remove(String key) { - return redisson.getBucket(key).delete() ? 1 : 0; - } - - //--------------------- incr ------------------------------ - @Override - public long incr(final String key) { - return redisson.getAtomicLong(key).incrementAndGet(); - } - - @Override - public CompletableFuture incrAsync(final String key) { - return completableFuture(redisson.getAtomicLong(key).incrementAndGetAsync()); - } - - @Override - public long incr(final String key, long num) { - return redisson.getAtomicLong(key).addAndGet(num); - } - - @Override - public CompletableFuture incrAsync(final String key, long num) { - return completableFuture(redisson.getAtomicLong(key).addAndGetAsync(num)); - } - - //--------------------- decr ------------------------------ - @Override - public long decr(final String key) { - return redisson.getAtomicLong(key).decrementAndGet(); - } - - @Override - public CompletableFuture decrAsync(final String key) { - return completableFuture(redisson.getAtomicLong(key).decrementAndGetAsync()); - } - - @Override - public long decr(final String key, long num) { - return redisson.getAtomicLong(key).addAndGet(-num); - } - - @Override - public CompletableFuture decrAsync(final String key, long num) { - return completableFuture(redisson.getAtomicLong(key).addAndGetAsync(-num)); - } - - @Override - public int hremove(final String key, String... fields) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - return (int) map.fastRemove(fields); - } - - @Override - public int hsize(final String key) { - return redisson.getMap(key, MapByteArrayCodec.instance).size(); - } - - @Override - public List hkeys(final String key) { - return (List) new ArrayList<>(redisson.getMap(key, MapStringCodec.instance).keySet()); - } - - @Override - public long hincr(final String key, String field) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return map.addAndGet(field, 1L); - } - - @Override - public long hincr(final String key, String field, long num) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return map.addAndGet(field, num); - } - - @Override - public long hdecr(final String key, String field) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return map.addAndGet(field, -1L); - } - - @Override - public long hdecr(final String key, String field, long num) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return map.addAndGet(field, num); - } - - @Override - public boolean hexists(final String key, String field) { - return redisson.getMap(key, MapByteArrayCodec.instance).containsKey(field); - } - - @Override - public void hset(final String key, final String field, final Convert convert0, final T value) { - if (value == null) return; - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - map.fastPut(field, (convert0 == null ? convert : convert0).convertToBytes(objValueType, value)); - } - - @Override - public void hset(final String key, final String field, final Type type, final T value) { - if (value == null) return; - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - map.fastPut(field, this.convert.convertToBytes(type, value)); - } - - @Override - public void hset(final String key, final String field, final Convert convert0, final Type type, final T value) { - if (value == null) return; - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - map.fastPut(field, (convert0 == null ? convert : convert0).convertToBytes(type, value)); - } - - @Override - public void hsetString(final String key, final String field, final String value) { - if (value == null) return; - RMap map = redisson.getMap(key, MapStringCodec.instance); - map.fastPut(field, value); - } - - @Override - public void hsetLong(final String key, final String field, final long value) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - map.fastPut(field, value); - } - - @Override - public void hmset(final String key, final Serializable... values) { - Map vals = new HashMap<>(); - for (int i = 0; i < values.length; i += 2) { - vals.put(String.valueOf(values[i]), this.convert.convertToBytes(values[i + 1])); - } - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - map.putAll(vals); - } - - @Override - public List hmget(final String key, final Type type, final String... fields) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - Map rs = map.getAll(Set.of(fields)); - List list = new ArrayList<>(fields.length); - for (String field : fields) { - byte[] bs = rs.get(field); - if (bs == null) { - list.add(null); - } else { - list.add(convert.convertFrom(type, bs)); - } - } - return list; - } - - @Override - public Map hmap(final String key, final Type type, int offset, int limit, String pattern) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - Iterator it = map.keySet(pattern, offset + limit).iterator(); - final Map rs = new HashMap<>(); - int index = -1; - while (it.hasNext()) { - if (++index < offset) continue; - if (index >= offset + limit) break; - String field = it.next(); - byte[] bs = map.get(field); - if (bs != null) rs.put(field, convert.convertFrom(type, bs)); - } - return rs; - } - - @Override - public Map hmap(final String key, final Type type, int offset, int limit) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - Iterator it = map.keySet(offset + limit).iterator(); - final Map rs = new HashMap<>(); - int index = -1; - while (it.hasNext()) { - if (++index < offset) continue; - if (index >= offset + limit) break; - String field = it.next(); - byte[] bs = map.get(field); - if (bs != null) rs.put(field, convert.convertFrom(type, bs)); - } - return rs; - } - - @Override - public T hget(final String key, final String field, final Type type) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - byte[] bs = map.get(field); - return bs == null ? null : convert.convertFrom(type, bs); - } - - @Override - public String hgetString(final String key, final String field) { - RMap map = redisson.getMap(key, MapStringCodec.instance); - return map.get(field); - } - - @Override - public long hgetLong(final String key, final String field, long defValue) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - Long rs = map.get(field); - return rs == null ? defValue : rs; - } - - @Override - public CompletableFuture hremoveAsync(final String key, String... fields) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - return completableFuture(map.fastRemoveAsync(fields).thenApply(r -> r.intValue())); - } - - @Override - public CompletableFuture hsizeAsync(final String key) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - return completableFuture(map.sizeAsync()); - } - - @Override - public CompletableFuture> hkeysAsync(final String key) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - return completableFuture(map.readAllKeySetAsync().thenApply(set -> set == null ? null : new ArrayList(set))); - } - - @Override - public CompletableFuture hincrAsync(final String key, String field) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return completableFuture(map.addAndGetAsync(field, 1L)); - } - - @Override - public CompletableFuture hincrAsync(final String key, String field, long num) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return completableFuture(map.addAndGetAsync(field, num)); - } - - @Override - public CompletableFuture hdecrAsync(final String key, String field) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return completableFuture(map.addAndGetAsync(field, -1L)); - } - - @Override - public CompletableFuture hdecrAsync(final String key, String field, long num) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return completableFuture(map.addAndGetAsync(field, -num)); - } - - @Override - public CompletableFuture hexistsAsync(final String key, String field) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return completableFuture(map.containsKeyAsync(field)); - } - - @Override - public CompletableFuture hsetAsync(final String key, final String field, final Convert convert0, final T value) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - return completableFuture(map.fastPutAsync(field, (convert0 == null ? convert : convert0).convertToBytes(objValueType, value)).thenApply(r -> null)); - } - - @Override - public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - return completableFuture(map.fastPutAsync(field, convert.convertToBytes(type, value)).thenApply(r -> null)); - } - - @Override - public CompletableFuture hsetAsync(final String key, final String field, final Convert convert0, final Type type, final T value) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - return completableFuture(map.fastPutAsync(field, (convert0 == null ? convert : convert0).convertToBytes(type, value)).thenApply(r -> null)); - } - - @Override - public CompletableFuture hsetStringAsync(final String key, final String field, final String value) { - if (value == null) return CompletableFuture.completedFuture(null); - RMap map = redisson.getMap(key, MapStringCodec.instance); - return completableFuture(map.fastPutAsync(field, value).thenApply(r -> null)); - } - - @Override - public CompletableFuture hsetLongAsync(final String key, final String field, final long value) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return completableFuture(map.fastPutAsync(field, value).thenApply(r -> null)); - } - - @Override - public CompletableFuture hmsetAsync(final String key, final Serializable... values) { - Map vals = new HashMap<>(); - for (int i = 0; i < values.length; i += 2) { - vals.put(String.valueOf(values[i]), this.convert.convertToBytes(values[i + 1])); - } - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - return completableFuture(map.putAllAsync(vals)); - } - - @Override - public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - return completableFuture(map.getAllAsync(Set.of(fields)).thenApply(rs -> { - List list = new ArrayList<>(fields.length); - for (String field : fields) { - byte[] bs = rs.get(field); - if (bs == null) { - list.add(null); - } else { - list.add(convert.convertFrom(type, bs)); - } - } - return list; - })); - } - - @Override - public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit) { - return CompletableFuture.supplyAsync(() -> { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - - Iterator it = map.keySet(offset + limit).iterator(); - final Map rs = new HashMap<>(); - int index = -1; - while (it.hasNext()) { - if (++index < offset) continue; - if (index >= offset + limit) break; - String field = it.next(); - byte[] bs = map.get(field); - if (bs != null) rs.put(field, convert.convertFrom(type, bs)); - } - return rs; - }); - } - - @Override - public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit, String pattern) { - return CompletableFuture.supplyAsync(() -> { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - - Iterator it = map.keySet(pattern, offset + limit).iterator(); - final Map rs = new HashMap<>(); - int index = -1; - while (it.hasNext()) { - if (++index < offset) continue; - if (index >= offset + limit) break; - String field = it.next(); - byte[] bs = map.get(field); - if (bs != null) rs.put(field, convert.convertFrom(type, bs)); - } - return rs; - }); - } - - @Override - public CompletableFuture hgetAsync(final String key, final String field, final Type type) { - RMap map = redisson.getMap(key, MapByteArrayCodec.instance); - return completableFuture(map.getAsync(field).thenApply(r -> r == null ? null : convert.convertFrom(type, r))); - } - - @Override - public CompletableFuture hgetStringAsync(final String key, final String field) { - RMap map = redisson.getMap(key, MapStringCodec.instance); - return completableFuture(map.getAsync(field)); - } - - @Override - public CompletableFuture hgetLongAsync(final String key, final String field, long defValue) { - RMap map = redisson.getMap(key, MapLongCodec.instance); - return completableFuture(map.getAsync(field).thenApply(r -> r == null ? defValue : r.longValue())); - } - - //--------------------- collection ------------------------------ - @Override - public CompletableFuture getCollectionSizeAsync(String key) { - return completableFuture(redisson.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { - if (String.valueOf(type).contains("list")) { - return redisson.getList(key).sizeAsync(); - } else { - return redisson.getSet(key).sizeAsync(); - } - })); - } - - @Override - public int getCollectionSize(String key) { - String type = redisson.getScript().eval(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE); - if (String.valueOf(type).contains("list")) { - return redisson.getList(key).size(); - } else { - return redisson.getSet(key).size(); - } - } - - @Override - @Deprecated - public CompletableFuture> getCollectionAsync(String key) { - return getCollectionAsync(key, objValueType); - } - - @Override - public CompletableFuture> getCollectionAsync(String key, final Type componentType) { - return completableFuture(redisson.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { - if (String.valueOf(type).contains("list")) { - return (CompletionStage) redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { - if (list == null || list.isEmpty()) return list; - List rs = new ArrayList<>(); - for (Object item : list) { - byte[] bs = (byte[]) item; - if (bs == null) { - rs.add(null); - } else { - rs.add(convert.convertFrom(componentType, bs)); - } - } - return rs; - }); - } else { - return (CompletionStage) redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).readAllAsync().thenApply(set -> { - if (set == null || set.isEmpty()) return set; - Set rs = new HashSet<>(); - for (Object item : set) { - byte[] bs = (byte[]) item; - if (bs == null) { - rs.add(null); - } else { - rs.add(convert.convertFrom(componentType, bs)); - } - } - return rs; - }); - } - })); -// 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) { - return completableFuture(redisson.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).getAsync(keys)); - } - - @Override - public CompletableFuture getLongArrayAsync(String... keys) { - return completableFuture(redisson.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).getAsync(keys).thenApply(map -> { - Long[] rs = new Long[keys.length]; - for (int i = 0; i < rs.length; i++) { - rs[i] = (Long) map.get(keys[i]); - } - return rs; - })); - } - - @Override - public CompletableFuture getStringArrayAsync(String... keys) { - return completableFuture(redisson.getBuckets(org.redisson.client.codec.StringCodec.INSTANCE).getAsync(keys).thenApply(map -> { - String[] rs = new String[keys.length]; - for (int i = 0; i < rs.length; i++) { - rs[i] = (String) map.get(keys[i]); - } - return rs; - })); - } - - @Override - public CompletableFuture> getStringMapAsync(String... keys) { - return completableFuture(redisson.getBuckets(org.redisson.client.codec.StringCodec.INSTANCE).getAsync(keys)); - } - - @Override - public CompletableFuture> getMapAsync(final Type componentType, String... keys) { - return completableFuture(redisson.getBuckets(org.redisson.client.codec.ByteArrayCodec.INSTANCE).getAsync(keys).thenApply(map -> { - Map rs = new HashMap(); - map.forEach((k, v) -> rs.put(k, convert.convertFrom(componentType, (byte[]) v))); - return rs; - })); - } - - @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] = completableFuture(redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { - if (list == null || list.isEmpty()) return list; - List rs = new ArrayList<>(); - for (Object item : list) { - byte[] bs = (byte[]) item; - if (bs == null) { - rs.add(null); - } else { - rs.add(convert.convertFrom(componentType, bs)); - } - } - synchronized (map) { - map.put(key, rs); - } - return rs; - })); - } - } else { - for (int i = 0; i < keys.length; i++) { - final String key = keys[i]; - futures[i] = completableFuture(redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { - if (list == null || list.isEmpty()) return list; - List rs = new ArrayList<>(); - for (Object item : list) { - byte[] bs = (byte[]) item; - if (bs == null) { - rs.add(null); - } else { - rs.add(convert.convertFrom(componentType, bs)); - } - } - synchronized (map) { - map.put(key, rs); - } - return rs; - })); - } - } - 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 getCollection(key, objValueType); - } - - @Override - public Collection getCollection(String key, final Type componentType) { - return (Collection) getCollectionAsync(key, componentType).join(); - } - - @Override - public Map getLongMap(final String... keys) { - return redisson.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).get(keys); - } - - @Override - public Long[] getLongArray(final String... keys) { - Map map = redisson.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).get(keys); - Long[] rs = new Long[keys.length]; - for (int i = 0; i < rs.length; i++) { - rs[i] = map.get(keys[i]); - } - return rs; - } - - @Override - public Map getStringMap(final String... keys) { - return redisson.getBuckets(org.redisson.client.codec.StringCodec.INSTANCE).get(keys); - } - - @Override - public String[] getStringArray(final String... keys) { - Map map = redisson.getBuckets(org.redisson.client.codec.StringCodec.INSTANCE).get(keys); - String[] rs = new String[keys.length]; - for (int i = 0; i < rs.length; i++) { - rs[i] = map.get(keys[i]); - } - return rs; - } - - @Override - public Map getMap(final Type componentType, final String... keys) { - Map map = redisson.getBuckets(org.redisson.client.codec.ByteArrayCodec.INSTANCE).get(keys); - Map rs = new HashMap(map.size()); - map.forEach((k, v) -> rs.put(k, convert.convertFrom(componentType, v))); - return rs; - } - - @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(redisson.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { - if (String.valueOf(type).contains("list")) { - return (CompletionStage) redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE).readAllAsync(); - } else { - return (CompletionStage) redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE).readAllAsync().thenApply(s -> s == null ? null : new ArrayList(s)); - } - })); - } - - @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] = completableFuture(redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE).readAllAsync().thenApply(r -> { - if (r != null) { - synchronized (map) { - map.put(key, (Collection) r); - } - } - return null; - })); - } - } else { - for (int i = 0; i < keys.length; i++) { - final String key = keys[i]; - futures[i] = completableFuture(redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE).readAllAsync().thenApply(r -> { - if (r != null) { - synchronized (map) { - map.put(key, new ArrayList(r)); - } - } - return null; - })); - } - } - 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(redisson.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { - if (String.valueOf(type).contains("list")) { - return (CompletionStage) redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync(); - } else { - return (CompletionStage) redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync().thenApply(s -> s == null ? null : new ArrayList(s)); - } - })); - } - - @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] = completableFuture(redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync().thenApply(r -> { - if (r != null) { - synchronized (map) { - map.put(key, (Collection) r); - } - } - return null; - })); - } - } else { - for (int i = 0; i < keys.length; i++) { - final String key = keys[i]; - futures[i] = completableFuture(redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync().thenApply(r -> { - if (r != null) { - synchronized (map) { - map.put(key, new ArrayList(r)); - } - } - return null; - })); - } - } - 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 getCollectionAndRefreshAsync(key, expireSeconds, objValueType); - } - - @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 getCollectionAndRefresh(key, expireSeconds, objValueType); - } - - @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 existsSetItem(key, objValueType, value); - } - - @Override - public boolean existsSetItem(String key, final Type componentType, T value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return bucket.contains(convert.convertToBytes(componentType, value)); - } - - @Override - @Deprecated - public CompletableFuture existsSetItemAsync(String key, V value) { - return existsSetItemAsync(key, objValueType, value); - } - - @Override - public CompletableFuture existsSetItemAsync(String key, final Type componentType, T value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.containsAsync(convert.convertToBytes(componentType, value))); - } - - @Override - public boolean existsStringSetItem(String key, String value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); - return bucket.contains(value); - } - - @Override - public CompletableFuture existsStringSetItemAsync(String key, String value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); - return completableFuture(bucket.containsAsync(value)); - } - - @Override - public boolean existsLongSetItem(String key, long value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); - return bucket.contains(value); - } - - @Override - public CompletableFuture existsLongSetItemAsync(String key, long value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); - return completableFuture(bucket.containsAsync(value)); - } - - //--------------------- appendListItem ------------------------------ - @Override - @Deprecated - public CompletableFuture appendListItemAsync(String key, V value) { - return appendListItemAsync(key, objValueType, value); - } - - @Override - public CompletableFuture appendListItemAsync(String key, final Type componentType, T value) { - final RList bucket = redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.addAsync(convert.convertToBytes(componentType, value)).thenApply(r -> null)); - } - - @Override - @Deprecated - public void appendListItem(String key, V value) { - appendListItem(key, objValueType, value); - } - - @Override - public void appendListItem(String key, final Type componentType, T value) { - final RList bucket = redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.add(convert.convertToBytes(componentType, value)); - } - - @Override - public CompletableFuture appendStringListItemAsync(String key, String value) { - final RList bucket = redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE); - return completableFuture(bucket.addAsync(value).thenApply(r -> null)); - } - - @Override - public void appendStringListItem(String key, String value) { - final RList bucket = redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE); - bucket.add(value); - } - - @Override - public CompletableFuture appendLongListItemAsync(String key, long value) { - final RList bucket = redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE); - return completableFuture(bucket.addAsync(value).thenApply(r -> null)); - } - - @Override - public void appendLongListItem(String key, long value) { - final RList bucket = redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE); - bucket.add(value); - } - - //--------------------- removeListItem ------------------------------ - @Override - @Deprecated - public CompletableFuture removeListItemAsync(String key, V value) { - return removeListItemAsync(key, objValueType, value); - } - - @Override - public CompletableFuture removeListItemAsync(String key, final Type componentType, T value) { - return completableFuture(redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).removeAsync(convert.convertToBytes(componentType, value)).thenApply(r -> r ? 1 : 0)); - } - - @Override - @Deprecated - public int removeListItem(String key, V value) { - return removeListItem(key, objValueType, value); - } - - @Override - public int removeListItem(String key, final Type componentType, T value) { - final RList bucket = redisson.getList(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return bucket.remove(convert.convertToBytes(componentType, value)) ? 1 : 0; - } - - @Override - public CompletableFuture removeStringListItemAsync(String key, String value) { - return completableFuture(redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE).removeAsync(value).thenApply(r -> r ? 1 : 0)); - } - - @Override - public int removeStringListItem(String key, String value) { - return redisson.getList(key, org.redisson.client.codec.StringCodec.INSTANCE).remove(value) ? 1 : 0; - } - - @Override - public CompletableFuture removeLongListItemAsync(String key, long value) { - return completableFuture(redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).removeAsync((Object) value).thenApply(r -> r ? 1 : 0)); - } - - @Override - public int removeLongListItem(String key, long value) { - return redisson.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).remove((Object) value) ? 1 : 0; - } - - //--------------------- appendSetItem ------------------------------ - @Override - @Deprecated - public CompletableFuture appendSetItemAsync(String key, V value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.addAsync(convert.convertToBytes(objValueType, value)).thenApply(r -> null)); - } - - @Override - public CompletableFuture appendSetItemAsync(String key, Type componentType, T value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.addAsync(convert.convertToBytes(componentType, value)).thenApply(r -> null)); - } - - @Override - public CompletableFuture spopSetItemAsync(String key, Type componentType) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.removeRandomAsync().thenApply(bs -> bs == null ? null : convert.convertFrom(componentType, bs))); - } - - @Override - public CompletableFuture> spopSetItemAsync(String key, int count, Type componentType) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.removeRandomAsync(count).thenApply((Set bslist) -> { - if (bslist == null || bslist.isEmpty()) return new ArrayList<>(); - List rs = new ArrayList<>(); - for (byte[] bs : bslist) { - rs.add(convert.convertFrom(componentType, bs)); - } - return rs; - })); - } - - @Override - public CompletableFuture spopStringSetItemAsync(String key) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); - return completableFuture(bucket.removeRandomAsync()); - } - - @Override - public CompletableFuture> spopStringSetItemAsync(String key, int count) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); - return completableFuture(bucket.removeRandomAsync(count).thenApply(r -> r == null ? null : new ArrayList<>(r))); - } - - @Override - public CompletableFuture spopLongSetItemAsync(String key) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); - return completableFuture(bucket.removeRandomAsync()); - } - - @Override - public CompletableFuture> spopLongSetItemAsync(String key, int count) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); - return completableFuture(bucket.removeRandomAsync(count).thenApply(r -> r == null ? null : new ArrayList<>(r))); - } - - @Override - @Deprecated - public void appendSetItem(String key, V value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.add(convert.convertToBytes(objValueType, value)); - } - - @Override - public void appendSetItem(String key, final Type componentType, T value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.add(convert.convertToBytes(componentType, value)); - } - - @Override - public T spopSetItem(String key, final Type componentType) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - byte[] bs = bucket.removeRandom(); - return bs == null ? null : convert.convertFrom(componentType, bs); - } - - @Override - public List spopSetItem(String key, int count, final Type componentType) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - Set< byte[]> bslist = bucket.removeRandom(count); - List rs = new ArrayList<>(); - if (bslist == null) return rs; - for (byte[] bs : bslist) { - rs.add(convert.convertFrom(componentType, bs)); - } - return rs; - } - - @Override - public String spopStringSetItem(String key) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); - return bucket.removeRandom(); - } - - @Override - public List spopStringSetItem(String key, int count) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); - Set rs = bucket.removeRandom(count); - return rs == null ? null : new ArrayList<>(rs); - } - - @Override - public Long spopLongSetItem(String key) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); - return bucket.removeRandom(); - } - - @Override - public List spopLongSetItem(String key, int count) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); - Set rs = bucket.removeRandom(count); - return rs == null ? null : new ArrayList<>(rs); - } - - @Override - public CompletableFuture appendStringSetItemAsync(String key, String value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); - return completableFuture(bucket.addAsync(value).thenApply(r -> null)); - } - - @Override - public void appendStringSetItem(String key, String value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE); - bucket.add(value); - } - - @Override - public CompletableFuture appendLongSetItemAsync(String key, long value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); - return completableFuture(bucket.addAsync(value).thenApply(r -> null)); - } - - @Override - public void appendLongSetItem(String key, long value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); - bucket.add(value); - } - - //--------------------- removeSetItem ------------------------------ - @Override - @Deprecated - public CompletableFuture removeSetItemAsync(String key, V value) { - return removeSetItemAsync(key, objValueType, value); - } - - @Override - public CompletableFuture removeSetItemAsync(String key, final Type componentType, T value) { - return completableFuture(redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE).removeAsync(convert.convertToBytes(componentType, value)).thenApply(r -> r ? 1 : 0)); - } - - @Override - @Deprecated - public int removeSetItem(String key, V value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return bucket.remove(convert.convertToBytes(objValueType, value)) ? 1 : 0; - } - - @Override - public int removeSetItem(String key, final Type componentType, T value) { - final RSet bucket = redisson.getSet(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return bucket.remove(convert.convertToBytes(componentType, value)) ? 1 : 0; - } - - @Override - public CompletableFuture removeStringSetItemAsync(String key, String value) { - return completableFuture(redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE).removeAsync(value).thenApply(r -> r ? 1 : 0)); - } - - @Override - public int removeStringSetItem(String key, String value) { - return redisson.getSet(key, org.redisson.client.codec.StringCodec.INSTANCE).remove(value) ? 1 : 0; - } - - @Override - public CompletableFuture removeLongSetItemAsync(String key, long value) { - return completableFuture(redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).removeAsync(value).thenApply(r -> r ? 1 : 0)); - } - - @Override - public int removeLongSetItem(String key, long value) { - return redisson.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).remove(value) ? 1 : 0; - } - - //--------------------- queryKeys ------------------------------ - @Override - public List queryKeys() { - return redisson.getKeys().getKeysStream().collect(Collectors.toList()); - } - - @Override - public List queryKeysStartsWith(String startsWith) { - return redisson.getKeys().getKeysStreamByPattern(startsWith + "*").collect(Collectors.toList()); - } - - @Override - public List queryKeysEndsWith(String endsWith) { - return redisson.getKeys().getKeysStreamByPattern("*" + endsWith).collect(Collectors.toList()); - } - - @Override - public byte[] getBytes(final String key) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return bucket.get(); - } - - @Override - public byte[] getBytesAndRefresh(final String key, final int expireSeconds) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - byte[] bs = bucket.get(); - if (bs == null) return bs; - bucket.expire(expireSeconds, TimeUnit.SECONDS); - return bs; - } - - @Override - public void setBytes(final String key, final byte[] value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.set(value); - } - - @Override - public void setBytes(final int expireSeconds, final String key, final byte[] value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.set(value); - bucket.expire(expireSeconds, TimeUnit.SECONDS); - } - - @Override - public void setBytes(final String key, final Convert convert0, final Type type, final T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.set((convert0 == null ? convert : convert0).convertToBytes(type, value)); - } - - @Override - public void setBytes(final int expireSeconds, final String key, final Convert convert0, final Type type, final T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - bucket.set((convert0 == null ? convert : convert0).convertToBytes(type, value)); - bucket.expire(expireSeconds, TimeUnit.SECONDS); - } - - @Override - public CompletableFuture getBytesAsync(final String key) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.getAsync()); - } - - @Override - public CompletableFuture getBytesAndRefreshAsync(final String key, final int expireSeconds) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.getAsync().thenCompose(bs -> bs == null ? CompletableFuture.completedFuture(null) : bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> bs))); - } - - @Override - public CompletableFuture setBytesAsync(final String key, final byte[] value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.setAsync(value)); - } - - @Override - public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final byte[] value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.setAsync(value).thenCompose(r -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> null))); - } - - @Override - public CompletableFuture setBytesAsync(final String key, final Convert convert0, final Type type, final T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.setAsync((convert0 == null ? convert : convert0).convertToBytes(type, value)).thenApply(v -> null)); - } - - @Override - public CompletableFuture setBytesAsync(final int expireSeconds, final String key, final Convert convert0, final Type type, final T value) { - final RBucket bucket = redisson.getBucket(key, org.redisson.client.codec.ByteArrayCodec.INSTANCE); - return completableFuture(bucket.setAsync((convert0 == null ? convert : convert0).convertToBytes(type, value)).thenCompose(r -> bucket.expireAsync(expireSeconds, TimeUnit.SECONDS).thenApply(v -> null))); - } - - @Override - public CompletableFuture> queryKeysAsync() { - return CompletableFuture.supplyAsync(() -> queryKeys()); - } - - @Override - public CompletableFuture> queryKeysStartsWithAsync(String startsWith) { - if (startsWith == null) return CompletableFuture.supplyAsync(() -> queryKeys()); - return CompletableFuture.supplyAsync(() -> queryKeysStartsWith(startsWith)); - } - - @Override - public CompletableFuture> queryKeysEndsWithAsync(String endsWith) { - if (endsWith == null) return CompletableFuture.supplyAsync(() -> queryKeys()); - return CompletableFuture.supplyAsync(() -> queryKeysEndsWith(endsWith)); - } - - //--------------------- getKeySize ------------------------------ - @Override - public int getKeySize() { - return (int) redisson.getKeys().count(); - } - - @Override - public CompletableFuture getKeySizeAsync() { - return completableFuture(redisson.getKeys().countAsync().thenApply(r -> r.intValue())); - } - - //--------------------- queryList ------------------------------ - @Override - public List> queryList() { - return queryListAsync().join(); - } - - @Override - public CompletableFuture>> queryListAsync() { - return CompletableFuture.completedFuture(new ArrayList<>()); //不返回数据 - } - - protected static class MapByteArrayCodec extends org.redisson.client.codec.ByteArrayCodec { - - public static final MapByteArrayCodec instance = new MapByteArrayCodec(); - - @Override - public org.redisson.client.protocol.Decoder getMapKeyDecoder() { - return org.redisson.client.codec.StringCodec.INSTANCE.getValueDecoder(); - } - - @Override - public org.redisson.client.protocol.Encoder getMapKeyEncoder() { - return org.redisson.client.codec.StringCodec.INSTANCE.getValueEncoder(); - } - } - - protected static class MapStringCodec extends org.redisson.client.codec.StringCodec { - - public static final MapStringCodec instance = new MapStringCodec(); - - @Override - public org.redisson.client.protocol.Decoder getMapKeyDecoder() { - return org.redisson.client.codec.StringCodec.INSTANCE.getValueDecoder(); - } - - @Override - public org.redisson.client.protocol.Encoder getMapKeyEncoder() { - return org.redisson.client.codec.StringCodec.INSTANCE.getValueEncoder(); - } - } - - protected static class MapLongCodec extends org.redisson.client.codec.LongCodec { - - public static final MapLongCodec instance = new MapLongCodec(); - - @Override - public org.redisson.client.protocol.Decoder getMapKeyDecoder() { - return org.redisson.client.codec.StringCodec.INSTANCE.getValueDecoder(); - } - - @Override - public org.redisson.client.protocol.Encoder getMapKeyEncoder() { - return org.redisson.client.codec.StringCodec.INSTANCE.getValueEncoder(); - } - } -} -*/ diff --git a/src/com/zdemo/kafak/KafakConsumer.java b/src/com/zdemo/kafak/KafakConsumer.java deleted file mode 100644 index c4fc561..0000000 --- a/src/com/zdemo/kafak/KafakConsumer.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.zdemo.kafak; - -import com.zdemo.AbstractConsumer; -import com.zdemo.IConsumer; -import org.apache.kafka.clients.consumer.ConsumerRecords; -import org.apache.kafka.clients.consumer.KafkaConsumer; -import org.apache.kafka.common.errors.WakeupException; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.AutoLoad; - -import javax.annotation.Resource; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.time.Duration; -import java.util.Properties; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * 消费 - */ -@AutoLoad(false) -public abstract class KafakConsumer extends AbstractConsumer implements IConsumer, Service { - - public Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - @Resource(name = "APP_HOME") - protected File APP_HOME; - - private final LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); - - @Override - public final void init(AnyValue config) { - if (!preInit()) { - return; - } - try (FileInputStream fis = new FileInputStream(new File(APP_HOME, "conf/kafak.properties"));) { - Properties props = new Properties(); - props.load(fis); - - new Thread(() -> { - try { - props.put("group.id", getGroupid()); - KafkaConsumer consumer = new KafkaConsumer<>(props); - consumer.subscribe(getTopics()); - while (true) { - ConsumerRecords records = consumer.poll(Duration.ofMillis(1_000)); - records.forEach(record -> { - String topic = record.topic(); - long offset = record.offset(); - String value = record.value(); - try { - accept(topic, value); - } catch (Exception e) { - logger.log(Level.WARNING, String.format("topic[%s] event accept error, offset=%s,value:%s", topic, offset, value), e); - } - }); - - if (!queue.isEmpty()) { - Runnable runnable; - while ((runnable = queue.poll()) != null) { - runnable.run(); - } - - consumer.unsubscribe(); - consumer.subscribe(getTopics()); - } - } - } catch (WakeupException ex) { - System.out.println("WakeupException !!!!"); - } - - }, "thread-consumer-[" + getGroupid() + "]").start(); - } catch (IOException e) { - logger.log(Level.WARNING, "", e); - } - } - - @Override - public void unsubscribe(String topic) { - queue.add(() -> super.removeEventType(topic)); // 加入延时执行队列(下一次订阅变更检查周期执行) - } - - @Override - protected void subscribe(String topic) { - queue.add(() -> { - // just set flag, nothing to do - }); - } -} diff --git a/src/com/zdemo/kafak/KafakProducer.java b/src/com/zdemo/kafak/KafakProducer.java deleted file mode 100644 index 1c272a3..0000000 --- a/src/com/zdemo/kafak/KafakProducer.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.zdemo.kafak; - -import com.zdemo.IProducer; -import org.apache.kafka.clients.producer.KafkaProducer; -import org.apache.kafka.clients.producer.ProducerRecord; -import org.redkale.convert.json.JsonConvert; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.AutoLoad; - -import javax.annotation.Resource; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Properties; -import java.util.logging.Level; - -/** - * 生产 - * - * @param - */ -@AutoLoad(false) -public class KafakProducer implements IProducer, Service { - private KafkaProducer producer; - - @Resource(name = "APP_HOME") - protected File APP_HOME; - - @Override - public void init(AnyValue config) { - File file = new File(APP_HOME, "conf/kafak.properties"); - try (FileInputStream fis = new FileInputStream(file)) { - Properties props = new Properties(); - props.load(fis); - producer = new KafkaProducer(props); - } catch (IOException e) { - logger.log(Level.WARNING, "未初始化kafak 生产者,kafak发布消息不可用", e); - } - } - - @Override - public boolean publish(String topic, Object v) { - producer.send(new ProducerRecord(topic, toStr(v))); - return true; - } - - @Override - public void destroy(AnyValue config) { - producer.close(); - } - - private String toStr(V v) { - if (v instanceof String) { - return (String) v; - } - return JsonConvert.root().convertTo(v); - } -} diff --git a/src/com/zdemo/pulsar/AService.java b/src/com/zdemo/pulsar/AService.java deleted file mode 100644 index fe39874..0000000 --- a/src/com/zdemo/pulsar/AService.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.zdemo.pulsar; - -import com.zdemo.zhub.ZHubClient; -import org.redkale.net.http.RestMapping; -import org.redkale.net.http.RestService; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.Utility; - -import javax.annotation.Resource; - -@RestService -public class AService implements Service { - - @Resource(name = "zhub") - private ZHubClient zhub; - - @Override - public void init(AnyValue config) { - zhub.timer("a", () -> { - System.out.println(Utility.now() + " timer RANK-DATA-RELOADALL 执行了"); - }); - } - - @RestMapping - public void x() { - - } -} diff --git a/src/com/zdemo/pulsar/PulsarConsumer.java b/src/com/zdemo/pulsar/PulsarConsumer.java deleted file mode 100644 index 3008e08..0000000 --- a/src/com/zdemo/pulsar/PulsarConsumer.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.zdemo.pulsar; - -import com.zdemo.AbstractConsumer; -import com.zdemo.EventType; -import com.zdemo.IConsumer; -import org.apache.pulsar.client.api.*; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; - -import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; - -public abstract class PulsarConsumer extends AbstractConsumer implements IConsumer, Service { - - @Resource(name = "property.pulsar.serviceurl") - private String serviceurl = "pulsar://127.0.0.1:6650"; - private PulsarClient client; - private Consumer consumer; - - public abstract String getGroupid(); - - private final LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); - - @Override - public void addEventType(EventType... eventTypes) { - super.addEventType(eventTypes); - - // 增加变更标记 - queue.add(() -> logger.info("PulsarConsumer add new topic!")); - } - - @Override - public void init(AnyValue config) { - if (!preInit()) { - return; - } - queue.add(() -> logger.info("PulsarConsumer starting ...")); - new Thread(() -> { - try { - client = PulsarClient.builder() - .serviceUrl(serviceurl) - .build(); - - while (true) { - // 动态新增订阅 - if (!queue.isEmpty()) { - Runnable runnable; - while ((runnable = queue.poll()) != null) { - runnable.run(); - } - - consumer.unsubscribe(); - consumer = client.newConsumer() - .topics(new ArrayList<>(getTopics())) - .subscriptionName(getGroupid()) - .subscriptionType(SubscriptionType.Shared) - .subscribe(); - } - - // Wait for a message - Message msg = consumer.receive(10, TimeUnit.SECONDS); - if (msg == null) { - continue; - } - - String topic = msg.getTopicName().replace("persistent://public/default/", ""); - long offset = 0; - String value = new String(msg.getData()); - try { - accept(topic, value); - - consumer.acknowledge(msg); // Acknowledge the message so that it can be deleted by the message broker - } catch (Exception e) { - logger.log(Level.WARNING, String.format("topic[%s] event accept error, offset=%s,value:%s", topic, offset, value), e); - consumer.negativeAcknowledge(msg); // Message failed to process, redeliver later - } - } - } catch (PulsarClientException e) { - e.printStackTrace(); - } - }).start(); - } - - @Override - public void unsubscribe(String topic) { - - } -} diff --git a/src/com/zdemo/pulsar/PulsarProducer.java b/src/com/zdemo/pulsar/PulsarProducer.java deleted file mode 100644 index 219efcc..0000000 --- a/src/com/zdemo/pulsar/PulsarProducer.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.zdemo.pulsar; - -import com.zdemo.Event; -import com.zdemo.IProducer; -import org.apache.pulsar.client.api.Producer; -import org.apache.pulsar.client.api.PulsarClient; -import org.apache.pulsar.client.api.PulsarClientException; -import org.redkale.convert.json.JsonConvert; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.Comment; - -import javax.annotation.Resource; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; - -public class PulsarProducer implements IProducer, Service { - - @Resource(name = "property.pulsar.serviceurl") - private String serviceurl = "pulsar://127.0.0.1:6650"; - - @Comment("消息生产者") - private Map> producerMap = new HashMap(); - private PulsarClient client; - - @Override - public void init(AnyValue config) { - try { - client = PulsarClient.builder() - .serviceUrl(serviceurl) - .build(); - } catch (PulsarClientException e) { - e.printStackTrace(); - } - } - - public Producer getProducer(String topic) { - Producer producer = producerMap.get(topic); - if (producer != null) { - return producer; - } - - synchronized (this) { - if ((producer = producerMap.get(topic)) == null) { - try { - producer = client.newProducer() - .topic(topic) - .batchingMaxPublishDelay(10, TimeUnit.MILLISECONDS) - .sendTimeout(10, TimeUnit.SECONDS) - .blockIfQueueFull(true) - .create(); - producerMap.put(topic, producer); - - return producer; - } catch (PulsarClientException e) { - e.printStackTrace(); - } - } - } - return producer; - } - - @Override - public void send(T t) { - try { - Producer producer = getProducer(t.topic); - - String v = JsonConvert.root().convertTo(t.value); - if (v.startsWith("\"") && v.endsWith("\"")) { - v = v.substring(1, v.length() - 1); - } - producer.newMessage() - .key("") - .value(v.getBytes()) - .send(); - } catch (Exception e) { - logger.log(Level.WARNING, "", e); - } - } -} diff --git a/src/com/zdemo/redis/RedisConsumer.java b/src/com/zdemo/redis/RedisConsumer.java deleted file mode 100644 index 5c59665..0000000 --- a/src/com/zdemo/redis/RedisConsumer.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.zdemo.redis; - -import com.zdemo.AbstractConsumer; -import com.zdemo.IConsumer; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.AutoLoad; - -import javax.annotation.Resource; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.logging.Level; -import java.util.logging.Logger; - -@AutoLoad(false) -public class RedisConsumer extends AbstractConsumer implements IConsumer, Service { - - public Logger logger = Logger.getLogger(this.getClass().getSimpleName()); - - @Resource(name = "property.redis.host") - private String host = "127.0.0.1"; - @Resource(name = "property.redis.password") - private String password = ""; - @Resource(name = "property.redis.port") - private int port = 6379; - - private Socket client; - private OutputStreamWriter writer; - private BufferedReader reader; - - @Override - public void init(AnyValue config) { - try { - client = new Socket(); - client.connect(new InetSocketAddress(host, port)); - client.setKeepAlive(true); - - writer = new OutputStreamWriter(client.getOutputStream()); - writer.write("AUTH " + password + "\r\n"); - writer.flush(); - - StringBuffer buf = new StringBuffer("SUBSCRIBE"); - for (String topic : getTopics()) { - buf.append(" ").append(topic); - } - buf.append("\r\n"); - writer.write(buf.toString()); - writer.flush(); - - reader = new BufferedReader(new InputStreamReader(client.getInputStream())); - } catch (IOException e) { - logger.log(Level.WARNING, "Redis Consumer 初始化失败!", e); - } - - new Thread(() -> { - try { - while (true) { - String readLine = reader.readLine(); - String type = ""; - if ("*3".equals(readLine)) { - readLine = reader.readLine(); // $7 len() - type = reader.readLine(); // message - if (!"message".equals(type)) { - continue; - } - reader.readLine(); //$n len(key) - String topic = reader.readLine(); // topic - - reader.readLine(); //$n len(value) - String value = reader.readLine(); // value - try { - accept(topic, value); - } catch (Exception e) { - logger.log(Level.WARNING, "topic[" + topic + "] event accept error :" + value, e); - } - } - } - } catch (IOException e) { - logger.log(Level.WARNING, "", e); - } - }).start(); - } - - @Override - protected String getGroupid() { - return null; - } - - @Override - public void unsubscribe(String topic) { - try { - writer.write("UNSUBSCRIBE " + topic + "\r\n"); - writer.flush(); - } catch (IOException e) { - logger.log(Level.WARNING, "", e); - } - super.removeEventType(topic); - } - - @Override - protected void subscribe(String topic) { - //新增订阅 - try { - writer.write("SUBSCRIBE " + topic + "\r\n"); - writer.flush(); - } catch (IOException e) { - logger.log(Level.WARNING, "", e); - } - } -} diff --git a/src/com/zdemo/redis/RedisProducer.java b/src/com/zdemo/redis/RedisProducer.java deleted file mode 100644 index 91bc7f2..0000000 --- a/src/com/zdemo/redis/RedisProducer.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.zdemo.redis; - -import com.zdemo.IProducer; -import org.redkale.convert.json.JsonConvert; -import org.redkale.service.Service; -import org.redkale.util.AnyValue; -import org.redkale.util.AutoLoad; - -import javax.annotation.Resource; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.util.logging.Level; - -@AutoLoad(false) -public class RedisProducer implements IProducer, Service { - - @Resource(name = "property.redis.host") - private String host = "127.0.0.1"; - @Resource(name = "property.redis.password") - private String password = ""; - @Resource(name = "property.redis.port") - private int port = 6379; - - private OutputStreamWriter osw; - - @Override - public void init(AnyValue config) { - try { - Socket client = new Socket(); - client.connect(new InetSocketAddress(host, port)); - client.setKeepAlive(true); - - osw = new OutputStreamWriter(client.getOutputStream()); - osw.write("AUTH " + password + "\r\n"); - osw.flush(); - } catch (IOException e) { - logger.log(Level.WARNING, "", e); - } - } - - @Override - public boolean publish(String topic, Object v) { - try { - osw.write("PUBLISH " + topic + " '" + toStr(v) + "' \r\n"); - osw.flush(); - return true; - } catch (IOException e) { - logger.log(Level.WARNING, "", e); - } - return false; - } - - private String toStr(Object v) { - if (v instanceof String) { - return (String) v; - } - return JsonConvert.root().convertTo(v); - } -} diff --git a/src/com/zdemo/zhub/ZHubClient.java b/src/com/zdemo/zhub/ZHubClient.java index a86b606..7236e16 100644 --- a/src/com/zdemo/zhub/ZHubClient.java +++ b/src/com/zdemo/zhub/ZHubClient.java @@ -2,8 +2,14 @@ package com.zdemo.zhub; import com.zdemo.*; import net.tccn.timer.Timers; +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.ResourceType; +import org.redkale.service.Local; import org.redkale.service.Service; -import org.redkale.util.*; +import org.redkale.util.AnyValue; +import org.redkale.util.Comment; +import org.redkale.util.TypeToken; +import org.redkale.util.Utility; import java.io.BufferedReader; import java.io.IOException; @@ -22,7 +28,9 @@ import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; -@AutoLoad(value = false) +@Local +@AutoLoad(false) +@ResourceType(ZHubClient.class) public class ZHubClient extends AbstractConsumer implements IConsumer, IProducer, Service { public Logger logger = Logger.getLogger(ZHubClient.class.getSimpleName()); @@ -47,16 +55,27 @@ public class ZHubClient extends AbstractConsumer implements IConsumer, IProducer } };*/ - /*private static boolean isFirst = true; - private boolean isMain = false;*/ private static Map mainHub = new HashMap<>(); // 127.0.0.1:1216 - ZHubClient @Override public void init(AnyValue config) { - if (!preInit()) { + /*if (!preInit()) { + return; + }*/ + + if (config == null) { + initClient(null); return; } + Map nodes = getNodes(config); + for (String rsName : nodes.keySet()) { + ZHubClient client = new ZHubClient().initClient(nodes.get(rsName)); + application.getResourceFactory().register(rsName, client); + } + } + + private ZHubClient initClient(AnyValue config) { // 自动注入 if (config != null) { addr = config.getValue("addr", addr); @@ -72,19 +91,16 @@ public class ZHubClient extends AbstractConsumer implements IConsumer, IProducer } // 设置第一个启动的 实例为主实例 - /*if (isFirst) { - isMain = true; - isFirst = false; - }*/ if (!mainHub.containsKey(addr)) { // 确保同步执行此 init 逻辑 mainHub.put(addr, this); } - if (!initSocket(0)) { - return; - } // 消息 事件接收 new Thread(() -> { + if (!initSocket(0)) { + return; + } + while (true) { try { String readLine = reader.readLine(); @@ -289,6 +305,32 @@ public class ZHubClient extends AbstractConsumer implements IConsumer, IProducer } }).start(); + return this; + } + + public boolean acceptsConf(AnyValue config) { + if (config == null) { + return false; + } + + if (!getNodes(config).isEmpty()) { + return true; + } + return false; + } + + private HashMap getNodes(AnyValue config) { + AnyValue[] zhubs = config.getAnyValues("zhub"); + HashMap confMap = new HashMap<>(); + + for (AnyValue zhub : zhubs) { + String[] names = zhub.getNames(); + for (String name : names) { + confMap.put(name, zhub.getAnyValue(name)); + } + } + + return confMap; } // --------------------- @@ -366,8 +408,6 @@ public class ZHubClient extends AbstractConsumer implements IConsumer, IProducer send("groupid " + groupid); StringBuffer buf = new StringBuffer("subscribe lock"); - /*if (isMain) { - }*/ if (mainHub.containsValue(this)) { buf.append(" " + APP_NAME); } diff --git a/src/org/redkalex/cache/redis/AbstractRedisSource.java b/src/org/redkalex/cache/redis/AbstractRedisSource.java new file mode 100644 index 0000000..53b9398 --- /dev/null +++ b/src/org/redkalex/cache/redis/AbstractRedisSource.java @@ -0,0 +1,131 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package org.redkalex.cache.redis; + +import org.redkale.annotation.Resource; +import org.redkale.convert.Convert; +import org.redkale.convert.json.JsonConvert; +import org.redkale.source.AbstractCacheSource; +import org.redkale.util.AnyValue; +import org.redkale.util.RedkaleClassLoader; +import org.redkale.util.RedkaleException; +import org.redkale.util.ResourceFactory; + +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; + +/** + * @author zhangjx + * @since 2.8.0 + */ +public abstract class AbstractRedisSource extends AbstractCacheSource { + + public static final String CACHE_SOURCE_CRYPTOR = "cryptor"; + + protected String name; + + @Resource(required = false) + protected ResourceFactory resourceFactory; + + @Resource(required = false) + protected JsonConvert defaultConvert; + + @Resource(name = "$_convert", required = false) + protected JsonConvert convert; + + protected int db; + + protected RedisCryptor cryptor; + + protected AnyValue config; + + @Override + public void init(AnyValue conf) { + this.config = conf; + super.init(conf); + this.name = conf.getValue("name", ""); + if (this.convert == null) this.convert = this.defaultConvert; + if (conf != null) { + String cryptStr = conf.getValue(CACHE_SOURCE_CRYPTOR, "").trim(); + if (!cryptStr.isEmpty()) { + try { + Class cryptClass = (Class) getClass().getClassLoader().loadClass(cryptStr); + RedkaleClassLoader.putReflectionPublicConstructors(cryptClass, cryptClass.getName()); + this.cryptor = cryptClass.getConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new RedkaleException(e); + } + } + } + if (cryptor != null) { + if (resourceFactory != null) { + resourceFactory.inject(cryptor); + } + cryptor.init(conf); + } + } + + @Override + public void destroy(AnyValue conf) { + super.destroy(conf); + if (cryptor != null) { + cryptor.destroy(conf); + } + } + + @Override + public void close() throws Exception { //在 Application 关闭时调用 + destroy(null); + } + + @Override + public String resourceName() { + return name; + } + + protected String decryptValue(String key, RedisCryptor cryptor, String value) { + return cryptor != null ? cryptor.decrypt(key, value) : value; + } + + protected T decryptValue(String key, RedisCryptor cryptor, Type type, byte[] bs) { + return decryptValue(key, cryptor, convert, type, bs); + } + + protected T decryptValue(String key, RedisCryptor cryptor, Convert c, Type type, byte[] bs) { + if (bs == null) return null; + if (type == byte[].class) return (T) bs; + if (cryptor == null || (type instanceof Class && (((Class) type).isPrimitive() || Number.class.isAssignableFrom((Class) type)))) { + return (T) (c == null ? this.convert : c).convertFrom(type, bs); + } + String deval = cryptor.decrypt(key, new String(bs, StandardCharsets.UTF_8)); + return deval == null ? null : (T) (c == null ? this.convert : c).convertFrom(type, deval.getBytes(StandardCharsets.UTF_8)); + } + + protected String encryptValue(String key, RedisCryptor cryptor, String value) { + return cryptor != null ? cryptor.encrypt(key, value) : value; + } + + protected byte[] encryptValue(String key, RedisCryptor cryptor, Convert c, T value) { + return encryptValue(key, cryptor, null, c, value); + } + + protected byte[] encryptValue(String key, RedisCryptor cryptor, Type type, Convert c, T value) { + if (value == null) return null; + Type t = type == null ? value.getClass() : type; + if (cryptor == null && type == String.class) { + return value.toString().getBytes(StandardCharsets.UTF_8); + } + return encryptValue(key, cryptor, t, (c == null ? this.convert : c).convertToBytes(t, value)); + } + + protected byte[] encryptValue(String key, RedisCryptor cryptor, Type type, byte[] bs) { + if (bs == null) return null; + if (cryptor == null || (type instanceof Class && (((Class) type).isPrimitive() || Number.class.isAssignableFrom((Class) type)))) { + return bs; + } + String enval = cryptor.encrypt(key, new String(bs, StandardCharsets.UTF_8)); + return enval == null ? null : enval.getBytes(StandardCharsets.UTF_8); + } +} diff --git a/src/org/redkalex/cache/redis/MyRedisCacheSource.java b/src/org/redkalex/cache/redis/MyRedisCacheSource.java new file mode 100644 index 0000000..f0a5925 --- /dev/null +++ b/src/org/redkalex/cache/redis/MyRedisCacheSource.java @@ -0,0 +1,137 @@ +package org.redkalex.cache.redis; + +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.ResourceType; +import org.redkale.service.Local; +import org.redkale.source.CacheSource; +import org.redkale.util.AnyValue; + +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; + +@Local +@AutoLoad(false) +@ResourceType(CacheSource.class) +public class MyRedisCacheSource extends RedisCacheSource { + + @Override + public void init(AnyValue conf) { + super.init(conf); + } + + //--------------------- bit ------------------------------ + public boolean getBit(String key, int offset) { + return sendAsync("GETBIT", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(offset).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getIntValue(0) > 0).join(); + } + + public void setBit(String key, int offset, boolean bool) { + sendAsync("SETBIT", key, offset, bool ? 1 : 0).join(); + } + //--------------------- bit ------------------------------ + + //--------------------- lock ------------------------------ + // 尝试加锁,成功返回0,否则返回上一锁剩余毫秒值 + public long tryLock(String key, int millis) { + Serializable[] obj = {"" + + "if (redis.call('EXISTS',KEYS[1]) == 0) then " + + "redis.call('PSETEX',KEYS[1],ARGV[1],1); " + + "return 0; " + + "else " + + "return redis.call('PTTL',KEYS[1]); " + + "end;", 1, key, millis + }; + + return sendAsync("EVAL", null, obj).thenApply(v -> v.getIntValue(1)).join(); + } + + // 加锁 + public void lock(String key, int millis) { + long i; + do { + i = tryLock(key, millis); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } while (i > 0); + } + + // 解锁 + public void unlock(String key) { + remove(key); + } + + //--------------------- key ------------------------------ + + public String get(String key) { + return get(key, String.class); + } + + //--------------------- set ------------------------------ + /*public void sadd(String key, Collection args) { + saddAsync(key, args.toArray(Serializable[]::new)).join(); + }*/ + + public void sadd(String key, Serializable... args) { + saddAsync(key, Arrays.stream(args).toArray(Serializable[]::new)).join(); + } + + public void srem(String key, Serializable... args) { + sremAsync(key, args).join(); + } + + public CompletableFuture saddAsync(String key, Serializable... args) { + return sendAsync("SADD", key, args); + } + + public CompletableFuture sremAsync(String key, Serializable... args) { + return sendAsync("SREM", key, args); + } + + //--------------------- hm ------------------------------ + public void setHms(String key, Map kv) { + setHmsAsync(key, kv).join(); + } + + public CompletableFuture setHmsAsync(String key, Map kv) { + List args = new ArrayList(); + kv.forEach((k, v) -> { + args.add(k); + args.add(v); + }); + + return sendAsync("HMSET", key, args.toArray(Serializable[]::new)); + } + + public String getHm(String key, String field) { + return getHm(key, String.class, field); + } + + public T getHm(String key, Class type, String field) { + List list = super.hmget(key, type, field); + if (list == null && list.isEmpty()) { + return null; + } + return (T) list.get(0); + } + + public Map getHms(String key, String... field) { + return getHms(key, String.class, field); + } + + public Map getHms(String key, Class type, String... field) { + List list = super.hmget(key, type, field); + if (list == null && list.isEmpty()) { + return null; + } + Map map = new HashMap<>(field.length); + + for (int i = 0; i < field.length; i++) { + map.put(field[i], (T) list.get(i)); + } + return map; + } +} diff --git a/src/org/redkalex/cache/redis/RedisCRC16.java b/src/org/redkalex/cache/redis/RedisCRC16.java new file mode 100644 index 0000000..2c0d38f --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCRC16.java @@ -0,0 +1,78 @@ +/* + * + */ +package org.redkalex.cache.redis; + +import org.redkale.util.Utility; + +import java.util.Arrays; + +/** + * @author zhangjx + */ +public class RedisCRC16 { + + private static final int[] LOOKUP_TABLE = {0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, + 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, + 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, + 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, + 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, + 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, + 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, + 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, + 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, + 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, + 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, + 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, + 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, + 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, + 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, + 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, + 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, + 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, + 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, + 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, + 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, + 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0}; + + private RedisCRC16() { + } + + public static int crc16(byte[] bytes) { + int crc = 0x0000; + for (byte b : bytes) { + crc = (crc << 8) ^ LOOKUP_TABLE[((crc >>> 8) ^ (b & 0xFF)) & 0xFF]; + } + return crc & 0xFFFF; + } + + public static int calcSlot(int maxSlot, byte[] key) { + if (key == null) { + return 0; + } + int start = Utility.indexOf(key, (byte) '{'); + if (start != -1) { + int end = Utility.indexOf(key, start + 1, (byte) '}'); + if (end != -1) { + key = Arrays.copyOfRange(key, start + 1, end); + } + } + int result = crc16(key) % maxSlot; + return result; + } + + public static int calcSlot(int maxSlot, String key) { + if (key == null) { + return 0; + } + int start = key.indexOf('{'); + if (start != -1) { + int end = key.indexOf('}'); + if (end != -1 && start + 1 < end) { + key = key.substring(start + 1, end); + } + } + int result = crc16(key.getBytes()) % maxSlot; + return result; + } +} diff --git a/src/org/redkalex/cache/redis/RedisCacheClient.java b/src/org/redkalex/cache/redis/RedisCacheClient.java new file mode 100644 index 0000000..3bdca16 --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheClient.java @@ -0,0 +1,36 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.net.AsyncConnection; +import org.redkale.net.AsyncGroup; +import org.redkale.net.client.Client; +import org.redkale.net.client.ClientAddress; + +/** + * @author zhangjx + */ +public class RedisCacheClient extends Client { + + public RedisCacheClient(String name, AsyncGroup group, String key, ClientAddress address, int maxConns, int maxPipelines, RedisCacheReqAuth authReq, RedisCacheReqDB dbReq) { + super(name, group, true, address, maxConns, maxPipelines, () -> new RedisCacheReqPing(), () -> new RedisCacheReqClose(), null); //maxConns + if (authReq != null || dbReq != null) { + if (authReq != null && dbReq != null) { + this.authenticate = conn -> writeChannel(conn, authReq).thenCompose(v -> writeChannel(conn, dbReq)).thenApply(v -> conn); + } else if (authReq != null) { + this.authenticate = conn -> writeChannel(conn, authReq).thenApply(v -> conn); + } else { + this.authenticate = conn -> writeChannel(conn, dbReq).thenApply(v -> conn); + } + } + } + + @Override + protected RedisCacheConnection createClientConnection(final int index, AsyncConnection channel) { + return new RedisCacheConnection(this, index, channel); + } + +} diff --git a/src/org/redkalex/cache/redis/RedisCacheCodec.java b/src/org/redkalex/cache/redis/RedisCacheCodec.java new file mode 100644 index 0000000..41902c7 --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheCodec.java @@ -0,0 +1,249 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.net.client.ClientCodec; +import org.redkale.net.client.ClientConnection; +import org.redkale.util.ByteArray; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +/** + * @author zhangjx + */ +public class RedisCacheCodec extends ClientCodec { + + protected static final byte TYPE_STRING = '+'; //简单字符串(不包含CRLF)类型 + + protected static final byte TYPE_ERROR = '-'; //错误(不包含CRLF)类型 + + protected static final byte TYPE_NUMBER = ':'; //整型 + + protected static final byte TYPE_BULK = '$'; //块字符串 + + protected static final byte TYPE_ARRAY = '*'; //数组 + + protected static final Logger logger = Logger.getLogger(RedisCacheCodec.class.getSimpleName()); + + protected byte halfFrameCmd; + + protected int halfFrameBulkLength = -10; + + protected int halfFrameArraySize = -10; + + protected int halfFrameArrayIndex; //从0开始 + + protected int halfFrameArrayItemLength = -10; + + protected ByteArray halfFrameBytes; + + protected byte frameType; + + protected byte[] frameValue; //(不包含CRLF) + + protected List frameList; //(不包含CRLF) + + private ByteArray recyclableArray; + + public RedisCacheCodec(ClientConnection connection) { + super(connection); + } + + protected ByteArray pollArray(ByteArray array) { + if (recyclableArray == null) { + recyclableArray = new ByteArray(); + } else { + recyclableArray.clear(); + } + recyclableArray.clear(); + if (array != null) { + recyclableArray.put(array, 0, array.length()); + } + return recyclableArray; + } + + private boolean checkBytesFrame(RedisCacheConnection conn, ByteBuffer buffer, ByteArray array) { +// byte[] dbs = new byte[buffer.remaining()]; +// for (int i = 0; i < dbs.length; i++) { +// dbs[i] = buffer.get(buffer.position() + i); +// } +// ArrayDeque deque = (ArrayDeque) responseQueue(conn); +// logger.log(Level.FINEST, "[" + Utility.nowMillis() + "] [" + Thread.currentThread().getName() + "]: " + conn + ", 原始数据: " + new String(dbs).replace("\r\n", " ") + ", req=" + deque.getFirst().getRequest()); + + array.clear(); + byte type = halfFrameCmd == 0 ? buffer.get() : halfFrameCmd; + if (halfFrameBytes != null) { + array.put(halfFrameBytes, 0, halfFrameBytes.length()); + } + frameType = type; + if (type == TYPE_STRING || type == TYPE_ERROR || type == TYPE_NUMBER) { + if (readComplete(buffer, array)) { + frameValue = array.getBytes(); + } else { + halfFrameCmd = type; + halfFrameBytes = pollArray(array); + return false; + } + } else if (type == TYPE_BULK) { + int bulkLength = halfFrameBulkLength; + if (bulkLength < -2) { + if (!readComplete(buffer, array)) { //没有读到bulkLength + halfFrameCmd = type; + halfFrameBulkLength = -10; + halfFrameBytes = pollArray(array); + return false; + } + bulkLength = Integer.parseInt(array.toString(StandardCharsets.UTF_8)); + array.clear(); + } + if (bulkLength == -1) { + frameValue = null; + } else if (readComplete(buffer, array)) { + frameValue = array.getBytes(); + } else { + halfFrameCmd = type; + halfFrameBulkLength = bulkLength; + halfFrameBytes = pollArray(array); + return false; + } + } else if (type == TYPE_ARRAY) { + int arraySize = halfFrameArraySize; + if (arraySize < -2) { + if (!readComplete(buffer, array)) { //没有读到arraySize + halfFrameCmd = type; + halfFrameArraySize = -10; + halfFrameArrayIndex = 0; + halfFrameArrayItemLength = -10; + halfFrameBytes = pollArray(array); + return false; + } + arraySize = Integer.parseInt(array.toString(StandardCharsets.UTF_8)); + array.clear(); + } + int arrayIndex = halfFrameArrayIndex; + for (int i = arrayIndex; i < arraySize; i++) { + int itemLength = halfFrameArrayItemLength; + halfFrameArrayItemLength = -10; + if (itemLength < -2) { + if (!readComplete(buffer, array)) { //没有读到bulkLength + halfFrameCmd = type; + halfFrameArraySize = arraySize; + halfFrameArrayIndex = i; + halfFrameArrayItemLength = -10; + halfFrameBytes = pollArray(array); + return false; + } + byte sign = array.get(0); + itemLength = Integer.parseInt(array.toString(1, StandardCharsets.UTF_8)); + array.clear(); + if (sign == TYPE_ARRAY) { //数组中嵌套数组,目前有 HSCAN + frameValue = null; + if (frameList != null) { + frameList.clear(); + } + clearHalfFrame(); + if (itemLength == 0) { + return true; + } + halfFrameCmd = sign; + halfFrameArraySize = itemLength; + if (!buffer.hasRemaining()) { + return false; + } + return checkBytesFrame(conn, buffer, array); + } + } + int cha = itemLength - array.length(); + if (itemLength == -1) { + if (frameList == null) { + frameList = new ArrayList<>(); + } + frameList.add(null); + array.clear(); + } else if (buffer.remaining() >= cha + 2) { + for (int j = 0; j < cha; j++) array.put(buffer.get()); + buffer.get(); //\r + buffer.get(); //\n + if (frameList == null) { + frameList = new ArrayList<>(); + } + frameList.add(array.getBytes()); + array.clear(); + } else { + while (buffer.hasRemaining()) array.put(buffer.get()); + halfFrameCmd = type; + halfFrameArraySize = arraySize; + halfFrameArrayIndex = i; + halfFrameArrayItemLength = itemLength; + halfFrameBytes = pollArray(array); + return false; + } + } + } + clearHalfFrame(); + return true; + } + + protected void clearHalfFrame() { + halfFrameCmd = 0; + halfFrameBulkLength = -10; + halfFrameArraySize = -10; + halfFrameArrayIndex = 0; + halfFrameArrayItemLength = -10; + halfFrameBytes = null; + } + + @Override + public void decodeMessages(ByteBuffer realbuf, ByteArray array) { + RedisCacheConnection conn = (RedisCacheConnection) connection; + if (!realbuf.hasRemaining()) { + return; + } + ByteBuffer buffer = realbuf; + if (!checkBytesFrame(conn, buffer, array)) { + return; + } + //buffer必然包含一个完整的frame数据 + boolean first = true; + RedisCacheRequest request = null; + while (first || buffer.hasRemaining()) { + if (request == null) { + request = nextRequest(); + } + if (!first && !checkBytesFrame(conn, buffer, array)) { + break; + } + if (frameType == TYPE_ERROR) { + addMessage(request, new RuntimeException(new String(frameValue, StandardCharsets.UTF_8))); + } else { + addMessage(request, conn.pollResultSet(request).prepare(frameType, frameValue, frameList)); + } + frameType = 0; + frameValue = null; + frameList = null; + halfFrameCmd = 0; + halfFrameBytes = null; + first = false; + buffer = realbuf; + } + } + + protected boolean readComplete(ByteBuffer buffer, ByteArray array) { + while (buffer.hasRemaining()) { + byte b = buffer.get(); + if (b == '\n') { + array.removeLastByte(); //移除 \r + return true; + } + array.put(b); + } + return false; + } +} diff --git a/src/org/redkalex/cache/redis/RedisCacheConnection.java b/src/org/redkalex/cache/redis/RedisCacheConnection.java new file mode 100644 index 0000000..8741e1b --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheConnection.java @@ -0,0 +1,49 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.net.AsyncConnection; +import org.redkale.net.WorkThread; +import org.redkale.net.client.Client; +import org.redkale.net.client.ClientCodec; +import org.redkale.net.client.ClientConnection; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +/** + * @author zhangjx + */ +public class RedisCacheConnection extends ClientConnection { + + public RedisCacheConnection(Client client, int index, AsyncConnection channel) { + super(client, index, channel); + } + + @Override + protected ClientCodec createCodec() { + return new RedisCacheCodec(this); + } + + protected CompletableFuture writeRequest(RedisCacheRequest request) { + return super.writeChannel(request); + } + + protected CompletableFuture writeRequest(RedisCacheRequest request, Function respTransfer) { + return super.writeChannel(request, respTransfer); + } + + public RedisCacheResult pollResultSet(RedisCacheRequest request) { + RedisCacheResult rs = new RedisCacheResult(); + return rs; + } + + public RedisCacheRequest pollRequest(WorkThread workThread) { + RedisCacheRequest rs = new RedisCacheRequest().currThread(workThread); + return rs; + } + +} diff --git a/src/org/redkalex/cache/redis/RedisCacheReqAuth.java b/src/org/redkalex/cache/redis/RedisCacheReqAuth.java new file mode 100644 index 0000000..41dbd2f --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheReqAuth.java @@ -0,0 +1,45 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.net.client.ClientConnection; +import org.redkale.util.ByteArray; + +import java.nio.charset.StandardCharsets; + +/** + * @author zhangjx + */ +public class RedisCacheReqAuth extends RedisCacheRequest { + + private static final byte[] PS = "AUTH".getBytes(StandardCharsets.UTF_8); + + protected String password; + + public RedisCacheReqAuth(String password) { + this.password = password; + } + + @Override + public void writeTo(ClientConnection conn, ByteArray writer) { + byte[] pwd = password.getBytes(); + writer.put((byte) '*'); + writer.put((byte) '2'); + writer.put((byte) '\r', (byte) '\n'); + writer.put((byte) '$'); + writer.put((byte) '4'); + writer.put((byte) '\r', (byte) '\n'); + writer.put(PS); + writer.put((byte) '\r', (byte) '\n'); + + writer.put((byte) '$'); + writer.put(String.valueOf(pwd.length).getBytes(StandardCharsets.UTF_8)); + writer.put((byte) '\r', (byte) '\n'); + writer.put(pwd); + writer.put((byte) '\r', (byte) '\n'); + + } +} diff --git a/src/org/redkalex/cache/redis/RedisCacheReqClose.java b/src/org/redkalex/cache/redis/RedisCacheReqClose.java new file mode 100644 index 0000000..67432f8 --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheReqClose.java @@ -0,0 +1,36 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.net.client.ClientConnection; +import org.redkale.util.ByteArray; + +import java.nio.charset.StandardCharsets; + +/** + * @author zhangjx + */ +public class RedisCacheReqClose extends RedisCacheRequest { + + private static final byte[] PS = "QUIT".getBytes(StandardCharsets.UTF_8); + + @Override + public final boolean isCloseType() { + return true; + } + + @Override + public void writeTo(ClientConnection conn, ByteArray writer) { + writer.put((byte) '*'); + writer.put((byte) '1'); + writer.put((byte) '\r', (byte) '\n'); + writer.put((byte) '$'); + writer.put((byte) '4'); + writer.put((byte) '\r', (byte) '\n'); + writer.put(PS); + writer.put((byte) '\r', (byte) '\n'); + } +} diff --git a/src/org/redkalex/cache/redis/RedisCacheReqDB.java b/src/org/redkalex/cache/redis/RedisCacheReqDB.java new file mode 100644 index 0000000..37ef12a --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheReqDB.java @@ -0,0 +1,43 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.net.client.ClientConnection; +import org.redkale.util.ByteArray; + +import java.nio.charset.StandardCharsets; + +/** + * @author zhangjx + */ +public class RedisCacheReqDB extends RedisCacheRequest { + + protected int db; + + public RedisCacheReqDB(int db) { + this.db = db; + } + + @Override + public void writeTo(ClientConnection conn, ByteArray writer) { + writer.put((byte) '*'); + writer.put((byte) '2'); + writer.put((byte) '\r', (byte) '\n'); + writer.put((byte) '$'); + writer.put((byte) '6'); + writer.put((byte) '\r', (byte) '\n'); + writer.put("SELECT".getBytes(StandardCharsets.UTF_8)); + writer.put((byte) '\r', (byte) '\n'); + + byte[] dbs = String.valueOf(db).getBytes(StandardCharsets.UTF_8); + writer.put((byte) '$'); + writer.put(String.valueOf(dbs.length).getBytes(StandardCharsets.UTF_8)); + writer.put((byte) '\r', (byte) '\n'); + writer.put(dbs); + writer.put((byte) '\r', (byte) '\n'); + + } +} diff --git a/src/org/redkalex/cache/redis/RedisCacheReqPing.java b/src/org/redkalex/cache/redis/RedisCacheReqPing.java new file mode 100644 index 0000000..114bb10 --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheReqPing.java @@ -0,0 +1,31 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.net.client.ClientConnection; +import org.redkale.util.ByteArray; + +import java.nio.charset.StandardCharsets; + +/** + * @author zhangjx + */ +public class RedisCacheReqPing extends RedisCacheRequest { + + private static final byte[] PS = "PING".getBytes(StandardCharsets.UTF_8); + + @Override + public void writeTo(ClientConnection conn, ByteArray writer) { + writer.put((byte) '*'); + writer.put((byte) '1'); + writer.put((byte) '\r', (byte) '\n'); + writer.put((byte) '$'); + writer.put((byte) '4'); + writer.put((byte) '\r', (byte) '\n'); + writer.put(PS); + writer.put((byte) '\r', (byte) '\n'); + } +} diff --git a/src/org/redkalex/cache/redis/RedisCacheRequest.java b/src/org/redkalex/cache/redis/RedisCacheRequest.java new file mode 100644 index 0000000..403b7a8 --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheRequest.java @@ -0,0 +1,61 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.net.client.ClientConnection; +import org.redkale.net.client.ClientRequest; +import org.redkale.util.ByteArray; + +import java.nio.charset.StandardCharsets; + +/** + * @author zhangjx + */ +public class RedisCacheRequest extends ClientRequest { + + static final byte[] TRUE = new byte[]{'t'}; + + static final byte[] FALSE = new byte[]{'f'}; + + protected String key; + + protected String command; + + protected byte[][] args; + + public RedisCacheRequest prepare(String command, String key, byte[]... args) { + super.prepare(); + this.command = command; + this.key = key; + this.args = args; + return this; + } + + @Override + public void writeTo(ClientConnection conn, ByteArray writer) { + writer.put((byte) '*'); + writer.put(String.valueOf(args.length + 1).getBytes(StandardCharsets.UTF_8)); + writer.put((byte) '\r', (byte) '\n'); + writer.put((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((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'); + } + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{command=" + command + ", key=" + key + "}"; + } +} diff --git a/src/org/redkalex/cache/redis/RedisCacheResult.java b/src/org/redkalex/cache/redis/RedisCacheResult.java new file mode 100644 index 0000000..96e8445 --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheResult.java @@ -0,0 +1,151 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.convert.json.JsonConvert; + +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * @author zhangjx + */ +public class RedisCacheResult { + + //+ 简单字符串类型 (不包含CRLF) + //- 错误类型 (不包含CRLF) + //': 整型 + //$ 块字符串 + //* 数组 + protected byte frameType; + + protected byte[] frameValue; //(不包含CRLF) + + protected List frameList; //(不包含CRLF) + + public RedisCacheResult prepare(byte byteType, byte[] val, List bytesList) { + this.frameType = byteType; + this.frameValue = val; + this.frameList = bytesList; + return this; + } + + public Void getVoidValue() { + return null; + } + + public byte[] getFrameValue() { + return frameValue; + } + + public Boolean getBoolValue() { + if (frameValue == null) { + return false; + } + String val = new String(frameValue, StandardCharsets.UTF_8); + if ("OK".equals(val)) { + return true; + } + return Integer.parseInt(val) > 0; + } + + public String getStringValue(String key, RedisCryptor cryptor) { + if (frameValue == null) { + return null; + } + String val = new String(frameValue, StandardCharsets.UTF_8); + if (cryptor != null) { + val = cryptor.decrypt(key, val); + } + return val; + } + + public Double getDoubleValue(Double defvalue) { + return frameValue == null ? defvalue : Double.parseDouble(new String(frameValue, StandardCharsets.UTF_8)); + } + + public Long getLongValue(Long defvalue) { + return frameValue == null ? defvalue : Long.parseLong(new String(frameValue, StandardCharsets.UTF_8)); + } + + public Integer getIntValue(Integer defvalue) { + return frameValue == null ? defvalue : Integer.parseInt(new String(frameValue, StandardCharsets.UTF_8)); + } + + public T getObjectValue(String key, RedisCryptor cryptor, Type type) { + return formatValue(key, cryptor, frameValue, type); + } + + protected Set getSetValue(String key, RedisCryptor cryptor, Type type) { + if (frameList == null || frameList.isEmpty()) { + return new LinkedHashSet<>(); + } + Set set = new LinkedHashSet<>(); + for (byte[] bs : frameList) { + set.add(formatValue(key, cryptor, bs, type)); + } + return set; + } + + protected List getListValue(String key, RedisCryptor cryptor, Type type) { + if (frameList == null || frameList.isEmpty()) { + return new ArrayList<>(); + } + List list = new ArrayList<>(); + for (byte[] bs : frameList) { + list.add(formatValue(key, cryptor, bs, type)); + } + return list; + } + + protected Map getMapValue(String key, RedisCryptor cryptor, Type type) { + if (frameList == null || frameList.isEmpty()) { + return new LinkedHashMap<>(); + } + Map map = new LinkedHashMap<>(); + for (int i = 0; i < frameList.size(); i += 2) { + byte[] bs1 = frameList.get(i); + byte[] bs2 = frameList.get(i + 1); + T val = formatValue(key, cryptor, bs2, type); + if (val != null) { + map.put(formatValue(key, cryptor, bs1, String.class).toString(), val); + } + } + return map; + } + + protected static T formatValue(String key, RedisCryptor cryptor, byte[] frames, Type type) { + if (frames == null) { + return null; + } + if (type == byte[].class) { + return (T) frames; + } + if (type == String.class) { + String val = new String(frames, StandardCharsets.UTF_8); + if (cryptor != null) { + val = cryptor.decrypt(key, val); + } + return (T) val; + } + if (type == boolean.class || type == Boolean.class) { + return (T) (Boolean) "t".equalsIgnoreCase(new String(frames, StandardCharsets.UTF_8)); + } + if (type == long.class || type == Long.class) { + return (T) (Long) Long.parseLong(new String(frames, StandardCharsets.UTF_8)); + } + if (type == double.class || type == Double.class) { + return (T) (Double) Double.parseDouble(new String(frames, StandardCharsets.UTF_8)); + } + if (cryptor != null) { + String val = cryptor.decrypt(key, new String(frames, StandardCharsets.UTF_8)); + return (T) JsonConvert.root().convertFrom(type, val); + } + return (T) JsonConvert.root().convertFrom(type, frames); + } + +} diff --git a/src/org/redkalex/cache/redis/RedisCacheSource.java b/src/org/redkalex/cache/redis/RedisCacheSource.java new file mode 100644 index 0000000..eef81e0 --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheSource.java @@ -0,0 +1,1790 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.Resource; +import org.redkale.annotation.ResourceListener; +import org.redkale.annotation.ResourceType; +import org.redkale.convert.Convert; +import org.redkale.convert.json.JsonConvert; +import org.redkale.net.AsyncGroup; +import org.redkale.net.WorkThread; +import org.redkale.net.client.ClientAddress; +import org.redkale.service.Local; +import org.redkale.source.CacheSource; +import org.redkale.util.*; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.redkale.boot.Application.RESNAME_APP_CLIENT_ASYNCGROUP; +import static org.redkale.boot.Application.RESNAME_APP_EXECUTOR; + +/** + * 详情见: https://redkale.org + * + * @author zhangjx + */ +@Local +@AutoLoad(false) +@ResourceType(CacheSource.class) +public class RedisCacheSource extends AbstractRedisSource { + + static final boolean debug = false; //System.getProperty("os.name").contains("Window") || System.getProperty("os.name").contains("Mac"); + + protected static final byte FRAME_TYPE_BULK = '$'; //块字符串 + + protected static final byte FRAME_TYPE_ARRAY = '*'; //数组 + + protected static final byte FRAME_TYPE_STRING = '+'; //简单字符串(不包含CRLF)类型 + + protected static final byte FRAME_TYPE_ERROR = '-'; //错误(不包含CRLF)类型 + + protected static final byte FRAME_TYPE_NUMBER = ':'; //整型 + + protected static final byte[] NX = "NX".getBytes(); + + protected static final byte[] EX = "EX".getBytes(); + + private final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + @Resource(name = RESNAME_APP_CLIENT_ASYNCGROUP, required = false) + protected AsyncGroup clientAsyncGroup; + + //配置 APP_EXECUTOR资源为null + @Resource(name = RESNAME_APP_EXECUTOR, required = false) + protected ExecutorService workExecutor; + + protected RedisCacheClient client; + + protected InetSocketAddress address; + + @Override + public void init(AnyValue conf) { + super.init(conf); + if (conf == null) { + conf = AnyValue.create(); + } + initClient(conf); + } + + private void initClient(AnyValue conf) { + String password = null; + int urlmaxconns = Utility.cpus(); + int urlpipelines = org.redkale.net.client.Client.DEFAULT_MAX_PIPELINES; + for (AnyValue node : getNodes(conf)) { + String urluser = ""; + String urlpwd = ""; + String urldb = ""; + String addrstr = node.getValue(CACHE_SOURCE_URL, node.getValue("addr")); //兼容addr + if (addrstr.startsWith("redis://")) { //兼容 redis://:1234@127.0.0.1:6379?db=2 + URI uri = URI.create(addrstr); + address = new InetSocketAddress(uri.getHost(), uri.getPort() > 0 ? uri.getPort() : 6379); + String userInfo = uri.getUserInfo(); + if (userInfo == null || userInfo.isEmpty()) { + String authority = uri.getAuthority(); + if (authority != null && authority.indexOf('@') > 0) { + userInfo = authority.substring(0, authority.indexOf('@')); + } + } + if (userInfo != null && !userInfo.isEmpty()) { + urlpwd = userInfo; + if (urlpwd.startsWith(":")) { + urlpwd = urlpwd.substring(1); + } else { + int index = urlpwd.indexOf(':'); + if (index > 0) { + urluser = urlpwd.substring(0, index); + urlpwd = urlpwd.substring(index + 1); + } + } + } + if (uri.getQuery() != null && !uri.getQuery().isEmpty()) { + String[] qrys = uri.getQuery().split("&|="); + for (int i = 0; i < qrys.length; i += 2) { + if (CACHE_SOURCE_USER.equals(qrys[i])) { + urluser = i == qrys.length - 1 ? "" : qrys[i + 1]; + } else if (CACHE_SOURCE_PASSWORD.equals(qrys[i])) { + urlpwd = i == qrys.length - 1 ? "" : qrys[i + 1]; + } else if (CACHE_SOURCE_DB.equals(qrys[i])) { + urldb = i == qrys.length - 1 ? "" : qrys[i + 1]; + } else if (CACHE_SOURCE_MAXCONNS.equals(qrys[i])) { + urlmaxconns = i == qrys.length - 1 ? Utility.cpus() : Integer.parseInt(qrys[i + 1]); + } else if (CACHE_SOURCE_PIPELINES.equals(qrys[i])) { + urlpipelines = i == qrys.length - 1 ? org.redkale.net.client.Client.DEFAULT_MAX_PIPELINES : Integer.parseInt(qrys[i + 1]); + } + } + } + } else { //兼容addr和port分开 + address = new InetSocketAddress(addrstr, node.getIntValue("port")); + } + password = node.getValue(CACHE_SOURCE_PASSWORD, urlpwd).trim(); + String db0 = node.getValue(CACHE_SOURCE_DB, urldb).trim(); + if (!db0.isEmpty()) { + db = Integer.valueOf(db0); + } + break; + } + AsyncGroup ioGroup = clientAsyncGroup; + if (clientAsyncGroup == null) { + String f = "Redkalex-Redis-IOThread-" + resourceName() + "-%s"; + ioGroup = AsyncGroup.create(f, workExecutor, 16 * 1024, Utility.cpus() * 4).start(); + } + int maxconns = conf.getIntValue(CACHE_SOURCE_MAXCONNS, urlmaxconns); + int pipelines = conf.getIntValue(CACHE_SOURCE_PIPELINES, urlpipelines); + RedisCacheClient old = this.client; + this.client = new RedisCacheClient(resourceName(), ioGroup, resourceName() + "." + db, new ClientAddress(address), maxconns, pipelines, + password == null || password.isEmpty() ? null : new RedisCacheReqAuth(password), db > 0 ? new RedisCacheReqDB(db) : null); + if (old != null) { + old.close(); + } + //if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, RedisCacheSource.class.getSimpleName() + ": addr=" + address + ", db=" + db); + } + + @Override + @ResourceListener + public void onResourceChange(ResourceEvent[] events) { + if (events == null || events.length < 1) { + return; + } + StringBuilder sb = new StringBuilder(); + for (ResourceEvent event : events) { + sb.append("CacheSource(name=").append(resourceName()).append(") change '").append(event.name()).append("' to '").append(event.coverNewValue()).append("'\r\n"); + } + initClient(this.config); + if (sb.length() > 0) { + logger.log(Level.INFO, sb.toString()); + } + } + + public boolean acceptsConf(AnyValue config) { + if (config == null) { + return false; + } + AnyValue[] nodes = getNodes(config); + if (nodes == null || nodes.length == 0) { + return false; + } + for (AnyValue node : nodes) { + String val = node.getValue(CACHE_SOURCE_URL, node.getValue("addr")); //兼容addr + if (val != null && val.startsWith("redis://")) { + return true; + } + } + return false; + } + + protected AnyValue[] getNodes(AnyValue config) { + AnyValue[] nodes = config.getAnyValues(CACHE_SOURCE_NODE); + if (nodes == null || nodes.length == 0) { + AnyValue one = config.getAnyValue(CACHE_SOURCE_NODE); + if (one == null) { + String val = config.getValue(CACHE_SOURCE_URL); + if (val == null) { + return nodes; + } + nodes = new AnyValue[]{config}; + } else { + nodes = new AnyValue[]{one}; + } + } + return nodes; + } + + @Override + public final String getType() { + return "redis"; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{name=" + resourceName() + ", addrs=" + this.address + ", db=" + this.db + "}"; + } + + @Override + public void destroy(AnyValue conf) { + super.destroy(conf); + if (client != null) { + client.close(); + } + } + + //--------------------- exists ------------------------------ + @Override + public CompletableFuture existsAsync(String key) { + return sendAsync("EXISTS", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getIntValue(0) > 0); + } + + @Override + public boolean exists(String key) { + return existsAsync(key).join(); + } + + //--------------------- get ------------------------------ + @Override + public CompletableFuture getAsync(String key, Type type) { + return sendAsync("GET", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getObjectValue(key, cryptor, type)); + } + + @Override + public CompletableFuture getStringAsync(String key) { + return sendAsync("GET", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getStringValue(key, cryptor)); + } + + @Override + public CompletableFuture getSetStringAsync(String key, String value) { + return sendAsync("GETSET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getStringValue(key, cryptor)); + } + + @Override + public CompletableFuture getLongAsync(String key, long defValue) { + return sendAsync("GET", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getLongValue(defValue)); + } + + @Override + public CompletableFuture getSetLongAsync(String key, long value, long defValue) { + return sendAsync("GETSET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(value)).thenApply(v -> v.getLongValue(defValue)); + } + + @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 String getSetString(String key, String value) { + return getSetStringAsync(key, value).join(); + } + + @Override + public long getLong(String key, long defValue) { + return getLongAsync(key, defValue).join(); + } + + @Override + public long getSetLong(String key, long value, long defValue) { + return getSetLongAsync(key, value, defValue).join(); + } + + //--------------------- getex ------------------------------ + @Override + public CompletableFuture getexAsync(String key, int expireSeconds, final Type type) { + return sendAsync("GETEX", key, key.getBytes(StandardCharsets.UTF_8), "EX".getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getObjectValue(key, cryptor, type)); + } + + @Override + public T getex(String key, final int expireSeconds, final Type type) { + return (T) getexAsync(key, expireSeconds, type).join(); + } + + @Override + public CompletableFuture getexStringAsync(String key, int expireSeconds) { + return sendAsync("GETEX", key, key.getBytes(StandardCharsets.UTF_8), "EX".getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getStringValue(key, cryptor)); + } + + @Override + public String getexString(String key, final int expireSeconds) { + return getexStringAsync(key, expireSeconds).join(); + } + + @Override + public CompletableFuture getexLongAsync(String key, int expireSeconds, long defValue) { + return sendAsync("GETEX", key, key.getBytes(StandardCharsets.UTF_8), "EX".getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getLongValue(defValue)); + } + + @Override + public long getexLong(String key, final int expireSeconds, long defValue) { + return getexLongAsync(key, expireSeconds, defValue).join(); + } + + @Override + public CompletableFuture getexBytesAsync(final String key, final int expireSeconds) { + return sendAsync("GETEX", key, key.getBytes(StandardCharsets.UTF_8), "EX".getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getFrameValue()); + } + + @Override + public byte[] getexBytes(final String key, final int expireSeconds) { + return getexBytesAsync(key, expireSeconds).join(); + } + + @Override + public CompletableFuture msetAsync(final Object... keyVals) { + if (keyVals.length % 2 != 0) { + throw new RedkaleException("key value must be paired"); + } + byte[][] bs = new byte[keyVals.length][]; + for (int i = 0; i < keyVals.length; i += 2) { + String key = keyVals[i].toString(); + bs[i] = key.getBytes(StandardCharsets.UTF_8); + bs[i + 1] = formatValue(key, cryptor, keyVals[i + 1]); + } + return sendAsync("MSET", keyVals[0].toString(), bs).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture msetAsync(final Map map) { + if (map == null || map.isEmpty()) { + return CompletableFuture.completedFuture(null); + } + List bs = new ArrayList<>(); + StringWrapper onekey = new StringWrapper(); + map.forEach((key, val) -> { + onekey.setValue(key.toString()); + bs.add(key.toString().getBytes(StandardCharsets.UTF_8)); + bs.add(formatValue(key.toString(), cryptor, val)); + }); + return sendAsync("MSET", onekey.getValue(), bs.toArray(new byte[bs.size()][])).thenApply(v -> v.getVoidValue()); + } + + //--------------------- setex ------------------------------ + @Override + public CompletableFuture setAsync(String key, final Type type, T value) { + return sendAsync("SET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, (Convert) null, type, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture setAsync(String key, Convert convert, final Type type, T value) { + return sendAsync("SET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, convert, type, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture setnxAsync(String key, final Type type, T value) { + return sendAsync("SETNX", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, (Convert) null, type, value)).thenApply(v -> v.getBoolValue()); + } + + @Override + public CompletableFuture setnxAsync(String key, Convert convert, final Type type, T value) { + return sendAsync("SETNX", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, convert, type, value)).thenApply(v -> v.getBoolValue()); + } + + @Override + public boolean setnxBytes(final String key, final byte[] value) { + return setnxBytesAsync(key, value).join(); + } + + @Override + public CompletableFuture setnxBytesAsync(final String key, byte[] value) { + return sendAsync("SETNX", key, key.getBytes(StandardCharsets.UTF_8), value).thenApply(v -> v.getBoolValue()); + } + + @Override + public CompletableFuture getSetAsync(String key, final Type type, T value) { + return sendAsync("GETSET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, (Convert) null, type, value)).thenApply(v -> v.getObjectValue(key, cryptor, type)); + } + + @Override + public CompletableFuture getSetAsync(String key, Convert convert, final Type type, T value) { + return sendAsync("GETSET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, convert, type, value)).thenApply(v -> v.getObjectValue(key, cryptor, type)); + } + + @Override + public void mset(final Object... keyVals) { + msetAsync(keyVals).join(); + } + + @Override + public void mset(final Map map) { + msetAsync(map).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 boolean setnx(final String key, final Type type, T value) { + return setnxAsync(key, type, value).join(); + } + + @Override + public boolean setnx(String key, final Convert convert, final Type type, T value) { + return setnxAsync(key, convert, type, value).join(); + } + + @Override + public T getSet(String key, final Type type, T value) { + return getSetAsync(key, type, value).join(); + } + + @Override + public T getSet(String key, Convert convert, final Type type, T value) { + return getSetAsync(key, convert, type, value).join(); + } + + @Override + public CompletableFuture setStringAsync(String key, String value) { + return sendAsync("SET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture setnxStringAsync(String key, String value) { + return sendAsync("SETNX", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getBoolValue()); + } + + @Override + public void setString(String key, String value) { + setStringAsync(key, value).join(); + } + + @Override + public boolean setnxString(String key, String value) { + return setnxStringAsync(key, value).join(); + } + + @Override + public CompletableFuture setLongAsync(String key, long value) { + return sendAsync("SET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture setnxLongAsync(String key, long value) { + return sendAsync("SETNX", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getBoolValue()); + } + + @Override + public void setLong(String key, long value) { + setLongAsync(key, value).join(); + } + + @Override + public boolean setnxLong(String key, long value) { + return setnxLongAsync(key, value).join(); + } + + //--------------------- setex ------------------------------ + @Override + public CompletableFuture setexAsync(String key, int expireSeconds, final Type type, T value) { + return sendAsync("SETEX", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, (Convert) null, type, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture setexAsync(String key, int expireSeconds, Convert convert, final Type type, T value) { + return sendAsync("SETEX", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, convert, type, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public void setex(String key, int expireSeconds, final Type type, T value) { + setexAsync(key, expireSeconds, type, value).join(); + } + + @Override + public void setex(String key, int expireSeconds, Convert convert, final Type type, T value) { + setexAsync(key, expireSeconds, convert, type, value).join(); + } + + @Override + public CompletableFuture setexStringAsync(String key, int expireSeconds, String value) { + return sendAsync("SETEX", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public void setexString(String key, int expireSeconds, String value) { + setexStringAsync(key, expireSeconds, value).join(); + } + + @Override + public CompletableFuture setexLongAsync(String key, int expireSeconds, long value) { + return sendAsync("SETEX", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public void setexLong(String key, int expireSeconds, long value) { + setexLongAsync(key, expireSeconds, value).join(); + } + + @Override + public CompletableFuture setnxexStringAsync(String key, int expireSeconds, String value) { + return sendAsync("SET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value), NX, EX, String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getBoolValue()); + } + + @Override + public CompletableFuture setnxexLongAsync(String key, int expireSeconds, long value) { + return sendAsync("SET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value), NX, EX, String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getBoolValue()); + } + + @Override + public CompletableFuture setnxexBytesAsync(String key, int expireSeconds, byte[] value) { + return sendAsync("SET", key, key.getBytes(StandardCharsets.UTF_8), value, NX, EX, String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getBoolValue()); + } + + @Override + public CompletableFuture setnxexAsync(String key, int expireSeconds, final Type type, T value) { + return sendAsync("SET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, (Convert) null, type, value), NX, EX, String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getBoolValue()); + } + + @Override + public CompletableFuture setnxexAsync(String key, int expireSeconds, Convert convert, final Type type, T value) { + return sendAsync("SET", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, convert, type, value), NX, EX, String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getBoolValue()); + } + + @Override + public boolean setnxex(final String key, final int expireSeconds, final Type type, final T value) { + return setnxexAsync(key, expireSeconds, type, value).join(); + } + + @Override + public boolean setnxex(final String key, final int expireSeconds, final Convert convert, final Type type, final T value) { + return setnxexAsync(key, expireSeconds, convert, type, value).join(); + } + + @Override + public boolean setnxexString(final String key, final int expireSeconds, final String value) { + return setnxexStringAsync(key, expireSeconds, value).join(); + } + + @Override + public boolean setnxexLong(final String key, final int expireSeconds, final long value) { + return setnxexLongAsync(key, expireSeconds, value).join(); + } + + @Override + public boolean setnxexBytes(final String key, final int expireSeconds, final byte[] value) { + return setnxexBytesAsync(key, expireSeconds, value).join(); + } + + //--------------------- expire ------------------------------ + @Override + public CompletableFuture expireAsync(String key, int expireSeconds) { + return sendAsync("EXPIRE", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getVoidValue()); + } + + @Override + public void expire(String key, int expireSeconds) { + expireAsync(key, expireSeconds).join(); + } + + //--------------------- del ------------------------------ + @Override + public CompletableFuture delAsync(String... keys) { + if (keys.length == 0) { + return CompletableFuture.completedFuture(0); + } + if (keys.length == 1) { + return sendAsync("DEL", keys[0], keys[0].getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getIntValue(0)); + } else { + byte[][] bs = new byte[keys.length][]; + for (int i = 0; i < keys.length; i++) { + bs[i] = keys[i].getBytes(StandardCharsets.UTF_8); + } + return sendAsync("DEL", keys[0], bs).thenApply(v -> v.getIntValue(0)); + } + } + + @Override + public int del(String... keys) { + return delAsync(keys).join(); + } + + //--------------------- incrby ------------------------------ + @Override + public long incr(final String key) { + return incrAsync(key).join(); + } + + @Override + public CompletableFuture incrAsync(final String key) { + return sendAsync("INCR", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getLongValue(0L)); + } + + @Override + public long incrby(final String key, long num) { + return incrbyAsync(key, num).join(); + } + + @Override + public double incrbyFloat(final String key, double num) { + return incrbyFloatAsync(key, num).join(); + } + + @Override + public CompletableFuture incrbyAsync(final String key, long num) { + return sendAsync("INCRBY", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getLongValue(0L)); + } + + @Override + public CompletableFuture incrbyFloatAsync(final String key, double num) { + return sendAsync("INCRBYFLOAT", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getDoubleValue(0.d)); + } + + //--------------------- decrby ------------------------------ + @Override + public long decr(final String key) { + return decrAsync(key).join(); + } + + @Override + public CompletableFuture decrAsync(final String key) { + return sendAsync("DECR", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getLongValue(0L)); + } + + @Override + public long decrby(final String key, long num) { + return decrbyAsync(key, num).join(); + } + + @Override + public CompletableFuture decrbyAsync(final String key, long num) { + return sendAsync("DECRBY", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getLongValue(0L)); + } + + @Override + public int hdel(final String key, String... fields) { + return hdelAsync(key, fields).join(); + } + + @Override + public int hlen(final String key) { + return hlenAsync(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 hincrby(final String key, String field, long num) { + return hincrbyAsync(key, field, num).join(); + } + + @Override + public double hincrbyFloat(final String key, String field, double num) { + return hincrbyFloatAsync(key, field, num).join(); + } + + @Override + public long hdecr(final String key, String field) { + return hdecrAsync(key, field).join(); + } + + @Override + public long hdecrby(final String key, String field, long num) { + return hdecrbyAsync(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 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 boolean hsetnx(final String key, final String field, final Type type, final T value) { + return hsetnxAsync(key, field, type, value).join(); + } + + @Override + public boolean hsetnx(final String key, final String field, final Convert convert, final Type type, final T value) { + return hsetnxAsync(key, field, convert, type, value).join(); + } + + @Override + public boolean hsetnxString(final String key, final String field, final String value) { + return hsetnxStringAsync(key, field, value).join(); + } + + @Override + public boolean hsetnxLong(final String key, final String field, final long value) { + return hsetnxLongAsync(key, field, value).join(); + } + + @Override + public void hmset(final String key, final Serializable... values) { + hmsetAsync(key, values).join(); + } + + @Override + public void hmset(final String key, final Map map) { + hmsetAsync(key, map).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 hdelAsync(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 sendAsync("HDEL", key, bs).thenApply(v -> v.getIntValue(0)); + } + + @Override + public CompletableFuture hlenAsync(final String key) { + return sendAsync("HLEN", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getIntValue(0)); + } + + @Override + public CompletableFuture> hkeysAsync(final String key) { + return sendAsync("HKEYS", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> (List) v.getListValue(key, cryptor, String.class)); + } + + @Override + public CompletableFuture hincrAsync(final String key, String field) { + return hincrbyAsync(key, field, 1); + } + + @Override + public CompletableFuture hincrbyAsync(final String key, String field, long num) { + return sendAsync("HINCRBY", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getLongValue(0L)); + } + + @Override + public CompletableFuture hincrbyFloatAsync(final String key, String field, double num) { + return sendAsync("HINCRBYFLOAT", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), String.valueOf(num).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getDoubleValue(0.d)); + } + + @Override + public CompletableFuture hdecrAsync(final String key, String field) { + return hincrbyAsync(key, field, -1); + } + + @Override + public CompletableFuture hdecrbyAsync(final String key, String field, long num) { + return hincrbyAsync(key, field, -num); + } + + @Override + public CompletableFuture hexistsAsync(final String key, String field) { + return sendAsync("HEXISTS", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getIntValue(0) > 0); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync("HSET", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, null, type, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final Type type, final T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync("HSET", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, convert, type, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture hsetStringAsync(final String key, final String field, final String value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync("HSET", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture hsetLongAsync(final String key, final String field, final long value) { + return sendAsync("HSET", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture hsetnxAsync(final String key, final String field, final Type type, final T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync("HSETNX", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, null, type, value)).thenApply(v -> v.getBoolValue()); + } + + @Override + public CompletableFuture hsetnxAsync(final String key, final String field, final Convert convert, final Type type, final T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync("HSETNX", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, convert, type, value)).thenApply(v -> v.getBoolValue()); + } + + @Override + public CompletableFuture hsetnxStringAsync(final String key, final String field, final String value) { + if (value == null) { + return CompletableFuture.completedFuture(false); + } + return sendAsync("HSETNX", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getBoolValue()); + } + + @Override + public CompletableFuture hsetnxLongAsync(final String key, final String field, final long value) { + return sendAsync("HSETNX", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getBoolValue()); + } + + @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(key, cryptor, values[i + 1]); + } + return sendAsync("HMSET", key, bs).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture hmsetAsync(final String key, final Map map) { + if (map == null || map.isEmpty()) { + return CompletableFuture.completedFuture(null); + } + List bs = new ArrayList<>(); + bs.add(key.getBytes(StandardCharsets.UTF_8)); + map.forEach((k, v) -> { + bs.add(k.toString().getBytes(StandardCharsets.UTF_8)); + bs.add(formatValue(k.toString(), cryptor, v)); + }); + return sendAsync("HMSET", key, bs.toArray(new byte[bs.size()][])).thenApply(v -> v.getVoidValue()); + } + + @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 sendAsync("HMGET", key, bs).thenApply(v -> (List) v.getListValue(key, cryptor, type)); + } + + @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 sendAsync("HSCAN", key, bs).thenApply(v -> v.getMapValue(key, cryptor, type)); + } + + @Override + public CompletableFuture hgetAsync(final String key, final String field, final Type type) { + return sendAsync("HGET", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getObjectValue(key, cryptor, type)); + } + + @Override + public CompletableFuture hgetStringAsync(final String key, final String field) { + return sendAsync("HGET", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getStringValue(key, cryptor)); + } + + @Override + public CompletableFuture hgetLongAsync(final String key, final String field, long defValue) { + return sendAsync("HGET", key, key.getBytes(StandardCharsets.UTF_8), field.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getLongValue(defValue)); + } + + @Override + public CompletableFuture> smembersAsync(String key, final Type componentType) { + return sendAsync("SMEMBERS", key, keySetArgs(key)).thenApply(v -> v.getSetValue(key, cryptor, componentType)); + } + + @Override + public CompletableFuture> lrangeAsync(String key, final Type componentType) { + return sendAsync("LRANGE", key, keyListArgs(key)).thenApply(v -> v.getListValue(key, cryptor, componentType)); + } + + //--------------------- collection ------------------------------ + @Override + public CompletableFuture llenAsync(String key) { + return sendAsync("LLEN", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getIntValue(0)); + } + + @Override + public CompletableFuture scardAsync(String key) { + return sendAsync("SCARD", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getIntValue(0)); + } + + @Override + public int llen(String key) { + return llenAsync(key).join(); + } + + @Override + public int scard(String key) { + return scardAsync(key).join(); + } + + @Override + public CompletableFuture> mgetLongAsync(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 sendAsync("MGET", keys[0], bs).thenApply(v -> { + List list = (List) v.getListValue(keys[0], cryptor, long.class); + 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> mgetStringAsync(final 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 sendAsync("MGET", keys[0], bs).thenApply(v -> { + List list = (List) v.getListValue(keys[0], cryptor, String.class); + 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> mgetAsync(final Type componentType, final 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 sendAsync("MGET", keys[0], bs).thenApply(v -> { + List list = (List) v.getListValue(keys[0], cryptor, componentType); + 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> mgetBytesAsync(final 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 sendAsync("MGET", keys[0], bs).thenApply(v -> { + List list = (List) v.getListValue(keys[0], cryptor, byte[].class); + 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>> smembersAsync(final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = sendAsync("SMEMBERS", key, keySetArgs(key)).thenAccept(v -> { + Set c = v.getSetValue(key, cryptor, componentType); + if (c != null) { + mapLock.lock(); + try { + map.put(key, c); + } finally { + mapLock.unlock(); + } + } + }); + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public CompletableFuture>> lrangeAsync(final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = sendAsync("LRANGE", key, keyListArgs(key)).thenAccept(v -> { + List c = v.getListValue(key, cryptor, componentType); + if (c != null) { + mapLock.lock(); + try { + map.put(key, c); + } finally { + mapLock.unlock(); + } + } + }); + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public Set smembers(String key, final Type componentType) { + return (Set) smembersAsync(key, componentType).join(); + } + + @Override + public List lrange(String key, final Type componentType) { + return (List) lrangeAsync(key, componentType).join(); + } + + @Override + public Map mgetBytes(final String... keys) { + return mgetBytesAsync(keys).join(); + } + + @Override + public Map mgetLong(final String... keys) { + return mgetLongAsync(keys).join(); + } + + @Override + public Map mgetString(final String... keys) { + return mgetStringAsync(keys).join(); + } + + @Override + public Map mget(final Type componentType, final String... keys) { + return (Map) mgetAsync(componentType, keys).join(); + } + + @Override + public Map> smembers(final Type componentType, String... keys) { + return (Map) smembersAsync(componentType, keys).join(); + } + + @Override + public Map> lrange(final Type componentType, String... keys) { + return (Map) lrangeAsync(componentType, keys).join(); + } + + //--------------------- existsItem ------------------------------ + @Override + public boolean sismember(String key, final Type componentType, T value) { + return sismemberAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture sismemberAsync(String key, final Type componentType, T value) { + return sendAsync("SISMEMBER", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, (Convert) null, componentType, value)).thenApply(v -> v.getIntValue(0) > 0); + } + + @Override + public boolean sismemberString(String key, String value) { + return sismemberStringAsync(key, value).join(); + } + + @Override + public CompletableFuture sismemberStringAsync(String key, String value) { + return sendAsync("SISMEMBER", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getIntValue(0) > 0); + } + + @Override + public boolean sismemberLong(String key, long value) { + return sismemberLongAsync(key, value).join(); + } + + @Override + public CompletableFuture sismemberLongAsync(String key, long value) { + return sendAsync("SISMEMBER", key, key.getBytes(StandardCharsets.UTF_8), formatValue(value)).thenApply(v -> v.getIntValue(0) > 0); + } + + //--------------------- rpush ------------------------------ + @Override + public CompletableFuture rpushAsync(String key, final Type componentType, T value) { + return sendAsync("RPUSH", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, (Convert) null, componentType, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public void rpush(String key, final Type componentType, T value) { + rpushAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture rpushStringAsync(String key, String value) { + return sendAsync("RPUSH", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public void rpushString(String key, String value) { + rpushStringAsync(key, value).join(); + } + + @Override + public CompletableFuture rpushLongAsync(String key, long value) { + return sendAsync("RPUSH", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public void rpushLong(String key, long value) { + rpushLongAsync(key, value).join(); + } + + //--------------------- lrem ------------------------------ + @Override + public CompletableFuture lremAsync(String key, final Type componentType, T value) { + return sendAsync("LREM", key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(key, cryptor, (Convert) null, componentType, value)).thenApply(v -> v.getIntValue(0)); + } + + @Override + public int lrem(String key, final Type componentType, T value) { + return lremAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture lremStringAsync(String key, String value) { + return sendAsync("LREM", key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(key, cryptor, value)).thenApply(v -> v.getIntValue(0)); + } + + @Override + public int lremString(String key, String value) { + return lremStringAsync(key, value).join(); + } + + @Override + public CompletableFuture lremLongAsync(String key, long value) { + return sendAsync("LREM", key, key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, formatValue(key, cryptor, value)).thenApply(v -> v.getIntValue(0)); + } + + @Override + public int lremLong(String key, long value) { + return lremLongAsync(key, value).join(); + } + + //--------------------- sadd ------------------------------ + @Override + public CompletableFuture saddAsync(String key, Type componentType, T value) { + return sendAsync("SADD", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, (Convert) null, componentType, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture spopAsync(String key, Type componentType) { + return sendAsync("SPOP", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getObjectValue(key, cryptor, componentType)); + } + + @Override + public CompletableFuture> spopAsync(String key, int count, Type componentType) { + return sendAsync("SPOP", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(count).getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getObjectValue(key, cryptor, componentType)); + } + + @Override + public CompletableFuture spopStringAsync(String key) { + return sendAsync("SPOP", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getStringValue(key, cryptor)); + } + + @Override + public CompletableFuture> spopStringAsync(String key, int count) { + return sendAsync("SPOP", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(count).getBytes(StandardCharsets.UTF_8)).thenApply(v -> (Set) v.getSetValue(key, cryptor, String.class)); + } + + @Override + public CompletableFuture spopLongAsync(String key) { + return sendAsync("SPOP", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getLongValue(0L)); + } + + @Override + public CompletableFuture> spopLongAsync(String key, int count) { + return sendAsync("SPOP", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(count).getBytes(StandardCharsets.UTF_8)).thenApply(v -> (Set) v.getSetValue(key, cryptor, long.class)); + } + + @Override + public void sadd(String key, final Type componentType, T value) { + saddAsync(key, componentType, value).join(); + } + + @Override + public T spop(String key, final Type componentType) { + return (T) spopAsync(key, componentType).join(); + } + + @Override + public Set spop(String key, int count, final Type componentType) { + return (Set) spopAsync(key, count, componentType).join(); + } + + @Override + public String spopString(String key) { + return spopStringAsync(key).join(); + } + + @Override + public Set spopString(String key, int count) { + return spopStringAsync(key, count).join(); + } + + @Override + public Long spopLong(String key) { + return spopLongAsync(key).join(); + } + + @Override + public Set spopLong(String key, int count) { + return spopLongAsync(key, count).join(); + } + + @Override + public CompletableFuture saddStringAsync(String key, String value) { + return sendAsync("SADD", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public void saddString(String key, String value) { + saddStringAsync(key, value).join(); + } + + @Override + public CompletableFuture saddLongAsync(String key, long value) { + return sendAsync("SADD", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getVoidValue()); + } + + @Override + public void saddLong(String key, long value) { + saddLongAsync(key, value).join(); + } + + //--------------------- srem ------------------------------ + @Override + public CompletableFuture sremAsync(String key, final Type componentType, T value) { + return sendAsync("SREM", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, (Convert) null, componentType, value)).thenApply(v -> v.getIntValue(0)); + } + + @Override + public int srem(String key, final Type componentType, T value) { + return sremAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture sremStringAsync(String key, String value) { + return sendAsync("SREM", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getIntValue(0)); + } + + @Override + public int sremString(String key, String value) { + return sremStringAsync(key, value).join(); + } + + @Override + public CompletableFuture sremLongAsync(String key, long value) { + return sendAsync("SREM", key, key.getBytes(StandardCharsets.UTF_8), formatValue(key, cryptor, value)).thenApply(v -> v.getIntValue(0)); + } + + @Override + public int sremLong(String key, long value) { + return sremLongAsync(key, value).join(); + } + + //--------------------- keys ------------------------------ + @Override + public List keys(String pattern) { + return keysAsync(pattern).join(); + } + + @Override + public byte[] getBytes(final String key) { + return getBytesAsync(key).join(); + } + + @Override + public byte[] getSetBytes(final String key, final byte[] value) { + return getSetBytesAsync(key, value).join(); + } + + @Override + public void setBytes(final String key, final byte[] value) { + setBytesAsync(key, value).join(); + } + + @Override + public void setexBytes(final String key, final int expireSeconds, final byte[] value) { + setexBytesAsync(key, expireSeconds, value).join(); + } + + @Override + public CompletableFuture getBytesAsync(final String key) { + return sendAsync("GET", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getFrameValue()); + } + + @Override + public CompletableFuture getSetBytesAsync(final String key, final byte[] value) { + return sendAsync("GETSET", key, key.getBytes(StandardCharsets.UTF_8), value).thenApply(v -> v.getFrameValue()); + } + + @Override + public CompletableFuture setBytesAsync(final String key, final byte[] value) { + return sendAsync("SET", key, key.getBytes(StandardCharsets.UTF_8), value).thenApply(v -> v.getVoidValue()); + + } + + @Override + public CompletableFuture setexBytesAsync(final String key, final int expireSeconds, final byte[] value) { + return sendAsync("SETEX", key, key.getBytes(StandardCharsets.UTF_8), String.valueOf(expireSeconds).getBytes(StandardCharsets.UTF_8), value).thenApply(v -> v.getVoidValue()); + } + + @Override + public CompletableFuture> keysAsync(String pattern) { + String key = pattern == null || pattern.isEmpty() ? "*" : pattern; + return sendAsync("KEYS", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> (List) v.getListValue(key, cryptor, String.class)); + } + + //--------------------- dbsize ------------------------------ + @Override + public long dbsize() { + return dbsizeAsync().join(); + } + + @Override + public CompletableFuture dbsizeAsync() { + return sendAsync("DBSIZE", null).thenApply(v -> v.getLongValue(0L)); + } + + //--------------------- send ------------------------------ + @Local + public CompletableFuture sendAsync(final String command, final String key, final Serializable... args) { + int start = key == null ? 0 : 1; + byte[][] bs = new byte[args.length + start][]; + if (key != null) { + bs[0] = key.getBytes(StandardCharsets.UTF_8); + for (int i = start; i < bs.length; i++) { + if (args[i - start].getClass() == String.class) { + bs[i] = ((String) args[i - start]).getBytes(StandardCharsets.UTF_8); + } else { + bs[i] = JsonConvert.root().convertToBytes(args[i - start]); + } + } + } else { + for (int i = start; i < bs.length; i++) { + bs[i] = String.valueOf(args[i]).getBytes(StandardCharsets.UTF_8); + } + } + /*for (int i = start; i < bs.length; i++) { + bs[i] = JsonConvert.root().convertToBytes(args[i-1]); + }*/ + return client.connect().thenCompose(conn -> conn.writeRequest(conn.pollRequest(WorkThread.currWorkThread()).prepare(command, key, bs))).orTimeout(6, TimeUnit.SECONDS); + } + + @Local + public CompletableFuture sendAsync(final String command, final String key, final byte[]... args) { + return client.connect().thenCompose(conn -> conn.writeRequest(conn.pollRequest(WorkThread.currWorkThread()).prepare(command, key, args))).orTimeout(6, TimeUnit.SECONDS); + } + + private byte[][] keySetArgs(String key) { + return new byte[][]{key.getBytes(StandardCharsets.UTF_8)}; + } + + private byte[][] keyListArgs(String key) { + return new byte[][]{key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}}; + } + + private byte[][] keyArgs(boolean set, String key) { + if (set) { + return new byte[][]{key.getBytes(StandardCharsets.UTF_8)}; + } + return new byte[][]{key.getBytes(StandardCharsets.UTF_8), new byte[]{'0'}, new byte[]{'-', '1'}}; + } + + private byte[] formatValue(long value) { + return String.valueOf(value).getBytes(StandardCharsets.UTF_8); + } + + private byte[] formatValue(String key, RedisCryptor cryptor, String value) { + if (cryptor != null) { + value = cryptor.encrypt(key, value); + } + if (value == null) { + throw new NullPointerException(); + } + return value.getBytes(StandardCharsets.UTF_8); + } + + private byte[] formatValue(String key, RedisCryptor cryptor, Object value) { + return formatValue(key, cryptor, null, null, value); + } + + private byte[] formatValue(String key, RedisCryptor cryptor, Convert convert0, Type type, Object value) { + if (value == null) { + throw new NullPointerException(); + } + if (value instanceof Boolean) { + return (Boolean) value ? RedisCacheRequest.TRUE : RedisCacheRequest.FALSE; + } + if (value instanceof byte[]) { + if (cryptor != null) { + String val = cryptor.encrypt(key, new String((byte[]) value, StandardCharsets.UTF_8)); + return val.getBytes(StandardCharsets.UTF_8); + } + return (byte[]) value; + } + if (value instanceof CharSequence) { + if (cryptor != null) { + value = cryptor.encrypt(key, String.valueOf(value)); + } + return String.valueOf(value).getBytes(StandardCharsets.UTF_8); + } + if (value.getClass().isPrimitive() || Number.class.isAssignableFrom(value.getClass())) { + return String.valueOf(value).getBytes(StandardCharsets.US_ASCII); + } + if (convert0 == null) { + if (convert == null) { //compile模式下convert可能为null + convert = JsonConvert.root(); + } + convert0 = convert; + } + byte[] bs = convert0.convertToBytes(type == null ? value.getClass() : type, value); + if (cryptor != null) { + String val = cryptor.encrypt(key, new String(bs, StandardCharsets.UTF_8)); + return val.getBytes(StandardCharsets.UTF_8); + } + return bs; + } + + @Override + public CompletableFuture>> getCollectionMapAsync(final boolean set, final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = sendAsync(set ? "SMEMBERS" : "LRANGE", key, keyArgs(set, key)).thenAccept(v -> { + Collection c = set ? v.getSetValue(key, cryptor, componentType) : v.getListValue(key, cryptor, componentType); + if (c != null) { + mapLock.lock(); + try { + map.put(key, (Collection) c); + } finally { + mapLock.unlock(); + } + } + }); + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public CompletableFuture getCollectionSizeAsync(String key) { + return sendAsync("TYPE", key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { + String type = t.getStringValue(key, cryptor); + if (type == null) { + return CompletableFuture.completedFuture(0); + } + return sendAsync(type.contains("list") ? "LLEN" : "SCARD", key, key.getBytes(StandardCharsets.UTF_8)).thenApply(v -> v.getIntValue(0)); + }); + } + + @Override + public int getCollectionSize(String key) { + return getCollectionSizeAsync(key).join(); + } + + @Override + public CompletableFuture> getCollectionAsync(String key, final Type componentType) { + return sendAsync("TYPE", key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { + String type = t.getStringValue(key, cryptor); + if (type == null) { + return CompletableFuture.completedFuture(null); + } + boolean set = !type.contains("list"); + return sendAsync(set ? "SMEMBERS" : "LRANGE", key, keyArgs(set, key)).thenApply(v -> set ? v.getSetValue(key, cryptor, componentType) : v.getListValue(key, cryptor, componentType)); + }); + } + + @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 sendAsync("MGET", keys[0], bs).thenApply(v -> { + List list = (List) v.getListValue(keys[0], cryptor, long.class); + 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 sendAsync("MGET", keys[0], bs).thenApply(v -> { + List list = (List) v.getListValue(keys[0], cryptor, String.class); + 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 Collection getCollection(String key, final Type componentType) { + return (Collection) getCollectionAsync(key, componentType).join(); + } + + @Override + public Long[] getLongArray(final String... keys) { + return getLongArrayAsync(keys).join(); + } + + @Override + public String[] getStringArray(final String... keys) { + return getStringArrayAsync(keys).join(); + } + + @Override + public CompletableFuture> getStringCollectionAsync(String key) { + return sendAsync("TYPE", key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { + String type = t.getStringValue(key, cryptor); + if (type == null) { + return CompletableFuture.completedFuture(null); + } + boolean set = !type.contains("list"); + return sendAsync(set ? "SMEMBERS" : "LRANGE", key, keyArgs(set, key)).thenApply(v -> set ? v.getSetValue(key, cryptor, String.class) : v.getListValue(key, cryptor, String.class)); + }); + } + + @Override + public CompletableFuture>> getStringCollectionMapAsync(final boolean set, String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = sendAsync(set ? "SMEMBERS" : "LRANGE", key, keyArgs(set, key)).thenAccept(v -> { + Collection c = set ? v.getSetValue(key, cryptor, String.class) : v.getListValue(key, cryptor, String.class); + if (c != null) { + mapLock.lock(); + try { + map.put(key, (Collection) c); + } finally { + mapLock.unlock(); + } + } + }); + } + 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 sendAsync("TYPE", key, key.getBytes(StandardCharsets.UTF_8)).thenCompose(t -> { + String type = t.getStringValue(key, cryptor); + if (type == null) { + return CompletableFuture.completedFuture(null); + } + boolean set = !type.contains("list"); + return sendAsync(set ? "SMEMBERS" : "LRANGE", key, keyArgs(set, key)).thenApply(v -> set ? v.getSetValue(key, cryptor, long.class) : v.getListValue(key, cryptor, long.class)); + }); + } + + @Override + public CompletableFuture>> getLongCollectionMapAsync(final boolean set, String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = sendAsync(set ? "SMEMBERS" : "LRANGE", key, keyArgs(set, key)).thenAccept(v -> { + Collection c = set ? v.getSetValue(key, cryptor, long.class) : v.getListValue(key, cryptor, long.class); + if (c != null) { + mapLock.lock(); + try { + map.put(key, (Collection) c); + } finally { + mapLock.unlock(); + } + } + }); + } + 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(); + } + + //--------------------- getexCollection ------------------------------ + @Override + public CompletableFuture> getexCollectionAsync(String key, int expireSeconds, final Type componentType) { + return (CompletableFuture) expireAsync(key, expireSeconds).thenCompose(v -> getCollectionAsync(key, componentType)); + } + + @Override + public Collection getexCollection(String key, final int expireSeconds, final Type componentType) { + return (Collection) getexCollectionAsync(key, expireSeconds, componentType).join(); + } + + @Override + public CompletableFuture> getexStringCollectionAsync(String key, int expireSeconds) { + return (CompletableFuture) expireAsync(key, expireSeconds).thenCompose(v -> getStringCollectionAsync(key)); + } + + @Override + public Collection getexStringCollection(String key, final int expireSeconds) { + return getexStringCollectionAsync(key, expireSeconds).join(); + } + + @Override + public CompletableFuture> getexLongCollectionAsync(String key, int expireSeconds) { + return (CompletableFuture) expireAsync(key, expireSeconds).thenCompose(v -> getLongCollectionAsync(key)); + } + + @Override + public Collection getexLongCollection(String key, final int expireSeconds) { + return getexLongCollectionAsync(key, expireSeconds).join(); + } + + @Override + public Map> getCollectionMap(final boolean set, final Type componentType, String... keys) { + return (Map) getCollectionMapAsync(set, componentType, keys).join(); + } +} diff --git a/src/org/redkalex/cache/redis/RedisCacheSourceProvider.java b/src/org/redkalex/cache/redis/RedisCacheSourceProvider.java new file mode 100644 index 0000000..5b62979 --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCacheSourceProvider.java @@ -0,0 +1,29 @@ +/* + * 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 org.redkalex.cache.redis; + +import org.redkale.annotation.Priority; +import org.redkale.source.CacheSource; +import org.redkale.source.CacheSourceProvider; +import org.redkale.util.AnyValue; + +/** + * @author zhangjx + */ +@Priority(10001) +public class RedisCacheSourceProvider implements CacheSourceProvider { + + @Override + public boolean acceptsConf(AnyValue config) { + return new MyRedisCacheSource().acceptsConf(config); + } + + @Override + public CacheSource createInstance() { + return new MyRedisCacheSource(); + } + +} diff --git a/src/org/redkalex/cache/redis/RedisCryptor.java b/src/org/redkalex/cache/redis/RedisCryptor.java new file mode 100644 index 0000000..96f6ee6 --- /dev/null +++ b/src/org/redkalex/cache/redis/RedisCryptor.java @@ -0,0 +1,46 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package org.redkalex.cache.redis; + +import org.redkale.util.AnyValue; + +/** + * @author zhangjx + */ +public interface RedisCryptor { + + /** + * 初始化 + * + * @param conf 配置 + */ + public void init(AnyValue conf); + + /** + * 加密, 无需加密的key对应的值需要直接返回value + * + * @param key key + * @param value 明文 + * @return 密文 + */ + public String encrypt(String key, String value); + + /** + * 解密, 无需解密的key对应的值需要直接返回value + * + * @param key key + * @param value 密文 + * @return 明文 + */ + public String decrypt(String key, String value); + + /** + * 销毁 + * + * @param conf 配置 + */ + public void destroy(AnyValue conf); + +} diff --git a/src/org/redkalex/cache/redis/lettuce/RedisLettuceCacheSource.java b/src/org/redkalex/cache/redis/lettuce/RedisLettuceCacheSource.java new file mode 100644 index 0000000..43f2831 --- /dev/null +++ b/src/org/redkalex/cache/redis/lettuce/RedisLettuceCacheSource.java @@ -0,0 +1,2670 @@ +/* + * 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 org.redkalex.cache.redis.lettuce; + +import com.zdemo.cachex.AbstractRedisSource; +import com.zdemo.cachex.RedisCryptor; +import io.lettuce.core.*; +import io.lettuce.core.api.StatefulRedisConnection; +import io.lettuce.core.api.async.RedisAsyncCommands; +import io.lettuce.core.api.sync.RedisCommands; +import io.lettuce.core.cluster.RedisClusterClient; +import io.lettuce.core.cluster.api.StatefulRedisClusterConnection; +import io.lettuce.core.cluster.api.async.*; +import io.lettuce.core.cluster.api.sync.*; +import io.lettuce.core.codec.*; +import io.lettuce.core.support.*; +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.ResourceListener; +import org.redkale.annotation.ResourceType; +import org.redkale.convert.Convert; +import org.redkale.service.Local; +import org.redkale.source.CacheSource; +import org.redkale.util.AnyValue; +import org.redkale.util.RedkaleException; +import org.redkale.util.ResourceEvent; +import org.redkale.util.Utility; +import org.redkalex.cache.redis.AbstractRedisSource; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 注意: 目前Lettuce连接数过小时会出现连接池频频报连接耗尽的错误,推荐使用Redission实现方式。 + * + * @author zhangjx + */ +@Local +@AutoLoad(false) +@ResourceType(CacheSource.class) +public class RedisLettuceCacheSource extends AbstractRedisSource { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected Type objValueType = String.class; + + protected List nodeAddrs; + + protected io.lettuce.core.AbstractRedisClient client; + + protected BoundedAsyncPool> singleBytesConnPool; + + protected BoundedAsyncPool> singleStringConnPool; + + protected BoundedAsyncPool> clusterBytesConnPool; + + protected BoundedAsyncPool> clusterStringConnPool; + + protected RedisCodec stringByteArrayCodec; + + protected RedisCodec stringStringCodec; + + @Override + public void init(AnyValue conf) { + super.init(conf); + if (conf == null) { + conf = AnyValue.create(); + } + initClient(conf); + } + + private void initClient(AnyValue conf) { + this.stringByteArrayCodec = (RedisCodec) RedisCodec.of(StringCodec.UTF8, ByteArrayCodec.INSTANCE); + this.stringStringCodec = StringCodec.UTF8; + + final List addresses = new ArrayList<>(); + AnyValue[] nodes = getNodes(conf); + List uris = new ArrayList(nodes.length); + int urlmaxconns = Utility.cpus(); + String gdb = conf.getValue(CACHE_SOURCE_DB, "").trim(); + String gusername = conf.getValue(CACHE_SOURCE_USER, "").trim(); + String gpassword = conf.getValue(CACHE_SOURCE_PASSWORD, "").trim(); + for (AnyValue node : nodes) { + String addr = node.getValue(CACHE_SOURCE_URL, node.getValue("addr")); //兼容addr + addresses.add(addr); + String dbstr = node.getValue(CACHE_SOURCE_DB, "").trim(); + String username = node.getValue(CACHE_SOURCE_USER, "").trim(); + String password = node.getValue(CACHE_SOURCE_PASSWORD, "").trim(); + URI uri = URI.create(addr); + if (uri.getQuery() != null && !uri.getQuery().isEmpty()) { + String[] qrys = uri.getQuery().split("&|="); + for (int i = 0; i < qrys.length; i += 2) { + if (CACHE_SOURCE_MAXCONNS.equals(qrys[i])) { + urlmaxconns = i == qrys.length - 1 ? Utility.cpus() : Integer.parseInt(qrys[i + 1]); + } + } + } + RedisURI ruri = RedisURI.create(addr); + if (!dbstr.isEmpty()) { + db = Integer.parseInt(dbstr); + ruri.setDatabase(db); + } else if (!gdb.isEmpty()) { + ruri.setDatabase(Integer.parseInt(gdb)); + } +// if (!username.isEmpty()) { +// ruri.setUsername(username); +// } else if (!gusername.isEmpty()) { +// ruri.setUsername(gusername); +// } +// if (!password.isEmpty()) { +// ruri.setPassword(password.toCharArray()); +// } else if (!gpassword.isEmpty()) { +// ruri.setPassword(gpassword.toCharArray()); +// } + if (!username.isEmpty() || !gusername.isEmpty()) { + RedisCredentials authCredentials = RedisCredentials.just(!username.isEmpty() ? username : gusername, !password.isEmpty() ? password : (!gpassword.isEmpty() ? gpassword : "")); + ruri.setCredentialsProvider(RedisCredentialsProvider.from(() -> authCredentials)); + } + + uris.add(ruri); + } + final int maxconns = conf.getIntValue(CACHE_SOURCE_MAXCONNS, urlmaxconns); + final RedisURI singleRedisURI = uris.get(0); + io.lettuce.core.AbstractRedisClient old = this.client; + + RedisClient singleClient = null; + RedisClusterClient clusterClient = null; + if (uris.size() < 2) { + singleClient = io.lettuce.core.RedisClient.create(singleRedisURI); + this.client = singleClient; + } else { + clusterClient = RedisClusterClient.create(uris); + this.client = clusterClient; + } + this.nodeAddrs = addresses; + BoundedPoolConfig bpc = BoundedPoolConfig.builder().maxTotal(maxconns).maxIdle(maxconns).minIdle(0).build(); + if (clusterClient == null) { + RedisClient sClient = singleClient; + this.singleBytesConnPool = AsyncConnectionPoolSupport.createBoundedObjectPool(() -> sClient.connectAsync(stringByteArrayCodec, singleRedisURI), bpc); + this.singleStringConnPool = AsyncConnectionPoolSupport.createBoundedObjectPool(() -> sClient.connectAsync(stringStringCodec, singleRedisURI), bpc); + } else { + RedisClusterClient sClient = clusterClient; + this.clusterBytesConnPool = AsyncConnectionPoolSupport.createBoundedObjectPool(() -> sClient.connectAsync(stringByteArrayCodec), bpc); + this.clusterStringConnPool = AsyncConnectionPoolSupport.createBoundedObjectPool(() -> sClient.connectAsync(stringStringCodec), bpc); + } + if (old != null) { + old.close(); + } + //if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, RedisLettuceCacheSource.class.getSimpleName() + ": addrs=" + addresses); + } + + @Override + @ResourceListener + public void onResourceChange(ResourceEvent[] events) { + if (events == null || events.length < 1) { + return; + } + StringBuilder sb = new StringBuilder(); + for (ResourceEvent event : events) { + sb.append("CacheSource(name=").append(resourceName()).append(") change '").append(event.name()).append("' to '").append(event.coverNewValue()).append("'\r\n"); + } + initClient(this.config); + if (sb.length() > 0) { + logger.log(Level.INFO, sb.toString()); + } + } + + public boolean acceptsConf(AnyValue config) { + if (config == null) { + return false; + } + AnyValue[] nodes = getNodes(config); + if (nodes == null || nodes.length == 0) { + return false; + } + for (AnyValue node : nodes) { + String val = node.getValue(CACHE_SOURCE_URL, node.getValue("addr")); //兼容addr + if (val != null && val.startsWith("redis://")) { + return true; + } + if (val != null && val.startsWith("rediss://")) { + return true; + } + if (val != null && val.startsWith("redis-socket://")) { + return true; + } + if (val != null && val.startsWith("redis-sentinel://")) { + return true; + } + } + return false; + } + + protected AnyValue[] getNodes(AnyValue config) { + AnyValue[] nodes = config.getAnyValues(CACHE_SOURCE_NODE); + if (nodes == null || nodes.length == 0) { + AnyValue one = config.getAnyValue(CACHE_SOURCE_NODE); + if (one == null) { + String val = config.getValue(CACHE_SOURCE_URL); + if (val == null) { + return nodes; + } + nodes = new AnyValue[]{config}; + } else { + nodes = new AnyValue[]{one}; + } + } + return nodes; + } + + @Override + public final String getType() { + return "redis"; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{addrs=" + this.nodeAddrs + ", db=" + this.db + "}"; + } + + @Local + public io.lettuce.core.AbstractRedisClient getRedisClient() { + return this.client; + } + + protected List formatCollection(String key, RedisCryptor cryptor, List collection, Convert convert0, final Type componentType) { + List rs = new ArrayList<>(); + if (collection == null) { + return rs; + } + for (byte[] bs : collection) { + if (bs == null) { + continue; + } + rs.add((T) decryptValue(key, cryptor, convert0, componentType, bs)); + } + return rs; + } + + protected Set formatCollection(String key, RedisCryptor cryptor, Set collection, Convert convert0, final Type componentType) { + Set rs = new LinkedHashSet<>(); + if (collection == null) { + return rs; + } + for (byte[] bs : collection) { + if (bs == null) { + continue; + } + rs.add((T) decryptValue(key, cryptor, convert0, componentType, bs)); + } + return rs; + } + + protected Collection formatLongCollection(boolean set, Collection list) { + if (set) { + Set rs = new LinkedHashSet<>(); + for (String str : list) { + rs.add(Long.parseLong(str)); + } + return rs; + } else { + List rs = new ArrayList<>(); + for (String str : list) { + rs.add(Long.parseLong(str)); + } + return rs; + } + } + + protected Collection formatStringCollection(String key, RedisCryptor cryptor, boolean set, Collection list) { + if (cryptor == null) { + return list; + } + if (set) { + Set rs = new LinkedHashSet<>(); + for (String str : list) { + rs.add(cryptor.decrypt(key, str)); + } + return rs; + } else { + List rs = new ArrayList<>(); + for (String str : list) { + rs.add(cryptor.decrypt(key, str)); + } + return rs; + } + } + + @Override + public void destroy(AnyValue conf) { + super.destroy(conf); + if (client != null) { + client.shutdown(); + } + } + + protected CompletableFuture completableBoolFuture(RedisClusterAsyncCommands command, CompletionStage rf) { + return (CompletableFuture) rf.toCompletableFuture().whenComplete((v, e) -> releaseBytesCommand(command)); + } + + protected CompletableFuture completableBoolFuture(String key, RedisCryptor cryptor, RedisClusterAsyncCommands command, CompletionStage rf) { + return (CompletableFuture) rf.toCompletableFuture().whenComplete((v, e) -> releaseStringCommand(command)); + } + + protected CompletableFuture completableBytesFuture(RedisClusterAsyncCommands command, CompletionStage rf) { + return (CompletableFuture) rf.toCompletableFuture().whenComplete((v, e) -> releaseBytesCommand(command)); + } + + protected CompletableFuture completableStringFuture(String key, RedisCryptor cryptor, RedisClusterAsyncCommands command, CompletionStage rf) { + if (cryptor != null) { + return (CompletableFuture) rf.toCompletableFuture() + .thenApply(v -> v == null ? v : cryptor.decrypt(key, v.toString())) + .whenComplete((v, e) -> releaseStringCommand(command)); + } + return (CompletableFuture) rf.toCompletableFuture() + .whenComplete((v, e) -> releaseStringCommand(command)); + } + + protected CompletableFuture completableLongFuture(RedisClusterAsyncCommands command, CompletionStage rf) { + return (CompletableFuture) rf.toCompletableFuture() + .whenComplete((v, e) -> releaseStringCommand(command)); + } + + protected CompletableFuture> connectBytesAsync() { + if (clusterBytesConnPool == null) { + return singleBytesConnPool.acquire().thenApply(c -> c.async()); + } else { + return clusterBytesConnPool.acquire().thenApply(c -> c.async()); + } + } + + protected CompletableFuture> connectStringAsync() { + if (clusterBytesConnPool == null) { + return singleStringConnPool.acquire().thenApply(c -> c.async()); + } else { + return clusterStringConnPool.acquire().thenApply(c -> c.async()); + } + } + + protected RedisClusterCommands connectBytes() { + if (clusterBytesConnPool == null) { + return singleBytesConnPool.acquire().join().sync(); + } else { + return clusterBytesConnPool.acquire().join().sync(); + } + } + + protected RedisClusterCommands connectString() { + if (clusterStringConnPool == null) { + return singleStringConnPool.acquire().join().sync(); + } else { + return clusterStringConnPool.acquire().join().sync(); + } + } + + protected void releaseBytesCommand(RedisClusterCommands command) { + if (command instanceof RedisCommands) { + singleBytesConnPool.release(((RedisCommands) command).getStatefulConnection()).join(); + } else { + clusterBytesConnPool.release(((RedisAdvancedClusterCommands) command).getStatefulConnection()).join(); + } + } + + protected void releaseStringCommand(RedisClusterCommands command) { + if (command instanceof RedisCommands) { + singleStringConnPool.release(((RedisCommands) command).getStatefulConnection()).join(); + } else { + clusterStringConnPool.release(((RedisAdvancedClusterCommands) command).getStatefulConnection()).join(); + } + } + + protected void releaseBytesCommand(RedisClusterAsyncCommands command) { + if (command instanceof RedisAsyncCommands) { + singleBytesConnPool.release(((RedisAsyncCommands) command).getStatefulConnection()); + } else { + clusterBytesConnPool.release(((RedisAdvancedClusterAsyncCommands) command).getStatefulConnection()); + } + } + + protected void releaseStringCommand(RedisClusterAsyncCommands command) { + if (command instanceof RedisAsyncCommands) { + singleStringConnPool.release(((RedisAsyncCommands) command).getStatefulConnection()); + } else { + clusterStringConnPool.release(((RedisAdvancedClusterAsyncCommands) command).getStatefulConnection()); + } + } + + //--------------------- exists ------------------------------ + @Override + public CompletableFuture existsAsync(String key) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.exists(key).thenApply(v -> v > 0)); + }); + } + + @Override + public boolean exists(String key) { + RedisClusterCommands command = connectBytes(); + boolean rs = command.exists(key) > 0; + releaseBytesCommand(command); + return rs; + } + + //--------------------- get ------------------------------ + @Override + public CompletableFuture getAsync(String key, Type type) { + return connectBytesAsync().thenCompose(command -> { + CompletableFuture rf = completableBytesFuture(command, command.get(key)); + return rf.thenApply(bs -> decryptValue(key, cryptor, type, bs)); + }); + } + + @Override + public CompletableFuture getStringAsync(String key) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(key, cryptor, command, command.get(key)); + }); + } + + @Override + public CompletableFuture getSetStringAsync(String key, String value) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(key, cryptor, command, command.setGet(key, encryptValue(key, cryptor, value))); + }); + } + + @Override + public CompletableFuture getLongAsync(String key, long defValue) { + return connectStringAsync().thenCompose(command -> { + return completableLongFuture(command, command.get(key).thenApply(v -> v == null ? defValue : Long.parseLong(v))); + }); + } + + @Override + public CompletableFuture getSetLongAsync(String key, long value, long defValue) { + return connectStringAsync().thenCompose(command -> { + return completableLongFuture(command, command.setGet(key, String.valueOf(value)).thenApply(v -> v == null ? defValue : Long.parseLong(v))); + }); + } + + @Override + public T get(String key, final Type type) { + final RedisClusterCommands command = connectBytes(); + byte[] bs = command.get(key); + releaseBytesCommand(command); + return decryptValue(key, cryptor, type, bs); + } + + @Override + public T getSet(String key, final Type type, T value) { + final RedisClusterCommands command = connectBytes(); + byte[] bs = command.setGet(key, encryptValue(key, cryptor, type, convert, value)); + releaseBytesCommand(command); + return decryptValue(key, cryptor, type, bs); + } + + @Override + public T getSet(String key, Convert convert0, final Type type, T value) { + Convert c = convert0 == null ? this.convert : convert0; + final RedisClusterCommands command = connectBytes(); + byte[] bs = command.setGet(key, encryptValue(key, cryptor, type, c, value)); + releaseBytesCommand(command); + return decryptValue(key, cryptor, c, type, bs); + } + + @Override + public String getString(String key) { + final RedisClusterCommands command = connectString(); + String rs = command.get(key); + releaseStringCommand(command); + return cryptor != null ? cryptor.decrypt(key, rs) : rs; + } + + @Override + public String getSetString(String key, String value) { + final RedisClusterCommands command = connectString(); + String rs = command.setGet(key, encryptValue(key, cryptor, value)); + releaseStringCommand(command); + return decryptValue(key, cryptor, rs); + } + + @Override + public long getLong(String key, long defValue) { + final RedisClusterCommands command = connectString(); + final String v = command.get(key); + releaseStringCommand(command); + return v == null ? defValue : Long.parseLong(v); + } + + @Override + public long getSetLong(String key, long value, long defValue) { + final RedisClusterCommands command = connectString(); + final String v = command.setGet(key, String.valueOf(value)); + releaseStringCommand(command); + return v == null ? defValue : Long.parseLong(v); + } + + //--------------------- getex ------------------------------ + @Override + public CompletableFuture getexAsync(String key, int expireSeconds, final Type type) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.getex(key, GetExArgs.Builder.ex(expireSeconds)).thenApply(v -> decryptValue(key, cryptor, type, v))); + }); + } + + @Override + public T getex(String key, final int expireSeconds, final Type type) { + final RedisClusterCommands command = connectBytes(); + byte[] bs = command.getex(key, GetExArgs.Builder.ex(expireSeconds)); + releaseBytesCommand(command); + if (bs == null) { + return null; + } + return decryptValue(key, cryptor, type, bs); + } + + @Override + public CompletableFuture getexStringAsync(String key, int expireSeconds) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(key, null, command, command.getex(key, GetExArgs.Builder.ex(expireSeconds)).thenApply(v -> cryptor != null ? cryptor.decrypt(key, v) : v)); + }); + } + + @Override + public String getexString(String key, final int expireSeconds) { + final RedisClusterCommands command = connectString(); + String v = command.getex(key, GetExArgs.Builder.ex(expireSeconds)); + releaseStringCommand(command); + if (v == null) { + return null; + } + return cryptor != null ? cryptor.decrypt(key, v) : v; + } + + @Override + public CompletableFuture getexLongAsync(String key, int expireSeconds, long defValue) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableLongFuture(command, command.getex(key, GetExArgs.Builder.ex(expireSeconds)).thenApply(v -> v == null ? defValue : Long.parseLong(v))); + }); + } + + @Override + public long getexLong(String key, final int expireSeconds, long defValue) { + final RedisClusterCommands command = connectString(); + String v = command.getex(key, GetExArgs.Builder.ex(expireSeconds)); + releaseStringCommand(command); + if (v == null) { + return defValue; + } + return Long.parseLong(v); + } + +// //--------------------- setex ------------------------------ + @Override + public CompletableFuture msetAsync(final Object... keyVals) { + if (keyVals.length % 2 != 0) { + throw new RedkaleException("key value must be paired"); + } + Map map = new LinkedHashMap<>(); + for (int i = 0; i < keyVals.length; i += 2) { + String key = keyVals[i].toString(); + Object val = keyVals[i + 1]; + map.put(key, encryptValue(key, cryptor, convert, val)); + } + return connectBytesAsync().thenCompose(command -> completableBytesFuture(command, command.mset(map))); + } + + @Override + public CompletableFuture msetAsync(final Map map) { + if (map == null || map.isEmpty()) { + return CompletableFuture.completedFuture(null); + } + Map rs = new LinkedHashMap<>(); + map.forEach((key, val) -> { + rs.put(key.toString(), encryptValue(key.toString(), cryptor, convert, val)); + }); + return connectBytesAsync().thenCompose(command -> completableBytesFuture(command, command.mset(rs))); + } + + @Override + public CompletableFuture setAsync(String key, final Type type, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.set(key, encryptValue(key, cryptor, type, this.convert, value))); + }); + } + + @Override + public CompletableFuture setAsync(String key, Convert convert0, final Type type, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.set(key, encryptValue(key, cryptor, type, convert0, value))); + }); + } + + @Override + public CompletableFuture setnxAsync(String key, final Type type, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBoolFuture(command, command.setnx(key, encryptValue(key, cryptor, type, this.convert, value))); + }); + } + + @Override + public CompletableFuture setnxAsync(String key, Convert convert0, final Type type, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBoolFuture(command, command.setnx(key, encryptValue(key, cryptor, type, convert0, value))); + }); + } + + @Override + public CompletableFuture getSetAsync(String key, final Type type, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.setGet(key, encryptValue(key, cryptor, type, this.convert, value)) + .thenApply(old -> decryptValue(key, cryptor, type, old))); + }); + } + + @Override + public CompletableFuture getSetAsync(String key, Convert convert0, final Type type, T value) { + return connectBytesAsync().thenCompose(command -> { + Convert c = convert0 == null ? this.convert : convert0; + return completableBytesFuture(command, command.setGet(key, encryptValue(key, cryptor, type, c, value)) + .thenApply(old -> decryptValue(key, cryptor, c, type, old))); + }); + } + + @Override + public void mset(final Object... keyVals) { + if (keyVals.length % 2 != 0) { + throw new RedkaleException("key value must be paired"); + } + Map map = new LinkedHashMap<>(); + for (int i = 0; i < keyVals.length; i += 2) { + String key = keyVals[i].toString(); + Object val = keyVals[i + 1]; + map.put(key, encryptValue(key, cryptor, convert, val)); + } + final RedisClusterCommands command = connectBytes(); + command.mset(map); + releaseBytesCommand(command); + } + + @Override + public void mset(final Map map) { + if (map == null || map.isEmpty()) { + return; + } + Map rs = new LinkedHashMap<>(); + map.forEach((key, val) -> { + rs.put(key.toString(), encryptValue(key.toString(), cryptor, convert, val)); + }); + final RedisClusterCommands command = connectBytes(); + command.mset(rs); + releaseBytesCommand(command); + } + + @Override + public void set(final String key, final Type type, T value) { + final RedisClusterCommands command = connectBytes(); + command.set(key, encryptValue(key, cryptor, type, this.convert, value)); + releaseBytesCommand(command); + } + + @Override + public void set(String key, final Convert convert0, final Type type, T value) { + final RedisClusterCommands command = connectBytes(); + command.set(key, encryptValue(key, cryptor, type, convert0, value)); + releaseBytesCommand(command); + } + + @Override + public boolean setnx(final String key, final Type type, T value) { + final RedisClusterCommands command = connectBytes(); + Boolean rs = command.setnx(key, encryptValue(key, cryptor, type, this.convert, value)); + releaseBytesCommand(command); + return rs; + } + + @Override + public boolean setnx(String key, final Convert convert0, final Type type, T value) { + final RedisClusterCommands command = connectBytes(); + Boolean rs = command.setnx(key, encryptValue(key, cryptor, type, convert0, value)); + releaseBytesCommand(command); + return rs; + } + + @Override + public CompletableFuture setStringAsync(String key, String value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.set(key, encryptValue(key, cryptor, value))); + }); + } + + @Override + public CompletableFuture setnxStringAsync(String key, String value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableBoolFuture(key, null, command, command.setnx(key, encryptValue(key, cryptor, value))); + }); + } + + @Override + public void setString(String key, String value) { + final RedisClusterCommands command = connectString(); + command.set(key, encryptValue(key, cryptor, value)); + releaseStringCommand(command); + } + + @Override + public boolean setnxString(String key, String value) { + final RedisClusterCommands command = connectString(); + Boolean rs = command.setnx(key, encryptValue(key, cryptor, value)); + releaseStringCommand(command); + return rs; + } + + @Override + public CompletableFuture setLongAsync(String key, long value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.set(key, String.valueOf(value))); + }); + } + + @Override + public CompletableFuture setnxLongAsync(String key, long value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.setnx(key, String.valueOf(value))); + }); + } + + @Override + public void setLong(String key, long value) { + final RedisClusterCommands command = connectString(); + command.set(key, String.valueOf(value)); + releaseStringCommand(command); + } + + @Override + public boolean setnxLong(String key, long value) { + final RedisClusterCommands command = connectString(); + Boolean rs = command.setnx(key, String.valueOf(value)); + releaseStringCommand(command); + return rs; + } + + @Override + public boolean setnxBytes(final String key, final byte[] value) { + final RedisClusterCommands command = connectBytes(); + Boolean rs = command.setnx(key, value); + releaseBytesCommand(command); + return rs; + } + + @Override + public CompletableFuture setnxBytesAsync(String key, byte[] value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.setnx(key, value)); + }); + } + +// //--------------------- setex ------------------------------ + @Override + public CompletableFuture setexAsync(String key, int expireSeconds, final Type type, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.setex(key, expireSeconds, encryptValue(key, cryptor, type, convert, value)).thenApply(r -> null)); + + }); + } + + @Override + public CompletableFuture setnxexAsync(String key, int expireSeconds, final Type type, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.set(key, encryptValue(key, cryptor, type, convert, value), SetArgs.Builder.nx().ex(expireSeconds)).thenApply(r -> r != null && ("OK".equals(r) || Integer.parseInt(r) > 0))); + }); + } + + @Override + public CompletableFuture setexAsync(String key, int expireSeconds, Convert convert0, final Type type, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.setex(key, expireSeconds, encryptValue(key, cryptor, type, convert0, value)).thenApply(r -> null)); + }); + } + + @Override + public CompletableFuture setnxexAsync(String key, int expireSeconds, Convert convert0, final Type type, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.set(key, encryptValue(key, cryptor, type, convert0, value), SetArgs.Builder.nx().ex(expireSeconds)).thenApply(r -> r != null && ("OK".equals(r) || Integer.parseInt(r) > 0))); + }); + } + + @Override + public boolean setnxex(String key, int expireSeconds, final Type type, T value) { + final RedisClusterCommands command = connectBytes(); + String r = command.set(key, encryptValue(key, cryptor, type, convert, value), SetArgs.Builder.nx().ex(expireSeconds)); + releaseBytesCommand(command); + return r != null && ("OK".equals(r) || Integer.parseInt(r) > 0); + } + + @Override + public boolean setnxex(String key, int expireSeconds, Convert convert0, final Type type, T value) { + final RedisClusterCommands command = connectBytes(); + String r = command.set(key, encryptValue(key, cryptor, type, convert0, value), SetArgs.Builder.nx().ex(expireSeconds)); + releaseBytesCommand(command); + return r != null && ("OK".equals(r) || Integer.parseInt(r) > 0); + } + + @Override + public void setex(String key, int expireSeconds, final Type type, T value) { + final RedisClusterCommands command = connectBytes(); + command.setex(key, expireSeconds, encryptValue(key, cryptor, type, convert, value)); + releaseBytesCommand(command); + } + + @Override + public void setex(String key, int expireSeconds, Convert convert0, final Type type, T value) { + final RedisClusterCommands command = connectBytes(); + command.setex(key, expireSeconds, encryptValue(key, cryptor, type, convert0, value)); + releaseBytesCommand(command); + } + + @Override + public CompletableFuture setexStringAsync(String key, int expireSeconds, String value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.setex(key, expireSeconds, encryptValue(key, cryptor, value)).thenApply(r -> null)); + }); + } + + @Override + public CompletableFuture setnxexStringAsync(String key, int expireSeconds, String value) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(key, null, command, command.set(key, encryptValue(key, cryptor, value), SetArgs.Builder.nx().ex(expireSeconds)).thenApply(r -> r != null && ("OK".equals(r) || Integer.parseInt(r) > 0))); + }); + } + + @Override + public void setexString(String key, int expireSeconds, String value) { + final RedisClusterCommands command = connectString(); + command.setex(key, expireSeconds, encryptValue(key, cryptor, value)); + releaseStringCommand(command); + } + + @Override + public boolean setnxexString(String key, int expireSeconds, String value) { + final RedisClusterCommands command = connectString(); + String r = command.set(key, encryptValue(key, cryptor, value), SetArgs.Builder.nx().ex(expireSeconds)); + releaseStringCommand(command); + return r != null && ("OK".equals(r) || Integer.parseInt(r) > 0); + } + + @Override + public CompletableFuture setexLongAsync(String key, int expireSeconds, long value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.setex(key, expireSeconds, String.valueOf(value)).thenApply(r -> null)); + }); + } + + @Override + public CompletableFuture setnxexLongAsync(String key, int expireSeconds, long value) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(key, null, command, command.set(key, String.valueOf(value), SetArgs.Builder.nx().ex(expireSeconds)).thenApply(r -> r != null && ("OK".equals(r) || Integer.parseInt(r) > 0))); + }); + } + + @Override + public void setexLong(String key, int expireSeconds, long value) { + final RedisClusterCommands command = connectString(); + command.setex(key, expireSeconds, String.valueOf(value)); + releaseStringCommand(command); + } + + @Override + public boolean setnxexLong(String key, int expireSeconds, long value) { + final RedisClusterCommands command = connectString(); + String r = command.set(key, String.valueOf(value), SetArgs.Builder.nx().ex(expireSeconds)); + releaseStringCommand(command); + return r != null && ("OK".equals(r) || Integer.parseInt(r) > 0); + } + +// //--------------------- expire ------------------------------ + @Override + public CompletableFuture expireAsync(String key, int expireSeconds) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.expire(key, Duration.ofSeconds(expireSeconds)).thenApply(r -> null)); + }); + } + + @Override + public void expire(String key, int expireSeconds) { + final RedisClusterCommands command = connectBytes(); + command.expire(key, Duration.ofSeconds(expireSeconds)); + releaseBytesCommand(command); + } + +// //--------------------- del ------------------------------ + @Override + public CompletableFuture delAsync(String... keys) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.del(keys).thenApply(rs -> rs > 0 ? 1 : 0)); + }); + } + + @Override + public int del(String... keys) { + final RedisClusterCommands command = connectBytes(); + int rs = command.del(keys).intValue(); + releaseBytesCommand(command); + return rs; + } + +// //--------------------- incrby ------------------------------ + @Override + public long incr(final String key) { + final RedisClusterCommands command = connectBytes(); + long rs = command.incr(key); + releaseBytesCommand(command); + return rs; + } + + @Override + public CompletableFuture incrAsync(final String key) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.incr(key)); + }); + } + + @Override + public long incrby(final String key, long num) { + final RedisClusterCommands command = connectBytes(); + long rs = command.incrby(key, num); + releaseBytesCommand(command); + return rs; + } + + @Override + public double incrbyFloat(final String key, double num) { + final RedisClusterCommands command = connectBytes(); + Double rs = command.incrbyfloat(key, num); + releaseBytesCommand(command); + return rs; + } + + @Override + public CompletableFuture incrbyAsync(final String key, long num) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.incrby(key, num)); + }); + } + + @Override + public CompletableFuture incrbyFloatAsync(final String key, double num) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.incrbyfloat(key, num)); + }); + } +// //--------------------- decrby ------------------------------ + + @Override + public long decr(final String key) { + final RedisClusterCommands command = connectBytes(); + long rs = command.decr(key); + releaseBytesCommand(command); + return rs; + } + + @Override + public CompletableFuture decrAsync(final String key) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.decr(key)); + }); + } + + @Override + public long decrby(final String key, long num) { + final RedisClusterCommands command = connectBytes(); + long rs = command.decrby(key, num); + releaseBytesCommand(command); + return rs; + } + + @Override + public CompletableFuture decrbyAsync(final String key, long num) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.decrby(key, num)); + }); + } + + @Override + public int hdel(final String key, String... fields) { + final RedisClusterCommands command = connectBytes(); + int rs = command.hdel(key, fields).intValue(); + releaseBytesCommand(command); + return rs; + } + + @Override + public int hlen(final String key) { + final RedisClusterCommands command = connectBytes(); + int rs = command.hlen(key).intValue(); + releaseBytesCommand(command); + return rs; + } + + @Override + public List hkeys(final String key) { + final RedisClusterCommands command = connectString(); + List rs = command.hkeys(key); + releaseStringCommand(command); + return rs; + } + + @Override + public long hincr(final String key, String field) { + final RedisClusterCommands command = connectString(); + long rs = command.hincrby(key, field, 1L); + releaseStringCommand(command); + return rs; + } + + @Override + public long hincrby(final String key, String field, long num) { + final RedisClusterCommands command = connectString(); + long rs = command.hincrby(key, field, num); + releaseStringCommand(command); + return rs; + } + + @Override + public double hincrbyFloat(final String key, String field, double num) { + final RedisClusterCommands command = connectString(); + double rs = command.hincrbyfloat(key, field, num); + releaseStringCommand(command); + return rs; + } + + @Override + public long hdecr(final String key, String field) { + final RedisClusterCommands command = connectString(); + long rs = command.hincrby(key, field, -1L); + releaseStringCommand(command); + return rs; + } + + @Override + public long hdecrby(final String key, String field, long num) { + final RedisClusterCommands command = connectString(); + long rs = command.hincrby(key, field, -num); + releaseStringCommand(command); + return rs; + } + + @Override + public boolean hexists(final String key, String field) { + final RedisClusterCommands command = connectBytes(); + boolean rs = command.hget(key, field) != null; + releaseBytesCommand(command); + return rs; + } + +// //--------------------- dbsize ------------------------------ + @Override + public long dbsize() { + final RedisClusterCommands command = connectBytes(); + Long rs = command.dbsize(); + releaseBytesCommand(command); + return rs; + } + + @Override + public CompletableFuture dbsizeAsync() { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.dbsize()); + }); + } + + @Override + public void hset(final String key, final String field, final Type type, final T value) { + if (value == null) { + return; + } + final RedisClusterCommands command = connectBytes(); + command.hset(key, field, encryptValue(key, cryptor, type, this.convert, value)); + releaseBytesCommand(command); + } + + @Override + public void hset(final String key, final String field, final Convert convert0, final Type type, final T value) { + if (value == null) { + return; + } + final RedisClusterCommands command = connectBytes(); + command.hset(key, field, encryptValue(key, cryptor, type, convert0, value)); + releaseBytesCommand(command); + } + + @Override + public void hsetString(final String key, final String field, final String value) { + if (value == null) { + return; + } + final RedisClusterCommands command = connectString(); + command.hset(key, field, encryptValue(key, cryptor, value)); + releaseStringCommand(command); + } + + @Override + public void hsetLong(final String key, final String field, final long value) { + final RedisClusterCommands command = connectString(); + command.hset(key, field, String.valueOf(value)); + releaseStringCommand(command); + } + + @Override + public boolean hsetnx(final String key, final String field, final Type type, final T value) { + if (value == null) { + return false; + } + final RedisClusterCommands command = connectBytes(); + Boolean rs = command.hsetnx(key, field, encryptValue(key, cryptor, type, this.convert, value)); + releaseBytesCommand(command); + return rs; + } + + @Override + public boolean hsetnx(final String key, final String field, final Convert convert0, final Type type, final T value) { + if (value == null) { + return false; + } + final RedisClusterCommands command = connectBytes(); + Boolean rs = command.hsetnx(key, field, encryptValue(key, cryptor, type, convert0, value)); + releaseBytesCommand(command); + return rs; + } + + @Override + public boolean hsetnxString(final String key, final String field, final String value) { + if (value == null) { + return false; + } + final RedisClusterCommands command = connectString(); + Boolean rs = command.hsetnx(key, field, encryptValue(key, cryptor, value)); + releaseStringCommand(command); + return rs; + } + + @Override + public boolean hsetnxLong(final String key, final String field, final long value) { + final RedisClusterCommands command = connectString(); + Boolean rs = command.hsetnx(key, field, String.valueOf(value)); + releaseStringCommand(command); + return rs; + } + + @Override + public void hmset(final String key, final Serializable... values) { + Map vals = new LinkedHashMap<>(); + for (int i = 0; i < values.length; i += 2) { + byte[] bs; + if (cryptor != null && values[i + 1] != null) { + bs = values[i + 1] instanceof String ? cryptor.encrypt(key, values[i + 1].toString()).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, values[i + 1].getClass(), this.convert, values[i + 1]); + } else { + bs = values[i + 1] instanceof String ? values[i + 1].toString().getBytes(StandardCharsets.UTF_8) : this.convert.convertToBytes(values[i + 1]); + } + vals.put(String.valueOf(values[i]), bs); + } + final RedisClusterCommands command = connectBytes(); + command.hmset(key, vals); + releaseBytesCommand(command); + } + + @Override + public void hmset(final String key, final Map map) { + Map vals = new LinkedHashMap<>(); + map.forEach((k, v) -> { + byte[] bs; + if (cryptor != null && v != null) { + bs = v instanceof String ? cryptor.encrypt(key, v.toString()).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, v.getClass(), this.convert, v); + } else { + bs = v instanceof String ? v.toString().getBytes(StandardCharsets.UTF_8) : this.convert.convertToBytes(v); + } + vals.put(k.toString(), bs); + }); + final RedisClusterCommands command = connectBytes(); + command.hmset(key, vals); + releaseBytesCommand(command); + } + + @Override + public List hmget(final String key, final Type type, final String... fields) { + final RedisClusterCommands command = connectBytes(); + List> rs = command.hmget(key, fields); + releaseBytesCommand(command); + List list = new ArrayList<>(fields.length); + for (String field : fields) { + byte[] bs = null; + for (KeyValue kv : rs) { + if (kv.getKey().equals(field)) { + bs = kv.hasValue() ? kv.getValue() : null; + break; + } + } + if (bs == null) { + list.add(null); + } else { + list.add(decryptValue(key, cryptor, type, bs)); + } + } + return list; + } + + @Override + public Map hmap(final String key, final Type type, int offset, int limit, String pattern) { + final RedisClusterCommands command = connectBytes(); + ScanArgs args = ScanArgs.Builder.limit(limit); + if (pattern != null) { + args = args.match(pattern); + } + MapScanCursor rs = command.hscan(key, new ScanCursor(String.valueOf(offset), false), args); + releaseBytesCommand(command); + final Map map = new LinkedHashMap<>(); + rs.getMap().forEach((k, v) -> map.put(k, decryptValue(key, cryptor, type, v))); + return map; + } + + @Override + public Map hmap(final String key, final Type type, int offset, int limit) { + return hmap(key, type, offset, limit, null); + } + + @Override + public T hget(final String key, final String field, final Type type) { + final RedisClusterCommands command = connectBytes(); + byte[] bs = command.hget(key, field); + releaseBytesCommand(command); + return decryptValue(key, cryptor, type, bs); + } + + @Override + public String hgetString(final String key, final String field) { + final RedisClusterCommands command = connectString(); + String rs = command.hget(key, field); + releaseStringCommand(command); + return cryptor != null ? cryptor.decrypt(key, rs) : rs; + } + + @Override + public long hgetLong(final String key, final String field, long defValue) { + final RedisClusterCommands command = connectString(); + String rs = command.hget(key, field); + releaseStringCommand(command); + if (rs == null) { + return defValue; + } + try { + return Long.parseLong(rs); + } catch (NumberFormatException e) { + return defValue; + } + } + + @Override + public Map mget(final Type componentType, final String... keys) { + final RedisClusterCommands command = connectBytes(); + List> rs = command.mget(keys); + releaseBytesCommand(command); + Map map = new LinkedHashMap(rs.size()); + rs.forEach(kv -> { + if (kv.hasValue()) { + map.put(kv.getKey(), decryptValue(kv.getKey(), cryptor, componentType, kv.getValue())); + } + }); + return map; + } + + @Override + public Map mgetBytes(final String... keys) { + final RedisClusterCommands command = connectBytes(); + List> rs = command.mget(keys); + releaseBytesCommand(command); + Map map = new LinkedHashMap(rs.size()); + rs.forEach(kv -> { + if (kv.hasValue()) { + map.put(kv.getKey(), decryptValue(kv.getKey(), cryptor, byte[].class, kv.getValue())); + } + }); + return map; + } + + @Override + public Set smembers(String key, final Type componentType) { + final RedisClusterCommands command = connectBytes(); + Set rs = formatCollection(key, cryptor, command.smembers(key), convert, componentType); + releaseBytesCommand(command); + return rs; + } + + @Override + public List lrange(String key, final Type componentType) { + final RedisClusterCommands command = connectBytes(); + List rs = formatCollection(key, cryptor, command.lrange(key, 0, -1), convert, componentType); + releaseBytesCommand(command); + return rs; + } + + protected Collection getCollection(final RedisClusterCommands command, String key, final Type componentType) { + final String type = command.type(key); + if (type.contains("list")) { + return formatCollection(key, cryptor, command.lrange(key, 0, -1), convert, componentType); + } else { //set + return formatCollection(key, cryptor, command.smembers(key), convert, componentType); + } + } + + @Override + public Map> smembers(final Type componentType, String... keys) { + final RedisClusterCommands command = connectBytes(); + final Map> map = new LinkedHashMap<>(); + for (String key : keys) { + map.put(key, formatCollection(key, cryptor, command.smembers(key), convert, componentType)); + } + releaseBytesCommand(command); + return map; + } + + @Override + public Map> lrange(final Type componentType, String... keys) { + final RedisClusterCommands command = connectBytes(); + final Map> map = new LinkedHashMap<>(); + for (String key : keys) { + map.put(key, formatCollection(key, cryptor, command.lrange(key, 0, -1), convert, componentType)); + } + releaseBytesCommand(command); + return map; + } + + @Override + public int llen(String key) { + final RedisClusterCommands command = connectBytes(); + int rs = command.llen(key).intValue(); + releaseBytesCommand(command); + return rs; + } + + @Override + public int scard(String key) { + final RedisClusterCommands command = connectBytes(); + int rs = command.scard(key).intValue(); + releaseBytesCommand(command); + return rs; + } + + @Override + @SuppressWarnings({"ConfusingArrayVararg", "PrimitiveArrayArgumentToVariableArgMethod"}) + public void rpush(String key, final Type componentType, T value) { + final RedisClusterCommands command = connectBytes(); + byte[] bs; + if (cryptor != null && componentType == String.class) { + bs = cryptor.encrypt(key, String.valueOf(value)).getBytes(StandardCharsets.UTF_8); + } else { + bs = encryptValue(key, cryptor, componentType, convert, value); + } + command.rpush(key, bs); + releaseBytesCommand(command); + } + + @Override + public int lrem(String key, final Type componentType, T value) { + final RedisClusterCommands command = connectBytes(); + byte[] bs; + if (cryptor != null && componentType == String.class) { + bs = cryptor.encrypt(key, String.valueOf(value)).getBytes(StandardCharsets.UTF_8); + } else { + bs = encryptValue(key, cryptor, componentType, convert, value); + } + int rs = command.lrem(key, 1L, bs).intValue(); + releaseBytesCommand(command); + return rs; + } + + @Override + public boolean sismember(String key, final Type componentType, T value) { + final RedisClusterCommands command = connectBytes(); + byte[] bs; + if (cryptor != null && componentType == String.class) { + bs = cryptor.encrypt(key, String.valueOf(value)).getBytes(StandardCharsets.UTF_8); + } else { + bs = encryptValue(key, cryptor, componentType, convert, value); + } + boolean rs = command.sismember(key, bs); + releaseBytesCommand(command); + return rs; + } + + @Override + @SuppressWarnings({"ConfusingArrayVararg", "PrimitiveArrayArgumentToVariableArgMethod"}) + public void sadd(String key, final Type componentType, T value) { + final RedisClusterCommands command = connectBytes(); + byte[] bs; + if (cryptor != null && componentType == String.class) { + bs = cryptor.encrypt(key, String.valueOf(value)).getBytes(StandardCharsets.UTF_8); + } else { + bs = encryptValue(key, cryptor, componentType, convert, value); + } + command.sadd(key, bs); + releaseBytesCommand(command); + } + + @Override + @SuppressWarnings({"ConfusingArrayVararg", "PrimitiveArrayArgumentToVariableArgMethod"}) + public int srem(String key, final Type componentType, T value) { + final RedisClusterCommands command = connectBytes(); + byte[] bs; + if (cryptor != null && componentType == String.class) { + bs = cryptor.encrypt(key, String.valueOf(value)).getBytes(StandardCharsets.UTF_8); + } else { + bs = encryptValue(key, cryptor, componentType, convert, value); + } + int rs = command.srem(key, bs).intValue(); + releaseBytesCommand(command); + return rs; + } + + @Override + public T spop(String key, final Type componentType) { + final RedisClusterCommands command = connectBytes(); + T rs = decryptValue(key, cryptor, componentType, command.spop(key)); + releaseBytesCommand(command); + return rs; + } + + @Override + public Set spop(String key, int count, final Type componentType) { + final RedisClusterCommands command = connectBytes(); + Set rs = formatCollection(key, cryptor, command.spop(key, count), convert, componentType); + releaseBytesCommand(command); + return rs; + } + + @Override + public byte[] getBytes(final String key) { + final RedisClusterCommands command = connectBytes(); + byte[] bs = command.get(key); + releaseBytesCommand(command); + return bs; + } + + @Override + public byte[] getSetBytes(final String key, byte[] value) { + final RedisClusterCommands command = connectBytes(); + byte[] bs = command.setGet(key, value); + releaseBytesCommand(command); + return bs; + } + + @Override + public byte[] getexBytes(final String key, final int expireSeconds) { + final RedisClusterCommands command = connectBytes(); + byte[] bs = command.getex(key, GetExArgs.Builder.ex(expireSeconds)); + releaseBytesCommand(command); + return bs; + } + + @Override + public void setBytes(final String key, final byte[] value) { + final RedisClusterCommands command = connectBytes(); + command.set(key, value); + releaseBytesCommand(command); + } + + @Override + public void setexBytes(final String key, final int expireSeconds, final byte[] value) { + final RedisClusterCommands command = connectBytes(); + command.setex(key, expireSeconds, value); + releaseBytesCommand(command); + } + + @Override + public boolean setnxexBytes(final String key, final int expireSeconds, final byte[] value) { + final RedisClusterCommands command = connectBytes(); + String r = command.set(key, value, SetArgs.Builder.nx().ex(expireSeconds)); + releaseBytesCommand(command); + return r != null && ("OK".equals(r) || Integer.parseInt(r) > 0); + } + + @Override + public List keys(String pattern) { + final RedisClusterCommands command = connectBytes(); + List rs = command.keys(pattern == null || pattern.isEmpty() ? "*" : pattern); + releaseBytesCommand(command); + return rs; + } + + @Override + public Map mgetString(final String... keys) { + final RedisClusterCommands command = connectString(); + List> rs = command.mget(keys); + releaseStringCommand(command); + Map map = new LinkedHashMap<>(); + rs.forEach(kv -> { + if (kv.hasValue()) { + map.put(kv.getKey(), cryptor != null ? cryptor.decrypt(kv.getKey(), kv.getValue()) : kv.getValue()); + } + }); + return map; + } + + protected Collection decryptStringCollection(String key, final boolean set, Collection collection) { + if (collection == null || collection.isEmpty() || cryptor == null) { + return collection; + } + if (set) { + Set newset = new LinkedHashSet<>(); + for (String value : collection) { + newset.add(cryptor.decrypt(key, value)); + } + return newset; + } else { + List newlist = new ArrayList<>(); + for (String value : collection) { + newlist.add(cryptor.decrypt(key, value)); + } + return newlist; + } + } + + protected Collection getStringCollection(final RedisClusterCommands command, String key) { + final String type = command.type(key); + if (type.contains("list")) { //list + return decryptStringCollection(key, false, command.lrange(key, 0, -1)); + } else { //set + return decryptStringCollection(key, true, command.smembers(key)); + } + } + + @Override + public void rpushString(String key, String value) { + final RedisClusterCommands command = connectString(); + command.rpush(key, encryptValue(key, cryptor, value)); + releaseStringCommand(command); + } + + @Override + public String spopString(String key) { + final RedisClusterCommands command = connectString(); + String rs = command.spop(key); + releaseStringCommand(command); + return cryptor != null ? cryptor.encrypt(key, rs) : rs; + } + + @Override + public Set spopString(String key, int count) { + final RedisClusterCommands command = connectString(); + Set rs = command.spop(key, count); + releaseStringCommand(command); + return (Set) decryptStringCollection(key, true, rs); + } + + @Override + public int lremString(String key, String value) { + final RedisClusterCommands command = connectString(); + int rs = command.lrem(key, 1, encryptValue(key, cryptor, value)).intValue(); + releaseStringCommand(command); + return rs; + } + + @Override + public boolean sismemberString(String key, String value) { + final RedisClusterCommands command = connectString(); + boolean rs = command.sismember(key, encryptValue(key, cryptor, value)); + releaseStringCommand(command); + return rs; + } + + @Override + public void saddString(String key, String value) { + final RedisClusterCommands command = connectString(); + command.sadd(key, encryptValue(key, cryptor, value)); + releaseStringCommand(command); + } + + @Override + public int sremString(String key, String value) { + final RedisClusterCommands command = connectString(); + int rs = command.srem(key, encryptValue(key, cryptor, value)).intValue(); + releaseStringCommand(command); + return rs; + } + + @Override + public Map mgetLong(String... keys) { + final RedisClusterCommands command = connectString(); + List> rs = command.mget(keys); + releaseStringCommand(command); + Map map = new LinkedHashMap<>(); + rs.forEach(kv -> { + if (kv.hasValue()) { + map.put(kv.getKey(), Long.parseLong(kv.getValue())); + } + }); + return map; + } + + @Override + public void rpushLong(String key, long value) { + final RedisClusterCommands command = connectString(); + command.rpush(key, String.valueOf(value)); + releaseStringCommand(command); + } + + @Override + public Long spopLong(String key) { + final RedisClusterCommands command = connectString(); + String value = command.spop(key); + releaseStringCommand(command); + return value == null ? null : Long.parseLong(value); + } + + @Override + public Set spopLong(String key, int count) { + final RedisClusterCommands command = connectString(); + Set rs = (Set) formatLongCollection(true, command.spop(key, count)); + releaseStringCommand(command); + return rs; + } + + @Override + public int lremLong(String key, long value) { + final RedisClusterCommands command = connectString(); + int rs = command.lrem(key, 1, String.valueOf(value)).intValue(); + releaseStringCommand(command); + return rs; + } + + @Override + public boolean sismemberLong(String key, long value) { + final RedisClusterCommands command = connectString(); + boolean rs = command.sismember(key, String.valueOf(value)); + releaseStringCommand(command); + return rs; + } + + @Override + public void saddLong(String key, long value) { + final RedisClusterCommands command = connectString(); + command.sadd(key, String.valueOf(value)); + releaseStringCommand(command); + } + + @Override + public int sremLong(String key, long value) { + final RedisClusterCommands command = connectString(); + int rs = command.srem(key, String.valueOf(value)).intValue(); + releaseStringCommand(command); + return rs; + } + + @Override + public CompletableFuture hdelAsync(String key, String... fields) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hdel(key, fields)); + }); + } + + @Override + public CompletableFuture> hkeysAsync(String key) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hkeys(key)); + }); + } + + @Override + public CompletableFuture hlenAsync(String key) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hlen(key)); + }); + } + + @Override + public CompletableFuture hincrAsync(String key, String field) { + return hincrbyAsync(key, field, 1); + } + + @Override + public CompletableFuture hincrbyAsync(String key, String field, long num) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.hincrby(key, field, num)); + }); + } + + @Override + public CompletableFuture hincrbyFloatAsync(String key, String field, double num) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.hincrbyfloat(key, field, num)); + }); + } + + @Override + public CompletableFuture hdecrAsync(String key, String field) { + return hincrbyAsync(key, field, -1); + } + + @Override + public CompletableFuture hdecrbyAsync(String key, String field, long num) { + return hincrbyAsync(key, field, -num); + } + + @Override + public CompletableFuture hexistsAsync(String key, String field) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hexists(key, field)); + }); + } + + @Override + public CompletableFuture hsetAsync(String key, String field, Type type, T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hset(key, field, convert.convertToBytes(type, value))); + }); + } + + @Override + public CompletableFuture hsetAsync(String key, String field, Convert convert0, Type type, T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hset(key, field, (convert0 == null ? convert : convert0).convertToBytes(type, value))); + }); + } + + @Override + public CompletableFuture hsetStringAsync(String key, String field, String value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.hset(key, field, value)); + }); + } + + @Override + public CompletableFuture hsetLongAsync(String key, String field, long value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.hset(key, field, String.valueOf(value))); + }); + } + + @Override + public CompletableFuture hsetnxAsync(String key, String field, Type type, T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hsetnx(key, field, convert.convertToBytes(type, value))); + }); + } + + @Override + public CompletableFuture hsetnxAsync(String key, String field, Convert convert0, Type type, T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hsetnx(key, field, (convert0 == null ? convert : convert0).convertToBytes(type, value))); + }); + } + + @Override + public CompletableFuture hsetnxStringAsync(String key, String field, String value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.hsetnx(key, field, value)); + }); + } + + @Override + public CompletableFuture hsetnxLongAsync(String key, String field, long value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.hsetnx(key, field, String.valueOf(value))); + }); + } + + @Override + public CompletableFuture hmsetAsync(String key, Serializable... values) { + Map vals = new LinkedHashMap<>(); + for (int i = 0; i < values.length; i += 2) { + byte[] bs; + if (cryptor != null && values[i + 1] != null) { + bs = values[i + 1] instanceof String ? cryptor.encrypt(key, values[i + 1].toString()).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, values[i + 1].getClass(), this.convert, values[i + 1]); + } else { + bs = values[i + 1] instanceof String ? values[i + 1].toString().getBytes(StandardCharsets.UTF_8) : this.convert.convertToBytes(values[i + 1]); + } + vals.put(String.valueOf(values[i]), bs); + } + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hmset(key, vals)); + }); + } + + @Override + public CompletableFuture hmsetAsync(String key, Map map) { + Map vals = new LinkedHashMap<>(); + map.forEach((k, v) -> { + byte[] bs; + if (cryptor != null && v != null) { + bs = v instanceof String ? cryptor.encrypt(key, v.toString()).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, v.getClass(), this.convert, v); + } else { + bs = v instanceof String ? v.toString().getBytes(StandardCharsets.UTF_8) : this.convert.convertToBytes(v); + } + vals.put(k.toString(), bs); + }); + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hmset(key, vals)); + }); + } + + @Override + public CompletableFuture> hmgetAsync(String key, Type type, String... fields) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hmget(key, fields).thenApply((List> rs) -> { + List list = new ArrayList<>(fields.length); + for (String field : fields) { + byte[] bs = null; + for (KeyValue kv : rs) { + if (kv.getKey().equals(field)) { + bs = kv.hasValue() ? kv.getValue() : null; + break; + } + } + if (bs == null) { + list.add(null); + } else { + list.add(decryptValue(key, cryptor, type, bs)); + } + } + return list; + })); + }); + } + + @Override + public CompletableFuture> hmapAsync(String key, Type type, int offset, int limit) { + return hmapAsync(key, type, offset, limit, null); + } + + @Override + public CompletableFuture> hmapAsync(String key, Type type, int offset, int limit, String pattern) { + return connectBytesAsync().thenCompose(command -> { + ScanArgs args = ScanArgs.Builder.limit(limit); + if (pattern != null) { + args = args.match(pattern); + } + return completableBytesFuture(command, command.hscan(key, new ScanCursor(String.valueOf(offset), false), args).thenApply((MapScanCursor rs) -> { + final Map map = new LinkedHashMap<>(); + rs.getMap().forEach((k, v) -> map.put(k, v == null ? null : decryptValue(key, cryptor, type, v))); + return map; + })); + }); + } + + @Override + public CompletableFuture hgetAsync(String key, String field, Type type) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.hget(key, field).thenApply(bs -> bs == null ? null : decryptValue(key, cryptor, type, bs))); + }); + } + + @Override + public CompletableFuture hgetStringAsync(String key, String field) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(key, cryptor, command, command.hget(key, field)); + }); + } + + @Override + public CompletableFuture hgetLongAsync(String key, String field, long defValue) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.hget(key, field).thenApply(bs -> bs == null ? defValue : Long.parseLong(bs))); + }); + } + + @Override + public CompletableFuture> mgetAsync(Type componentType, String... keys) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.mget(keys).thenApply((List> rs) -> { + Map map = new LinkedHashMap(rs.size()); + rs.forEach(kv -> { + if (kv.hasValue()) { + map.put(kv.getKey(), decryptValue(kv.getKey(), cryptor, componentType, kv.getValue())); + } + }); + return map; + })); + }); + } + + @Override + public CompletableFuture> mgetBytesAsync(String... keys) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.mget(keys).thenApply((List> rs) -> { + Map map = new LinkedHashMap(rs.size()); + rs.forEach(kv -> { + if (kv.hasValue()) { + map.put(kv.getKey(), decryptValue(kv.getKey(), cryptor, byte[].class, kv.getValue())); + } + }); + return map; + })); + }); + } + + @Override + public CompletableFuture> smembersAsync(String key, final Type componentType) { + return connectBytesAsync().thenCompose(command -> { + return command.smembers(key).thenApply(set -> formatCollection(key, cryptor, set, convert, componentType)); + }); + } + + @Override + public CompletableFuture> lrangeAsync(String key, final Type componentType) { + return connectBytesAsync().thenCompose(command -> { + return command.lrange(key, 0, -1).thenApply(list -> formatCollection(key, cryptor, list, convert, componentType)); + }); + } + + protected CompletableFuture> getCollectionAsync( + final RedisClusterAsyncCommands command, String key, final Type componentType) { + return completableBytesFuture(command, command.type(key).thenCompose(type -> { + if (type.contains("list")) { + return command.lrange(key, 0, -1).thenApply(list -> formatCollection(key, cryptor, list, convert, componentType)); + } else { //set + return command.smembers(key).thenApply(set -> formatCollection(key, cryptor, set, convert, componentType)); + } + })); + } + + @Override + public CompletableFuture>> lrangeAsync(Type componentType, String... keys) { + return connectBytesAsync().thenCompose(command -> { + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = command.lrange(key, 0, -1).thenAccept(rs -> { + if (rs != null) { + mapLock.lock(); + try { + map.put(key, formatCollection(key, cryptor, rs, convert, componentType)); + } finally { + mapLock.unlock(); + } + } + }).toCompletableFuture(); + } + return CompletableFuture.allOf(futures).thenApply(v -> map); + }); + } + + @Override + public CompletableFuture>> smembersAsync(Type componentType, String... keys) { + return connectBytesAsync().thenCompose(command -> { + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = command.smembers(key).thenAccept(rs -> { + if (rs != null) { + mapLock.lock(); + try { + map.put(key, formatCollection(key, cryptor, rs, convert, componentType)); + } finally { + mapLock.unlock(); + } + } + }).toCompletableFuture(); + } + return CompletableFuture.allOf(futures).thenApply(v -> map); + }); + } + + @Override + public CompletableFuture llenAsync(String key) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.type(key).thenCompose(type -> { + return command.llen(key).thenApply(v -> v.intValue()); + })); + }); + } + + @Override + public CompletableFuture scardAsync(String key) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.type(key).thenCompose(type -> { + return command.scard(key).thenApply(v -> v.intValue()); + })); + }); + } + + @Override + public CompletableFuture spopAsync(String key, Type componentType) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.spop(key).thenApply(bs -> bs == null ? null : decryptValue(key, cryptor, componentType, bs))); + }); + } + + @Override + public CompletableFuture> spopAsync(String key, int count, Type componentType) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.spop(key, count).thenApply(v -> formatCollection(key, cryptor, v, convert, componentType))); + }); + } + + @Override + public CompletableFuture rpushAsync(String key, Type componentType, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.rpush(key, encryptValue(key, cryptor, componentType, convert.convertToBytes(componentType, value)))); + }); + } + + @Override + public CompletableFuture lremAsync(String key, Type componentType, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.lrem(key, 1, encryptValue(key, cryptor, componentType, convert.convertToBytes(componentType, value))).thenApply(v -> v.intValue())); + }); + } + + @Override + public CompletableFuture sismemberAsync(String key, Type componentType, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.sismember(key, encryptValue(key, cryptor, componentType, convert.convertToBytes(componentType, value)))); + }); + } + + @Override + @SuppressWarnings({"ConfusingArrayVararg", "PrimitiveArrayArgumentToVariableArgMethod"}) + public CompletableFuture saddAsync(String key, Type componentType, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.sadd(key, encryptValue(key, cryptor, componentType, convert.convertToBytes(componentType, value)))); + }); + } + + @Override + public CompletableFuture sremAsync(String key, Type componentType, T value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.srem(key, encryptValue(key, cryptor, componentType, convert.convertToBytes(componentType, value))).thenApply(v -> v.intValue())); + }); + } + + @Override + public CompletableFuture getBytesAsync(String key) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.get(key)); + }); + } + + @Override + public CompletableFuture getSetBytesAsync(String key, byte[] value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.setGet(key, value)); + }); + } + + @Override + public CompletableFuture getexBytesAsync(String key, int expireSeconds) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.expire(key, expireSeconds).thenCompose(v -> command.get(key))); + }); + } + + @Override + public CompletableFuture setBytesAsync(String key, byte[] value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.set(key, value)); + }); + } + + @Override + public CompletableFuture setexBytesAsync(String key, int expireSeconds, byte[] value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.setex(key, expireSeconds, value)); + }); + } + + @Override + public CompletableFuture setnxexBytesAsync(String key, int expireSeconds, byte[] value) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.set(key, value, SetArgs.Builder.nx().ex(expireSeconds)).thenApply(r -> r != null && ("OK".equals(r) || Integer.parseInt(r) > 0))); + }); + } + + @Override + public CompletableFuture> keysAsync(String pattern) { + return connectStringAsync().thenCompose(command -> { + //此处获取key值,无需传cryptor进行解密 + return completableStringFuture(null, null, command, command.keys(pattern == null || pattern.isEmpty() ? "*" : pattern)); + }); + } + + @Override + public CompletableFuture> mgetStringAsync(String... keys) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(null, null, command, command.mget(keys).thenApply((List> rs) -> { + Map map = new LinkedHashMap<>(); + rs.forEach(kv -> { + if (kv.hasValue()) { + map.put(kv.getKey(), cryptor != null ? cryptor.decrypt(kv.getKey(), kv.getValue()) : kv.getValue()); + } + }); + return map; + })); + }); + } + + protected CompletableFuture> getStringCollectionAsync(CompletableFuture> commandFuture, String key) { + return commandFuture.thenCompose(command -> getStringCollectionAsync(command, key)); + } + + protected CompletableFuture> getStringCollectionAsync(RedisClusterAsyncCommands command, String key) { + return completableStringFuture(key, null, command, command.type(key).thenApply(type -> { + if (type.contains("list")) { + return command.lrange(key, 0, -1).thenApply(list -> formatStringCollection(key, cryptor, false, list)); + } else { //set + return command.smembers(key).thenApply(list -> formatStringCollection(key, cryptor, true, list)); + } + })); + } + + @Override + public CompletableFuture rpushStringAsync(String key, String value) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(key, null, command, command.rpush(key, encryptValue(key, cryptor, value))); + }); + } + + @Override + public CompletableFuture spopStringAsync(String key) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(key, cryptor, command, command.spop(key)); + }); + } + + @Override + public CompletableFuture> spopStringAsync(String key, int count) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(key, null, command, command.spop(key, count).thenApply(list -> formatStringCollection(key, cryptor, true, list))); + }); + } + + @Override + public CompletableFuture lremStringAsync(String key, String value) { + return connectStringAsync().thenCompose(command -> { + //此处获取的int值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.lrem(key, 1, value).thenApply(v -> v.intValue())); + }); + } + + @Override + public CompletableFuture sismemberStringAsync(String key, String value) { + return connectStringAsync().thenCompose(command -> { + //此处获取的boolean值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.sismember(key, value)); + }); + } + + @Override + public CompletableFuture saddStringAsync(String key, String value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.sadd(key, value)); + }); + } + + @Override + public CompletableFuture sremStringAsync(String key, String value) { + return connectStringAsync().thenCompose(command -> { + //此处获取的int值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.srem(key, value).thenApply(v -> v.intValue())); + }); + } + + @Override + public CompletableFuture> mgetLongAsync(String... keys) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(keys[0], null, command, command.mget(keys).thenApply((List> rs) -> { + Map map = new LinkedHashMap<>(); + rs.forEach(kv -> { + if (kv.hasValue()) { + map.put(kv.getKey(), Long.parseLong(kv.getValue())); + } + }); + return map; + })); + }); + } + + protected CompletableFuture> getLongCollectionAsync(final CompletableFuture> commandFuture, String key) { + return commandFuture.thenCompose(command -> getLongCollectionAsync(command, key)); + } + + protected CompletableFuture> getLongCollectionAsync(final RedisClusterAsyncCommands command, String key) { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.type(key).thenApply(type -> { + if (type.contains("list")) { + return command.lrange(key, 0, -1).thenApply(rs -> formatLongCollection(false, rs)); + } else { //set + return command.smembers(key).thenApply(rs -> formatLongCollection(true, rs)); + } + })); + } + + @Override + public CompletableFuture rpushLongAsync(String key, long value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.rpush(key, String.valueOf(value))); + }); + } + + @Override + public CompletableFuture spopLongAsync(String key) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.spop(key).thenApply(v -> v == null ? null : Long.parseLong(v))); + }); + } + + @Override + public CompletableFuture> spopLongAsync(String key, int count) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.spop(key, count).thenApply(v -> v == null ? null : formatLongCollection(true, v))); + }); + } + + @Override + public CompletableFuture lremLongAsync(String key, long value) { + return connectStringAsync().thenCompose(command -> { + //此处获取的int值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.lrem(key, 1, String.valueOf(value)).thenApply(v -> v.intValue())); + }); + } + + @Override + public CompletableFuture sismemberLongAsync(String key, long value) { + return connectStringAsync().thenCompose(command -> { + //此处获取的boolean值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.sismember(key, String.valueOf(value))); + }); + } + + @Override + public CompletableFuture saddLongAsync(String key, long value) { + return connectStringAsync().thenCompose(command -> { + //不处理返回值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.sadd(key, String.valueOf(value))); + }); + } + + @Override + public CompletableFuture sremLongAsync(String key, long value) { + return connectStringAsync().thenCompose(command -> { + //此处获取的int值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.srem(key, String.valueOf(value)).thenApply(v -> v.intValue())); + }); + } + + @Override + public CompletableFuture getLongArrayAsync(String... keys) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(keys[0], null, command, command.mget(keys).thenApply((List> rs) -> { + Long[] array = new Long[keys.length]; + for (int i = 0; i < array.length; i++) { + Long bs = null; + for (KeyValue kv : rs) { + if (kv.getKey().equals(keys[i])) { + bs = kv.hasValue() ? Long.parseLong(kv.getValue()) : null; + break; + } + } + array[i] = bs; + } + return array; + })); + }); + } + + @Override + public CompletableFuture> getLongCollectionAsync(String key) { + return getLongCollectionAsync(connectStringAsync(), key); + } + + @Override + public CompletableFuture>> getLongCollectionMapAsync(boolean set, String... keys) { + return connectStringAsync().thenCompose(command -> { + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + if (set) { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = command.smembers(key).thenAccept(rs -> { + if (rs != null) { + mapLock.lock(); + try { + map.put(key, formatLongCollection(set, rs)); + } finally { + mapLock.unlock(); + } + } + }).toCompletableFuture(); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = command.lrange(key, 0, -1).thenAccept(rs -> { + if (rs != null) { + mapLock.lock(); + try { + map.put(key, formatLongCollection(set, rs)); + } finally { + mapLock.unlock(); + } + } + }).toCompletableFuture(); + } + } + return CompletableFuture.allOf(futures).thenApply(v -> map); + }); + } + + @Override + public CompletableFuture> getexLongCollectionAsync(String key, int expireSeconds) { + return connectStringAsync().thenCompose(command -> { + //此处获取的long值,无需传cryptor进行解密 + return completableStringFuture(key, null, command, command.expire(key, expireSeconds).thenCompose(v -> getLongCollectionAsync(command, key))); + }); + } + + @Override + public CompletableFuture>> getStringCollectionMapAsync(boolean set, String... keys) { + return connectStringAsync().thenCompose(command -> { + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + if (set) { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = command.smembers(key).thenAccept(rs -> { + if (rs != null) { + mapLock.lock(); + try { + map.put(key, formatStringCollection(key, cryptor, set, rs)); + } finally { + mapLock.unlock(); + } + } + }).toCompletableFuture(); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = command.lrange(key, 0, -1).thenAccept(rs -> { + if (rs != null) { + mapLock.lock(); + try { + map.put(key, formatStringCollection(key, cryptor, set, rs)); + } finally { + mapLock.unlock(); + } + } + }).toCompletableFuture(); + } + } + return CompletableFuture.allOf(futures).thenApply(v -> map); + }); + } + + @Override + public CompletableFuture> getexStringCollectionAsync(String key, int expireSeconds) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(key, null, command, command.expire(key, expireSeconds).thenCompose(v -> getStringCollectionAsync(command, key))); + }); + } + + @Override + public Collection getCollection(String key, final Type componentType) { + final RedisClusterCommands command = connectBytes(); + Collection rs = getCollection(command, key, componentType); + releaseBytesCommand(command); + return rs; + } + + @Override + public Map> getCollectionMap(final boolean set, final Type componentType, String... keys) { + final RedisClusterCommands command = connectBytes(); + final Map> map = new LinkedHashMap<>(); + if (set) { //set + for (String key : keys) { + map.put(key, formatCollection(key, cryptor, command.smembers(key), convert, componentType)); + } + } else { //list + for (String key : keys) { + map.put(key, formatCollection(key, cryptor, command.lrange(key, 0, -1), convert, componentType)); + } + } + releaseBytesCommand(command); + return map; + } + + @Override + public int getCollectionSize(String key) { + final RedisClusterCommands command = connectBytes(); + final String type = command.type(key); + int rs; + if (type.contains("list")) { + rs = command.llen(key).intValue(); + } else { //set + rs = command.scard(key).intValue(); + } + releaseBytesCommand(command); + return rs; + } + + @Override + public Collection getexCollection(String key, final int expireSeconds, final Type componentType) { + final RedisClusterCommands command = connectBytes(); + command.expire(key, Duration.ofSeconds(expireSeconds)); + Collection rs = getCollection(command, key, componentType); + releaseBytesCommand(command); + return rs; + } + + @Override + public String[] getStringArray(final String... keys) { + final RedisClusterCommands command = connectString(); + List> rs = command.mget(keys); + releaseStringCommand(command); + String[] array = new String[keys.length]; + for (int i = 0; i < array.length; i++) { + String bs = null; + for (KeyValue kv : rs) { + if (kv.getKey().equals(keys[i])) { + bs = kv.hasValue() ? (cryptor != null ? cryptor.decrypt(kv.getKey(), kv.getValue()) : kv.getValue()) : null; + break; + } + } + array[i] = bs; + } + return array; + } + + @Override + public Collection getStringCollection(String key) { + final RedisClusterCommands command = connectString(); + Collection rs = getStringCollection(command, key); + releaseStringCommand(command); + return rs; + } + + @Override + public Map> getStringCollectionMap(final boolean set, String... keys) { + final RedisClusterCommands command = connectString(); + final Map> map = new LinkedHashMap<>(); + if (set) {//set + for (String key : keys) { + map.put(key, decryptStringCollection(key, true, command.smembers(key))); + } + } else { //list + for (String key : keys) { + map.put(key, decryptStringCollection(key, false, command.lrange(key, 0, -1))); + } + } + releaseStringCommand(command); + return map; + } + + @Override + public Collection getexStringCollection(String key, final int expireSeconds) { + final RedisClusterCommands command = connectString(); + command.expire(key, expireSeconds); + Collection rs = getStringCollection(command, key); + releaseStringCommand(command); + return rs; + } + + @Override + public Long[] getLongArray(String... keys) { + final RedisClusterCommands command = connectString(); + List> rs = command.mget(keys); + releaseStringCommand(command); + Long[] array = new Long[keys.length]; + for (int i = 0; i < array.length; i++) { + Long bs = null; + for (KeyValue kv : rs) { + if (kv.getKey().equals(keys[i])) { + bs = kv.hasValue() ? Long.parseLong(kv.getValue()) : null; + break; + } + } + array[i] = bs; + } + return array; + } + + @Override + public Collection getLongCollection(String key) { + final RedisClusterCommands command = connectString(); + Collection rs = getLongCollection(command, key); + releaseStringCommand(command); + return rs; + } + + protected Collection getLongCollection(final RedisClusterCommands command, String key) { + final String type = command.type(key); + Collection rs; + if (type.contains("list")) { //list + rs = formatLongCollection(false, command.lrange(key, 0, -1)); + } else { //set + rs = formatLongCollection(true, command.smembers(key)); + } + releaseStringCommand(command); + return rs; + } + + @Override + public Map> getLongCollectionMap(boolean set, String... keys) { + final RedisClusterCommands command = connectString(); + final Map> map = new LinkedHashMap<>(); + if (set) { //set + for (String key : keys) { + map.put(key, formatLongCollection(true, command.smembers(key))); + } + } else { //list + for (String key : keys) { + map.put(key, formatLongCollection(false, command.lrange(key, 0, -1))); + } + } + releaseStringCommand(command); + return map; + } + + @Override + public Collection getexLongCollection(String key, int expireSeconds) { + final RedisClusterCommands command = connectString(); + command.expire(key, expireSeconds); + releaseStringCommand(command); + return getLongCollection(key); + } + + @Override + public CompletableFuture getStringArrayAsync(String... keys) { + return connectStringAsync().thenCompose(command -> { + return completableStringFuture(null, null, command, command.mget(keys).thenApply((List> rs) -> { + String[] array = new String[keys.length]; + for (int i = 0; i < array.length; i++) { + String bs = null; + for (KeyValue kv : rs) { + if (kv.getKey().equals(keys[i])) { + bs = kv.hasValue() ? (cryptor != null ? cryptor.decrypt(kv.getKey(), kv.getValue()) : kv.getValue()) : null; + break; + } + } + array[i] = bs; + } + return array; + })); + }); + } + + @Override + public CompletableFuture> getexCollectionAsync(String key, int expireSeconds, final Type componentType) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.expire(key, expireSeconds).thenCompose(v -> getCollectionAsync(command, key, componentType))); + }); + } + + @Override + public CompletableFuture> getCollectionAsync(String key, final Type componentType) { + return connectBytesAsync().thenCompose(command -> { + return getCollectionAsync(command, key, componentType); + }); + } + + @Override + public CompletableFuture>> getCollectionMapAsync(boolean set, Type componentType, String... keys) { + return connectBytesAsync().thenCompose(command -> { + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + if (set) { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = command.smembers(key).thenAccept(rs -> { + if (rs != null) { + mapLock.lock(); + try { + map.put(key, formatCollection(key, cryptor, rs, convert, componentType)); + } finally { + mapLock.unlock(); + } + } + }).toCompletableFuture(); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = command.lrange(key, 0, -1).thenAccept(rs -> { + if (rs != null) { + mapLock.lock(); + try { + map.put(key, formatCollection(key, cryptor, rs, convert, componentType)); + } finally { + mapLock.unlock(); + } + } + }).toCompletableFuture(); + } + } + return CompletableFuture.allOf(futures).thenApply(v -> map); + }); + } + + @Override + public CompletableFuture getCollectionSizeAsync(String key) { + return connectBytesAsync().thenCompose(command -> { + return completableBytesFuture(command, command.type(key).thenCompose(type -> { + if (type.contains("list")) { + return command.llen(key).thenApply(v -> v.intValue()); + } else { //set + return command.scard(key).thenApply(v -> v.intValue()); + } + })); + }); + } + + @Override + public CompletableFuture> getStringCollectionAsync(String key) { + return getStringCollectionAsync(connectStringAsync(), key); + } + +} diff --git a/src/org/redkalex/cache/redis/lettuce/RedisLettuceCacheSourceProvider.java b/src/org/redkalex/cache/redis/lettuce/RedisLettuceCacheSourceProvider.java new file mode 100644 index 0000000..2c35c3d --- /dev/null +++ b/src/org/redkalex/cache/redis/lettuce/RedisLettuceCacheSourceProvider.java @@ -0,0 +1,35 @@ +/* + * 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 org.redkalex.cache.redis.lettuce; + +import org.redkale.annotation.Priority; +import org.redkale.source.CacheSource; +import org.redkale.source.CacheSourceProvider; +import org.redkale.util.AnyValue; + +/** + * + * @author zhangjx + */ +@Priority(-100) +public class RedisLettuceCacheSourceProvider implements CacheSourceProvider { + + @Override + public boolean acceptsConf(AnyValue config) { + try { + Object.class.isAssignableFrom(io.lettuce.core.support.BoundedPoolConfig.class); //试图加载Lettuce相关类 + return new RedisLettuceCacheSource().acceptsConf(config); + } catch (Throwable e) { + return false; + } + } + + @Override + public CacheSource createInstance() { + return new RedisLettuceCacheSource(); + } + +} diff --git a/src/org/redkalex/cache/redis/redission/RedissionCacheSource.java b/src/org/redkalex/cache/redis/redission/RedissionCacheSource.java new file mode 100644 index 0000000..a6039f3 --- /dev/null +++ b/src/org/redkalex/cache/redis/redission/RedissionCacheSource.java @@ -0,0 +1,2226 @@ +/* + * 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 org.redkalex.cache.redis.redission; + +import com.zdemo.cachex.AbstractRedisSource; +import com.zdemo.cachex.RedisCryptor; +import org.redisson.Redisson; +import org.redisson.api.*; +import org.redisson.client.codec.*; +import org.redisson.config.*; +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.ResourceListener; +import org.redkale.annotation.ResourceType; +import org.redkale.convert.Convert; +import org.redkale.service.Local; +import org.redkale.source.CacheSource; +import org.redkale.util.AnyValue; +import org.redkale.util.ResourceEvent; +import org.redkale.util.Utility; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + * //https://www.cnblogs.com/xiami2046/p/13934146.html + * + * @author zhangjx + */ +@Local +@AutoLoad(false) +@ResourceType(CacheSource.class) +public class RedissionCacheSource extends AbstractRedisSource { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected List nodeAddrs; + + protected RedissonClient client; + + @Override + public void init(AnyValue conf) { + super.init(conf); + if (conf == null) { + conf = AnyValue.create(); + } + initClient(conf); + } + + private void initClient(AnyValue conf) { + final List addresses = new ArrayList<>(); + Config redisConfig = new Config(); + AnyValue[] nodes = getNodes(conf); + String cluster = conf.getOrDefault("cluster", ""); + int maxconns = conf.getIntValue(CACHE_SOURCE_MAXCONNS, Utility.cpus()); + BaseConfig baseConfig = null; + for (AnyValue node : nodes) { + String addr = node.getValue(CACHE_SOURCE_URL, node.getValue("addr")); //兼容addr + String db0 = node.getValue(CACHE_SOURCE_DB, "").trim(); + if (!db0.isEmpty()) { + this.db = Integer.valueOf(db0); + } + String username = node.getValue(CACHE_SOURCE_USER, "").trim(); + String password = node.getValue(CACHE_SOURCE_PASSWORD, "").trim(); + if (addr.startsWith("redis")) { + URI uri = URI.create(addr); + if (uri.getQuery() != null && !uri.getQuery().isEmpty()) { + String[] qrys = uri.getQuery().split("&|="); + for (int i = 0; i < qrys.length; i += 2) { + if (CACHE_SOURCE_USER.equals(qrys[i])) { + username = i == qrys.length - 1 ? "" : qrys[i + 1]; + } else if (CACHE_SOURCE_PASSWORD.equals(qrys[i])) { + password = i == qrys.length - 1 ? "" : qrys[i + 1]; + } else if (CACHE_SOURCE_DB.equals(qrys[i])) { + String urldb = i == qrys.length - 1 ? "-1" : qrys[i + 1]; + this.db = Integer.valueOf(urldb); + } + if (CACHE_SOURCE_MAXCONNS.equals(qrys[i])) { + maxconns = i == qrys.length - 1 ? Utility.cpus() : Integer.parseInt(qrys[i + 1]); + } + } + } + } + addresses.add(addr); + if (nodes.length == 1) { + baseConfig = redisConfig.useSingleServer(); + if (maxconns > 0) { + redisConfig.useSingleServer().setConnectionMinimumIdleSize(maxconns / 2 + 1); + redisConfig.useSingleServer().setConnectionPoolSize(maxconns); + } + redisConfig.useSingleServer().setAddress(addr); + redisConfig.useSingleServer().setDatabase(this.db); + } else if ("masterslave".equalsIgnoreCase(cluster)) { //主从 + baseConfig = redisConfig.useMasterSlaveServers(); + if (maxconns > 0) { + redisConfig.useMasterSlaveServers().setMasterConnectionMinimumIdleSize(maxconns / 2 + 1); + redisConfig.useMasterSlaveServers().setMasterConnectionPoolSize(maxconns); + redisConfig.useMasterSlaveServers().setSlaveConnectionMinimumIdleSize(maxconns / 2 + 1); + redisConfig.useMasterSlaveServers().setSlaveConnectionPoolSize(maxconns); + } + if (node.get("master") != null) { + redisConfig.useMasterSlaveServers().setMasterAddress(addr); + } else { + redisConfig.useMasterSlaveServers().addSlaveAddress(addr); + } + redisConfig.useMasterSlaveServers().setDatabase(this.db); + } else if ("cluster".equalsIgnoreCase(cluster)) { //集群 + baseConfig = redisConfig.useClusterServers(); + if (maxconns > 0) { + redisConfig.useClusterServers().setMasterConnectionMinimumIdleSize(maxconns / 2 + 1); + redisConfig.useClusterServers().setMasterConnectionPoolSize(maxconns); + redisConfig.useClusterServers().setSlaveConnectionMinimumIdleSize(maxconns / 2 + 1); + redisConfig.useClusterServers().setSlaveConnectionPoolSize(maxconns); + } + redisConfig.useClusterServers().addNodeAddress(addr); + } else if ("replicated".equalsIgnoreCase(cluster)) { // + baseConfig = redisConfig.useReplicatedServers(); + if (maxconns > 0) { + redisConfig.useReplicatedServers().setMasterConnectionMinimumIdleSize(maxconns / 2 + 1); + redisConfig.useReplicatedServers().setMasterConnectionPoolSize(maxconns); + redisConfig.useReplicatedServers().setSlaveConnectionMinimumIdleSize(maxconns / 2 + 1); + redisConfig.useReplicatedServers().setSlaveConnectionPoolSize(maxconns); + } + redisConfig.useReplicatedServers().addNodeAddress(addr); + redisConfig.useReplicatedServers().setDatabase(this.db); + } else if ("sentinel".equalsIgnoreCase(cluster)) { // + baseConfig = redisConfig.useSentinelServers(); + if (maxconns > 0) { + redisConfig.useSentinelServers().setMasterConnectionMinimumIdleSize(maxconns / 2 + 1); + redisConfig.useSentinelServers().setMasterConnectionPoolSize(maxconns); + redisConfig.useSentinelServers().setSlaveConnectionMinimumIdleSize(maxconns / 2 + 1); + redisConfig.useSentinelServers().setSlaveConnectionPoolSize(maxconns); + } + redisConfig.useSentinelServers().addSentinelAddress(addr); + redisConfig.useSentinelServers().setDatabase(this.db); + } + if (baseConfig != null) { //单个进程的不同自定义密码 + if (!username.isEmpty()) { + baseConfig.setUsername(username); + } + if (!password.isEmpty()) { + baseConfig.setPassword(password); + } + } + } + if (baseConfig != null) { //配置全局密码 + String username = conf.getValue(CACHE_SOURCE_USER, "").trim(); + String password = conf.getValue(CACHE_SOURCE_PASSWORD, "").trim(); + String retryAttempts = conf.getValue("retryAttempts", "").trim(); + String retryInterval = conf.getValue("retryInterval", "").trim(); + if (!username.isEmpty()) { + baseConfig.setUsername(username); + } + if (!password.isEmpty()) { + baseConfig.setPassword(password); + } + if (!retryAttempts.isEmpty()) { + baseConfig.setRetryAttempts(Integer.parseInt(retryAttempts)); + } + if (!retryInterval.isEmpty()) { + baseConfig.setRetryInterval(Integer.parseInt(retryInterval)); + } + } + RedissonClient old = this.client; + this.client = Redisson.create(redisConfig); + this.nodeAddrs = addresses; + if (old != null) { + old.shutdown(); + } +// RTopic topic = client.getTopic("__keyevent@" + db + "__:expired", new StringCodec()); +// topic.addListener(String.class, (CharSequence cs, String key) -> { +// if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, RedissionCacheSource.class.getSimpleName() + "." + db + ": expired key=" + key + ", cs=" + cs); +// }); + //if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, RedissionCacheSource.class.getSimpleName() + ": addrs=" + addresses + ", db=" + db); + + } + + @Override + @ResourceListener + public void onResourceChange(ResourceEvent[] events) { + if (events == null || events.length < 1) { + return; + } + StringBuilder sb = new StringBuilder(); + for (ResourceEvent event : events) { + sb.append("CacheSource(name=").append(resourceName()).append(") change '").append(event.name()).append("' to '").append(event.coverNewValue()).append("'\r\n"); + } + initClient(this.config); + if (sb.length() > 0) { + logger.log(Level.INFO, sb.toString()); + } + } + + public boolean acceptsConf(AnyValue config) { + if (config == null) { + return false; + } + AnyValue[] nodes = getNodes(config); + if (nodes == null || nodes.length == 0) { + return false; + } + for (AnyValue node : nodes) { + String val = node.getValue(CACHE_SOURCE_URL, node.getValue("addr")); //兼容addr + if (val != null && val.startsWith("redis://")) { + return true; + } + if (val != null && val.startsWith("rediss://")) { + return true; + } + } + return false; + } + + protected AnyValue[] getNodes(AnyValue config) { + AnyValue[] nodes = config.getAnyValues(CACHE_SOURCE_NODE); + if (nodes == null || nodes.length == 0) { + AnyValue one = config.getAnyValue(CACHE_SOURCE_NODE); + if (one == null) { + String val = config.getValue(CACHE_SOURCE_URL); + if (val == null) { + return nodes; + } + nodes = new AnyValue[]{config}; + } else { + nodes = new AnyValue[]{one}; + } + } + return nodes; + } + + @Override + public final String getType() { + return "redis"; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{addrs=" + this.nodeAddrs + ", db=" + this.db + "}"; + } + + @Local + public RedissonClient getRedissonClient() { + return client; + } + + protected CompletableFuture completableFuture(CompletionStage rf) { + return rf.toCompletableFuture(); + } + + protected CompletableFuture completableFuture(String key, RedisCryptor cryptor, CompletionStage rf) { + return cryptor != null ? rf.toCompletableFuture().thenApply(v -> cryptor.decrypt(key, v)) : rf.toCompletableFuture(); + } + + protected CompletableFuture completableFuture(String key, RedisCryptor cryptor, Type type, CompletionStage rf) { + return rf.toCompletableFuture().thenApply(bs -> decryptValue(key, cryptor, type, bs)); + } + + protected CompletableFuture completableFuture(String key, RedisCryptor cryptor, Convert c, Type type, CompletionStage rf) { + return rf.toCompletableFuture().thenApply(bs -> decryptValue(key, cryptor, c, type, bs)); + } + + @Override + public void destroy(AnyValue conf) { + super.destroy(conf); + if (client != null) { + client.shutdown(); + } + } + + //--------------------- exists ------------------------------ + @Override + public CompletableFuture existsAsync(String key) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.isExistsAsync()); + } + + @Override + public boolean exists(String key) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return bucket.isExists(); + } + + //--------------------- get ------------------------------ + @Override + public CompletableFuture getAsync(String key, Type type) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(key, cryptor, type, bucket.getAsync()); + } + + @Override + public CompletableFuture getStringAsync(String key) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(key, cryptor, bucket.getAsync()); + } + + @Override + public CompletableFuture getSetStringAsync(String key, String value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(key, cryptor, bucket.getAndSetAsync(encryptValue(key, cryptor, value))); + } + + @Override + public CompletableFuture getLongAsync(String key, long defValue) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(bucket.getAsync().thenApply(v -> v == null ? defValue : Long.parseLong(v))); + } + + @Override + public CompletableFuture getSetLongAsync(String key, long value, long defValue) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(bucket.getAndSetAsync(String.valueOf(value)).thenApply(v -> v == null ? defValue : Long.parseLong(v))); + } + + @Override + public T get(String key, final Type type) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return decryptValue(key, cryptor, type, bucket.get()); + } + + @Override + public String getString(String key) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return decryptValue(key, cryptor, bucket.get()); + } + + @Override + public String getSetString(String key, String value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return decryptValue(key, cryptor, bucket.getAndSet(encryptValue(key, cryptor, value))); + } + + @Override + public long getLong(String key, long defValue) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + String v = bucket.get(); + return v == null ? defValue : Long.parseLong(v); + } + + @Override + public long getSetLong(String key, long value, long defValue) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + String v = bucket.getAndSet(String.valueOf(value)); + return v == null ? defValue : Long.parseLong(v); + } + + //--------------------- getex ------------------------------ + @Override + public CompletableFuture getexAsync(String key, int expireSeconds, final Type type) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.getAndExpireAsync(Duration.ofSeconds(expireSeconds)).thenApply(bs -> decryptValue(key, cryptor, type, bs))); + } + + @Override + public T getex(String key, final int expireSeconds, final Type type) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return decryptValue(key, cryptor, type, bucket.getAndExpire(Duration.ofSeconds(expireSeconds))); + } + + @Override + public CompletableFuture getexStringAsync(String key, int expireSeconds) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(bucket.getAndExpireAsync(Duration.ofSeconds(expireSeconds)).thenApply(v -> decryptValue(key, cryptor, v))); + } + + @Override + public String getexString(String key, final int expireSeconds) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + String rs = bucket.getAndExpire(Duration.ofSeconds(expireSeconds)); + return rs == null ? rs : decryptValue(key, cryptor, rs); + } + + @Override + public CompletableFuture getexLongAsync(String key, int expireSeconds, long defValue) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(bucket.getAndExpireAsync(Duration.ofSeconds(expireSeconds)).thenApply(v -> v == null ? defValue : Long.parseLong(v))); + } + + @Override + public long getexLong(String key, final int expireSeconds, long defValue) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + String v = bucket.getAndExpire(Duration.ofSeconds(expireSeconds)); + return v == null ? defValue : Long.parseLong(v); + } + + //--------------------- setex ------------------------------ + @Override + public CompletableFuture setAsync(String key, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(type == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, type, convert, value))); + } + + @Override + public CompletableFuture setAsync(String key, Convert convert0, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(type == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, type, convert0, value))); + } + + @Override + public CompletableFuture setnxAsync(String key, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setIfAbsentAsync(type == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, type, convert, value))); + } + + @Override + public CompletableFuture setnxAsync(String key, Convert convert0, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setIfAbsentAsync(type == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, type, convert0, value))); + } + + @Override + public CompletableFuture getSetAsync(String key, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.getAndSetAsync(type == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, type, convert, value)) + .thenApply(old -> old == null ? null : convert.convertFrom(type, old))); + } + + @Override + public CompletableFuture getSetAsync(String key, Convert convert0, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + Convert c = convert0 == null ? this.convert : convert0; + return completableFuture(bucket.getAndSetAsync(type == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, type, c, value)) + .thenApply(old -> old == null ? null : (T) c.convertFrom(type, old))); + } + + @Override + public boolean setnxBytes(final String key, final byte[] value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return bucket.setIfAbsent(value); + } + + @Override + public CompletableFuture setnxBytesAsync(final String key, byte[] value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setIfAbsentAsync(value)); + } + + @Override + public CompletableFuture msetAsync(Object... keyVals) { + Map map = new LinkedHashMap<>(); + for (int i = 0; i < keyVals.length; i += 2) { + String key = keyVals[i].toString(); + Object val = keyVals[i + 1]; + map.put(key, val instanceof String ? encryptValue(key, cryptor, val.toString()).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, this.convert, val)); + } + final RBuckets bucket = client.getBuckets(ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(map).thenApply(v -> null)); + } + + @Override + public CompletableFuture msetAsync(Map map) { + Map bs = new LinkedHashMap<>(); + map.forEach((key, val) -> { + bs.put(key.toString(), val instanceof String ? encryptValue(key.toString(), cryptor, val.toString()).getBytes(StandardCharsets.UTF_8) : encryptValue(key.toString(), cryptor, this.convert, val)); + }); + final RBuckets bucket = client.getBuckets(ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(bs).thenApply(v -> null)); + } + + @Override + public void mset(Object... keyVals) { + Map map = new LinkedHashMap<>(); + for (int i = 0; i < keyVals.length; i += 2) { + String key = keyVals[i].toString(); + Object val = keyVals[i + 1]; + map.put(key, val instanceof String ? encryptValue(key, cryptor, val.toString()).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, this.convert, val)); + } + client.getBuckets(ByteArrayCodec.INSTANCE).set(map); + } + + @Override + public void mset(Map map) { + Map bs = new LinkedHashMap<>(); + map.forEach((key, val) -> { + bs.put(key.toString(), val instanceof String ? encryptValue(key.toString(), cryptor, val.toString()).getBytes(StandardCharsets.UTF_8) : encryptValue(key.toString(), cryptor, this.convert, val)); + }); + client.getBuckets(ByteArrayCodec.INSTANCE).set(bs); + } + + @Override + public void set(final String key, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + bucket.set(type == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, type, convert, value)); + } + + @Override + public void set(String key, final Convert convert0, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + bucket.set(encryptValue(key, cryptor, type, convert0, value)); + } + + @Override + public boolean setnx(final String key, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return bucket.setIfAbsent(type == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, type, convert, value)); + } + + @Override + public boolean setnx(String key, final Convert convert0, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return bucket.setIfAbsent(encryptValue(key, cryptor, type, convert0, value)); + } + + @Override + public T getSet(final String key, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + byte[] old = bucket.getAndSet(type == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, type, convert, value)); + return old == null ? null : convert.convertFrom(type, old); + } + + @Override + public T getSet(String key, final Convert convert0, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + Convert c = convert0 == null ? this.convert : convert0; + byte[] old = bucket.getAndSet(encryptValue(key, cryptor, type, c, value)); + return decryptValue(key, cryptor, c, type, old); + } + + @Override + public CompletableFuture setStringAsync(String key, String value) { + return completableFuture(client.getBucket(key, StringCodec.INSTANCE).setAsync(value)); + } + + @Override + public CompletableFuture setnxStringAsync(String key, String value) { + return completableFuture(client.getBucket(key, StringCodec.INSTANCE).setIfAbsentAsync(value)); + } + + @Override + public void setString(String key, String value) { + client.getBucket(key, StringCodec.INSTANCE).set(value); + } + + @Override + public boolean setnxString(String key, String value) { + return client.getBucket(key, StringCodec.INSTANCE).setIfAbsent(value); + } + + @Override + public CompletableFuture setLongAsync(String key, long value) { + return completableFuture(client.getAtomicLong(key).setAsync(value)); + } + + @Override + public CompletableFuture setnxLongAsync(String key, long value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(bucket.setIfAbsentAsync(String.valueOf(value))); + } + + @Override + public void setLong(String key, long value) { + client.getAtomicLong(key).set(value); + } + + @Override + public boolean setnxLong(String key, long value) { + return client.getBucket(key, StringCodec.INSTANCE).setIfAbsent(String.valueOf(value)); + } + + //--------------------- setex ------------------------------ + @Override + public CompletableFuture setexAsync(String key, int expireSeconds, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(encryptValue(key, cryptor, type, convert, value), expireSeconds, TimeUnit.SECONDS).thenApply(r -> null)); + } + + @Override + public CompletableFuture setexAsync(String key, int expireSeconds, Convert convert0, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(encryptValue(key, cryptor, type, convert0, value), expireSeconds, TimeUnit.SECONDS).thenApply(r -> null)); + } + + @Override + public void setex(String key, int expireSeconds, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + bucket.set(encryptValue(key, cryptor, type, convert, value), expireSeconds, TimeUnit.SECONDS); + } + + @Override + public void setex(String key, int expireSeconds, Convert convert0, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + bucket.set(encryptValue(key, cryptor, type, convert0, value), expireSeconds, TimeUnit.SECONDS); + } + + @Override + public CompletableFuture setexStringAsync(String key, int expireSeconds, String value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(bucket.setAsync(encryptValue(key, cryptor, value), expireSeconds, TimeUnit.SECONDS).thenApply(r -> null)); + } + + @Override + public void setexString(String key, int expireSeconds, String value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + bucket.set(encryptValue(key, cryptor, value), expireSeconds, TimeUnit.SECONDS); + } + + @Override + public CompletableFuture setexLongAsync(String key, int expireSeconds, long value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(bucket.setAsync(String.valueOf(value), expireSeconds, TimeUnit.SECONDS).thenApply(r -> null)); + } + + @Override + public void setexLong(String key, int expireSeconds, long value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + bucket.set(String.valueOf(value), expireSeconds, TimeUnit.SECONDS); + } + + //--------------------- setex ------------------------------ + @Override + public CompletableFuture setnxexAsync(String key, int expireSeconds, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setIfAbsentAsync(encryptValue(key, cryptor, type, convert, value), Duration.ofSeconds(expireSeconds))); + } + + @Override + public CompletableFuture setnxexAsync(String key, int expireSeconds, Convert convert0, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setIfAbsentAsync(encryptValue(key, cryptor, type, convert0, value), Duration.ofSeconds(expireSeconds))); + } + + @Override + public boolean setnxex(String key, int expireSeconds, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return bucket.setIfAbsent(encryptValue(key, cryptor, type, convert, value), Duration.ofSeconds(expireSeconds)); + } + + @Override + public boolean setnxex(String key, int expireSeconds, Convert convert0, final Type type, T value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return bucket.setIfAbsent(encryptValue(key, cryptor, type, convert0, value), Duration.ofSeconds(expireSeconds)); + } + + @Override + public CompletableFuture setnxexStringAsync(String key, int expireSeconds, String value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(bucket.setIfAbsentAsync(encryptValue(key, cryptor, value), Duration.ofSeconds(expireSeconds))); + } + + @Override + public boolean setnxexString(String key, int expireSeconds, String value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return bucket.setIfAbsent(encryptValue(key, cryptor, value), Duration.ofSeconds(expireSeconds)); + } + + @Override + public CompletableFuture setnxexLongAsync(String key, int expireSeconds, long value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return completableFuture(bucket.setIfAbsentAsync(String.valueOf(value), Duration.ofSeconds(expireSeconds))); + } + + @Override + public boolean setnxexLong(String key, int expireSeconds, long value) { + final RBucket bucket = client.getBucket(key, StringCodec.INSTANCE); + return bucket.setIfAbsent(String.valueOf(value), Duration.ofSeconds(expireSeconds)); + } + + //--------------------- expire ------------------------------ + @Override + public CompletableFuture expireAsync(String key, int expireSeconds) { + return completableFuture(client.getBucket(key).expireAsync(Duration.ofSeconds(expireSeconds)).thenApply(r -> null)); + } + + @Override + public void expire(String key, int expireSeconds) { + client.getBucket(key).expire(Duration.ofSeconds(expireSeconds)); + } + + //--------------------- del ------------------------------ + @Override + public CompletableFuture delAsync(String... keys) { + return completableFuture(client.getKeys().deleteAsync(keys).thenApply(rs -> rs.intValue())); + } + + @Override + public int del(String... keys) { + return (int) client.getKeys().delete(keys); + } + + //--------------------- incrby ------------------------------ + @Override + public long incr(final String key) { + return client.getAtomicLong(key).incrementAndGet(); + } + + @Override + public CompletableFuture incrAsync(final String key) { + return completableFuture(client.getAtomicLong(key).incrementAndGetAsync()); + } + + @Override + public long incrby(final String key, long num) { + return client.getAtomicLong(key).addAndGet(num); + } + + @Override + public double incrbyFloat(final String key, double num) { + return client.getAtomicDouble(key).addAndGet(num); + } + + @Override + public CompletableFuture incrbyAsync(final String key, long num) { + return completableFuture(client.getAtomicLong(key).addAndGetAsync(num)); + } + + @Override + public CompletableFuture incrbyFloatAsync(final String key, double num) { + return completableFuture(client.getAtomicDouble(key).addAndGetAsync(num)); + } + + //--------------------- decrby ------------------------------ + @Override + public long decr(final String key) { + return client.getAtomicLong(key).decrementAndGet(); + } + + @Override + public CompletableFuture decrAsync(final String key) { + return completableFuture(client.getAtomicLong(key).decrementAndGetAsync()); + } + + @Override + public long decrby(final String key, long num) { + return client.getAtomicLong(key).addAndGet(-num); + } + + @Override + public CompletableFuture decrbyAsync(final String key, long num) { + return completableFuture(client.getAtomicLong(key).addAndGetAsync(-num)); + } + + @Override + public int hdel(final String key, String... fields) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return (int) map.fastRemove(fields); + } + + @Override + public int hlen(final String key) { + return client.getMap(key, MapByteArrayCodec.instance).size(); + } + + @Override + public List hkeys(final String key) { + return (List) new ArrayList<>(client.getMap(key, MapStringCodec.instance).keySet()); + } + + @Override + public long hincr(final String key, String field) { + RMap map = client.getMap(key, MapLongCodec.instance); + return map.addAndGet(field, 1L); + } + + @Override + public long hincrby(final String key, String field, long num) { + RMap map = client.getMap(key, MapLongCodec.instance); + return map.addAndGet(field, num); + } + + @Override + public double hincrbyFloat(final String key, String field, double num) { + RMap map = client.getMap(key, MapDoubleCodec.instance); + return map.addAndGet(field, num); + } + + @Override + public long hdecr(final String key, String field) { + RMap map = client.getMap(key, MapLongCodec.instance); + return map.addAndGet(field, -1L); + } + + @Override + public long hdecrby(final String key, String field, long num) { + RMap map = client.getMap(key, MapLongCodec.instance); + return map.addAndGet(field, -num); + } + + @Override + public boolean hexists(final String key, String field) { + return client.getMap(key, MapByteArrayCodec.instance).containsKey(field); + } + + @Override + public void hset(final String key, final String field, final Type type, final T value) { + if (value == null) { + return; + } + RMap map = client.getMap(key, MapByteArrayCodec.instance); + map.fastPut(field, encryptValue(key, cryptor, type, convert, value)); + } + + @Override + public void hset(final String key, final String field, final Convert convert0, final Type type, final T value) { + if (value == null) { + return; + } + RMap map = client.getMap(key, MapByteArrayCodec.instance); + map.fastPut(field, encryptValue(key, cryptor, type, convert0, value)); + } + + @Override + public boolean hsetnx(final String key, final String field, final Type type, final T value) { + if (value == null) { + return false; + } + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return map.fastPutIfAbsent(field, encryptValue(key, cryptor, type, convert, value)); + } + + @Override + public boolean hsetnx(final String key, final String field, final Convert convert0, final Type type, final T value) { + if (value == null) { + return false; + } + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return map.fastPutIfAbsent(field, encryptValue(key, cryptor, type, convert0, value)); + } + + @Override + public void hsetString(final String key, final String field, final String value) { + if (value == null) { + return; + } + RMap map = client.getMap(key, MapStringCodec.instance); + map.fastPut(field, encryptValue(key, cryptor, value)); + } + + @Override + public boolean hsetnxString(final String key, final String field, final String value) { + if (value == null) { + return false; + } + RMap map = client.getMap(key, MapStringCodec.instance); + return map.fastPutIfAbsent(field, encryptValue(key, cryptor, value)); + } + + @Override + public void hsetLong(final String key, final String field, final long value) { + RMap map = client.getMap(key, MapLongCodec.instance); + map.fastPut(field, value); + } + + @Override + public boolean hsetnxLong(final String key, final String field, final long value) { + RMap map = client.getMap(key, MapLongCodec.instance); + return map.fastPutIfAbsent(field, value); + } + + @Override + public void hmset(final String key, final Serializable... values) { + Map vals = new LinkedHashMap<>(); + for (int i = 0; i < values.length; i += 2) { + vals.put(String.valueOf(values[i]), values[i + 1] instanceof String ? encryptValue(key, cryptor, values[i + 1].toString()).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, this.convert, values[i + 1])); + } + RMap rm = client.getMap(key, MapByteArrayCodec.instance); + rm.putAll(vals); + } + + @Override + public void hmset(final String key, final Map map) { + Map vals = new LinkedHashMap<>(); + map.forEach((k, v) -> { + vals.put(k.toString(), v instanceof String ? encryptValue(key, cryptor, v.toString()).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, this.convert, v)); + }); + RMap rm = client.getMap(key, MapByteArrayCodec.instance); + rm.putAll(vals); + } + + @Override + public List hmget(final String key, final Type type, final String... fields) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + Map rs = map.getAll(Utility.ofSet(fields)); + List list = new ArrayList<>(fields.length); + for (String field : fields) { + byte[] bs = rs.get(field); + if (bs == null) { + list.add(null); + } else { + list.add(decryptValue(key, cryptor, type, bs)); + } + } + return list; + } + + @Override + public Map hmap(final String key, final Type type, int offset, int limit, String pattern) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + Iterator it = map.keySet(pattern, offset + limit).iterator(); + final Map rs = new LinkedHashMap<>(); + int index = -1; + while (it.hasNext()) { + if (++index < offset) { + continue; + } + if (index >= offset + limit) { + break; + } + String field = it.next(); + byte[] bs = map.get(field); + if (bs != null) { + rs.put(field, decryptValue(key, cryptor, type, bs)); + } + } + return rs; + } + + @Override + public Map hmap(final String key, final Type type, int offset, int limit) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + Iterator it = map.keySet(offset + limit).iterator(); + final Map rs = new LinkedHashMap<>(); + int index = -1; + while (it.hasNext()) { + if (++index < offset) { + continue; + } + if (index >= offset + limit) { + break; + } + String field = it.next(); + byte[] bs = map.get(field); + if (bs != null) { + rs.put(field, decryptValue(key, cryptor, type, bs)); + } + } + return rs; + } + + @Override + public T hget(final String key, final String field, final Type type) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + byte[] bs = map.get(field); + return decryptValue(key, cryptor, type, bs); + } + + @Override + public String hgetString(final String key, final String field) { + RMap map = client.getMap(key, MapStringCodec.instance); + return decryptValue(key, cryptor, map.get(field)); + } + + @Override + public long hgetLong(final String key, final String field, long defValue) { + RMap map = client.getMap(key, MapLongCodec.instance); + Long rs = map.get(field); + return rs == null ? defValue : rs; + } + + @Override + public CompletableFuture hdelAsync(final String key, String... fields) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.fastRemoveAsync(fields).thenApply(r -> r.intValue())); + } + + @Override + public CompletableFuture hlenAsync(final String key) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.sizeAsync()); + } + + @Override + public CompletableFuture> hkeysAsync(final String key) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.readAllKeySetAsync().thenApply(set -> set == null ? null : new ArrayList(set))); + } + + @Override + public CompletableFuture hincrAsync(final String key, String field) { + RMap map = client.getMap(key, MapLongCodec.instance); + return completableFuture(map.addAndGetAsync(field, 1L)); + } + + @Override + public CompletableFuture hincrbyAsync(final String key, String field, long num) { + RMap map = client.getMap(key, MapLongCodec.instance); + return completableFuture(map.addAndGetAsync(field, num)); + } + + @Override + public CompletableFuture hincrbyFloatAsync(final String key, String field, double num) { + RMap map = client.getMap(key, MapDoubleCodec.instance); + return completableFuture(map.addAndGetAsync(field, num)); + } + + @Override + public CompletableFuture hdecrAsync(final String key, String field) { + RMap map = client.getMap(key, MapLongCodec.instance); + return completableFuture(map.addAndGetAsync(field, -1L)); + } + + @Override + public CompletableFuture hdecrbyAsync(final String key, String field, long num) { + RMap map = client.getMap(key, MapLongCodec.instance); + return completableFuture(map.addAndGetAsync(field, -num)); + } + + @Override + public CompletableFuture hexistsAsync(final String key, String field) { + RMap map = client.getMap(key, MapLongCodec.instance); + return completableFuture(map.containsKeyAsync(field)); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.fastPutAsync(field, encryptValue(key, cryptor, type, convert, value)).thenApply(r -> null)); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert0, final Type type, final T value) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.fastPutAsync(field, encryptValue(key, cryptor, type, convert0, value)).thenApply(r -> null)); + } + + @Override + public CompletableFuture hsetnxAsync(final String key, final String field, final Type type, final T value) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.fastPutIfAbsentAsync(field, encryptValue(key, cryptor, type, convert, value))); + } + + @Override + public CompletableFuture hsetnxAsync(final String key, final String field, final Convert convert0, final Type type, final T value) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.fastPutIfAbsentAsync(field, encryptValue(key, cryptor, type, convert0, value))); + } + + @Override + public CompletableFuture hsetStringAsync(final String key, final String field, final String value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + RMap map = client.getMap(key, MapStringCodec.instance); + return completableFuture(map.fastPutAsync(field, encryptValue(key, cryptor, value)).thenApply(r -> null)); + } + + @Override + public CompletableFuture hsetnxStringAsync(final String key, final String field, final String value) { + if (value == null) { + return CompletableFuture.completedFuture(false); + } + RMap map = client.getMap(key, MapStringCodec.instance); + return completableFuture(map.fastPutIfAbsentAsync(field, encryptValue(key, cryptor, value))); + } + + @Override + public CompletableFuture hsetLongAsync(final String key, final String field, final long value) { + RMap map = client.getMap(key, MapLongCodec.instance); + return completableFuture(map.fastPutAsync(field, value).thenApply(r -> null)); + } + + @Override + public CompletableFuture hsetnxLongAsync(final String key, final String field, final long value) { + RMap map = client.getMap(key, MapLongCodec.instance); + return completableFuture(map.fastPutIfAbsentAsync(field, value)); + } + + @Override + public CompletableFuture hmsetAsync(final String key, final Serializable... values) { + Map vals = new LinkedHashMap<>(); + for (int i = 0; i < values.length; i += 2) { + vals.put(String.valueOf(values[i]), encryptValue(key, cryptor, convert, values[i + 1])); + } + RMap rm = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(rm.putAllAsync(vals)); + } + + @Override + public CompletableFuture hmsetAsync(final String key, final Map map) { + Map vals = new LinkedHashMap<>(); + map.forEach((k, v) -> { + vals.put(k.toString(), encryptValue(key, cryptor, convert, v)); + }); + RMap rm = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(rm.putAllAsync(vals)); + } + + @Override + public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.getAllAsync(Utility.ofSet(fields)).thenApply(rs -> { + List list = new ArrayList<>(fields.length); + for (String field : fields) { + byte[] bs = rs.get(field); + if (bs == null) { + list.add(null); + } else { + list.add(decryptValue(key, cryptor, type, bs)); + } + } + return list; + })); + } + + @Override + public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit) { + return CompletableFuture.supplyAsync(() -> { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + + Iterator it = map.keySet(offset + limit).iterator(); + final Map rs = new LinkedHashMap<>(); + int index = -1; + while (it.hasNext()) { + if (++index < offset) { + continue; + } + if (index >= offset + limit) { + break; + } + String field = it.next(); + byte[] bs = map.get(field); + if (bs != null) { + rs.put(field, decryptValue(key, cryptor, type, bs)); + } + } + return rs; + }); + } + + @Override + public CompletableFuture> hmapAsync(final String key, final Type type, int offset, int limit, String pattern) { + return CompletableFuture.supplyAsync(() -> { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + + Iterator it = map.keySet(pattern, offset + limit).iterator(); + final Map rs = new LinkedHashMap<>(); + int index = -1; + while (it.hasNext()) { + if (++index < offset) { + continue; + } + if (index >= offset + limit) { + break; + } + String field = it.next(); + byte[] bs = map.get(field); + if (bs != null) { + rs.put(field, decryptValue(key, cryptor, type, bs)); + } + } + return rs; + }); + } + + @Override + public CompletableFuture hgetAsync(final String key, final String field, final Type type) { + RMap map = client.getMap(key, MapByteArrayCodec.instance); + return completableFuture(map.getAsync(field).thenApply(r -> decryptValue(key, cryptor, type, r))); + } + + @Override + public CompletableFuture hgetStringAsync(final String key, final String field) { + RMap map = client.getMap(key, MapStringCodec.instance); + return completableFuture(key, cryptor, map.getAsync(field)); + } + + @Override + public CompletableFuture hgetLongAsync(final String key, final String field, long defValue) { + RMap map = client.getMap(key, MapLongCodec.instance); + return completableFuture(map.getAsync(field).thenApply(r -> r == null ? defValue : r.longValue())); + } + + //--------------------- collection ------------------------------ + @Override + public CompletableFuture llenAsync(String key) { + return completableFuture(client.getList(key).sizeAsync()); + } + + @Override + public CompletableFuture scardAsync(String key) { + return completableFuture(client.getSet(key).sizeAsync()); + } + + @Override + public int llen(String key) { + return client.getList(key).size(); + } + + @Override + public int scard(String key) { + return client.getSet(key).size(); + } + + @Override + public CompletableFuture> smembersAsync(String key, final Type componentType) { + return completableFuture((CompletionStage) client.getSet(key, ByteArrayCodec.INSTANCE).readAllAsync().thenApply(set -> { + if (set == null || set.isEmpty()) { + return set; + } + Set rs = new LinkedHashSet<>(); + for (Object item : set) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(componentType == String.class ? (T) decryptValue(key, cryptor, new String(bs, StandardCharsets.UTF_8)) : (T) decryptValue(key, cryptor, componentType, bs)); + } + } + return rs; + })); + } + + @Override + public CompletableFuture> lrangeAsync(String key, final Type componentType) { + return completableFuture((CompletionStage) client.getList(key, ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { + if (list == null || list.isEmpty()) { + return list; + } + List rs = new ArrayList<>(); + for (Object item : list) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(componentType == String.class ? (T) decryptValue(key, cryptor, new String(bs, StandardCharsets.UTF_8)) : (T) decryptValue(key, cryptor, componentType, bs)); + } + } + return rs; + })); + } + + @Override + public CompletableFuture> mgetLongAsync(String... keys) { + return completableFuture(client.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).getAsync(keys)); + } + + @Override + public CompletableFuture> mgetStringAsync(String... keys) { + return completableFuture(client.getBuckets(StringCodec.INSTANCE).getAsync(keys).thenApply(map -> { + if (cryptor == null) { + return (Map) map; + } + Map rs = new LinkedHashMap(); + map.forEach((k, v) -> rs.put(k, decryptValue(k, cryptor, v == null ? null : v.toString()))); + return rs; + })); + } + + @Override + public CompletableFuture> mgetAsync(final Type componentType, String... keys) { + return completableFuture(client.getBuckets(ByteArrayCodec.INSTANCE).getAsync(keys).thenApply(map -> { + Map rs = new LinkedHashMap(); + map.forEach((k, v) -> rs.put(k, decryptValue(k, cryptor, componentType, (byte[]) v))); + return rs; + })); + } + + @Override + public CompletableFuture> mgetBytesAsync(String... keys) { + return completableFuture(client.getBuckets(ByteArrayCodec.INSTANCE).getAsync(keys).thenApply(map -> { + Map rs = new LinkedHashMap(); + map.forEach((k, v) -> rs.put(k, decryptValue(k, cryptor, byte[].class, (byte[]) v))); + return rs; + })); + } + + @Override + public CompletableFuture>> lrangeAsync(final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(client.getList(key, ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { + if (list == null || list.isEmpty()) { + return list; + } + List rs = new ArrayList<>(); + for (Object item : list) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(decryptValue(key, cryptor, componentType, bs)); + } + } + mapLock.lock(); + try { + map.put(key, rs); + } finally { + mapLock.unlock(); + } + return rs; + })); + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public CompletableFuture>> smembersAsync(final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(client.getSet(key, ByteArrayCodec.INSTANCE).readAllAsync().thenApply(set -> { + if (set == null || set.isEmpty()) { + return set; + } + Set rs = new LinkedHashSet<>(); + for (Object item : set) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(decryptValue(key, cryptor, componentType, bs)); + } + } + mapLock.lock(); + try { + map.put(key, rs); + } finally { + mapLock.unlock(); + } + return rs; + })); + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public Set smembers(String key, final Type componentType) { + return (Set) smembersAsync(key, componentType).join(); + } + + @Override + public List lrange(String key, final Type componentType) { + return (List) lrangeAsync(key, componentType).join(); + } + + @Override + public Map mgetLong(final String... keys) { + return client.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).get(keys); + } + + @Override + public Map mgetString(final String... keys) { + Map map = client.getBuckets(StringCodec.INSTANCE).get(keys); + if (cryptor != null && !map.isEmpty()) { + Map rs = new LinkedHashMap<>(); + map.forEach((k, v) -> rs.put(k, decryptValue(k, cryptor, v))); + return rs; + } + return map; + } + + @Override + public Map mget(final Type componentType, final String... keys) { + Map map = client.getBuckets(ByteArrayCodec.INSTANCE).get(keys); + Map rs = new LinkedHashMap(map.size()); + map.forEach((k, v) -> rs.put(k, decryptValue(k, cryptor, componentType, v))); + return rs; + } + + @Override + public Map mgetBytes(final String... keys) { + Map map = client.getBuckets(ByteArrayCodec.INSTANCE).get(keys); + Map rs = new LinkedHashMap(map.size()); + map.forEach((k, v) -> rs.put(k, decryptValue(k, cryptor, byte[].class, v))); + return rs; + } + + @Override + public Map> smembers(final Type componentType, String... keys) { + return (Map) smembersAsync(componentType, keys).join(); + } + + @Override + public Map> lrange(final Type componentType, String... keys) { + return (Map) lrangeAsync(componentType, keys).join(); + } + + //--------------------- existsItem ------------------------------ + @Override + public boolean sismember(String key, final Type componentType, T value) { + final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE); + return bucket.contains(componentType == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, componentType, convert, value)); + } + + @Override + public CompletableFuture sismemberAsync(String key, final Type componentType, T value) { + final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.containsAsync(encryptValue(key, cryptor, componentType, convert, value))); + } + + @Override + public boolean sismemberString(String key, String value) { + final RSet bucket = client.getSet(key, StringCodec.INSTANCE); + return bucket.contains(encryptValue(key, cryptor, value)); + } + + @Override + public CompletableFuture sismemberStringAsync(String key, String value) { + final RSet bucket = client.getSet(key, StringCodec.INSTANCE); + return completableFuture(bucket.containsAsync(encryptValue(key, cryptor, value))); + } + + @Override + public boolean sismemberLong(String key, long value) { + final RSet bucket = client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return bucket.contains(value); + } + + @Override + public CompletableFuture sismemberLongAsync(String key, long value) { + final RSet bucket = client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return completableFuture(bucket.containsAsync(value)); + } + + //--------------------- rpush ------------------------------ + @Override + public CompletableFuture rpushAsync(String key, final Type componentType, T value) { + final RList bucket = client.getList(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.addAsync(encryptValue(key, cryptor, componentType, convert, value)).thenApply(r -> null)); + } + + @Override + public void rpush(String key, final Type componentType, T value) { + final RList bucket = client.getList(key, ByteArrayCodec.INSTANCE); + bucket.add(componentType == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, componentType, convert, value)); + } + + @Override + public CompletableFuture rpushStringAsync(String key, String value) { + final RList bucket = client.getList(key, StringCodec.INSTANCE); + return completableFuture(bucket.addAsync(encryptValue(key, cryptor, value)).thenApply(r -> null)); + } + + @Override + public void rpushString(String key, String value) { + final RList bucket = client.getList(key, StringCodec.INSTANCE); + bucket.add(encryptValue(key, cryptor, value)); + } + + @Override + public CompletableFuture rpushLongAsync(String key, long value) { + final RList bucket = client.getList(key, org.redisson.client.codec.LongCodec.INSTANCE); + return completableFuture(bucket.addAsync(value).thenApply(r -> null)); + } + + @Override + public void rpushLong(String key, long value) { + final RList bucket = client.getList(key, org.redisson.client.codec.LongCodec.INSTANCE); + bucket.add(value); + } + + //--------------------- lrem ------------------------------ + @Override + public CompletableFuture lremAsync(String key, final Type componentType, T value) { + return completableFuture(client.getList(key, ByteArrayCodec.INSTANCE).removeAsync(encryptValue(key, cryptor, componentType, convert, value)).thenApply(r -> r ? 1 : 0)); + } + + @Override + public int lrem(String key, final Type componentType, T value) { + final RList bucket = client.getList(key, ByteArrayCodec.INSTANCE); + return bucket.remove(componentType == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, componentType, convert, value)) ? 1 : 0; + } + + @Override + public CompletableFuture lremStringAsync(String key, String value) { + return completableFuture(client.getList(key, StringCodec.INSTANCE).removeAsync(encryptValue(key, cryptor, value)).thenApply(r -> r ? 1 : 0)); + } + + @Override + public int lremString(String key, String value) { + return client.getList(key, StringCodec.INSTANCE).remove(encryptValue(key, cryptor, value)) ? 1 : 0; + } + + @Override + public CompletableFuture lremLongAsync(String key, long value) { + return completableFuture(client.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).removeAsync((Object) value).thenApply(r -> r ? 1 : 0)); + } + + @Override + public int lremLong(String key, long value) { + return client.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).remove((Object) value) ? 1 : 0; + } + + //--------------------- sadd ------------------------------ + @Override + public CompletableFuture saddAsync(String key, Type componentType, T value) { + final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.addAsync(encryptValue(key, cryptor, componentType, convert, value)).thenApply(r -> null)); + } + + @Override + public CompletableFuture spopAsync(String key, Type componentType) { + final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync().thenApply(bs -> bs == null ? null : decryptValue(key, cryptor, componentType, bs))); + } + + @Override + public CompletableFuture> spopAsync(String key, int count, Type componentType) { + final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync(count).thenApply((Set bslist) -> { + if (bslist == null || bslist.isEmpty()) { + return new LinkedHashSet(); + } + Set rs = new LinkedHashSet<>(); + for (byte[] bs : bslist) { + rs.add(decryptValue(key, cryptor, componentType, bs)); + } + return rs; + })); + } + + @Override + public CompletableFuture spopStringAsync(String key) { + final RSet bucket = client.getSet(key, StringCodec.INSTANCE); + return completableFuture(key, cryptor, bucket.removeRandomAsync()); + } + + @Override + public CompletableFuture> spopStringAsync(String key, int count) { + final RSet bucket = client.getSet(key, StringCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync(count).thenApply(r -> { + if (r == null) { + return r; + } + if (cryptor == null) { + return new LinkedHashSet<>(r); + } + Set rs = new LinkedHashSet<>(); + for (Object item : r) { + rs.add(item == null ? null : decryptValue(key, cryptor, item.toString())); + } + return rs; + })); + } + + @Override + public CompletableFuture spopLongAsync(String key) { + final RSet bucket = client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync()); + } + + @Override + public CompletableFuture> spopLongAsync(String key, int count) { + final RSet bucket = client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return completableFuture(bucket.removeRandomAsync(count)); + } + + @Override + public void sadd(String key, final Type componentType, T value) { + final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE); + bucket.add(componentType == String.class ? encryptValue(key, cryptor, String.valueOf(value)).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, componentType, convert, value)); + } + + @Override + public T spop(String key, final Type componentType) { + final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE); + byte[] bs = bucket.removeRandom(); + return decryptValue(key, cryptor, componentType, bs); + } + + @Override + public Set spop(String key, int count, final Type componentType) { + final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE); + Set< byte[]> bslist = bucket.removeRandom(count); + Set rs = new LinkedHashSet<>(); + if (bslist == null) { + return rs; + } + for (byte[] bs : bslist) { + rs.add(decryptValue(key, cryptor, componentType, bs)); + } + return rs; + } + + @Override + public String spopString(String key) { + final RSet bucket = client.getSet(key, StringCodec.INSTANCE); + return decryptValue(key, cryptor, bucket.removeRandom()); + } + + @Override + public Set spopString(String key, int count) { + final RSet bucket = client.getSet(key, StringCodec.INSTANCE); + Set r = bucket.removeRandom(count); + if (cryptor == null) { + return r; + } + Set rs = new LinkedHashSet<>(); + for (String item : r) { + rs.add(decryptValue(key, cryptor, item)); + } + return rs; + } + + @Override + public Long spopLong(String key) { + final RSet bucket = client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return bucket.removeRandom(); + } + + @Override + public Set spopLong(String key, int count) { + final RSet bucket = client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return bucket.removeRandom(count); + } + + @Override + public CompletableFuture saddStringAsync(String key, String value) { + final RSet bucket = client.getSet(key, StringCodec.INSTANCE); + return completableFuture(bucket.addAsync(encryptValue(key, cryptor, value)).thenApply(r -> null)); + } + + @Override + public void saddString(String key, String value) { + final RSet bucket = client.getSet(key, StringCodec.INSTANCE); + bucket.add(encryptValue(key, cryptor, value)); + } + + @Override + public CompletableFuture saddLongAsync(String key, long value) { + final RSet bucket = client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + return completableFuture(bucket.addAsync(value).thenApply(r -> null)); + } + + @Override + public void saddLong(String key, long value) { + final RSet bucket = client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE); + bucket.add(value); + } + + //--------------------- srem ------------------------------ + @Override + public CompletableFuture sremAsync(String key, final Type componentType, T value) { + return completableFuture(client.getSet(key, ByteArrayCodec.INSTANCE).removeAsync(encryptValue(key, cryptor, componentType, convert, value)).thenApply(r -> r ? 1 : 0)); + } + + @Override + public int srem(String key, final Type componentType, T value) { + final RSet bucket = client.getSet(key, ByteArrayCodec.INSTANCE); + return bucket.remove(componentType == String.class ? String.valueOf(value).getBytes(StandardCharsets.UTF_8) : encryptValue(key, cryptor, componentType, convert, value)) ? 1 : 0; + } + + @Override + public CompletableFuture sremStringAsync(String key, String value) { + return completableFuture(client.getSet(key, StringCodec.INSTANCE).removeAsync(encryptValue(key, cryptor, value)).thenApply(r -> r ? 1 : 0)); + } + + @Override + public int sremString(String key, String value) { + return client.getSet(key, StringCodec.INSTANCE).remove(encryptValue(key, cryptor, value)) ? 1 : 0; + } + + @Override + public CompletableFuture sremLongAsync(String key, long value) { + return completableFuture(client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).removeAsync(value).thenApply(r -> r ? 1 : 0)); + } + + @Override + public int sremLong(String key, long value) { + return client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).remove(value) ? 1 : 0; + } + + //--------------------- keys ------------------------------ + @Override + public List keys(String pattern) { + if (pattern == null || pattern.isEmpty()) { + return client.getKeys().getKeysStream().collect(Collectors.toList()); + } else { + return client.getKeys().getKeysStreamByPattern(pattern).collect(Collectors.toList()); + } + } + + @Override + public byte[] getBytes(final String key) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return bucket.get(); + } + + @Override + public byte[] getSetBytes(final String key, byte[] value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return bucket.getAndSet(value); + } + + @Override + public byte[] getexBytes(final String key, final int expireSeconds) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return bucket.getAndExpire(Duration.ofSeconds(expireSeconds)); + } + + @Override + public void setBytes(final String key, final byte[] value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + bucket.set(value); + } + + @Override + public void setexBytes(final String key, final int expireSeconds, final byte[] value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + bucket.set(value, expireSeconds, TimeUnit.SECONDS); + } + + @Override + public boolean setnxexBytes(final String key, final int expireSeconds, final byte[] value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return bucket.setIfAbsent(value, Duration.ofSeconds(expireSeconds)); + } + + @Override + public CompletableFuture getBytesAsync(final String key) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.getAsync()); + } + + @Override + public CompletableFuture getSetBytesAsync(final String key, byte[] value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.getAndSetAsync(value)); + } + + @Override + public CompletableFuture getexBytesAsync(final String key, final int expireSeconds) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.getAndExpireAsync(Duration.ofSeconds(expireSeconds))); + } + + @Override + public CompletableFuture setBytesAsync(final String key, final byte[] value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(value)); + } + + @Override + public CompletableFuture setexBytesAsync(final String key, final int expireSeconds, final byte[] value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setAsync(value, expireSeconds, TimeUnit.SECONDS).thenApply(v -> null)); + } + + @Override + public CompletableFuture setnxexBytesAsync(final String key, final int expireSeconds, final byte[] value) { + final RBucket bucket = client.getBucket(key, ByteArrayCodec.INSTANCE); + return completableFuture(bucket.setIfAbsentAsync(value, Duration.ofSeconds(expireSeconds))); + } + + @Override + public CompletableFuture> keysAsync(String pattern) { + return CompletableFuture.supplyAsync(() -> keys(pattern)); + } + + //--------------------- dbsize ------------------------------ + @Override + public long dbsize() { + return client.getKeys().count(); + } + + @Override + public CompletableFuture dbsizeAsync() { + return completableFuture(client.getKeys().countAsync()); + } + + protected static class MapByteArrayCodec extends ByteArrayCodec { + + public static final MapByteArrayCodec instance = new MapByteArrayCodec(); + + @Override + public org.redisson.client.protocol.Decoder getMapKeyDecoder() { + return StringCodec.INSTANCE.getValueDecoder(); + } + + @Override + public org.redisson.client.protocol.Encoder getMapKeyEncoder() { + return StringCodec.INSTANCE.getValueEncoder(); + } + } + + protected static class MapStringCodec extends StringCodec { + + public static final MapStringCodec instance = new MapStringCodec(); + + @Override + public org.redisson.client.protocol.Decoder getMapKeyDecoder() { + return StringCodec.INSTANCE.getValueDecoder(); + } + + @Override + public org.redisson.client.protocol.Encoder getMapKeyEncoder() { + return StringCodec.INSTANCE.getValueEncoder(); + } + } + + protected static class MapLongCodec extends org.redisson.client.codec.LongCodec { + + public static final MapLongCodec instance = new MapLongCodec(); + + @Override + public org.redisson.client.protocol.Decoder getMapKeyDecoder() { + return StringCodec.INSTANCE.getValueDecoder(); + } + + @Override + public org.redisson.client.protocol.Encoder getMapKeyEncoder() { + return StringCodec.INSTANCE.getValueEncoder(); + } + } + + protected static class MapDoubleCodec extends org.redisson.client.codec.DoubleCodec { + + public static final MapLongCodec instance = new MapLongCodec(); + + @Override + public org.redisson.client.protocol.Decoder getMapKeyDecoder() { + return StringCodec.INSTANCE.getValueDecoder(); + } + + @Override + public org.redisson.client.protocol.Encoder getMapKeyEncoder() { + return StringCodec.INSTANCE.getValueEncoder(); + } + } + + @Override + public CompletableFuture>> getCollectionMapAsync(final boolean set, final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + 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] = completableFuture(client.getList(key, ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { + if (list == null || list.isEmpty()) { + return list; + } + List rs = new ArrayList<>(); + for (Object item : list) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(decryptValue(key, cryptor, componentType, bs)); + } + } + mapLock.lock(); + try { + map.put(key, rs); + } finally { + mapLock.unlock(); + } + return rs; + })); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(client.getSet(key, ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { + if (list == null || list.isEmpty()) { + return list; + } + List rs = new ArrayList<>(); + for (Object item : list) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(decryptValue(key, cryptor, componentType, bs)); + } + } + mapLock.lock(); + try { + map.put(key, rs); + } finally { + mapLock.unlock(); + } + return rs; + })); + } + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public CompletableFuture getCollectionSizeAsync(String key) { + return completableFuture(client.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { + if (String.valueOf(type).contains("list")) { + return client.getList(key).sizeAsync(); + } else { + return client.getSet(key).sizeAsync(); + } + })); + } + + @Override + public int getCollectionSize(String key) { + String type = client.getScript().eval(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE); + if (String.valueOf(type).contains("list")) { + return client.getList(key).size(); + } else { + return client.getSet(key).size(); + } + } + + @Override + public CompletableFuture> getCollectionAsync(String key, final Type componentType) { + return completableFuture(client.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { + if (String.valueOf(type).contains("list")) { + return (CompletionStage) client.getList(key, ByteArrayCodec.INSTANCE).readAllAsync().thenApply(list -> { + if (list == null || list.isEmpty()) { + return list; + } + List rs = new ArrayList<>(); + for (Object item : list) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(componentType == String.class ? (T) decryptValue(key, cryptor, new String(bs, StandardCharsets.UTF_8)) : (T) decryptValue(key, cryptor, componentType, bs)); + } + } + return rs; + }); + } else { + return (CompletionStage) client.getSet(key, ByteArrayCodec.INSTANCE).readAllAsync().thenApply(set -> { + if (set == null || set.isEmpty()) { + return set; + } + Set rs = new LinkedHashSet<>(); + for (Object item : set) { + byte[] bs = (byte[]) item; + if (bs == null) { + rs.add(null); + } else { + rs.add(componentType == String.class ? (T) decryptValue(key, cryptor, new String(bs, StandardCharsets.UTF_8)) : (T) decryptValue(key, cryptor, componentType, bs)); + } + } + return rs; + }); + } + })); + } + + @Override + public CompletableFuture getLongArrayAsync(String... keys) { + return completableFuture(client.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).getAsync(keys).thenApply(map -> { + Long[] rs = new Long[keys.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = (Long) map.get(keys[i]); + } + return rs; + })); + } + + @Override + public CompletableFuture getStringArrayAsync(String... keys) { + return completableFuture(client.getBuckets(StringCodec.INSTANCE).getAsync(keys).thenApply(map -> { + String[] rs = new String[keys.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = decryptValue(keys[i], cryptor, (String) map.get(keys[i])); + } + return rs; + })); + } + + @Override + public CompletableFuture> getStringCollectionAsync(String key) { + return completableFuture(client.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { + if (String.valueOf(type).contains("list")) { + return (CompletionStage) client.getList(key, StringCodec.INSTANCE).readAllAsync().thenApply(list -> { + if (list == null || list.isEmpty() || cryptor == null) { + return list; + } + List rs = new ArrayList<>(); + for (Object item : list) { + rs.add(item == null ? null : decryptValue(key, cryptor, item.toString())); + } + return rs; + }); + } else { + return (CompletionStage) client.getSet(key, StringCodec.INSTANCE).readAllAsync().thenApply(set -> { + if (set == null) { + return set; + } + if (set.isEmpty() || cryptor == null) { + return new ArrayList<>(set); + } + List rs = new ArrayList<>(); //不用set + for (Object item : set) { + rs.add(item == null ? null : decryptValue(key, cryptor, item.toString())); + } + return rs; + }); + } + })); + } + + @Override + public CompletableFuture>> getStringCollectionMapAsync(final boolean set, String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + 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] = completableFuture(client.getList(key, StringCodec.INSTANCE).readAllAsync().thenApply((Collection r) -> { + if (r != null) { + if (cryptor != null && !r.isEmpty()) { + List rs = new ArrayList<>(); + for (Object item : r) { + rs.add(item == null ? null : decryptValue(key, cryptor, item.toString())); + } + r = rs; + } + mapLock.lock(); + try { + map.put(key, r); + } finally { + mapLock.unlock(); + } + } + return null; + })); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(client.getSet(key, StringCodec.INSTANCE).readAllAsync().thenApply((Collection r) -> { + if (r != null) { + boolean changed = false; + if (cryptor != null && !r.isEmpty()) { + List rs = new ArrayList<>(); + for (Object item : r) { + rs.add(item == null ? null : decryptValue(key, cryptor, item.toString())); + } + r = rs; + changed = true; + } + mapLock.lock(); + try { + map.put(key, changed ? r : new ArrayList(r)); + } finally { + mapLock.unlock(); + } + } + return null; + })); + } + } + 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(client.getScript().evalAsync(RScript.Mode.READ_ONLY, "return redis.call('TYPE', '" + key + "')", RScript.ReturnType.VALUE).thenCompose(type -> { + if (String.valueOf(type).contains("list")) { + return (CompletionStage) client.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync(); + } else { + return (CompletionStage) client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync().thenApply(s -> s == null ? null : new ArrayList(s)); + } + })); + } + + @Override + public CompletableFuture>> getLongCollectionMapAsync(final boolean set, String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + 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] = completableFuture(client.getList(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync().thenApply(r -> { + if (r != null) { + mapLock.lock(); + try { + map.put(key, (Collection) r); + } finally { + mapLock.unlock(); + } + } + return null; + })); + } + } else { + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = completableFuture(client.getSet(key, org.redisson.client.codec.LongCodec.INSTANCE).readAllAsync().thenApply(r -> { + if (r != null) { + mapLock.lock(); + try { + map.put(key, new ArrayList(r)); + } finally { + mapLock.unlock(); + } + } + return null; + })); + } + } + 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(); + } + + //--------------------- getexCollection ------------------------------ + @Override + public CompletableFuture> getexCollectionAsync(String key, int expireSeconds, final Type componentType) { + return (CompletableFuture) expireAsync(key, expireSeconds).thenCompose(v -> getCollectionAsync(key, componentType)); + } + + @Override + public Collection getexCollection(String key, final int expireSeconds, final Type componentType) { + return (Collection) getexCollectionAsync(key, expireSeconds, componentType).join(); + } + + @Override + public CompletableFuture> getexStringCollectionAsync(String key, int expireSeconds) { + return (CompletableFuture) expireAsync(key, expireSeconds).thenCompose(v -> getStringCollectionAsync(key)); + } + + @Override + public Collection getexStringCollection(String key, final int expireSeconds) { + return getexStringCollectionAsync(key, expireSeconds).join(); + } + + @Override + public CompletableFuture> getexLongCollectionAsync(String key, int expireSeconds) { + return (CompletableFuture) expireAsync(key, expireSeconds).thenCompose(v -> getLongCollectionAsync(key)); + } + + @Override + public Collection getexLongCollection(String key, final int expireSeconds) { + return getexLongCollectionAsync(key, expireSeconds).join(); + } + + @Override + public Collection getCollection(String key, final Type componentType) { + return (Collection) getCollectionAsync(key, componentType).join(); + } + + @Override + public Long[] getLongArray(final String... keys) { + Map map = client.getBuckets(org.redisson.client.codec.LongCodec.INSTANCE).get(keys); + Long[] rs = new Long[keys.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = map.get(keys[i]); + } + return rs; + } + + @Override + public String[] getStringArray(final String... keys) { + Map map = client.getBuckets(StringCodec.INSTANCE).get(keys); + String[] rs = new String[keys.length]; + for (int i = 0; i < rs.length; i++) { + rs[i] = decryptValue(keys[i], cryptor, map.get(keys[i])); + } + return rs; + } + + @Override + public Map> getCollectionMap(final boolean set, final Type componentType, String... keys) { + return (Map) getCollectionMapAsync(set, componentType, keys).join(); + } + +} diff --git a/src/org/redkalex/cache/redis/redission/RedissionCacheSourceProvider.java b/src/org/redkalex/cache/redis/redission/RedissionCacheSourceProvider.java new file mode 100644 index 0000000..9242b4b --- /dev/null +++ b/src/org/redkalex/cache/redis/redission/RedissionCacheSourceProvider.java @@ -0,0 +1,35 @@ +/* + * 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 org.redkalex.cache.redis.redission; + +import org.redkale.annotation.Priority; +import org.redkale.source.CacheSource; +import org.redkale.source.CacheSourceProvider; +import org.redkale.util.AnyValue; + +/** + * + * @author zhangjx + */ +@Priority(-300) +public class RedissionCacheSourceProvider implements CacheSourceProvider { + + @Override + public boolean acceptsConf(AnyValue config) { + try { + Object.class.isAssignableFrom(org.redisson.config.Config.class); //试图加载Redission相关类 + return new RedissionCacheSource().acceptsConf(config); + } catch (Throwable e) { + return false; + } + } + + @Override + public CacheSource createInstance() { + return new RedissionCacheSource(); + } + +} diff --git a/src/org/redkalex/cache/redis/vertx/RedisVertxCacheSource.java b/src/org/redkalex/cache/redis/vertx/RedisVertxCacheSource.java new file mode 100644 index 0000000..7f7ac49 --- /dev/null +++ b/src/org/redkalex/cache/redis/vertx/RedisVertxCacheSource.java @@ -0,0 +1,1781 @@ +/* + */ +package org.redkalex.cache.redis.vertx; + +import com.zdemo.cachex.AbstractRedisSource; +import com.zdemo.cachex.RedisCryptor; +import io.vertx.core.*; +import io.vertx.redis.client.*; +import org.redkale.annotation.AutoLoad; +import org.redkale.annotation.ResourceListener; +import org.redkale.annotation.ResourceType; +import org.redkale.convert.Convert; +import org.redkale.convert.json.JsonConvert; +import org.redkale.service.Local; +import org.redkale.source.CacheSource; +import org.redkale.util.*; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author zhangjx + */ +@Local +@AutoLoad(false) +@ResourceType(CacheSource.class) +public class RedisVertxCacheSource extends AbstractRedisSource { + + protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName()); + + protected Type objValueType = String.class; + + protected List nodeAddrs; + + protected Vertx vertx; + + protected io.vertx.redis.client.RedisAPI client; + + @Override + public void init(AnyValue conf) { + super.init(conf); + if (conf == null) { + conf = AnyValue.create(); + } + initClient(conf); + } + + private void initClient(AnyValue conf) { + String password = null; + int urlmaxconns = Utility.cpus(); + List addrs = new ArrayList<>(); + for (AnyValue node : getNodes(conf)) { + String addrstr = node.getValue(CACHE_SOURCE_URL); + addrs.add(addrstr); + password = node.getValue(CACHE_SOURCE_PASSWORD, null); + if (db < 0) { + String db0 = node.getValue(CACHE_SOURCE_DB, "").trim(); + if (!db0.isEmpty()) { + db = Integer.valueOf(db0); + } + } + URI uri = URI.create(addrstr); + if (uri.getQuery() != null && !uri.getQuery().isEmpty()) { + String[] qrys = uri.getQuery().split("&|="); + for (int i = 0; i < qrys.length; i += 2) { + if (CACHE_SOURCE_MAXCONNS.equals(qrys[i])) { + urlmaxconns = i == qrys.length - 1 ? Utility.cpus() : Integer.parseInt(qrys[i + 1]); + } + } + } + } + int maxconns = conf.getIntValue(CACHE_SOURCE_MAXCONNS, urlmaxconns); + //Redis链接 + RedisOptions redisConfig = new RedisOptions(); + if (maxconns > 0) { + redisConfig.setMaxPoolSize(maxconns); + } + if (password != null) { + redisConfig.setPassword(password.trim()); + } + if (maxconns > 0) { + redisConfig.setMaxPoolWaiting(maxconns != Utility.cpus() ? maxconns : maxconns * 10); + } + redisConfig.setEndpoints(addrs); + if (this.vertx == null) { + this.vertx = Vertx.vertx(new VertxOptions().setWorkerPoolSize(Utility.cpus()).setPreferNativeTransport(true)); + } + RedisAPI old = this.client; + this.client = RedisAPI.api(Redis.createClient(this.vertx, redisConfig)); + if (old != null) { + old.close(); + } + } + + @Override + @ResourceListener + public void onResourceChange(ResourceEvent[] events) { + if (events == null || events.length < 1) { + return; + } + StringBuilder sb = new StringBuilder(); + for (ResourceEvent event : events) { + sb.append("CacheSource(name=").append(resourceName()).append(") change '").append(event.name()).append("' to '").append(event.coverNewValue()).append("'\r\n"); + } + initClient(this.config); + if (sb.length() > 0) { + logger.log(Level.INFO, sb.toString()); + } + } + + public boolean acceptsConf(AnyValue config) { + if (config == null) { + return false; + } + AnyValue[] nodes = getNodes(config); + if (nodes == null || nodes.length == 0) { + return false; + } + for (AnyValue node : nodes) { + String val = node.getValue(CACHE_SOURCE_URL); + if (val != null && val.startsWith("redis://")) { + return true; + } + if (val != null && val.startsWith("rediss://")) { + return true; + } + } + return false; + } + + protected AnyValue[] getNodes(AnyValue config) { + AnyValue[] nodes = config.getAnyValues(CACHE_SOURCE_NODE); + if (nodes == null || nodes.length == 0) { + AnyValue one = config.getAnyValue(CACHE_SOURCE_NODE); + if (one == null) { + String val = config.getValue(CACHE_SOURCE_URL); + if (val == null) { + return nodes; + } + nodes = new AnyValue[]{config}; + } else { + nodes = new AnyValue[]{one}; + } + } + return nodes; + } + + @Override + public final String getType() { + return "redis"; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{addrs=" + this.nodeAddrs + ", db=" + this.db + "}"; + } + + @Override + public void destroy(AnyValue conf) { + super.destroy(conf); + if (client != null) { + client.close(); + } + if (this.vertx != null) { + this.vertx.close(); + } + } + + protected CompletableFuture completableFuture(io.vertx.core.Future rf) { + return rf.toCompletionStage().toCompletableFuture(); + } + + protected CompletableFuture sendAsync(Command cmd, String... args) { + return completableFuture(redisAPI().send(cmd, args)); + } + + protected RedisAPI redisAPI() { + return client; + } + + protected Long orElse(Long v, long def) { + return v == null ? def : v; + } + + protected Integer orElse(Integer v, int def) { + return v == null ? def : v; + } + + protected Boolean getBooleanValue(Response resp) { + if (resp == null) { + return false; + } + Boolean v = resp.toBoolean(); + return v == null ? false : v; + } + + protected String getStringValue(String key, RedisCryptor cryptor, Response resp) { + if (resp == null) { + return null; + } + String val = resp.toString(StandardCharsets.UTF_8); + if (cryptor == null) { + return val; + } + return cryptor.decrypt(key, val); + } + + protected Long getLongValue(Response resp, long defvalue) { + if (resp == null) { + return defvalue; + } + Long v = resp.toLong(); + return v == null ? defvalue : v; + } + + protected Double getDoubleValue(Response resp, double defvalue) { + if (resp == null) { + return defvalue; + } + Double v = resp.toDouble(); + return v == null ? defvalue : v; + } + + protected Integer getIntValue(Response resp, int defvalue) { + if (resp == null) { + return defvalue; + } + Integer v = resp.toInteger(); + return v == null ? defvalue : v; + } + + protected Boolean getBoolValue(Response resp) { + if (resp == null) { + return false; + } + Integer v = resp.toInteger(); + return v == null ? false : v > 0; + } + + protected T getObjectValue(String key, RedisCryptor cryptor, String bs, Type type) { + if (bs == null) { + return null; + } + if (type == byte[].class) { + return (T) bs.getBytes(StandardCharsets.UTF_8); + } + if (type == String.class) { + return (T) decryptValue(key, cryptor, bs); + } + if (type == long.class) { + return (T) (Long) Long.parseLong(bs); + } + return (T) JsonConvert.root().convertFrom(type, decryptValue(key, cryptor, bs)); + } + + protected T getObjectValue(String key, RedisCryptor cryptor, Response resp, Type type) { + return getObjectValue(key, cryptor, resp == null ? null : resp.toString(StandardCharsets.UTF_8), type); + } + + protected Collection getCollectionValue(String key, RedisCryptor cryptor, Response resp, boolean set, Type type) { + int size = resp == null ? 0 : resp.size(); + if (size == 0) { + return set ? new LinkedHashSet<>() : new ArrayList<>(); + } + Collection list = set ? new LinkedHashSet<>() : new ArrayList<>(); + for (int i = 0; i < size; i++) { + list.add(getObjectValue(key, cryptor, resp.get(i), type)); + } + return list; + } + + protected Map getMapValue(String key, RedisCryptor cryptor, Response gresp, Type type) { + int gsize = gresp.size(); + if (gsize == 0) { + return new LinkedHashMap<>(); + } + Map map = new LinkedHashMap<>(); + //resp.tostring = [0, [key1, 10, key2, 30]] + for (int j = 0; j < gsize; j++) { + Response resp = gresp.get(j); + if (resp.type() != ResponseType.MULTI) { + continue; + } + int size = resp.size(); + for (int i = 0; i < size; i += 2) { + String bs1 = resp.get(i).toString(StandardCharsets.UTF_8); + String bs2 = resp.get(i + 1).toString(StandardCharsets.UTF_8); + T val = getObjectValue(key, cryptor, bs2, type); + if (val != null) { + map.put(getObjectValue(key, cryptor, bs1, String.class).toString(), val); + } + } + } + return map; + } + + protected String[] keyArgs(boolean set, String key) { + if (set) { + return new String[]{key}; + } + return new String[]{key, "0", "-1"}; + } + + protected String formatValue(long value) { + return String.valueOf(value); + } + + protected String formatValue(String key, RedisCryptor cryptor, String value) { + return encryptValue(key, cryptor, value); + } + + protected String formatValue(String key, RedisCryptor cryptor, Object value) { + return formatValue(key, cryptor, null, null, value); + } + + protected String formatValue(String key, RedisCryptor cryptor, Convert convert0, Type type, Object value) { + if (value == null) { + throw new NullPointerException(); + } + if (value instanceof byte[]) { + return new String((byte[]) value, StandardCharsets.UTF_8); + } + if (convert0 == null) { + if (convert == null) { + convert = JsonConvert.root(); //compile模式下convert可能为null + } + convert0 = convert; + } + if (type == null) { + type = value.getClass(); + } + Class clz = value.getClass(); + if (clz == String.class || clz == Long.class + || Number.class.isAssignableFrom(clz) || CharSequence.class.isAssignableFrom(clz)) { + return String.valueOf(value); + } + String val = (convert0 instanceof JsonConvert) ? ((JsonConvert) convert0).convertTo(type, value) : new String(convert0.convertToBytes(type, value), StandardCharsets.UTF_8); + return encryptValue(key, cryptor, val); + } + + //--------------------- exists ------------------------------ + @Override + public CompletableFuture existsAsync(String key) { + return sendAsync(Command.EXISTS, key).thenApply(v -> getBooleanValue(v)); + } + + @Override + public boolean exists(String key) { + return existsAsync(key).join(); + } + + //--------------------- get ------------------------------ + @Override + public CompletableFuture getAsync(String key, Type type) { + return sendAsync(Command.GET, key).thenApply(v -> getObjectValue(key, cryptor, v, type)); + } + + @Override + public CompletableFuture getStringAsync(String key) { + return sendAsync(Command.GET, key).thenApply(v -> getStringValue(key, cryptor, v)); + } + + @Override + public CompletableFuture getLongAsync(String key, long defValue) { + return sendAsync(Command.GET, key).thenApply(v -> getLongValue(v, defValue)); + } + + @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 String getSetString(String key, String value) { + return getSetStringAsync(key, value).join(); + } + + @Override + public long getLong(String key, long defValue) { + return getLongAsync(key, defValue).join(); + } + + @Override + public long getSetLong(String key, long value, long defValue) { + return getSetLongAsync(key, value, defValue).join(); + } + + //--------------------- getex ------------------------------ + @Override + public CompletableFuture getexAsync(String key, int expireSeconds, final Type type) { + return sendAsync(Command.GETEX, key, "EX", String.valueOf(expireSeconds)).thenApply(v -> getObjectValue(key, cryptor, v, type)); + } + + @Override + public T getex(String key, final int expireSeconds, final Type type) { + return (T) getexAsync(key, expireSeconds, type).join(); + } + + @Override + public CompletableFuture getexStringAsync(String key, int expireSeconds) { + return sendAsync(Command.GETEX, key, "EX", String.valueOf(expireSeconds)).thenApply(v -> getStringValue(key, cryptor, v)); + } + + @Override + public String getexString(String key, final int expireSeconds) { + return getexStringAsync(key, expireSeconds).join(); + } + + @Override + public CompletableFuture getexLongAsync(String key, int expireSeconds, long defValue) { + return sendAsync(Command.GETEX, key, "EX", String.valueOf(expireSeconds)).thenApply(v -> getLongValue(v, defValue)); + } + + @Override + public long getexLong(String key, final int expireSeconds, long defValue) { + return getexLongAsync(key, expireSeconds, defValue).join(); + } + + @Override + public void mset(final Object... keyVals) { + msetAsync(keyVals).join(); + } + + @Override + public void mset(final Map map) { + msetAsync(map).join(); + } + + //--------------------- set ------------------------------ + @Override + public CompletableFuture msetAsync(final Object... keyVals) { + if (keyVals.length % 2 != 0) { + throw new RedkaleException("key value must be paired"); + } + String[] args = new String[keyVals.length]; + for (int i = 0; i < keyVals.length; i += 2) { + String key = keyVals[i].toString(); + Object val = keyVals[i + 1]; + args[i] = key; + args[i + 1] = formatValue(key, cryptor, convert, val.getClass(), val); + } + return sendAsync(Command.MSET, args).thenApply(v -> null); + } + + @Override + public CompletableFuture msetAsync(final Map map) { + if (map == null || map.isEmpty()) { + return CompletableFuture.completedFuture(null); + } + List bs = new ArrayList<>(); + map.forEach((key, val) -> { + bs.add(key.toString()); + bs.add(formatValue(key.toString(), cryptor, convert, val.getClass(), val)); + }); + return sendAsync(Command.MSET, bs.toArray(new String[bs.size()])).thenApply(v -> null); + } + + @Override + public CompletableFuture setAsync(String key, final Type type, T value) { + return sendAsync(Command.SET, key, formatValue(key, cryptor, (Convert) null, type, value)).thenApply(v -> null); + } + + @Override + public CompletableFuture setAsync(String key, Convert convert, final Type type, T value) { + return sendAsync(Command.SET, key, formatValue(key, cryptor, convert, type, value)).thenApply(v -> null); + } + + @Override + public CompletableFuture setnxAsync(String key, final Type type, T value) { + return sendAsync(Command.SETNX, key, formatValue(key, cryptor, (Convert) null, type, value)).thenApply(v -> getBoolValue(v)); + } + + @Override + public CompletableFuture setnxAsync(String key, Convert convert, final Type type, T value) { + return sendAsync(Command.SETNX, key, formatValue(key, cryptor, convert, type, value)).thenApply(v -> getBoolValue(v)); + } + + @Override + public CompletableFuture getSetAsync(String key, final Type type, T value) { + return sendAsync(Command.GETSET, key, formatValue(key, cryptor, convert, type, value)).thenApply(v -> getObjectValue(key, cryptor, v, type)); + } + + @Override + public CompletableFuture getSetAsync(String key, Convert convert0, final Type type, T value) { + return sendAsync(Command.GETSET, key, formatValue(key, cryptor, convert0, type, value)).thenApply(v -> getObjectValue(key, cryptor, v, type)); + } + + @Override + public void set(final String key, final Type type, T value) { + setAsync(key, type, value).join(); + } + + @Override + public void set(final String key, final Convert convert, final Type type, T value) { + setAsync(key, convert, type, value).join(); + } + + @Override + public boolean setnx(final String key, final Type type, T value) { + return setnxAsync(key, type, value).join(); + } + + @Override + public boolean setnx(final String key, final Convert convert, final Type type, T value) { + return setnxAsync(key, convert, type, value).join(); + } + + @Override + public T getSet(final String key, final Type type, T value) { + return getSetAsync(key, type, value).join(); + } + + @Override + public T getSet(String key, final Convert convert, final Type type, T value) { + return getSetAsync(key, convert, type, value).join(); + } + + @Override + public CompletableFuture setStringAsync(String key, String value) { + return sendAsync(Command.SET, key, formatValue(key, cryptor, value)).thenApply(v -> null); + } + + @Override + public CompletableFuture setnxStringAsync(String key, String value) { + return sendAsync(Command.SETNX, key, formatValue(key, cryptor, value)).thenApply(v -> getBoolValue(v)); + } + + @Override + public CompletableFuture getSetStringAsync(String key, String value) { + return sendAsync(Command.GETSET, key, formatValue(key, cryptor, value)).thenApply(v -> getStringValue(key, cryptor, v)); + } + + @Override + public void setString(String key, String value) { + setStringAsync(key, value).join(); + } + + @Override + public boolean setnxString(String key, String value) { + return setnxStringAsync(key, value).join(); + } + + @Override + public CompletableFuture setLongAsync(String key, long value) { + return sendAsync(Command.SET, key, formatValue(value)).thenApply(v -> null); + } + + @Override + public CompletableFuture setnxLongAsync(String key, long value) { + return sendAsync(Command.SETNX, key, formatValue(value)).thenApply(v -> getBoolValue(v)); + } + + @Override + public CompletableFuture getSetLongAsync(String key, long value, long defvalue) { + return sendAsync(Command.GETSET, key, formatValue(value)).thenApply(v -> getLongValue(v, defvalue)); + } + + @Override + public void setLong(String key, long value) { + setLongAsync(key, value).join(); + } + + @Override + public boolean setnxLong(String key, long value) { + return setnxLongAsync(key, value).join(); + } + + //--------------------- setex ------------------------------ + @Override + public CompletableFuture setexAsync(String key, int expireSeconds, final Type type, T value) { + return sendAsync(Command.SETEX, key, String.valueOf(expireSeconds), formatValue(key, cryptor, (Convert) null, type, value)).thenApply(v -> null); + } + + @Override + public CompletableFuture setexAsync(String key, int expireSeconds, Convert convert, final Type type, T value) { + return sendAsync(Command.SETEX, key, String.valueOf(expireSeconds), formatValue(key, cryptor, convert, type, value)).thenApply(v -> null); + } + + @Override + public CompletableFuture setnxexAsync(String key, int expireSeconds, final Type type, T value) { + return sendAsync(Command.SET, key, formatValue(key, cryptor, (Convert) null, type, value), "NX", "EX", String.valueOf(expireSeconds)).thenApply(v -> v != null && ("OK".equals(v.toString()) || v.toInteger() > 0)); + } + + @Override + public CompletableFuture setnxexAsync(String key, int expireSeconds, Convert convert, final Type type, T value) { + return sendAsync(Command.SET, key, formatValue(key, cryptor, convert, type, value), "NX", "EX", String.valueOf(expireSeconds)).thenApply(v -> v != null && ("OK".equals(v.toString()) || v.toInteger() > 0)); + } + + @Override + public void setex(String key, int expireSeconds, final Type type, T value) { + setexAsync(key, expireSeconds, type, value).join(); + } + + @Override + public void setex(String key, int expireSeconds, Convert convert, final Type type, T value) { + setexAsync(key, expireSeconds, convert, type, value).join(); + } + + @Override + public boolean setnxex(String key, int expireSeconds, final Type type, T value) { + return setnxexAsync(key, expireSeconds, type, value).join(); + } + + @Override + public boolean setnxex(String key, int expireSeconds, Convert convert, final Type type, T value) { + return setnxexAsync(key, expireSeconds, convert, type, value).join(); + } + + @Override + public CompletableFuture setexStringAsync(String key, int expireSeconds, String value) { + return sendAsync(Command.SETEX, key, String.valueOf(expireSeconds), formatValue(key, cryptor, value)).thenApply(v -> null); + } + + @Override + public CompletableFuture setnxexStringAsync(String key, int expireSeconds, String value) { + return sendAsync(Command.SET, key, formatValue(key, cryptor, value), "NX", "EX", String.valueOf(expireSeconds)).thenApply(v -> v != null && ("OK".equals(v.toString()) || v.toInteger() > 0)); + } + + @Override + public void setexString(String key, int expireSeconds, String value) { + setexStringAsync(key, expireSeconds, value).join(); + } + + @Override + public boolean setnxexString(String key, int expireSeconds, String value) { + return setnxexStringAsync(key, expireSeconds, value).join(); + } + + @Override + public CompletableFuture setexLongAsync(String key, int expireSeconds, long value) { + return sendAsync(Command.SETEX, key, String.valueOf(expireSeconds), formatValue(value)).thenApply(v -> null); + } + + @Override + public void setexLong(String key, int expireSeconds, long value) { + setexLongAsync(key, expireSeconds, value).join(); + } + + @Override + public CompletableFuture setnxexLongAsync(String key, int expireSeconds, long value) { + return sendAsync(Command.SET, key, formatValue(value), "NX", "EX", String.valueOf(expireSeconds)).thenApply(v -> v != null && ("OK".equals(v.toString()) || v.toInteger() > 0)); + } + + @Override + public boolean setnxexLong(String key, int expireSeconds, long value) { + return setnxexLongAsync(key, expireSeconds, value).join(); + } + + //--------------------- expire ------------------------------ + @Override + public CompletableFuture expireAsync(String key, int expireSeconds) { + return sendAsync(Command.EXPIRE, key, String.valueOf(expireSeconds)).thenApply(v -> null); + } + + @Override + public void expire(String key, int expireSeconds) { + expireAsync(key, expireSeconds).join(); + } + + //--------------------- del ------------------------------ + @Override + public CompletableFuture delAsync(String... keys) { + return sendAsync(Command.DEL, keys).thenApply(v -> v.toInteger()); + } + + @Override + public int del(String... keys) { + return delAsync(keys).join(); + } + + //--------------------- incrby ------------------------------ + @Override + public long incr(final String key) { + return incrAsync(key).join(); + } + + @Override + public CompletableFuture incrAsync(final String key) { + return sendAsync(Command.INCR, key).thenApply(v -> getLongValue(v, 0L)); + } + + @Override + public long incrby(final String key, long num) { + return incrbyAsync(key, num).join(); + } + + @Override + public double incrbyFloat(final String key, double num) { + return incrbyFloatAsync(key, num).join(); + } + + @Override + public CompletableFuture incrbyAsync(final String key, long num) { + return sendAsync(Command.INCRBY, key, String.valueOf(num)).thenApply(v -> getLongValue(v, 0L)); + } + + @Override + public CompletableFuture incrbyFloatAsync(final String key, double num) { + return sendAsync(Command.INCRBYFLOAT, key, String.valueOf(num)).thenApply(v -> getDoubleValue(v, 0.d)); + } + + //--------------------- decrby ------------------------------ + @Override + public long decr(final String key) { + return decrAsync(key).join(); + } + + @Override + public CompletableFuture decrAsync(final String key) { + return sendAsync(Command.DECR, key).thenApply(v -> getLongValue(v, 0L)); + } + + @Override + public long decrby(final String key, long num) { + return decrbyAsync(key, num).join(); + } + + @Override + public CompletableFuture decrbyAsync(final String key, long num) { + return sendAsync(Command.DECRBY, key, String.valueOf(num)).thenApply(v -> getLongValue(v, 0L)); + } + + @Override + public int hdel(final String key, String... fields) { + return hdelAsync(key, fields).join(); + } + + @Override + public int hlen(final String key) { + return hlenAsync(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 hincrby(final String key, String field, long num) { + return hincrbyAsync(key, field, num).join(); + } + + @Override + public double hincrbyFloat(final String key, String field, double num) { + return hincrbyFloatAsync(key, field, num).join(); + } + + @Override + public long hdecr(final String key, String field) { + return hdecrAsync(key, field).join(); + } + + @Override + public long hdecrby(final String key, String field, long num) { + return hdecrbyAsync(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 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 boolean hsetnx(final String key, final String field, final Type type, final T value) { + return hsetnxAsync(key, field, type, value).join(); + } + + @Override + public boolean hsetnx(final String key, final String field, final Convert convert, final Type type, final T value) { + return hsetnxAsync(key, field, convert, type, value).join(); + } + + @Override + public boolean hsetnxString(final String key, final String field, final String value) { + return hsetnxStringAsync(key, field, value).join(); + } + + @Override + public boolean hsetnxLong(final String key, final String field, final long value) { + return hsetnxLongAsync(key, field, value).join(); + } + + @Override + public void hmset(final String key, final Serializable... values) { + hmsetAsync(key, values).join(); + } + + @Override + public void hmset(final String key, final Map map) { + hmsetAsync(key, map).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 hdelAsync(final String key, String... fields) { + String[] args = new String[fields.length + 1]; + args[0] = key; + System.arraycopy(fields, 0, args, 1, fields.length); + return sendAsync(Command.HDEL, args).thenApply(v -> getIntValue(v, 0)); + } + + @Override + public CompletableFuture hlenAsync(final String key) { + return sendAsync(Command.HLEN, key).thenApply(v -> getIntValue(v, 0)); + } + + @Override + public CompletableFuture> hkeysAsync(final String key) { + return sendAsync(Command.HKEYS, key).thenApply(v -> (List) getCollectionValue(key, cryptor, v, false, String.class)); + } + + @Override + public CompletableFuture hincrAsync(final String key, String field) { + return hincrbyAsync(key, field, 1); + } + + @Override + public CompletableFuture hincrbyAsync(final String key, String field, long num) { + return sendAsync(Command.HINCRBY, key, field, String.valueOf(num)).thenApply(v -> getLongValue(v, 0L)); + } + + @Override + public CompletableFuture hincrbyFloatAsync(final String key, String field, double num) { + return sendAsync(Command.HINCRBYFLOAT, key, field, String.valueOf(num)).thenApply(v -> getDoubleValue(v, 0d)); + } + + @Override + public CompletableFuture hdecrAsync(final String key, String field) { + return hincrbyAsync(key, field, -1); + } + + @Override + public CompletableFuture hdecrbyAsync(final String key, String field, long num) { + return hincrbyAsync(key, field, -num); + } + + @Override + public CompletableFuture hexistsAsync(final String key, String field) { + return sendAsync(Command.HEXISTS, key, field).thenApply(v -> getIntValue(v, 0) > 0); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Type type, final T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync(Command.HSET, key, field, formatValue(key, cryptor, null, type, value)).thenApply(v -> null); + } + + @Override + public CompletableFuture hsetAsync(final String key, final String field, final Convert convert, final Type type, final T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync(Command.HSET, key, field, formatValue(key, cryptor, convert, type, value)).thenApply(v -> null); + } + + @Override + public CompletableFuture hsetStringAsync(final String key, final String field, final String value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync(Command.HSET, key, field, formatValue(key, cryptor, value)).thenApply(v -> null); + } + + @Override + public CompletableFuture hsetLongAsync(final String key, final String field, final long value) { + return sendAsync(Command.HSET, key, field, formatValue(value)).thenApply(v -> null); + } + + @Override + public CompletableFuture hsetnxAsync(final String key, final String field, final Type type, final T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync(Command.HSETNX, key, field, formatValue(key, cryptor, null, type, value)).thenApply(v -> getBoolValue(v)); + } + + @Override + public CompletableFuture hsetnxAsync(final String key, final String field, final Convert convert, final Type type, final T value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync(Command.HSETNX, key, field, formatValue(key, cryptor, convert, type, value)).thenApply(v -> getBoolValue(v)); + } + + @Override + public CompletableFuture hsetnxStringAsync(final String key, final String field, final String value) { + if (value == null) { + return CompletableFuture.completedFuture(null); + } + return sendAsync(Command.HSETNX, key, field, formatValue(key, cryptor, value)).thenApply(v -> getBoolValue(v)); + } + + @Override + public CompletableFuture hsetnxLongAsync(final String key, final String field, final long value) { + return sendAsync(Command.HSETNX, key, field, formatValue(value)).thenApply(v -> getBoolValue(v)); + } + + @Override + public CompletableFuture hmsetAsync(final String key, final Serializable... values) { + String[] args = new String[values.length + 1]; + args[0] = key; + for (int i = 0; i < values.length; i += 2) { + args[i + 1] = String.valueOf(values[i]); + args[i + 2] = formatValue(key, cryptor, values[i + 1]); + } + return sendAsync(Command.HMSET, args).thenApply(v -> null); + } + + @Override + public CompletableFuture hmsetAsync(final String key, final Map map) { + if (map == null || map.isEmpty()) { + return CompletableFuture.completedFuture(null); + } + List bs = new ArrayList<>(); + bs.add(key); + map.forEach((k, v) -> { + bs.add(k.toString()); + bs.add(formatValue(k.toString(), cryptor, convert, v.getClass(), v)); + }); + return sendAsync(Command.HMSET, bs.toArray(new String[bs.size()])).thenApply(v -> null); + } + + @Override + public CompletableFuture> hmgetAsync(final String key, final Type type, final String... fields) { + String[] args = new String[fields.length + 1]; + args[0] = key; + for (int i = 0; i < fields.length; i++) { + args[i + 1] = fields[i]; + } + return sendAsync(Command.HMGET, args).thenApply(v -> (List) getCollectionValue(key, cryptor, v, false, type)); + } + + @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) { + String[] args = new String[pattern == null || pattern.isEmpty() ? 4 : 6]; + int index = -1; + args[++index] = key; + args[++index] = String.valueOf(offset); + if (pattern != null && !pattern.isEmpty()) { + args[++index] = "MATCH"; + args[++index] = pattern; + } + args[++index] = "COUNT"; + args[++index] = String.valueOf(limit); + return sendAsync(Command.HSCAN, args).thenApply(v -> getMapValue(key, cryptor, v, type)); + } + + @Override + public CompletableFuture hgetAsync(final String key, final String field, final Type type) { + return sendAsync(Command.HGET, key, field).thenApply(v -> getObjectValue(key, cryptor, v, type)); + } + + @Override + public CompletableFuture hgetStringAsync(final String key, final String field) { + return sendAsync(Command.HGET, key, field).thenApply(v -> getStringValue(key, cryptor, v)); + } + + @Override + public CompletableFuture hgetLongAsync(final String key, final String field, long defValue) { + return sendAsync(Command.HGET, key, field).thenApply(v -> getLongValue(v, defValue)); + } + + //--------------------- collection ------------------------------ + @Override + public CompletableFuture llenAsync(String key) { + return sendAsync(Command.TYPE, key).thenCompose(t -> sendAsync(Command.LLEN, key).thenApply(v -> getIntValue(v, 0))); + } + + @Override + public CompletableFuture scardAsync(String key) { + return sendAsync(Command.TYPE, key).thenCompose(t -> sendAsync(Command.SCARD, key).thenApply(v -> getIntValue(v, 0))); + } + + @Override + public int llen(String key) { + return llenAsync(key).join(); + } + + @Override + public int scard(String key) { + return scardAsync(key).join(); + } + + @Override + public CompletableFuture> smembersAsync(String key, final Type componentType) { + return sendAsync(Command.SMEMBERS, keyArgs(true, key)).thenApply(v -> (Set) getCollectionValue(key, cryptor, v, true, componentType)); + } + + @Override + public CompletableFuture> lrangeAsync(String key, final Type componentType) { + return sendAsync(Command.LRANGE, keyArgs(false, key)).thenApply(v -> (List) getCollectionValue(key, cryptor, v, false, componentType)); + } + + @Override + public CompletableFuture> mgetLongAsync(String... keys) { + return sendAsync(Command.MGET, keys).thenApply(v -> { + List list = (List) getCollectionValue(null, null, v, false, long.class); + 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> mgetStringAsync(String... keys) { + return sendAsync(Command.MGET, keys).thenApply(v -> { + List list = (List) getCollectionValue(keys[0], cryptor, v, false, String.class); + 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> mgetAsync(final Type componentType, String... keys) { + return sendAsync(Command.MGET, keys).thenApply(v -> { + List list = (List) getCollectionValue(keys[0], cryptor, v, false, componentType); + 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> mgetBytesAsync(String... keys) { + return sendAsync(Command.MGET, keys).thenApply(v -> { + List list = (List) getCollectionValue(keys[0], cryptor, v, false, byte[].class); + 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>> lrangeAsync(final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = sendAsync(Command.LRANGE, keyArgs(false, key)).thenAccept(v -> { + List c = (List) getCollectionValue(key, cryptor, v, false, componentType); + if (c != null) { + mapLock.lock(); + try { + map.put(key, c); + } finally { + mapLock.unlock(); + } + } + }); + } + CompletableFuture.allOf(futures) + .whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + } + ); + return rsFuture; + } + + @Override + public CompletableFuture>> smembersAsync(final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = sendAsync(Command.SMEMBERS, keyArgs(true, key)).thenAccept(v -> { + Set c = (Set) getCollectionValue(key, cryptor, v, true, componentType); + if (c != null) { + mapLock.lock(); + try { + map.put(key, c); + } finally { + mapLock.unlock(); + } + } + }); + } + CompletableFuture.allOf(futures) + .whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + } + ); + return rsFuture; + } + + @Override + public Set smembers(String key, final Type componentType) { + return (Set) smembersAsync(key, componentType).join(); + } + + @Override + public List lrange(String key, final Type componentType) { + return (List) lrangeAsync(key, componentType).join(); + } + + @Override + public Map mgetLong(final String... keys) { + return mgetLongAsync(keys).join(); + } + + @Override + public Map mgetString(final String... keys) { + return mgetStringAsync(keys).join(); + } + + @Override + public Map mget(final Type componentType, final String... keys) { + return (Map) mgetAsync(componentType, keys).join(); + } + + @Override + public Map mgetBytes(final String... keys) { + return (Map) mgetBytesAsync(keys).join(); + } + + @Override + public Map> smembers(final Type componentType, String... keys) { + return (Map) smembersAsync(componentType, keys).join(); + } + + @Override + public Map> lrange(final Type componentType, String... keys) { + return (Map) lrangeAsync(componentType, keys).join(); + } + + //--------------------- existsItem ------------------------------ + @Override + public boolean sismember(String key, final Type componentType, T value) { + return sismemberAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture sismemberAsync(String key, final Type componentType, T value) { + return sendAsync(Command.SISMEMBER, key, formatValue(key, cryptor, (Convert) null, componentType, value)).thenApply(v -> getIntValue(v, 0) > 0); + } + + @Override + public boolean sismemberString(String key, String value) { + return sismemberStringAsync(key, value).join(); + } + + @Override + public CompletableFuture sismemberStringAsync(String key, String value) { + return sendAsync(Command.SISMEMBER, key, formatValue(key, cryptor, value)).thenApply(v -> getIntValue(v, 0) > 0); + } + + @Override + public boolean sismemberLong(String key, long value) { + return sismemberLongAsync(key, value).join(); + } + + @Override + public CompletableFuture sismemberLongAsync(String key, long value) { + return sendAsync(Command.SISMEMBER, key, formatValue(value)).thenApply(v -> getIntValue(v, 0) > 0); + } + + //--------------------- rpush ------------------------------ + @Override + public CompletableFuture rpushAsync(String key, final Type componentType, T value) { + return sendAsync(Command.RPUSH, key, formatValue(key, cryptor, (Convert) null, componentType, value)).thenApply(v -> null); + } + + @Override + public void rpush(String key, final Type componentType, T value) { + rpushAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture rpushStringAsync(String key, String value) { + return sendAsync(Command.RPUSH, key, formatValue(key, cryptor, value)).thenApply(v -> null); + } + + @Override + public void rpushString(String key, String value) { + rpushStringAsync(key, value).join(); + } + + @Override + public CompletableFuture rpushLongAsync(String key, long value) { + return sendAsync(Command.RPUSH, key, formatValue(value)).thenApply(v -> null); + } + + @Override + public void rpushLong(String key, long value) { + rpushLongAsync(key, value).join(); + } + + //--------------------- lrem ------------------------------ + @Override + public CompletableFuture lremAsync(String key, final Type componentType, T value) { + return sendAsync(Command.LREM, key, "0", formatValue(key, cryptor, (Convert) null, componentType, value)).thenApply(v -> getIntValue(v, 0)); + } + + @Override + public int lrem(String key, final Type componentType, T value) { + return lremAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture lremStringAsync(String key, String value) { + return sendAsync(Command.LREM, key, "0", formatValue(key, cryptor, value)).thenApply(v -> getIntValue(v, 0)); + } + + @Override + public int lremString(String key, String value) { + return lremStringAsync(key, value).join(); + } + + @Override + public CompletableFuture lremLongAsync(String key, long value) { + return sendAsync(Command.LREM, key, "0", formatValue(value)).thenApply(v -> getIntValue(v, 0)); + } + + @Override + public int lremLong(String key, long value) { + return lremLongAsync(key, value).join(); + } + + //--------------------- sadd ------------------------------ + @Override + public CompletableFuture saddAsync(String key, Type componentType, T value) { + return sendAsync(Command.SADD, key, formatValue(key, cryptor, (Convert) null, componentType, value)).thenApply(v -> null); + } + + @Override + public CompletableFuture spopAsync(String key, Type componentType) { + return sendAsync(Command.SPOP, key).thenApply(v -> getObjectValue(key, cryptor, v, componentType)); + } + + @Override + public CompletableFuture> spopAsync(String key, int count, Type componentType) { + return sendAsync(Command.SPOP, key, String.valueOf(count)).thenApply(v -> getObjectValue(key, cryptor, v, componentType)); + } + + @Override + public CompletableFuture spopStringAsync(String key) { + return sendAsync(Command.SPOP, key).thenApply(v -> getStringValue(key, cryptor, v)); + } + + @Override + public CompletableFuture> spopStringAsync(String key, int count) { + return sendAsync(Command.SPOP, key, String.valueOf(count)).thenApply(v -> (Set) getCollectionValue(key, cryptor, v, true, String.class)); + } + + @Override + public CompletableFuture spopLongAsync(String key) { + return sendAsync(Command.SPOP, key).thenApply(v -> getLongValue(v, 0L)); + } + + @Override + public CompletableFuture> spopLongAsync(String key, int count) { + return sendAsync(Command.SPOP, key, String.valueOf(count)).thenApply(v -> (Set) getCollectionValue(key, cryptor, v, true, long.class)); + } + + @Override + public void sadd(String key, final Type componentType, T value) { + saddAsync(key, componentType, value).join(); + } + + @Override + public T spop(String key, final Type componentType) { + return (T) spopAsync(key, componentType).join(); + } + + @Override + public Set spop(String key, int count, final Type componentType) { + return (Set) spopAsync(key, count, componentType).join(); + } + + @Override + public String spopString(String key) { + return spopStringAsync(key).join(); + } + + @Override + public Set spopString(String key, int count) { + return spopStringAsync(key, count).join(); + } + + @Override + public Long spopLong(String key) { + return spopLongAsync(key).join(); + } + + @Override + public Set spopLong(String key, int count) { + return spopLongAsync(key, count).join(); + } + + @Override + public CompletableFuture saddStringAsync(String key, String value) { + return sendAsync(Command.SADD, key, formatValue(key, cryptor, value)).thenApply(v -> null); + } + + @Override + public void saddString(String key, String value) { + saddStringAsync(key, value).join(); + } + + @Override + public CompletableFuture saddLongAsync(String key, long value) { + return sendAsync(Command.SADD, key, formatValue(value)).thenApply(v -> null); + } + + @Override + public void saddLong(String key, long value) { + saddLongAsync(key, value).join(); + } + + //--------------------- srem ------------------------------ + @Override + public CompletableFuture sremAsync(String key, final Type componentType, T value) { + return sendAsync(Command.SREM, key, formatValue(key, cryptor, (Convert) null, componentType, value)).thenApply(v -> getIntValue(v, 0)); + } + + @Override + public int srem(String key, final Type componentType, T value) { + return sremAsync(key, componentType, value).join(); + } + + @Override + public CompletableFuture sremStringAsync(String key, String value) { + return sendAsync(Command.SREM, key, formatValue(key, cryptor, value)).thenApply(v -> getIntValue(v, 0)); + } + + @Override + public int sremString(String key, String value) { + return sremStringAsync(key, value).join(); + } + + @Override + public CompletableFuture sremLongAsync(String key, long value) { + return sendAsync(Command.SREM, key, formatValue(value)).thenApply(v -> getIntValue(v, 0)); + } + + @Override + public int sremLong(String key, long value) { + return sremLongAsync(key, value).join(); + } + + //--------------------- keys ------------------------------ + @Override + public List keys(String pattern) { + return keysAsync(pattern).join(); + } + + @Override + public byte[] getBytes(final String key) { + return getBytesAsync(key).join(); + } + + @Override + public byte[] getSetBytes(final String key, byte[] value) { + return getSetBytesAsync(key, value).join(); + } + + @Override + public byte[] getexBytes(final String key, final int expireSeconds) { + return getexBytesAsync(key, expireSeconds).join(); + } + + @Override + public void setBytes(final String key, final byte[] value) { + setBytesAsync(key, value).join(); + } + + @Override + public void setexBytes(final String key, final int expireSeconds, final byte[] value) { + setexBytesAsync(key, expireSeconds, value).join(); + } + + @Override + public boolean setnxexBytes(final String key, final int expireSeconds, final byte[] value) { + return setnxexBytesAsync(key, expireSeconds, value).join(); + } + + @Override + public CompletableFuture getBytesAsync(final String key) { + return sendAsync(Command.GET, key).thenApply(v -> v.toBytes()); + } + + @Override + public CompletableFuture getSetBytesAsync(final String key, byte[] value) { + return sendAsync(Command.GETSET, key, new String(value, StandardCharsets.UTF_8)).thenApply(v -> v.toBytes()); + } + + @Override + public CompletableFuture getexBytesAsync(final String key, final int expireSeconds) { + return sendAsync(Command.GETEX, key, "EX", String.valueOf(expireSeconds)).thenApply(v -> v.toBytes()); + } + + @Override + public CompletableFuture setBytesAsync(final String key, final byte[] value) { + return sendAsync(Command.SET, key, new String(value, StandardCharsets.UTF_8)).thenApply(v -> null); + } + + @Override + public boolean setnxBytes(final String key, final byte[] value) { + return setnxBytesAsync(key, value).join(); + } + + @Override + public CompletableFuture setnxBytesAsync(final String key, byte[] value) { + return sendAsync(Command.SETNX, key, new String(value, StandardCharsets.UTF_8)).thenApply(v -> getBoolValue(v)); + } + + @Override + public CompletableFuture setexBytesAsync(final String key, final int expireSeconds, final byte[] value) { + return sendAsync(Command.SETEX, key, String.valueOf(expireSeconds), new String(value, StandardCharsets.UTF_8)).thenApply(v -> null); + } + + @Override + public CompletableFuture setnxexBytesAsync(final String key, final int expireSeconds, final byte[] value) { + return sendAsync(Command.SET, key, new String(value, StandardCharsets.UTF_8), "NX", "EX", String.valueOf(expireSeconds)).thenApply(v -> v != null && ("OK".equals(v.toString()) || v.toInteger() > 0)); + } + + @Override + public CompletableFuture> keysAsync(String pattern) { + return sendAsync(Command.KEYS, pattern == null || pattern.isEmpty() ? "*" : pattern).thenApply(v -> (List) getCollectionValue(null, null, v, false, String.class)); + } + + //--------------------- dbsize ------------------------------ + @Override + public long dbsize() { + return dbsizeAsync().join(); + } + + @Override + public CompletableFuture dbsizeAsync() { + return sendAsync(Command.DBSIZE).thenApply(v -> getLongValue(v, 0L)); + } + + @Override + public CompletableFuture> getStringCollectionAsync(String key) { + return sendAsync(Command.TYPE, key).thenCompose(t -> { + String type = t.toString(); + if (type == null) { + return CompletableFuture.completedFuture(null); + } + boolean set = !type.contains("list"); + return sendAsync(set ? Command.SMEMBERS : Command.LRANGE, keyArgs(set, key)).thenApply(v -> getCollectionValue(key, cryptor, v, set, String.class)); + }); + } + + @Override + public CompletableFuture>> getStringCollectionMapAsync(final boolean set, String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = sendAsync(set ? Command.SMEMBERS : Command.LRANGE, keyArgs(set, key)).thenAccept(v -> { + Collection c = getCollectionValue(key, cryptor, v, set, String.class); + if (c != null) { + mapLock.lock(); + try { + map.put(key, (Collection) c); + } finally { + mapLock.unlock(); + } + } + }); + } + CompletableFuture.allOf(futures).whenComplete((w, e) -> { + if (e != null) { + rsFuture.completeExceptionally(e); + } else { + rsFuture.complete(map); + } + }); + return rsFuture; + } + + @Override + public Collection getCollection(String key, final Type componentType) { + return (Collection) getCollectionAsync(key, componentType).join(); + } + + @Override + public Long[] getLongArray(final String... keys) { + return getLongArrayAsync(keys).join(); + } + + @Override + public String[] getStringArray(final String... keys) { + return getStringArrayAsync(keys).join(); + } + + @Override + public Map> getCollectionMap(final boolean set, final Type componentType, String... keys) { + return (Map) getCollectionMapAsync(set, componentType, keys).join(); + } + + @Override + public CompletableFuture getCollectionSizeAsync(String key) { + return sendAsync(Command.TYPE, key).thenCompose(t -> { + String type = t.toString(); + if (type == null) { + return CompletableFuture.completedFuture(0); + } + return sendAsync(type.contains("list") ? Command.LLEN : Command.SCARD, key).thenApply(v -> getIntValue(v, 0)); + }); + } + + @Override + public int getCollectionSize(String key) { + return getCollectionSizeAsync(key).join(); + } + + @Override + public CompletableFuture> getCollectionAsync(String key, final Type componentType) { + return sendAsync(Command.TYPE, key).thenCompose(t -> { + String type = t.toString(); + if (type == null) { + return CompletableFuture.completedFuture(null); + } + boolean set = !type.contains("list"); + return sendAsync(set ? Command.SMEMBERS : Command.LRANGE, keyArgs(set, key)).thenApply(v -> getCollectionValue(key, cryptor, v, set, componentType)); + }); + } + + @Override + public CompletableFuture getLongArrayAsync(String... keys) { + return sendAsync(Command.MGET, keys).thenApply(v -> { + List list = (List) getCollectionValue(null, null, v, false, long.class); + 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) { + return sendAsync(Command.MGET, keys).thenApply(v -> { + List list = (List) getCollectionValue(keys[0], cryptor, v, false, String.class); + 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>> getCollectionMapAsync(final boolean set, final Type componentType, final String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = sendAsync(set ? Command.SMEMBERS : Command.LRANGE, keyArgs(set, key)).thenAccept(v -> { + Collection c = getCollectionValue(key, cryptor, v, set, componentType); + if (c != null) { + mapLock.lock(); + try { + map.put(key, (Collection) c); + } finally { + mapLock.unlock(); + } + } + }); + } + + 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 sendAsync(Command.TYPE, key).thenCompose(t -> { + String type = t.toString(); + if (type == null) { + return CompletableFuture.completedFuture(null); + } + boolean set = !type.contains("list"); + return sendAsync(set ? Command.SMEMBERS : Command.LRANGE, keyArgs(set, key)).thenApply(v -> getCollectionValue(key, cryptor, v, set, long.class)); + }); + } + + @Override + public CompletableFuture>> getLongCollectionMapAsync(final boolean set, String... keys) { + final CompletableFuture>> rsFuture = new CompletableFuture<>(); + final Map> map = new LinkedHashMap<>(); + final ReentrantLock mapLock = new ReentrantLock(); + final CompletableFuture[] futures = new CompletableFuture[keys.length]; + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + futures[i] = sendAsync(set ? Command.SMEMBERS : Command.LRANGE, keyArgs(set, key)).thenAccept(v -> { + Collection c = getCollectionValue(key, cryptor, v, set, long.class); + if (c != null) { + mapLock.lock(); + try { + map.put(key, (Collection) c); + } finally { + mapLock.unlock(); + } + } + }); + } + 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(); + } + + //--------------------- getexCollection ------------------------------ + @Override + public CompletableFuture> getexCollectionAsync(String key, int expireSeconds, final Type componentType) { + return (CompletableFuture) expireAsync(key, expireSeconds).thenCompose(v -> getCollectionAsync(key, componentType)); + } + + @Override + public Collection getexCollection(String key, final int expireSeconds, final Type componentType) { + return (Collection) getexCollectionAsync(key, expireSeconds, componentType).join(); + } + + @Override + public CompletableFuture> getexStringCollectionAsync(String key, int expireSeconds) { + return (CompletableFuture) expireAsync(key, expireSeconds).thenCompose(v -> getStringCollectionAsync(key)); + } + + @Override + public Collection getexStringCollection(String key, final int expireSeconds) { + return getexStringCollectionAsync(key, expireSeconds).join(); + } + + @Override + public CompletableFuture> getexLongCollectionAsync(String key, int expireSeconds) { + return (CompletableFuture) expireAsync(key, expireSeconds).thenCompose(v -> getLongCollectionAsync(key)); + } + + @Override + public Collection getexLongCollection(String key, final int expireSeconds) { + return getexLongCollectionAsync(key, expireSeconds).join(); + } + +} diff --git a/src/org/redkalex/cache/redis/vertx/RedisVertxCacheSourceProvider.java b/src/org/redkalex/cache/redis/vertx/RedisVertxCacheSourceProvider.java new file mode 100644 index 0000000..a54235c --- /dev/null +++ b/src/org/redkalex/cache/redis/vertx/RedisVertxCacheSourceProvider.java @@ -0,0 +1,32 @@ +/* + */ +package org.redkalex.cache.redis.vertx; + +import org.redkale.annotation.Priority; +import org.redkale.source.CacheSource; +import org.redkale.source.CacheSourceProvider; +import org.redkale.util.AnyValue; + +/** + * + * @author zhangjx + */ +@Priority(-200) +public class RedisVertxCacheSourceProvider implements CacheSourceProvider { + + @Override + public boolean acceptsConf(AnyValue config) { + try { + Object.class.isAssignableFrom(io.vertx.redis.client.RedisOptions.class); //试图加载vertx-redis相关类 + return new RedisVertxCacheSource().acceptsConf(config); + } catch (Throwable e) { + return false; + } + } + + @Override + public CacheSource createInstance() { + return new RedisVertxCacheSource(); + } + +} diff --git a/src/resources/META-INF/services/org.redkale.cluster.ClusterAgentProvider b/src/resources/META-INF/services/org.redkale.cluster.ClusterAgentProvider new file mode 100644 index 0000000..d511a2c --- /dev/null +++ b/src/resources/META-INF/services/org.redkale.cluster.ClusterAgentProvider @@ -0,0 +1 @@ +com.zdemo.ZhubProvider \ No newline at end of file diff --git a/src/resources/META-INF/services/org.redkale.source.CacheSourceProvider b/src/resources/META-INF/services/org.redkale.source.CacheSourceProvider new file mode 100644 index 0000000..41677c1 --- /dev/null +++ b/src/resources/META-INF/services/org.redkale.source.CacheSourceProvider @@ -0,0 +1 @@ +org.redkalex.cache.redis.RedisCacheSourceProvider \ No newline at end of file diff --git a/src/com/zdemo/cachex/RedisTest.java b/test/net.tccn/cache/RedisTest.java similarity index 75% rename from src/com/zdemo/cachex/RedisTest.java rename to test/net.tccn/cache/RedisTest.java index 669529b..f6e2b1a 100644 --- a/src/com/zdemo/cachex/RedisTest.java +++ b/test/net.tccn/cache/RedisTest.java @@ -1,25 +1,121 @@ -package com.zdemo.cachex; +package org.redkalex.cache.redis.test; -import org.redkale.convert.json.JsonFactory; +import org.redkale.net.AsyncIOGroup; import org.redkale.util.AnyValue; +import org.redkale.util.ResourceFactory; +import org.redkalex.cache.redis.MyRedisCacheSource; +import java.awt.*; +import java.io.Serializable; +import java.util.Collection; +import java.util.List; import java.util.Map; +import static org.redkale.boot.Application.RESNAME_APP_CLIENT_ASYNCGROUP; +import static org.redkale.source.AbstractCacheSource.*; + public class RedisTest { - static MyRedisCacheSource source = new MyRedisCacheSource(); + static MyRedisCacheSource source = new MyRedisCacheSource(); - static { - AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue(); + static { // redis://:*Zhong9307!@47.111.150.118:6064?db=2 + AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue().addValue(CACHE_SOURCE_MAXCONNS, "1"); + conf.addValue(CACHE_SOURCE_NODE, new AnyValue.DefaultAnyValue().addValue(CACHE_SOURCE_URL, "redis://:*Zhong9307!@47.111.150.118:6064?db=0")); + final ResourceFactory factory = ResourceFactory.create(); + final AsyncIOGroup asyncGroup = new AsyncIOGroup(8192, 16); + asyncGroup.start(); + factory.register(RESNAME_APP_CLIENT_ASYNCGROUP, asyncGroup); + factory.inject(source); + //source.defaultConvert = JsonFactory.root().getConvert(); + source.init(conf); + + //--------------------- bit ------------------------------ + /*boolean ax = source.getBit("ax", 6); + System.out.println("ax:"+ ax); + source.setBit("ax", 6, true); + + ax = source.getBit("ax", 6); + System.out.println("ax:"+ ax); + + source.setBit("ax", 6, false); + ax = source.getBit("ax", 6); + System.out.println("ax:"+ ax);*/ + //--------------------- bit ------------------------------ + + //--------------------- bit ------------------------------ + + /* + source.lock("lockx", 5000); + */ + + //--------------------- set ------------------------------ + source.del("setx"); + /* + int[] ints = {1, 2, 3}; + source.sadd("setx", ints); + */ + + //source.sadd("setx", list.toArray(Integer[]::new)); + List list = List.of(2, 3, 5); + // source.sadd("setx", list.toArray(Integer[]::new)); + source.sadd("setx", list.toArray(Integer[]::new)); + source.sadd("setx", 12,2312,213); + + source.keys("setx*").forEach(x -> { + System.out.println(x); + }); + + source.srem("setx", 213, 2312); + + + Collection setx1 = source.getCollection("setx", String.class); + + System.out.println(setx1); + + + //source.getexLong() + + source.setHms("hmx", Map.of("a", "5","b", "51", "c", "ads")); + + List hmget = source.hmget("hmx", int.class, "a"); + + System.out.println(hmget); + + Integer hm = source.getHm("hmx", int.class, "ads"); + System.out.println(hm); + + Map hms = source.getHms("hmx", "a", "b"); + System.out.println(hms); + + + + /*AnyValue.DefaultAnyValue conf = new AnyValue.DefaultAnyValue(); conf.addValue("node", new AnyValue.DefaultAnyValue().addValue("addr", "47.111.150.118").addValue("port", "6064").addValue("password", "*Zhong9307!").addValue("db", 2)); source.defaultConvert = JsonFactory.root().getConvert(); source.initValueType(String.class); //value用String类型 - source.init(conf); + source.init(conf);*/ } public static void main(String[] args) { + + //source.setLong("a", 125); + + /*long a = source.getLong("a", 0); + System.out.println(a); + + List keys = source.keys("farm*"); + keys.forEach(x -> System.out.println(x)); + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + }*/ + + + // =========================================== //System.out.println(source.remove("a", "b")); // bit @@ -115,10 +211,10 @@ public class RedisTest { System.out.println(source.getCollectionSize("sk")); // 2*/ - Map hms = source.getHms("supportusers", "5-kfeu0f", "xxxx", "3-0kbt7u8t", "95q- "); + /*Map hms = source.getHms("supportusers", "5-kfeu0f", "xxxx", "3-0kbt7u8t", "95q- "); hms.forEach((k, v) -> { System.out.println(k + " : " + v); - }); + });*/ /*MyRedisCacheSource source2 = new MyRedisCacheSource(); diff --git a/test/com/zdemo/test/AppTest.java b/test/net.tccn/mq/AppTest.java similarity index 100% rename from test/com/zdemo/test/AppTest.java rename to test/net.tccn/mq/AppTest.java diff --git a/test/com/zdemo/test/Delays.java b/test/net.tccn/mq/Delays.java similarity index 100% rename from test/com/zdemo/test/Delays.java rename to test/net.tccn/mq/Delays.java diff --git a/test/com/zdemo/test/HelloService.java b/test/net.tccn/mq/HelloService.java similarity index 93% rename from test/com/zdemo/test/HelloService.java rename to test/net.tccn/mq/HelloService.java index 9e46d6e..35c12d3 100644 --- a/test/com/zdemo/test/HelloService.java +++ b/test/net.tccn/mq/HelloService.java @@ -1,6 +1,7 @@ package com.zdemo.test; import com.zdemo.IType; +import com.zdemo.ZhubProvider; import com.zdemo.zhub.RpcResult; import com.zdemo.zhub.ZHubClient; import org.redkale.net.http.RestMapping; @@ -15,22 +16,28 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; -@RestService(automapping = true) +@RestService(automapping = true, name = "hello") public class HelloService implements Service { - @Resource(name = "zhub") + @Resource(name = "hub") private ZHubClient zhub; - private net.tccn.zhub.ZHubClient zhubx = null; + /*@Resource(name = "hubx") + private ZHubClient zhubx; + + @Resource(name = "vvvvhub2") + private ZHubClient zhub2;*/ + + //private net.tccn.zhub.ZHubClient zhubx = null; @Override public void init(AnyValue config) { - CompletableFuture.runAsync(() -> { + /*CompletableFuture.runAsync(() -> { zhubx = new net.tccn.zhub.ZHubClient("127.0.0.1", 1216, "g-dev", "DEV-LOCAL"); //zhubx = new net.tccn.zhub.ZHubClient("47.111.150.118", 6066, "g-dev", "DEV-LOCAL"); - }); + });*/ // Function, RpcResult> fun /*zhub.rpcSubscribe("x", new TypeToken() { @@ -47,7 +54,7 @@ public class HelloService implements Service { zhub.subscribe("sport:reqtime", x -> { System.out.println(x); }); - zhub.subscribe("abx", x -> { + zhub.subscribe("abx1", x -> { System.out.println(x); }); @@ -111,8 +118,8 @@ public class HelloService implements Service { /*RpcResult x = zhub.rpc("rpc:file:up-token", Map.of(), new TypeToken<>() { });*/ - net.tccn.zhub.RpcResult x = zhubx.rpc("y", v + i, new com.google.gson.reflect.TypeToken<>() { - }); + /*RpcResult x = zhubx.rpc("y", v + i, new com.google.gson.reflect.TypeToken<>() { + });*/ System.out.println("time: " + (System.currentTimeMillis() - start) + " ms"); @@ -122,6 +129,12 @@ public class HelloService implements Service { return "ok"; } + @RestMapping(name = "send") + public String send() { + zhub.publish("abx1", 1); + return "ok"; + } + public static void main(String[] args) { // "\"别人家的女娃子\uD83E\uDD1E\uD83C\uDFFB\"" diff --git a/test/com/zdemo/test/MyConsumer.java b/test/net.tccn/mq/MyConsumer.java similarity index 100% rename from test/com/zdemo/test/MyConsumer.java rename to test/net.tccn/mq/MyConsumer.java