mirror of
https://github.com/LamGC/ContentGrabbingJi.git
synced 2025-04-30 06:37:36 +00:00
[Add] BotEventHandler 增加启动预处理方法;
[Add] BotAdminCommandProcess 增加推送功能相关管理命令; [Change] RandomIntervalSendTimer 调整Timer管理过程; [Change] BotCommandProcess ranking方法对参数错误的处理调整为返回错误信息; [Fix] RankingUpdateTimer 修复参数错误的问题;
This commit is contained in:
parent
21466a49f9
commit
19605a9401
@ -1,29 +1,43 @@
|
||||
package net.lamgc.cgj.bot;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.lamgc.cgj.bot.message.MessageSenderBuilder;
|
||||
import net.lamgc.cgj.bot.message.MessageSource;
|
||||
import net.lamgc.cgj.pixiv.PixivDownload;
|
||||
import net.lamgc.utils.base.runner.Argument;
|
||||
import net.lamgc.utils.base.runner.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Date;
|
||||
import java.util.Properties;
|
||||
import java.util.*;
|
||||
|
||||
public class BotAdminCommandProcess {
|
||||
|
||||
private final static Logger log = LoggerFactory.getLogger(BotAdminCommandProcess.class.getSimpleName());
|
||||
|
||||
private final static File globalPropFile = new File("./global.properties");
|
||||
private final static File globalPropFile = new File("global.properties");
|
||||
|
||||
private final static File pushListFile = new File("pushList.json");
|
||||
|
||||
private final static Hashtable<Long, JsonObject> pushInfoMap = new Hashtable<>();
|
||||
|
||||
private final static Gson gson = new GsonBuilder()
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
|
||||
@Command
|
||||
public String clearCache() {
|
||||
public static String cleanCache() {
|
||||
BotCommandProcess.clearCache();
|
||||
return "操作已完成.";
|
||||
}
|
||||
|
||||
@Command
|
||||
public String setGlobalProperty(@Argument(name = "key") String key, @Argument(name = "value") String value, @Argument(name = "save", force = false) boolean saveNow) {
|
||||
public static String setGlobalProperty(@Argument(name = "key") String key, @Argument(name = "value") String value, @Argument(name = "save", force = false) boolean saveNow) {
|
||||
String lastValue = BotCommandProcess.globalProp.getProperty(key);
|
||||
BotCommandProcess.globalProp.setProperty(key, Strings.nullToEmpty(value));
|
||||
if(saveNow) {
|
||||
@ -33,12 +47,12 @@ public class BotAdminCommandProcess {
|
||||
}
|
||||
|
||||
@Command
|
||||
public String getGlobalProperty(@Argument(name = "key") String key) {
|
||||
public static String getGlobalProperty(@Argument(name = "key") String key) {
|
||||
return "全局配置项 " + key + " 当前值: " + BotCommandProcess.globalProp.getProperty(key, "(Empty)");
|
||||
}
|
||||
|
||||
@Command
|
||||
public String saveGlobalProperties() {
|
||||
public static String saveGlobalProperties() {
|
||||
log.info("正在保存全局配置文件...");
|
||||
|
||||
try {
|
||||
@ -58,7 +72,7 @@ public class BotAdminCommandProcess {
|
||||
}
|
||||
|
||||
@Command
|
||||
public String loadGlobalProperties(@Argument(name = "reload", force = false) boolean reload) {
|
||||
public static String loadGlobalProperties(@Argument(name = "reload", force = false) boolean reload) {
|
||||
Properties cache = new Properties();
|
||||
if(!globalPropFile.exists()) {
|
||||
return "未找到全局配置文件, 无法重载";
|
||||
@ -79,7 +93,7 @@ public class BotAdminCommandProcess {
|
||||
}
|
||||
|
||||
@Command
|
||||
public String runUpdateTask(@Argument(force = false, name = "date") Date queryTime) {
|
||||
public static String runUpdateTask(@Argument(force = false, name = "date") Date queryTime) {
|
||||
try {
|
||||
BotCommandProcess.runUpdateTimer(queryTime);
|
||||
} catch (Exception e) {
|
||||
@ -89,4 +103,122 @@ public class BotAdminCommandProcess {
|
||||
return "操作已完成.";
|
||||
}
|
||||
|
||||
@Command
|
||||
public static String addPushGroup(@Argument(name = "group") long groupId,
|
||||
@Argument(name = "minTime", force = false, defaultValue = "21600000") long minTime,
|
||||
@Argument(name = "floatTime", force = false, defaultValue = "10800000") int floatTime,
|
||||
@Argument(name = "rankingStart", force = false, defaultValue = "1") int rankingStart,
|
||||
@Argument(name = "rankingStop", force = false, defaultValue = "150") int rankingStop,
|
||||
@Argument(name = "original", force = false, defaultValue = "false") boolean original
|
||||
) {
|
||||
JsonObject setting = new JsonObject();
|
||||
setting.addProperty("time.min", minTime);
|
||||
setting.addProperty("time.float", floatTime);
|
||||
setting.addProperty("ranking.start", rankingStart);
|
||||
setting.addProperty("ranking.end", rankingStop);
|
||||
setting.addProperty("pageQuality.original", original);
|
||||
if(pushInfoMap.containsKey(groupId)) {
|
||||
log.info("群 {} 已存在Timer, 删除Timer...", groupId);
|
||||
removePushTimer(groupId);
|
||||
}
|
||||
|
||||
log.info("正在增加Timer...(Setting: {})", setting);
|
||||
pushInfoMap.put(groupId, setting);
|
||||
addPushTimer(groupId, setting);
|
||||
return "已在 " + groupId + " 开启定时推送功能。";
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载推送列表
|
||||
*/
|
||||
@Command
|
||||
public static String loadPushList() {
|
||||
pushInfoMap.clear();
|
||||
if(!pushListFile.exists()) {
|
||||
log.warn("推送列表文件不存在, 跳过加载.");
|
||||
return "文件不存在, 跳过加载.";
|
||||
}
|
||||
|
||||
try (Reader reader = new BufferedReader(new FileReader(pushListFile))) {
|
||||
pushInfoMap.putAll(gson.fromJson(reader, new TypeToken<Map<Long, JsonObject>>(){}.getType()));
|
||||
loadAllPushTimer(false);
|
||||
return "列表重载完成";
|
||||
} catch (IOException e) {
|
||||
log.error("重载推送列表时发生错误", e);
|
||||
return "加载时发生异常";
|
||||
}
|
||||
}
|
||||
|
||||
@Command
|
||||
public static String savePushList() {
|
||||
try {
|
||||
if(!pushListFile.exists()) {
|
||||
pushListFile.createNewFile();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("PushList.json文件创建失败", e);
|
||||
return "保存失败!请检查控制台信息.";
|
||||
}
|
||||
|
||||
try (Writer writer = new FileWriter(pushListFile)) {
|
||||
writer.write(gson.toJson(pushInfoMap));
|
||||
return "保存成功.";
|
||||
} catch (IOException e) {
|
||||
log.error("写入PushList.json文件失败!", e);
|
||||
return "保存失败!请检查控制台信息.";
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadAllPushTimer(boolean flush) {
|
||||
if(flush) {
|
||||
RandomIntervalSendTimer.timerIdSet().forEach(id -> RandomIntervalSendTimer.getTimerById(id).destroy());
|
||||
}
|
||||
cleanPushTimer();
|
||||
pushInfoMap.forEach(BotAdminCommandProcess::addPushTimer);
|
||||
}
|
||||
|
||||
private static void addPushTimer(long id, JsonObject setting) {
|
||||
try {
|
||||
RandomIntervalSendTimer.getTimerById(id);
|
||||
return;
|
||||
} catch(NoSuchElementException ignored) {
|
||||
}
|
||||
|
||||
AutoSender sender = new RandomRankingArtworksSender(
|
||||
MessageSenderBuilder.getMessageSender(MessageSource.Group, id),
|
||||
setting.get("ranking.start").getAsInt(),
|
||||
setting.get("ranking.end").getAsInt(),
|
||||
setting.get("pageQuality.original").getAsBoolean() ? PixivDownload.PageQuality.ORIGINAL : PixivDownload.PageQuality.REGULAR
|
||||
);
|
||||
|
||||
RandomIntervalSendTimer.createTimer(
|
||||
id,
|
||||
sender,
|
||||
setting.get("time.min").getAsLong(),
|
||||
setting.get("time.float").getAsInt(),
|
||||
true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个推送定时器
|
||||
* @param id 群号
|
||||
* @throws NoSuchElementException 当这个群号没有定时器的时候抛出异常
|
||||
*/
|
||||
@Command
|
||||
public static void removePushTimer(@Argument(name = "group") long id) {
|
||||
RandomIntervalSendTimer.getTimerById(id).destroy();
|
||||
pushInfoMap.remove(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据已修改的pushInfoMap将已经被删除的Timer取消
|
||||
*/
|
||||
private static void cleanPushTimer() {
|
||||
RandomIntervalSendTimer.timerIdSet().forEach(id -> {
|
||||
if(!pushInfoMap.containsKey(id)) {
|
||||
RandomIntervalSendTimer.getTimerById(id).destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -175,18 +175,22 @@ public class BotCommandProcess {
|
||||
}
|
||||
}
|
||||
|
||||
PixivURL.RankingMode mode = PixivURL.RankingMode.MODE_DAILY;
|
||||
PixivURL.RankingMode mode;
|
||||
try {
|
||||
mode = PixivURL.RankingMode.valueOf("MODE_" + contentMode.toUpperCase());
|
||||
String rankingModeValue = contentMode.toUpperCase();
|
||||
mode = PixivURL.RankingMode.valueOf(rankingModeValue.startsWith("MODE_") ? rankingModeValue : "MODE_" + rankingModeValue);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("无效的RankingMode值: {}", contentMode);
|
||||
return "参数无效, 请查看帮助信息";
|
||||
}
|
||||
|
||||
PixivURL.RankingContentType type = PixivURL.RankingContentType.TYPE_ILLUST;
|
||||
PixivURL.RankingContentType type;
|
||||
try {
|
||||
type = PixivURL.RankingContentType.valueOf("TYPE_" + contentType.toUpperCase());
|
||||
String contentTypeValue = contentType.toUpperCase();
|
||||
type = PixivURL.RankingContentType.valueOf(contentTypeValue.startsWith("TYPE_") ? contentTypeValue : "TYPE_" + contentTypeValue);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("无效的RankingContentType值: {}", contentType);
|
||||
return "参数无效, 请查看帮助信息";
|
||||
}
|
||||
|
||||
if(!type.isSupportedMode(mode)) {
|
||||
|
@ -4,9 +4,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Random;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
@ -16,6 +14,9 @@ public class RandomIntervalSendTimer extends TimerTask {
|
||||
|
||||
private final static Timer timer = new Timer("Thread-RIST");
|
||||
private final static Logger log = LoggerFactory.getLogger("RandomIntervalSendTimer");
|
||||
private final static Map<Long, RandomIntervalSendTimer> timerMap = new HashMap<>();
|
||||
|
||||
private final long timerId;
|
||||
private final Random timeRandom = new Random();
|
||||
private final AutoSender sender;
|
||||
private final long time;
|
||||
@ -23,21 +24,79 @@ public class RandomIntervalSendTimer extends TimerTask {
|
||||
private AtomicBoolean loop = new AtomicBoolean();
|
||||
private final AtomicBoolean start = new AtomicBoolean();
|
||||
|
||||
/**
|
||||
* 创建一个随机延迟发送器
|
||||
* @param timerId 该Timer的标识,
|
||||
* 标识必须是唯一的, 当使用相同id创建时, 将会返回该id所属的Timer对象
|
||||
* @param sender 自动发送器
|
||||
* @param time 最低时间(ms)
|
||||
* @param floatTime 浮动时间(ms)
|
||||
* @param startNow 现在开始
|
||||
* @param loop 是否循环
|
||||
*/
|
||||
public static RandomIntervalSendTimer createTimer(long timerId, AutoSender sender, long time, int floatTime, boolean startNow, boolean loop) {
|
||||
if(timerMap.containsKey(timerId)) {
|
||||
return timerMap.get(timerId);
|
||||
}
|
||||
|
||||
public RandomIntervalSendTimer(AutoSender sender, long time, int floatTime) {
|
||||
RandomIntervalSendTimer timer = new RandomIntervalSendTimer(timerId, sender, time, floatTime, startNow, loop);
|
||||
timerMap.put(timerId, timer);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Id获取Timer
|
||||
* @param id 待获取Timer对应的Id
|
||||
* @return 返回RandomIntervalSendTimer对象
|
||||
* @throws NoSuchElementException 当不存在Timer时抛出
|
||||
*/
|
||||
public static RandomIntervalSendTimer getTimerById(long id) {
|
||||
if(!timerMap.containsKey(id)) {
|
||||
throw new NoSuchElementException("id=" + id);
|
||||
}
|
||||
return timerMap.get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有id
|
||||
* @return 所有TimerId的集合
|
||||
*/
|
||||
public static Set<Long> timerIdSet() {
|
||||
return new HashSet<>(timerMap.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个随机延迟发送器
|
||||
* @param timerId 该Timer的标识
|
||||
* @param sender 自动发送器
|
||||
* @param time 最低时间(ms)
|
||||
* @param floatTime 浮动时间(ms)
|
||||
* @param startNow 现在开始
|
||||
* @param loop 是否循环
|
||||
*/
|
||||
private RandomIntervalSendTimer(long timerId, AutoSender sender, long time, int floatTime, boolean startNow, boolean loop) {
|
||||
this.timerId = timerId;
|
||||
this.sender = sender;
|
||||
this.time = time;
|
||||
this.floatTime = floatTime;
|
||||
timerMap.put(timerId, this);
|
||||
if(startNow) {
|
||||
start(loop);
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
start(this.loop.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动定时器
|
||||
* @param loop 是否循环, 如果为true, 则任务完成后会自动调用start方法继续循环, 直到被调用{@code #}或总定时器被销毁;
|
||||
*/
|
||||
public void start(boolean loop) {
|
||||
this.loop.set(loop);
|
||||
long nextDelay = time + timeRandom.nextInt(floatTime);
|
||||
log.info("定时器 {} 下一延迟: {}ms", Integer.toHexString(this.hashCode()), nextDelay);
|
||||
log.info("定时器 {} 下一延迟: {}ms ({}min)", Integer.toHexString(this.hashCode()), nextDelay, nextDelay / 1000F / 60F);
|
||||
if(start.get()) {
|
||||
try {
|
||||
Field state = this.getClass().getSuperclass().getDeclaredField("state");
|
||||
@ -61,10 +120,22 @@ public class RandomIntervalSendTimer extends TimerTask {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消该定时器
|
||||
* @return 取消成功返回true
|
||||
*/
|
||||
@Override
|
||||
public boolean cancel() {
|
||||
start.set(false);
|
||||
return super.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁这个定时器
|
||||
*/
|
||||
public void destroy() {
|
||||
cancel();
|
||||
timerMap.remove(this.timerId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ public class RankingUpdateTimer {
|
||||
//BotCommandProcess.getRankingInfoByCache(contentType, rankingMode, calendar.getTime(), 1, 0, true);
|
||||
BotEventHandler.executor.executorSync(
|
||||
new VirtualLoadMessageEvent(0,0,
|
||||
".cgj ranking -type " + rankingMode.modeParam + " -mode " + rankingMode.modeParam));
|
||||
".cgj ranking -type=" + contentType.name() + " -mode=" + rankingMode.name()));
|
||||
log.info("排行榜 {}.{} 更新完成.", rankingMode.name(), contentType.name());
|
||||
} catch (InterruptedException e) {
|
||||
log.error("排行榜 {}.{} 更新时发生异常. \n{}", rankingMode.name(), contentType.name(), Throwables.getStackTraceAsString(e));
|
||||
|
@ -30,17 +30,19 @@ import java.util.Objects;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class BotEventHandler implements EventHandler {
|
||||
|
||||
public final static String COMMAND_PREFIX = ".cgj ";
|
||||
public final static String ADMIN_COMMAND_PREFIX = ".cgjadmin ";
|
||||
|
||||
private final ArgumentsRunner processRunner;
|
||||
private final ArgumentsRunner adminRunner;
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger("BotEventHandler");
|
||||
private final static Logger log = LoggerFactory.getLogger("BotEventHandler");
|
||||
|
||||
/**
|
||||
* 所有缓存共用的JedisPool
|
||||
@ -95,6 +97,21 @@ public class BotEventHandler implements EventHandler {
|
||||
initialled = true;
|
||||
}
|
||||
|
||||
private final static AtomicBoolean preLoaded = new AtomicBoolean();
|
||||
/**
|
||||
* 预加载
|
||||
*/
|
||||
public synchronized static void preLoad() {
|
||||
if(preLoaded.get()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
BotAdminCommandProcess.loadPushList();
|
||||
} finally {
|
||||
preLoaded.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
private BotEventHandler() {
|
||||
ArgumentsRunnerConfig runnerConfig = new ArgumentsRunnerConfig();
|
||||
runnerConfig.setUseDefaultValueInsteadOfException(true);
|
||||
@ -151,12 +168,11 @@ public class BotEventHandler implements EventHandler {
|
||||
long time = System.currentTimeMillis();
|
||||
Object result;
|
||||
try {
|
||||
if(msg.toLowerCase().startsWith(COMMAND_PREFIX + "admin")) {
|
||||
if(msg.toLowerCase().startsWith(ADMIN_COMMAND_PREFIX)) {
|
||||
if(!String.valueOf(event.getFromQQ()).equals(BotCommandProcess.globalProp.getProperty("admin.adminId"))) {
|
||||
event.sendMessage("你没有执行该命令的权限!");
|
||||
return;
|
||||
result = "你没有执行该命令的权限!";
|
||||
} else {
|
||||
result = adminRunner.run(new BotAdminCommandProcess(), args.length <= 1 ? new String[0] : Arrays.copyOfRange(args, 1, args.length));
|
||||
result = adminRunner.run(args.length <= 1 ? new String[0] : Arrays.copyOfRange(args, 1, args.length));
|
||||
}
|
||||
} else {
|
||||
result = processRunner.run(args.length <= 1 ? new String[0] : Arrays.copyOfRange(args, 1, args.length));
|
||||
@ -186,7 +202,7 @@ public class BotEventHandler implements EventHandler {
|
||||
* @return 如果为true则提交
|
||||
*/
|
||||
public static boolean match(String message) {
|
||||
return message.startsWith(COMMAND_PREFIX);
|
||||
return message.startsWith(COMMAND_PREFIX) || message.startsWith(ADMIN_COMMAND_PREFIX);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user