feat: adding event handler system
This commit is contained in:
parent
c68305aa63
commit
db13460ae4
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@ -10,6 +10,6 @@
|
|||||||
<module name="MyBot.main" />
|
<module name="MyBot.main" />
|
||||||
</profile>
|
</profile>
|
||||||
</annotationProcessing>
|
</annotationProcessing>
|
||||||
<bytecodeTargetLevel target="17" />
|
<bytecodeTargetLevel target="11" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
2
.idea/fileTemplates/includes/Version.txt
generated
2
.idea/fileTemplates/includes/Version.txt
generated
@ -1 +1 @@
|
|||||||
0.0.3-dev
|
0.0.4-dev
|
1
.idea/modules.xml
generated
1
.idea/modules.xml
generated
@ -2,7 +2,6 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/MyBot.iml" filepath="$PROJECT_DIR$/MyBot.iml" />
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/MyBot.main.iml" filepath="$PROJECT_DIR$/.idea/modules/MyBot.main.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/MyBot.main.iml" filepath="$PROJECT_DIR$/.idea/modules/MyBot.main.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
|
@ -4,7 +4,7 @@ import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCach
|
|||||||
val projectName = rootProject.name
|
val projectName = rootProject.name
|
||||||
val groupName by extra("cn.wzpmc")
|
val groupName by extra("cn.wzpmc")
|
||||||
val projectArtifactId by extra("my-bot")
|
val projectArtifactId by extra("my-bot")
|
||||||
val projectVersion by extra("0.0.3-dev")
|
val projectVersion by extra("0.0.4-dev-SNAPSHOT")
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("java")
|
id("java")
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
package cn.wzpmc;
|
package cn.wzpmc;
|
||||||
|
|
||||||
|
import cn.wzpmc.api.plugins.BasePlugin;
|
||||||
import cn.wzpmc.commands.StopCommand;
|
import cn.wzpmc.commands.StopCommand;
|
||||||
import cn.wzpmc.configuration.Configuration;
|
import cn.wzpmc.configuration.Configuration;
|
||||||
import cn.wzpmc.console.MyBotConsole;
|
import cn.wzpmc.console.MyBotConsole;
|
||||||
import cn.wzpmc.entities.user.bot.MyBot;
|
import cn.wzpmc.entities.user.bot.MyBot;
|
||||||
import cn.wzpmc.network.WebSocketConnectionHandler;
|
import cn.wzpmc.network.WebSocketConnectionHandler;
|
||||||
import cn.wzpmc.plugins.CommandManager;
|
import cn.wzpmc.plugins.CommandManager;
|
||||||
|
import cn.wzpmc.plugins.PluginClassLoader;
|
||||||
|
import cn.wzpmc.plugins.PluginManager;
|
||||||
import cn.wzpmc.utils.JsonUtils;
|
import cn.wzpmc.utils.JsonUtils;
|
||||||
|
import cn.wzpmc.utils.ReflectionUtils;
|
||||||
import cn.wzpmc.utils.TemplateFileUtils;
|
import cn.wzpmc.utils.TemplateFileUtils;
|
||||||
import cn.wzpmc.utils.YamlUtils;
|
import cn.wzpmc.utils.YamlUtils;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
@ -14,40 +18,102 @@ import lombok.SneakyThrows;
|
|||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
@Log4j2
|
@Log4j2
|
||||||
public class Main {
|
public class Main {
|
||||||
private static final String DEFAULT_CONFIGURATION_FILE_PATH = "templates/config.yaml";
|
private static final String DEFAULT_CONFIGURATION_FILE_PATH = "templates/config.yaml";
|
||||||
@SneakyThrows
|
private static File pluginsDir;
|
||||||
public static void main(String[] args) {
|
public static void initializeJVM(){
|
||||||
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
|
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
|
||||||
System.setProperty("terminal.jline", "true");
|
System.setProperty("terminal.jline", "true");
|
||||||
|
}
|
||||||
|
public static void initializeJsonUtils(){
|
||||||
JsonUtils.initReader();
|
JsonUtils.initReader();
|
||||||
JsonUtils.initWriter();
|
JsonUtils.initWriter();
|
||||||
log.info("启动MyBot...");
|
}
|
||||||
|
public static Configuration getConfiguration() {
|
||||||
File configurationFile = new File("config.yaml");
|
File configurationFile = new File("config.yaml");
|
||||||
if (TemplateFileUtils.saveDefaultConfig(Main.class.getClassLoader(), DEFAULT_CONFIGURATION_FILE_PATH, configurationFile)) {
|
if (TemplateFileUtils.saveDefaultConfig(Main.class.getClassLoader(), DEFAULT_CONFIGURATION_FILE_PATH, configurationFile)) {
|
||||||
log.debug("创建日志文件成功!");
|
log.debug("创建日志文件成功!");
|
||||||
log.info("首次启动,默认配置文件已创建,请填写后再次启动MyBot!");
|
log.info("首次启动,默认配置文件已创建,请填写后再次启动MyBot!");
|
||||||
return;
|
return null;
|
||||||
|
}
|
||||||
|
pluginsDir = new File("plugins");
|
||||||
|
if (TemplateFileUtils.createDefaultDirectory(pluginsDir)) {
|
||||||
|
log.debug("plugin文件夹创建");
|
||||||
}
|
}
|
||||||
log.debug("读取配置文件 {}", configurationFile.getAbsolutePath());
|
log.debug("读取配置文件 {}", configurationFile.getAbsolutePath());
|
||||||
Configuration configuration = YamlUtils.readYamlFile(configurationFile, Configuration.class);
|
return YamlUtils.readYamlFile(configurationFile, Configuration.class);
|
||||||
|
}
|
||||||
|
public static MyBot createBot(Configuration configuration){
|
||||||
|
return new MyBot(configuration);
|
||||||
|
}
|
||||||
|
public static URI getUriFromConfiguration(Configuration configuration){
|
||||||
URI uri;
|
URI uri;
|
||||||
try {
|
try {
|
||||||
uri = new URI(configuration.getWebsocket());
|
uri = new URI(configuration.getWebsocket());
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
log.error("无法解析websocket地址");
|
return null;
|
||||||
|
}
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
public static void loadPlugins(MyBot myBot) throws MalformedURLException {
|
||||||
|
File[] files = pluginsDir.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
log.error("没有权限读取插件目录!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler();
|
PluginManager pluginManager = myBot.getPluginManager();
|
||||||
ChannelFuture future = webSocketConnectionHandler.connect(uri);
|
for (File file : files) {
|
||||||
MyBot myBot = new MyBot(configuration);
|
if (file.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = file.getName();
|
||||||
|
if (!name.endsWith(".jar")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
URI fileURI = file.toURI();
|
||||||
|
PluginClassLoader pluginClassLoader = new PluginClassLoader(new URL[]{fileURI.toURL()}, myBot);
|
||||||
|
BasePlugin load = ReflectionUtils.load(pluginClassLoader, file, pluginManager);
|
||||||
|
if (load == null){
|
||||||
|
log.info("插件{}加载失败!", name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
load.onLoad();
|
||||||
|
}
|
||||||
CommandManager commandManager = myBot.getCommandManager();
|
CommandManager commandManager = myBot.getCommandManager();
|
||||||
commandManager.registerCommand(new StopCommand(myBot));
|
commandManager.registerCommand(new StopCommand(myBot));
|
||||||
|
}
|
||||||
|
public static WebSocketConnectionHandler createConnection(MyBot myBot, URI uri){
|
||||||
|
WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler(myBot);
|
||||||
|
ChannelFuture future = webSocketConnectionHandler.connect(uri);
|
||||||
|
return webSocketConnectionHandler;
|
||||||
|
}
|
||||||
|
public static void startConsole(MyBot myBot, WebSocketConnectionHandler webSocketConnectionHandler){
|
||||||
MyBotConsole myBotConsole = new MyBotConsole(myBot, webSocketConnectionHandler);
|
MyBotConsole myBotConsole = new MyBotConsole(myBot, webSocketConnectionHandler);
|
||||||
myBotConsole.start();
|
myBotConsole.start();
|
||||||
}
|
}
|
||||||
|
@SneakyThrows
|
||||||
|
public static void main(String[] args) {
|
||||||
|
initializeJVM();
|
||||||
|
initializeJsonUtils();
|
||||||
|
log.info("启动MyBot...");
|
||||||
|
Configuration configuration = getConfiguration();
|
||||||
|
if (configuration == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MyBot myBot = createBot(configuration);
|
||||||
|
URI uri = getUriFromConfiguration(configuration);
|
||||||
|
if (uri == null){
|
||||||
|
log.error("无法解析websocket地址");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loadPlugins(myBot);
|
||||||
|
WebSocketConnectionHandler webSocketConnectionHandler = createConnection(myBot, uri);
|
||||||
|
startConsole(myBot, webSocketConnectionHandler);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package cn.wzpmc.api.plugins;
|
package cn.wzpmc.api.plugins;
|
||||||
|
|
||||||
import cn.wzpmc.api.user.IBot;
|
import cn.wzpmc.api.user.IBot;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插件基类
|
* 插件基类
|
||||||
@ -45,4 +46,8 @@ public interface BasePlugin {
|
|||||||
* @return 类加载器
|
* @return 类加载器
|
||||||
*/
|
*/
|
||||||
IPluginClassLoader getClassLoader();
|
IPluginClassLoader getClassLoader();
|
||||||
|
|
||||||
|
void onLoad();
|
||||||
|
void onUnload();
|
||||||
|
Logger getLogger();
|
||||||
}
|
}
|
||||||
|
@ -32,4 +32,20 @@ public abstract class IPluginClassLoader extends URLClassLoader {
|
|||||||
* @return Bot对象
|
* @return Bot对象
|
||||||
*/
|
*/
|
||||||
abstract public IBot getBot();
|
abstract public IBot getBot();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件名称
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/8 23:16 v0.0.4-dev
|
||||||
|
* @return 插件名称
|
||||||
|
*/
|
||||||
|
abstract public String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取插件版本
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/8 23:16 v0.0.4-dev
|
||||||
|
* @return 版本
|
||||||
|
*/
|
||||||
|
abstract public String getVersion();
|
||||||
}
|
}
|
||||||
|
25
src/main/java/cn/wzpmc/api/plugins/IPluginManager.java
Normal file
25
src/main/java/cn/wzpmc/api/plugins/IPluginManager.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package cn.wzpmc.api.plugins;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author wzp
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
* @since 2024/8/6 下午3:19
|
||||||
|
*/
|
||||||
|
public interface IPluginManager {
|
||||||
|
/**
|
||||||
|
* 初始化插件主类
|
||||||
|
*
|
||||||
|
* @param <T> 插件主类类型
|
||||||
|
* @param baseClass 插件主类
|
||||||
|
* @param name 插件名称
|
||||||
|
* @param version 插件版本
|
||||||
|
* @return 这个插件的实例
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/5 上午12:58 v0.0.4-dev
|
||||||
|
*/
|
||||||
|
<T extends BasePlugin> T initPlugin(Class<T> baseClass, String name, String version) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException;
|
||||||
|
List<BasePlugin> getPlugins();
|
||||||
|
}
|
38
src/main/java/cn/wzpmc/api/plugins/JavaPlugin.java
Normal file
38
src/main/java/cn/wzpmc/api/plugins/JavaPlugin.java
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package cn.wzpmc.api.plugins;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java插件基类
|
||||||
|
* @author wzp
|
||||||
|
* @version 0.0.2-dev
|
||||||
|
* @since 2024/7/31 下午7:01
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
public abstract class JavaPlugin implements BasePlugin {
|
||||||
|
private Logger logger;
|
||||||
|
@Override
|
||||||
|
public IPluginClassLoader getClassLoader() {
|
||||||
|
Class<? extends JavaPlugin> aClass = this.getClass();
|
||||||
|
ClassLoader loader = aClass.getClassLoader();
|
||||||
|
if (loader instanceof IPluginClassLoader){
|
||||||
|
return (IPluginClassLoader) loader;
|
||||||
|
}
|
||||||
|
throw new RuntimeException(new IllegalAccessException("You shouldn't load plugin class without PluginClassLoader!!!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Logger getLogger() {
|
||||||
|
IPluginClassLoader classLoader = this.getClassLoader();
|
||||||
|
String name = classLoader.getName();
|
||||||
|
String version = classLoader.getVersion();
|
||||||
|
if (this.logger == null){
|
||||||
|
this.logger = LogManager.getLogger(name + "-" + version);
|
||||||
|
}
|
||||||
|
return this.logger;
|
||||||
|
}
|
||||||
|
}
|
17
src/main/java/cn/wzpmc/api/plugins/event/EventHandler.java
Normal file
17
src/main/java/cn/wzpmc/api/plugins/event/EventHandler.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package cn.wzpmc.api.plugins.event;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用此注解以指定一个方法为事件执行器
|
||||||
|
* @author wzp
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
* @since 2024/8/15 23:47
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
public @interface EventHandler {
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
package cn.wzpmc.api.user;
|
package cn.wzpmc.api.user;
|
||||||
|
|
||||||
|
import cn.wzpmc.api.events.Event;
|
||||||
import cn.wzpmc.api.plugins.ICommandManager;
|
import cn.wzpmc.api.plugins.ICommandManager;
|
||||||
import cn.wzpmc.api.plugins.configuration.IConfiguration;
|
import cn.wzpmc.api.plugins.configuration.IConfiguration;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人接口
|
* 机器人接口
|
||||||
* @author wzp
|
* @author wzp
|
||||||
@ -32,4 +35,20 @@ public abstract class IBot extends CommandSender {
|
|||||||
* @since 2024/8/1 下午4:57 v0.0.2-dev
|
* @since 2024/8/1 下午4:57 v0.0.2-dev
|
||||||
*/
|
*/
|
||||||
public abstract void stop();
|
public abstract void stop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册事件执行器
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/15 23:46 v0.0.4-dev
|
||||||
|
* @param handler 事件执行器
|
||||||
|
*/
|
||||||
|
public abstract void registerEventHandler(Object handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 触发一个事件
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/16 00:49 v0.0.4-dev
|
||||||
|
* @param event 事件
|
||||||
|
*/
|
||||||
|
public abstract void triggerEvent(Event event) throws InvocationTargetException, IllegalAccessException;
|
||||||
}
|
}
|
||||||
|
65
src/main/java/cn/wzpmc/api/utils/IncreasbleHashMap.java
Normal file
65
src/main/java/cn/wzpmc/api/utils/IncreasbleHashMap.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package cn.wzpmc.api.utils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一个单Key对应多Value的HashMap
|
||||||
|
* @author wzp
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
* @since 2024/8/16 00:02
|
||||||
|
*/
|
||||||
|
public class IncreasbleHashMap<K, V> extends HashMap<K, List<V>> implements IncreasbleMap<K, V>{
|
||||||
|
@Override
|
||||||
|
public void add(K key, V value) {
|
||||||
|
List<V> newArrayList = super.getOrDefault(key, new ArrayList<>());
|
||||||
|
newArrayList.add(value);
|
||||||
|
super.put(key, newArrayList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean delete(K key, V value) {
|
||||||
|
if (!super.containsKey(key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<V> vs = super.get(key);
|
||||||
|
return vs.remove(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean delete(V value) {
|
||||||
|
boolean has = false;
|
||||||
|
for (List<V> vs : super.values()) {
|
||||||
|
if (vs.contains(value)){
|
||||||
|
has = true;
|
||||||
|
vs.remove(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return has;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAll(IncreasbleMap<K, V> increasbleMap) {
|
||||||
|
for (Entry<K, List<V>> entry : increasbleMap.entrySet()) {
|
||||||
|
this.addAll(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void addAll(K key, Collection<V> values) {
|
||||||
|
List<V> list = this.getOrDefault(key, new ArrayList<>());
|
||||||
|
list.addAll(values);
|
||||||
|
this.put(key, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsValue(Object value) {
|
||||||
|
for (List<V> vs : super.values()) {
|
||||||
|
if (vs.contains(value)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
58
src/main/java/cn/wzpmc/api/utils/IncreasbleMap.java
Normal file
58
src/main/java/cn/wzpmc/api/utils/IncreasbleMap.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package cn.wzpmc.api.utils;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一个单Key对应多Value的Map
|
||||||
|
* @author wzp
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
* @since 2024/8/15 23:57
|
||||||
|
*/
|
||||||
|
public interface IncreasbleMap<K, V> extends Map<K, List<V>> {
|
||||||
|
/**
|
||||||
|
* 向一个Key中添加元素
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/16 00:04 v0.0.4-dev
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
*/
|
||||||
|
void add(K key, V value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除某个key中的对应元素
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/16 00:05 v0.0.4-dev
|
||||||
|
* @param key 键
|
||||||
|
* @param value 值
|
||||||
|
* @return 是否删除成功
|
||||||
|
*/
|
||||||
|
boolean delete(K key, V value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除所有的对应value的值
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/16 00:05 v0.0.4-dev
|
||||||
|
* @param value 值
|
||||||
|
* @return 是否删除成功
|
||||||
|
*/
|
||||||
|
boolean delete(V value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将两个表融合
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/16 00:35 v0.0.4-dev
|
||||||
|
* @param increasbleMap 另一个表
|
||||||
|
*/
|
||||||
|
void addAll(IncreasbleMap<K, V> increasbleMap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将所有value添加到此key中
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/16 00:43 v0.0.4-dev
|
||||||
|
* @param key 键
|
||||||
|
* @param values 所有要添加的值的集合
|
||||||
|
*/
|
||||||
|
void addAll(K key, Collection<V> values);
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package cn.wzpmc.console.logger;
|
||||||
|
|
||||||
|
import cn.wzpmc.api.plugins.BasePlugin;
|
||||||
|
import cn.wzpmc.api.plugins.IPluginClassLoader;
|
||||||
|
import org.apache.logging.log4j.message.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
import static org.apache.logging.log4j.spi.AbstractLogger.DEFAULT_FLOW_MESSAGE_FACTORY_CLASS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author wzp
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
* @since 2024/8/9 00:35
|
||||||
|
*/
|
||||||
|
public class PluginMessageFactory implements MessageFactory {
|
||||||
|
private final String tag;
|
||||||
|
private static final MessageFactory baseFactory;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
baseFactory = (MessageFactory) DEFAULT_FLOW_MESSAGE_FACTORY_CLASS.getConstructor().newInstance();
|
||||||
|
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PluginMessageFactory(BasePlugin plugin) {
|
||||||
|
IPluginClassLoader classLoader = plugin.getClassLoader();
|
||||||
|
String name = classLoader.getName();
|
||||||
|
String version = classLoader.getVersion();
|
||||||
|
this.tag = '[' + name + '-' + version + "] ";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message newMessage(Object message) {
|
||||||
|
return baseFactory.newMessage(tag + "{}", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message newMessage(String message) {
|
||||||
|
return baseFactory.newMessage(this.tag + message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Message newMessage(String message, Object... params) {
|
||||||
|
return baseFactory.newMessage(this.tag + message, params);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package cn.wzpmc.entities.event;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author wzp
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
* @since 2024/8/15 23:53
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class EventHandlerMethod {
|
||||||
|
private final Object object;
|
||||||
|
private final Method method;
|
||||||
|
}
|
@ -1,17 +1,26 @@
|
|||||||
package cn.wzpmc.entities.user.bot;
|
package cn.wzpmc.entities.user.bot;
|
||||||
|
|
||||||
|
import cn.wzpmc.api.events.Event;
|
||||||
import cn.wzpmc.api.message.MessageComponent;
|
import cn.wzpmc.api.message.MessageComponent;
|
||||||
import cn.wzpmc.api.message.StringMessage;
|
import cn.wzpmc.api.message.StringMessage;
|
||||||
import cn.wzpmc.api.message.json.JsonMessage;
|
import cn.wzpmc.api.message.json.JsonMessage;
|
||||||
|
import cn.wzpmc.api.plugins.BasePlugin;
|
||||||
import cn.wzpmc.api.user.IBot;
|
import cn.wzpmc.api.user.IBot;
|
||||||
import cn.wzpmc.api.user.permission.Permissions;
|
import cn.wzpmc.api.user.permission.Permissions;
|
||||||
|
import cn.wzpmc.api.utils.IncreasbleHashMap;
|
||||||
import cn.wzpmc.configuration.Configuration;
|
import cn.wzpmc.configuration.Configuration;
|
||||||
import cn.wzpmc.console.MyBotConsole;
|
import cn.wzpmc.console.MyBotConsole;
|
||||||
|
import cn.wzpmc.entities.event.EventHandlerMethod;
|
||||||
import cn.wzpmc.plugins.CommandManager;
|
import cn.wzpmc.plugins.CommandManager;
|
||||||
|
import cn.wzpmc.plugins.PluginManager;
|
||||||
|
import cn.wzpmc.utils.ReflectionUtils;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机器人实现类
|
* 机器人实现类
|
||||||
* @author wzp
|
* @author wzp
|
||||||
@ -27,6 +36,8 @@ public class MyBot extends IBot {
|
|||||||
@Setter
|
@Setter
|
||||||
private String name;
|
private String name;
|
||||||
private final CommandManager commandManager = new CommandManager(this);
|
private final CommandManager commandManager = new CommandManager(this);
|
||||||
|
private final PluginManager pluginManager = new PluginManager();
|
||||||
|
private final IncreasbleHashMap<Class<? extends Event>, EventHandlerMethod> events = new IncreasbleHashMap<>();
|
||||||
@Setter
|
@Setter
|
||||||
private MyBotConsole console = null;
|
private MyBotConsole console = null;
|
||||||
public MyBot(Configuration configuration){
|
public MyBot(Configuration configuration){
|
||||||
@ -46,8 +57,24 @@ public class MyBot extends IBot {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
|
for (BasePlugin plugin : this.pluginManager.getPlugins()) {
|
||||||
|
plugin.onUnload();
|
||||||
|
}
|
||||||
if (this.console != null) {
|
if (this.console != null) {
|
||||||
this.console.shutdown();
|
this.console.shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerEventHandler(Object handler) {
|
||||||
|
this.events.addAll(ReflectionUtils.loadEvents(handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void triggerEvent(Event event) throws InvocationTargetException, IllegalAccessException {
|
||||||
|
List<EventHandlerMethod> eventHandlerMethods = this.events.get(event.getClass());
|
||||||
|
for (EventHandlerMethod eventHandlerMethod : eventHandlerMethods) {
|
||||||
|
eventHandlerMethod.getMethod().invoke(eventHandlerMethod.getObject(), event);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
package cn.wzpmc.network;
|
package cn.wzpmc.network;
|
||||||
|
|
||||||
import cn.wzpmc.api.events.Event;
|
import cn.wzpmc.api.events.Event;
|
||||||
|
import cn.wzpmc.api.user.IBot;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* websocket包处理器
|
* websocket包处理器
|
||||||
* @author wzp
|
* @author wzp
|
||||||
@ -14,7 +19,9 @@ import lombok.extern.log4j.Log4j2;
|
|||||||
* @since 2024/7/31 上午12:14
|
* @since 2024/7/31 上午12:14
|
||||||
*/
|
*/
|
||||||
@Log4j2
|
@Log4j2
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class PacketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
public class PacketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
||||||
|
private final IBot bot;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame webSocketFrame) {
|
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame webSocketFrame) {
|
||||||
@ -23,8 +30,22 @@ public class PacketHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
|||||||
log.warn("收到了无法处理的WebSocket数据包:{}", text);
|
log.warn("收到了无法处理的WebSocket数据包:{}", text);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
System.out.println(text);
|
JSONObject jsonObject = JSON.parseObject(text);
|
||||||
|
if (jsonObject.containsKey("echo")) {
|
||||||
|
handleApiEcho(jsonObject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handleEvent(text);
|
||||||
|
}
|
||||||
|
private void handleEvent(String text){
|
||||||
Event event = JSON.parseObject(text, Event.class);
|
Event event = JSON.parseObject(text, Event.class);
|
||||||
System.out.println(event);
|
try {
|
||||||
|
this.bot.triggerEvent(event);
|
||||||
|
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||||
|
log.error(new RuntimeException(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void handleApiEcho(JSONObject data){
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cn.wzpmc.network;
|
package cn.wzpmc.network;
|
||||||
|
|
||||||
|
import cn.wzpmc.api.user.IBot;
|
||||||
import io.netty.bootstrap.Bootstrap;
|
import io.netty.bootstrap.Bootstrap;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
@ -9,6 +10,7 @@ import io.netty.handler.codec.http.DefaultHttpHeaders;
|
|||||||
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
|
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
|
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
|
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@ -20,8 +22,10 @@ import java.net.URI;
|
|||||||
* @since 2024/7/30 下午11:54
|
* @since 2024/7/30 下午11:54
|
||||||
*/
|
*/
|
||||||
@Log4j2
|
@Log4j2
|
||||||
|
@RequiredArgsConstructor
|
||||||
public class WebSocketConnectionHandler {
|
public class WebSocketConnectionHandler {
|
||||||
private final EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
|
private final EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
|
||||||
|
private final IBot bot;
|
||||||
/**
|
/**
|
||||||
* 建立连接
|
* 建立连接
|
||||||
* @author wzp
|
* @author wzp
|
||||||
@ -34,7 +38,7 @@ public class WebSocketConnectionHandler {
|
|||||||
Bootstrap bootstrap = new Bootstrap();
|
Bootstrap bootstrap = new Bootstrap();
|
||||||
WebSocketClientHandshaker clientHandshaker = WebSocketClientHandshakerFactory.newHandshaker(websocket, WebSocketVersion.V13, null, false, new DefaultHttpHeaders());
|
WebSocketClientHandshaker clientHandshaker = WebSocketClientHandshakerFactory.newHandshaker(websocket, WebSocketVersion.V13, null, false, new DefaultHttpHeaders());
|
||||||
HandshakePacketHandler handshakePacketHandler = new HandshakePacketHandler(clientHandshaker);
|
HandshakePacketHandler handshakePacketHandler = new HandshakePacketHandler(clientHandshaker);
|
||||||
PacketHandler handler = new PacketHandler();
|
PacketHandler handler = new PacketHandler(this.bot);
|
||||||
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new WebSocketChannelInitializer(handler, handshakePacketHandler));
|
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new WebSocketChannelInitializer(handler, handshakePacketHandler));
|
||||||
return bootstrap.connect(websocket.getHost(), websocket.getPort());
|
return bootstrap.connect(websocket.getHost(), websocket.getPort());
|
||||||
}
|
}
|
||||||
|
@ -171,12 +171,8 @@ public class CommandManager implements ICommandManager, Completer, Highlighter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setErrorPattern(Pattern pattern) {
|
public void setErrorPattern(Pattern pattern) {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setErrorIndex(int i) {
|
public void setErrorIndex(int i) {}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
package cn.wzpmc.plugins;
|
|
||||||
|
|
||||||
import cn.wzpmc.api.plugins.BasePlugin;
|
|
||||||
import cn.wzpmc.api.plugins.IPluginClassLoader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Java插件基类
|
|
||||||
* @author wzp
|
|
||||||
* @version 0.0.2-dev
|
|
||||||
* @since 2024/7/31 下午7:01
|
|
||||||
*/
|
|
||||||
public class JavaPlugin implements BasePlugin {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IPluginClassLoader getClassLoader() {
|
|
||||||
Class<? extends JavaPlugin> aClass = this.getClass();
|
|
||||||
ClassLoader loader = aClass.getClassLoader();
|
|
||||||
if (loader instanceof IPluginClassLoader){
|
|
||||||
return (IPluginClassLoader) loader;
|
|
||||||
}
|
|
||||||
throw new RuntimeException(new IllegalAccessException("You shouldn't load plugin class without PluginClassLoader!!!"));
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ import lombok.Setter;
|
|||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插件类加载器实现
|
* 插件类加载器实现
|
||||||
@ -21,10 +22,20 @@ import java.net.URL;
|
|||||||
@ToString
|
@ToString
|
||||||
public class PluginClassLoader extends IPluginClassLoader {
|
public class PluginClassLoader extends IPluginClassLoader {
|
||||||
private final IBot bot;
|
private final IBot bot;
|
||||||
@Setter
|
|
||||||
private BasePlugin plugin;
|
private BasePlugin plugin;
|
||||||
|
private String name;
|
||||||
|
private String version;
|
||||||
public PluginClassLoader(URL[] urls, IBot bot) {
|
public PluginClassLoader(URL[] urls, IBot bot) {
|
||||||
super(urls);
|
super(urls);
|
||||||
this.bot = bot;
|
this.bot = bot;
|
||||||
}
|
}
|
||||||
|
public void setPlugin(BasePlugin plugin, String name, String version){
|
||||||
|
if (Objects.isNull(this.plugin)){
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.name = name;
|
||||||
|
this.version = version;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Cannot set plugin with a initialized class loader!!!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
37
src/main/java/cn/wzpmc/plugins/PluginManager.java
Normal file
37
src/main/java/cn/wzpmc/plugins/PluginManager.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package cn.wzpmc.plugins;
|
||||||
|
|
||||||
|
import cn.wzpmc.api.plugins.BasePlugin;
|
||||||
|
import cn.wzpmc.api.plugins.IPluginManager;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 插件管理器
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/4 下午2:38
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class PluginManager implements IPluginManager {
|
||||||
|
private final List<BasePlugin> plugins = new ArrayList<>();
|
||||||
|
public <T extends BasePlugin> T initPlugin(Class<T> baseClass, String name, String version) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
|
||||||
|
ClassLoader loader = baseClass.getClassLoader();
|
||||||
|
if (!(loader instanceof PluginClassLoader)){
|
||||||
|
throw new IllegalArgumentException("baseClass " + baseClass.getName() + " must be loaded with plugin class loader!!!");
|
||||||
|
}
|
||||||
|
PluginClassLoader pluginClassLoader = (PluginClassLoader) loader;
|
||||||
|
if (Objects.nonNull(pluginClassLoader.getPlugin())){
|
||||||
|
throw new IllegalStateException("baseClass " + baseClass.getName() + " has already been initialization!!!");
|
||||||
|
}
|
||||||
|
Constructor<T> constructor = baseClass.getConstructor();
|
||||||
|
T t = constructor.newInstance();
|
||||||
|
pluginClassLoader.setPlugin(t, name, version);
|
||||||
|
plugins.add(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
92
src/main/java/cn/wzpmc/utils/ReflectionUtils.java
Normal file
92
src/main/java/cn/wzpmc/utils/ReflectionUtils.java
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package cn.wzpmc.utils;
|
||||||
|
|
||||||
|
import cn.wzpmc.api.events.Event;
|
||||||
|
import cn.wzpmc.api.plugins.BasePlugin;
|
||||||
|
import cn.wzpmc.api.plugins.IPluginManager;
|
||||||
|
import cn.wzpmc.api.plugins.event.EventHandler;
|
||||||
|
import cn.wzpmc.api.utils.IncreasbleHashMap;
|
||||||
|
import cn.wzpmc.api.utils.IncreasbleMap;
|
||||||
|
import cn.wzpmc.entities.event.EventHandlerMethod;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.net.URLClassLoader;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.jar.JarEntry;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 反射工具类
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/5 上午1:42
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
*/
|
||||||
|
@Log4j2
|
||||||
|
public class ReflectionUtils {
|
||||||
|
public static BasePlugin load(URLClassLoader loader, File file, IPluginManager pluginManager){
|
||||||
|
String absolutePath = file.getAbsolutePath();
|
||||||
|
try(JarFile jarFile = new JarFile(file)){
|
||||||
|
Optional<JarEntry> first = jarFile.stream().filter((e) -> "plugin.yml".equals(e.getName())).findFirst();
|
||||||
|
if (first.isEmpty()){
|
||||||
|
log.error("cannot find plugin.yml in plugin {}", absolutePath);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
InputStream stream = loader.getResourceAsStream("plugin.yml");
|
||||||
|
Yaml yaml = new Yaml();
|
||||||
|
JSONObject jsonObject = yaml.loadAs(stream, JSONObject.class);
|
||||||
|
String main = jsonObject.getString("main");
|
||||||
|
String version = jsonObject.getString("version");
|
||||||
|
String name = jsonObject.getString("name");
|
||||||
|
try{
|
||||||
|
Class<?> aClass = loader.loadClass(main);
|
||||||
|
if (!BasePlugin.class.isAssignableFrom(aClass)) {
|
||||||
|
log.error("插件{}-{}的主类{}未继承cn.wzpmc.api.plugins.JavaPlugin", name, version, main);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
//noinspection unchecked
|
||||||
|
BasePlugin basePlugin = pluginManager.initPlugin((Class<? extends BasePlugin>) aClass, name, version);
|
||||||
|
log.info("插件{}-{}已成功加载", name, version);
|
||||||
|
return basePlugin;
|
||||||
|
} catch (NoSuchMethodException | InvocationTargetException | InstantiationException |
|
||||||
|
IllegalAccessException e) {
|
||||||
|
log.error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}catch (ClassNotFoundException e) {
|
||||||
|
log.error("无法为插件{}-{}加载主类{}!", name, version, main);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static IncreasbleMap<Class<? extends Event>, EventHandlerMethod> loadEvents(Object eventHandlerObject){
|
||||||
|
Class<?> eventHandlerClass = eventHandlerObject.getClass();
|
||||||
|
IncreasbleMap<Class<? extends Event>, EventHandlerMethod> result = new IncreasbleHashMap<>();
|
||||||
|
for (Method declaredMethod : eventHandlerClass.getDeclaredMethods()) {
|
||||||
|
declaredMethod.setAccessible(true);
|
||||||
|
if (!declaredMethod.isAnnotationPresent(EventHandler.class)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (declaredMethod.getParameterCount() == 1) {
|
||||||
|
Class<?> eventType = declaredMethod.getParameterTypes()[0];
|
||||||
|
if (Event.class.isAssignableFrom(eventType)){
|
||||||
|
//noinspection unchecked
|
||||||
|
result.add((Class<? extends Event>) eventType, new EventHandlerMethod(eventHandlerObject, declaredMethod));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.warn("Not event method {}::{} shouldn't been annotations with @EventHandler", eventHandlerClass, declaredMethod.getName());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -40,4 +40,22 @@ public class TemplateFileUtils {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建默认文件夹,当其不存在时会被创建
|
||||||
|
* @author wzp
|
||||||
|
* @since 2024/8/4 下午2:36 v0.0.4-dev
|
||||||
|
* @param path 文件夹路径
|
||||||
|
* @return 是否创建
|
||||||
|
*/
|
||||||
|
public static boolean createDefaultDirectory(File path){
|
||||||
|
log.debug("创建文件夹:{}", path.getAbsolutePath());
|
||||||
|
if (path.isDirectory()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (path.mkdir()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw new RuntimeException(new IOException("Cannot create directory " + path.getAbsolutePath()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
42
src/test/java/DemoEventHandler.java
Normal file
42
src/test/java/DemoEventHandler.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import cn.wzpmc.api.events.Event;
|
||||||
|
import cn.wzpmc.api.events.message.priv.PrivateMessageEvent;
|
||||||
|
import cn.wzpmc.api.events.notice.notify.PokeNotifyEvent;
|
||||||
|
import cn.wzpmc.api.plugins.event.EventHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author wzp
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
* @since 2024/8/16 01:02
|
||||||
|
*/
|
||||||
|
public final class DemoEventHandler {
|
||||||
|
@EventHandler
|
||||||
|
public void onMessage(PrivateMessageEvent event) {
|
||||||
|
System.out.println(event);
|
||||||
|
System.out.println("Called 1");
|
||||||
|
}
|
||||||
|
@EventHandler
|
||||||
|
public void onMessage2(PrivateMessageEvent event) {
|
||||||
|
System.out.println(event);
|
||||||
|
System.out.println("Called 2");
|
||||||
|
}
|
||||||
|
@EventHandler
|
||||||
|
public void onPoke(PokeNotifyEvent event) {
|
||||||
|
System.out.println(event);
|
||||||
|
System.out.println("Called poke");
|
||||||
|
}
|
||||||
|
public void otherMethod(Event event){
|
||||||
|
System.err.println(event);
|
||||||
|
System.err.println("otherMethod shouldn't called!");
|
||||||
|
}
|
||||||
|
@EventHandler
|
||||||
|
public void wrongMethod(Event event, String wrongArgs){
|
||||||
|
System.err.println(event);
|
||||||
|
System.err.println(wrongArgs);
|
||||||
|
System.err.println("wrongMethod shouldn't called!");
|
||||||
|
}
|
||||||
|
@EventHandler
|
||||||
|
public void wrongMethod(String wrongArgs){
|
||||||
|
System.err.println(wrongArgs);
|
||||||
|
System.err.println("wrongMethod2 shouldn't called!");
|
||||||
|
}
|
||||||
|
}
|
32
src/test/java/TestEventHandle.java
Normal file
32
src/test/java/TestEventHandle.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import cn.wzpmc.Main;
|
||||||
|
import cn.wzpmc.api.events.message.priv.PrivateMessageEvent;
|
||||||
|
import cn.wzpmc.api.events.notice.notify.PokeNotifyEvent;
|
||||||
|
import cn.wzpmc.api.user.Friend;
|
||||||
|
import cn.wzpmc.configuration.Configuration;
|
||||||
|
import cn.wzpmc.entities.user.bot.MyBot;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author wzp
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
* @since 2024/8/16 01:01
|
||||||
|
*/
|
||||||
|
public class TestEventHandle {
|
||||||
|
@Test
|
||||||
|
public void testEventHandle() throws InvocationTargetException, IllegalAccessException {
|
||||||
|
Configuration configuration = Main.getConfiguration();
|
||||||
|
Friend targetUser = new Friend();
|
||||||
|
targetUser.setNickname("test");
|
||||||
|
targetUser.setId(Long.valueOf(0));
|
||||||
|
MyBot bot = Main.createBot(configuration);
|
||||||
|
bot.registerEventHandler(new DemoEventHandler());
|
||||||
|
PokeNotifyEvent pokeNotifyEvent = new PokeNotifyEvent();
|
||||||
|
pokeNotifyEvent.setTargetId(Long.valueOf(0));
|
||||||
|
bot.triggerEvent(pokeNotifyEvent);
|
||||||
|
PrivateMessageEvent privateMessageEvent = new PrivateMessageEvent();
|
||||||
|
privateMessageEvent.setSender(targetUser);
|
||||||
|
bot.triggerEvent(privateMessageEvent);
|
||||||
|
}
|
||||||
|
}
|
18
src/test/java/TestEventHandler.java
Normal file
18
src/test/java/TestEventHandler.java
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import cn.wzpmc.api.events.Event;
|
||||||
|
import cn.wzpmc.api.events.message.priv.PrivateMessageEvent;
|
||||||
|
import cn.wzpmc.api.events.notice.notify.PokeNotifyEvent;
|
||||||
|
import cn.wzpmc.api.plugins.event.EventHandler;
|
||||||
|
import cn.wzpmc.utils.ReflectionUtils;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author wzp
|
||||||
|
* @version 0.0.4-dev
|
||||||
|
* @since 2024/8/16 00:12
|
||||||
|
*/
|
||||||
|
public class TestEventHandler {
|
||||||
|
@Test
|
||||||
|
public void testEventHandler() {
|
||||||
|
System.out.println(ReflectionUtils.loadEvents(new DemoEventHandler()));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user