mirror of
https://github.com/LamGC/ContentGrabbingJi.git
synced 2025-04-29 14:17:33 +00:00
[Add] RedisConnectionPool 添加对 Lua 脚本的支持;
[Add] LuaScript 添加 Lua 脚本声明定义类; [Add] RedisConnectionPool 添加对 Lua 脚本加载管理和执行的功能;
This commit is contained in:
parent
f1e76092a0
commit
752cf907d6
50
ContentGrabbingJi-CacheStore-redis/src/main/java/net/lamgc/cgj/bot/cache/redis/LuaScript.java
vendored
Normal file
50
ContentGrabbingJi-CacheStore-redis/src/main/java/net/lamgc/cgj/bot/cache/redis/LuaScript.java
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2021 LamGC
|
||||
*
|
||||
* ContentGrabbingJi is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License.
|
||||
*
|
||||
* ContentGrabbingJi is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.lamgc.cgj.bot.cache.redis;
|
||||
|
||||
/**
|
||||
* @author LamGC
|
||||
*/
|
||||
|
||||
public enum LuaScript {
|
||||
/**
|
||||
* [List] 检查元素是否存在.
|
||||
*/
|
||||
LIST_CHECK_ELEMENT_CONTAINS("CheckElementContains"),
|
||||
/**
|
||||
* [List] 删除指定索引的元素.
|
||||
*/
|
||||
LIST_REMOVE_ELEMENT_BY_INDEX("RemoveElementByIndex"),
|
||||
/**
|
||||
* [All] 删除所有前缀为指定字符串的键.
|
||||
*/
|
||||
STORE_REMOVE_KEYS_BY_PREFIX("RemoveKeysByPrefix")
|
||||
;
|
||||
|
||||
public final static String PACKAGE_PATH = "lua/";
|
||||
|
||||
private final String scriptName;
|
||||
|
||||
LuaScript(String scriptName) {
|
||||
this.scriptName = scriptName;
|
||||
}
|
||||
|
||||
public String getScriptName() {
|
||||
return scriptName;
|
||||
}
|
||||
}
|
@ -23,7 +23,13 @@ import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
|
||||
@ -38,6 +44,8 @@ class RedisConnectionPool {
|
||||
private final AtomicReference<JedisPool> POOL = new AtomicReference<>();
|
||||
private final AtomicReference<URL> CONNECTION_URL = new AtomicReference<>();
|
||||
|
||||
private final Map<LuaScript, String> scriptMap = new HashMap<>();
|
||||
|
||||
public synchronized void setConnectionUrl(URL connectionUrl) {
|
||||
if(CONNECTION_URL.get() != null) {
|
||||
CONNECTION_URL.set(connectionUrl);
|
||||
@ -60,6 +68,7 @@ class RedisConnectionPool {
|
||||
connectionUrl.getPath().toLowerCase().contains("ssl=true"));
|
||||
}
|
||||
POOL.set(jedisPool);
|
||||
loadScript();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,10 +119,83 @@ class RedisConnectionPool {
|
||||
return "pong".equalsIgnoreCase(jedis.ping());
|
||||
} catch (Exception e) {
|
||||
log.error("Redis 连接测试时发生异常", e);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定脚本的 Sha.
|
||||
* @param script 脚本.
|
||||
* @return 如果存在, 返回 Sha, 否则返回 null.
|
||||
*/
|
||||
public String getScriptSha(LuaScript script) {
|
||||
return scriptMap.get(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载脚本.
|
||||
*/
|
||||
private void loadScript() {
|
||||
for (LuaScript script : LuaScript.values()) {
|
||||
InputStream scriptStream = this.getClass().
|
||||
getResourceAsStream("/" + LuaScript.PACKAGE_PATH + script.getScriptName() + ".lua");
|
||||
if (scriptStream == null) {
|
||||
log.warn("脚本 {} 获取失败, 相关操作将无法使用, 请检查缓存组件是否损坏.", script.getScriptName());
|
||||
continue;
|
||||
}
|
||||
|
||||
String scriptContent;
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(scriptStream, StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
StringBuilder builder = new StringBuilder();
|
||||
while((line = reader.readLine()) != null) {
|
||||
builder.append(line).append('\n');
|
||||
}
|
||||
scriptContent = builder.toString();
|
||||
} catch (IOException e) {
|
||||
log.error("读取脚本文件时发生异常.(Script: " + script.getScriptName() + ")", e);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
String scriptSha = executeRedis(jedis -> jedis.scriptLoad(scriptContent));
|
||||
if (scriptSha != null) {
|
||||
scriptMap.put(script, scriptSha);
|
||||
log.debug("脚本 {} 已成功加载.(Sha: {})", script, scriptSha);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("加载脚本时发生异常.(Script: " + script.getScriptName() + ")", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行脚本.
|
||||
* @param script Lua 脚本.
|
||||
* @param keys 待传入脚本的键列表.
|
||||
* @param args 待传入脚本的参数列表.
|
||||
* @return 如果成功, 返回脚本所返回的数据, 需根据脚本实际返回转换对象.
|
||||
* @throws NullPointerException 当 script 为 {@code null} 时抛出.
|
||||
*/
|
||||
public Object executeScript(final LuaScript script, final List<String> keys, final List<String> args) {
|
||||
String scriptSha = this.getScriptSha(Objects.requireNonNull(script));
|
||||
if (scriptSha == null) {
|
||||
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
|
||||
log.warn("脚本未加载, 方法 {}() 无法执行(方法存在于Class {}:{}). (所需脚本: {})",
|
||||
stackTraceElements[2].getMethodName(),
|
||||
stackTraceElements[2].getClassName(),
|
||||
stackTraceElements[2].getLineNumber(),
|
||||
script.getScriptName());
|
||||
return false;
|
||||
}
|
||||
return executeRedis(jedis -> {
|
||||
List<String> keysList = (keys == null) ? Collections.emptyList() : keys;
|
||||
List<String> argsList = (args == null) ? Collections.emptyList() : args;
|
||||
return jedis.evalsha(scriptSha, keysList, argsList);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user