feat: adding api invoke function

feat: adding some api
This commit is contained in:
wzp 2024-08-23 21:58:29 +08:00
parent eb7cfe6f3d
commit a1d18b1277
55 changed files with 1774 additions and 71 deletions

View File

@ -1 +1 @@
0.0.4-dev 0.0.5-dev

5
.idea/misc.xml generated
View File

@ -5,8 +5,9 @@
<groovy codeStyle="LEGACY" /> <groovy codeStyle="LEGACY" />
</component> </component>
<component name="EntryPointsManager"> <component name="EntryPointsManager">
<list size="1"> <list size="2">
<item index="0" class="java.lang.String" itemvalue="com.alibaba.fastjson2.annotation.JSONField" /> <item index="0" class="java.lang.String" itemvalue="cn.wzpmc.api.plugins.event.EventHandler" />
<item index="1" class="java.lang.String" itemvalue="com.alibaba.fastjson2.annotation.JSONField" />
</list> </list>
</component> </component>
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />

View File

@ -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.4-dev") val projectVersion by extra("0.0.5-dev")
plugins { plugins {
id("java") id("java")

View File

@ -1,6 +1,13 @@
package cn.wzpmc; package cn.wzpmc;
import cn.wzpmc.api.events.message.group.GroupMessageEvent;
import cn.wzpmc.api.events.message.priv.PrivateMessageEvent;
import cn.wzpmc.api.message.StringMessage;
import cn.wzpmc.api.plugins.BasePlugin; import cn.wzpmc.api.plugins.BasePlugin;
import cn.wzpmc.api.plugins.event.EventHandler;
import cn.wzpmc.api.user.Friend;
import cn.wzpmc.api.user.group.GroupCommandSender;
import cn.wzpmc.api.user.group.GroupUser;
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;
@ -13,7 +20,6 @@ import cn.wzpmc.utils.JsonUtils;
import cn.wzpmc.utils.ReflectionUtils; 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 lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
@ -26,7 +32,7 @@ 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";
private static File pluginsDir;
public static void initializeJVM(){ 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");
@ -42,10 +48,6 @@ public class Main {
log.info("首次启动默认配置文件已创建请填写后再次启动MyBot"); log.info("首次启动默认配置文件已创建请填写后再次启动MyBot");
return null; return null;
} }
pluginsDir = new File("plugins");
if (TemplateFileUtils.createDefaultDirectory(pluginsDir)) {
log.debug("plugin文件夹创建");
}
log.debug("读取配置文件 {}", configurationFile.getAbsolutePath()); log.debug("读取配置文件 {}", configurationFile.getAbsolutePath());
return YamlUtils.readYamlFile(configurationFile, Configuration.class); return YamlUtils.readYamlFile(configurationFile, Configuration.class);
} }
@ -62,6 +64,11 @@ public class Main {
return uri; return uri;
} }
public static void loadPlugins(MyBot myBot) throws MalformedURLException { public static void loadPlugins(MyBot myBot) throws MalformedURLException {
File pluginsDir = new File("plugins");
if (TemplateFileUtils.createDefaultDirectory(pluginsDir)) {
log.debug("plugin文件夹创建");
}
myBot.setPluginsFolder(pluginsDir);
File[] files = pluginsDir.listFiles(); File[] files = pluginsDir.listFiles();
if (files == null) { if (files == null) {
log.error("没有权限读取插件目录!"); log.error("没有权限读取插件目录!");
@ -90,7 +97,7 @@ public class Main {
} }
public static WebSocketConnectionHandler createConnection(MyBot myBot, URI uri){ public static WebSocketConnectionHandler createConnection(MyBot myBot, URI uri){
WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler(myBot); WebSocketConnectionHandler webSocketConnectionHandler = new WebSocketConnectionHandler(myBot);
ChannelFuture future = webSocketConnectionHandler.connect(uri); webSocketConnectionHandler.connect(uri);
return webSocketConnectionHandler; return webSocketConnectionHandler;
} }
public static void startConsole(MyBot myBot, WebSocketConnectionHandler webSocketConnectionHandler){ public static void startConsole(MyBot myBot, WebSocketConnectionHandler webSocketConnectionHandler){
@ -107,6 +114,26 @@ public class Main {
return; return;
} }
MyBot myBot = createBot(configuration); MyBot myBot = createBot(configuration);
myBot.registerEventHandler(new Object(){
@EventHandler
public void onGroupMessage(GroupMessageEvent event){
GroupUser sender = event.getSender();
System.out.println(sender.getId());
if (sender.getId().equals(3357223099L)) {
System.out.println("send");
GroupCommandSender.of(event).sendMessage(StringMessage.text("test"));
System.out.println("called-group");
}
}
@EventHandler
public void onUserMessage(PrivateMessageEvent event){
Friend sender = event.getSender();
if (sender.getId().equals(3357223099L)){
sender.sendMessage(StringMessage.text("test-user"));
System.out.println("called-user");
}
}
});
URI uri = getUriFromConfiguration(configuration); URI uri = getUriFromConfiguration(configuration);
if (uri == null){ if (uri == null){
log.error("无法解析websocket地址"); log.error("无法解析websocket地址");
@ -114,6 +141,7 @@ public class Main {
} }
loadPlugins(myBot); loadPlugins(myBot);
WebSocketConnectionHandler webSocketConnectionHandler = createConnection(myBot, uri); WebSocketConnectionHandler webSocketConnectionHandler = createConnection(myBot, uri);
myBot.setConnectionHandler(webSocketConnectionHandler);
startConsole(myBot, webSocketConnectionHandler); startConsole(myBot, webSocketConnectionHandler);
} }
} }

View File

@ -0,0 +1,34 @@
package cn.wzpmc.api.api;
import lombok.*;
import java.util.UUID;
/**
* 抽象请求体
* @author wzp
* @since 2024/8/16 21:36
* @version 0.0.5-dev
*/
@Getter
@ToString
@EqualsAndHashCode
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Setter(AccessLevel.PROTECTED)
public class Action<REQUEST, RESPONSE> {
/**
* 请求操作类型
* @since 2024/8/23 21:29 v0.0.5-dev
*/
private Actions action;
/**
* 请求参数
* @since 2024/8/23 21:29 v0.0.5-dev
*/
private REQUEST params;
/**
* 请求回调值默认随机生成不建议自己修改
* @since 2024/8/23 21:29 v0.0.5-dev
*/
private final UUID echo = UUID.randomUUID();
}

View File

@ -0,0 +1,35 @@
package cn.wzpmc.api.api;
import lombok.Data;
import java.util.UUID;
/**
* 请求操作返回
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/16 17:43
*/
@Data
public class ActionResponse<RESPONSE> {
/**
* 请求返回消息
* @since 2024/8/23 21:30 v0.0.5-dev
*/
private final String status;
/**
* 请求返回码
* @since 2024/8/23 21:30 v0.0.5-dev
*/
private final short retcode;
/**
* 请求返回数据
* @since 2024/8/23 21:31 v0.0.5-dev
*/
private final RESPONSE data;
/**
* 请求返回回调
* @since 2024/8/23 21:31 v0.0.5-dev
*/
private final UUID echo;
}

View File

@ -0,0 +1,85 @@
package cn.wzpmc.api.api;
import cn.wzpmc.api.api.actions.message.send.SendMessageActionResponseData;
import cn.wzpmc.api.entities.MessageInformation;
/**
* 操作类型
* @author wzp
* @since 2024/8/16 22:24
* @version 0.0.5-dev
*/
public enum Actions {
/**
* 发送私聊消息
* @since 2024/8/23 21:07 v0.0.5-dev
*/
SEND_PRIVATE_MSG(SendMessageActionResponseData.class),
/**
* 发送群消息
* @since 2024/8/23 21:07 v0.0.5-dev
*/
SEND_GROUP_MSG(SendMessageActionResponseData.class),
/**
* 撤回消息
* @since 2024/8/23 21:07 v0.0.5-dev
*/
DELETE_MSG(),
/**
* 获取消息
* @since 2024/8/23 21:07 v0.0.5-dev
*/
GET_MSG(MessageInformation.class),
/**
* 获取合并转发消息
* @since 2024/8/23 21:08 v0.0.5-dev
*/
GET_FORWARD_MSG(MessageInformation.class),
/**
* 发送好友赞
* @since 2024/8/23 21:08 v0.0.5-dev
*/
SEND_LIKE(),
/**
* 群组踢人
* @since 2024/8/23 21:08 v0.0.5-dev
*/
SET_GROUP_KICK(),
/**
* 群组单人禁言
* @since 2024/8/23 21:08 v0.0.5-dev
*/
SET_GROUP_BAN(),
/**
* 群组匿名用户禁言
* @since 2024/8/23 21:08 v0.0.5-dev
*/
SET_GROUP_ANONYMOUS_BAN(),
/**
* 群组全员禁言
* @since 2024/8/23 21:09 v0.0.5-dev
*/
SET_GROUP_WHOLE_BAN(),
/**
* 群组设置管理员
* @since 2024/8/23 21:09 v0.0.5-dev
*/
SET_GROUP_ADMIN(),
/**
* 群组匿名
* @since 2024/8/23 21:09 v0.0.5-dev
*/
SET_GROUP_ANONYMOUS(),
/**
* 设置群名片群备注
* @since 2024/8/23 21:09 v0.0.5-dev
*/
SET_GROUP_CARD();
public final Class<?> responseClass;
Actions(Class<?> responseClass) {
this.responseClass = responseClass;
}
Actions(){
this(Void.class);
}
}

View File

@ -0,0 +1,21 @@
package cn.wzpmc.api.api;
/**
* 主Api接口
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/16 17:31
*/
public interface IMainApi {
/**
* 进行请求操作
* @author wzp
* @since 2024/8/23 21:32 v0.0.5-dev
* @param packet 请求包
* @return 请求返回包
* @param <REQUEST> 请求类型
* @param <RESPONSE> 返回类型
* @throws InterruptedException 请求过程中出现Ctrl+C时抛出
*/
<REQUEST, RESPONSE> ActionResponse<RESPONSE> doApiCall(Action<REQUEST, RESPONSE> packet) throws InterruptedException;
}

View File

@ -0,0 +1,36 @@
package cn.wzpmc.api.api.actions.message.delete;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 撤回消息
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/17 23:02
*/
public class DeleteMessageAction extends Action<DeleteMessageAction.Params, Void> {
/**
* 撤回消息
* @author wzp
* @since 2024/8/23 21:09 v0.0.5-dev
* @param messageId 消息ID
*/
public DeleteMessageAction(Integer messageId){
super.setAction(Actions.DELETE_MSG);
super.setParams(new Params(messageId));
}
@Data
@AllArgsConstructor
public static class Params {
/**
* 消息ID
* @since 2024/8/17 23:03 v0.0.5-dev
*/
@JSONField(name = "message_id")
private Integer messageId;
}
}

View File

@ -0,0 +1,35 @@
package cn.wzpmc.api.api.actions.message.get;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import cn.wzpmc.api.entities.MessageInformation;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 获取合并转发消息
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/23 19:46
*/
public class GetForwardMessageAction extends Action<GetForwardMessageAction.Params, MessageInformation> {
/**
* 获取合并转发消息
* @author wzp
* @since 2024/8/23 21:10 v0.0.5-dev
* @param id 合并转发ID
*/
public GetForwardMessageAction(String id){
super.setAction(Actions.GET_FORWARD_MSG);
super.setParams(new GetForwardMessageAction.Params(id));
}
@Data
@AllArgsConstructor
public static final class Params {
/**
* 合并转发ID
* @since 2024/8/23 19:47 v0.0.5-dev
*/
private String id;
}
}

View File

@ -0,0 +1,37 @@
package cn.wzpmc.api.api.actions.message.get;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import cn.wzpmc.api.entities.MessageInformation;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 获取消息
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/17 23:07
*/
public class GetMessageAction extends Action<GetMessageAction.Params, MessageInformation> {
/**
* 获取消息
* @author wzp
* @since 2024/8/23 21:11 v0.0.5-dev
* @param messageId 消息 ID
*/
public GetMessageAction(Integer messageId){
super.setAction(Actions.GET_MSG);
super.setParams(new Params(messageId));
}
@Data
@AllArgsConstructor
public static class Params {
/**
* 消息 ID
* @since 2024/8/23 21:11 v0.0.5-dev
*/
@JSONField(name = "message_id")
private Integer messageId;
}
}

View File

@ -0,0 +1,61 @@
package cn.wzpmc.api.api.actions.message.send;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import cn.wzpmc.api.message.MessageComponent;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 发送群消息
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/17 22:52
*/
public class SendGroupMessageAction extends Action<SendGroupMessageAction.Params, SendMessageActionResponseData> {
/**
* 发送群消息
* @author wzp
* @since 2024/8/23 21:11 v0.0.5-dev
* @param groupId 群号
* @param message 要发送的内容
* @param autoEscape 消息内容是否作为纯文本发送即不解析 CQ 只在 message 字段是字符串时有效
*/
public SendGroupMessageAction(Long groupId, MessageComponent message, boolean autoEscape){
super.setAction(Actions.SEND_GROUP_MSG);
super.setParams(new SendGroupMessageAction.Params(groupId, message, autoEscape));
}
/**
* 发送群消息
* @author wzp
* @since 2024/8/23 21:11 v0.0.5-dev
* @param groupId 群号
* @param message 要发送的内容
*/
public SendGroupMessageAction(Long groupId, MessageComponent message){
this(groupId, message, false);
}
@Data
@AllArgsConstructor
public static class Params {
/**
* 群号
* @since 2024/8/17 22:54 v0.0.5-dev
*/
@JSONField(name = "group_id")
private Long groupId;
/**
* 要发送的内容
* @since 2024/8/17 22:54 v0.0.5-dev
*/
private MessageComponent message;
/**
* 消息内容是否作为纯文本发送即不解析 CQ 只在 message 字段是字符串时有效
* @since 2024/8/17 22:51 v0.0.5-dev
*/
@JSONField(name = "auto_escape")
private boolean autoEscape;
}
}

View File

@ -0,0 +1,53 @@
package cn.wzpmc.api.api.actions.message.send;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 发送好友赞
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/23 19:49
*/
public class SendLikeAction extends Action<SendLikeAction.Params, Void> {
/**
* 发送好友赞
* @author wzp
* @since 2024/8/23 21:12 v0.0.5-dev
* @param userId 对方 QQ
* @param times 赞的次数每个好友每天最多 10
*/
public SendLikeAction(Long userId, Long times){
super.setAction(Actions.SEND_LIKE);
super.setParams(new Params(userId, times));
}
/**
* 发送好友赞
* @author wzp
* @since 2024/8/23 21:12 v0.0.5-dev
* @param userId 对方 QQ
*/
public SendLikeAction(Long userId){
this(userId, 1L);
}
@Data
@AllArgsConstructor
public static final class Params {
/**
* 对方 QQ
* @since 2024/8/23 21:12 v0.0.5-dev
*/
@JSONField(name = "user_id")
private Long userId;
/**
* 赞的次数每个好友每天最多 10
* @since 2024/8/23 21:12 v0.0.5-dev
*/
@JSONField(defaultValue = "1")
private Long times;
}
}

View File

@ -0,0 +1,20 @@
package cn.wzpmc.api.api.actions.message.send;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
/**
* 发送私聊消息返回
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/17 21:55
*/
@Data
public class SendMessageActionResponseData {
/**
* 消息 ID
* @since 2024/8/17 22:51 v0.0.5-dev
*/
@JSONField(name = "message_id")
private int messageId;
}

View File

@ -0,0 +1,61 @@
package cn.wzpmc.api.api.actions.message.send;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import cn.wzpmc.api.message.MessageComponent;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 发送私聊消息
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/17 21:54
*/
public class SendPrivateMessageAction extends Action<SendPrivateMessageAction.Params, SendMessageActionResponseData> {
/**
* 发送私聊消息
* @author wzp
* @since 2024/8/23 21:13 v0.0.5-dev
* @param userId 对方 QQ
* @param message 要发送的内容
* @param autoEscape 消息内容是否作为纯文本发送即不解析 CQ 只在 message 字段是字符串时有效
*/
public SendPrivateMessageAction(Long userId, MessageComponent message, boolean autoEscape){
super.setAction(Actions.SEND_PRIVATE_MSG);
super.setParams(new Params(userId, message, autoEscape));
}
/**
* 发送私聊消息
* @author wzp
* @since 2024/8/23 21:14 v0.0.5-dev
* @param userId 对方 QQ
* @param message 要发送的内容
*/
public SendPrivateMessageAction(Long userId, MessageComponent message){
this(userId, message, false);
}
@Data
@AllArgsConstructor
public static class Params {
/**
* 对方 QQ
* @since 2024/8/17 22:51 v0.0.5-dev
*/
@JSONField(name = "user_id")
private Long userId;
/**
* 要发送的内容
* @since 2024/8/17 22:51 v0.0.5-dev
*/
private MessageComponent message;
/**
* 消息内容是否作为纯文本发送即不解析 CQ 只在 message 字段是字符串时有效
* @since 2024/8/17 22:51 v0.0.5-dev
*/
@JSONField(name = "auto_escape")
private boolean autoEscape;
}
}

View File

@ -0,0 +1,61 @@
package cn.wzpmc.api.api.actions.message.set;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 群组设置管理员
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/23 20:51
*/
public class SetGroupAdminAction extends Action<SetGroupAdminAction.Params, Void> {
/**
* 群组设置管理员
* @author wzp
* @since 2024/8/23 21:14 v0.0.5-dev
* @param groupId 群号
* @param userId 要设置管理员的 QQ
* @param enable true 为设置false 为取消
*/
public SetGroupAdminAction(Long groupId, Long userId, Boolean enable){
super.setAction(Actions.SET_GROUP_ADMIN);
super.setParams(new Params(groupId, userId, enable));
}
/**
* 群组设置管理员
* @author wzp
* @since 2024/8/23 21:14 v0.0.5-dev
* @param groupId 群号
* @param userId 要设置管理员的 QQ
*/
public SetGroupAdminAction(Long groupId, Long userId) {
this(groupId, userId, true);
}
@Data
@AllArgsConstructor
public static final class Params {
/**
* 群号
* @since 2024/8/23 21:15 v0.0.5-dev
*/
@JSONField(name = "group_id")
private Long groupId;
/**
* 要设置管理员的 QQ
* @since 2024/8/23 21:15 v0.0.5-dev
*/
@JSONField(name = "user_id")
private Long userId;
/**
* true 为设置false 为取消
* @since 2024/8/23 21:15 v0.0.5-dev
*/
@JSONField(defaultValue = "true")
private Boolean enable;
}
}

View File

@ -0,0 +1,53 @@
package cn.wzpmc.api.api.actions.message.set;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 群组匿名
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/23 20:55
*/
public class SetGroupAnonymous extends Action<SetGroupAnonymous.Params, Void> {
/**
* 群组匿名
* @author wzp
* @since 2024/8/23 21:16 v0.0.5-dev
* @param groupId 群号
* @param enable 是否允许匿名聊天
*/
public SetGroupAnonymous(Long groupId, Boolean enable) {
super.setAction(Actions.SET_GROUP_ANONYMOUS);
super.setParams(new Params(groupId, enable));
}
/**
* 群组匿名
* @author wzp
* @since 2024/8/23 21:16 v0.0.5-dev
* @param groupId 群号
*/
public SetGroupAnonymous(Long groupId) {
this(groupId, true);
}
@Data
@AllArgsConstructor
public static final class Params {
/**
* 群号
* @since 2024/8/23 21:16 v0.0.5-dev
*/
@JSONField(name = "group_id")
private Long groupId;
/**
* 是否允许匿名聊天
* @since 2024/8/23 21:16 v0.0.5-dev
*/
@JSONField(defaultValue = "true")
private Boolean enable;
}
}

View File

@ -0,0 +1,102 @@
package cn.wzpmc.api.api.actions.message.set;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import cn.wzpmc.api.message.json.parts.Anonymous;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 群组匿名用户禁言
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/23 20:08
*/
public class SetGroupAnonymousBanAction extends Action<SetGroupAnonymousBanAction.Params, Void> {
/**
* 群组匿名用户禁言
* @author wzp
* @since 2024/8/23 21:17 v0.0.5-dev
* @param groupId 群号
* @param anonymous 可选要禁言的匿名用户对象群消息上报的 anonymous 字段
* @param flag 可选要禁言的匿名用户的 flag需从群消息上报的数据中获得
* @param duration 禁言时长单位秒无法取消匿名用户禁言默认30 * 60
*/
protected SetGroupAnonymousBanAction(Long groupId, Anonymous anonymous, String flag, Long duration) {
super.setAction(Actions.SET_GROUP_ANONYMOUS_BAN);
super.setParams(new Params(groupId, anonymous, flag, duration));
}
/**
* 群组匿名用户禁言
* @author wzp
* @since 2024/8/23 21:17 v0.0.5-dev
* @param groupId 群号
* @param anonymous 要禁言的匿名用户对象群消息上报的 anonymous 字段
* @param duration 禁言时长单位秒无法取消匿名用户禁言
*/
public SetGroupAnonymousBanAction(Long groupId, Anonymous anonymous, Long duration) {
this(groupId, anonymous, null, duration);
}
/**
* 群组匿名用户禁言
* @author wzp
* @since 2024/8/23 21:17 v0.0.5-dev
* @param groupId 群号
* @param anonymous 要禁言的匿名用户对象群消息上报的 anonymous 字段
*/
public SetGroupAnonymousBanAction(Long groupId, Anonymous anonymous) {
this(groupId, anonymous, 1800L);
}
/**
* 群组匿名用户禁言
* @author wzp
* @since 2024/8/23 21:17 v0.0.5-dev
* @param groupId 群号
* @param flag 要禁言的匿名用户的 flag需从群消息上报的数据中获得
* @param duration 禁言时长单位秒无法取消匿名用户禁言
*/
public SetGroupAnonymousBanAction(Long groupId, String flag, Long duration) {
this(groupId, null, flag, duration);
}
/**
* 群组匿名用户禁言
* @author wzp
* @since 2024/8/23 21:17 v0.0.5-dev
* @param groupId 群号
* @param flag 要禁言的匿名用户的 flag需从群消息上报的数据中获得
*/
public SetGroupAnonymousBanAction(Long groupId, String flag) {
this(groupId, flag, 1800L);
}
@Data
@AllArgsConstructor
public static final class Params {
/**
* 群号
* @since 2024/8/23 21:17 v0.0.5-dev
*/
@JSONField(name = "group_id")
private Long groupId;
/**
* 可选要禁言的匿名用户对象群消息上报的 anonymous 字段
* @since 2024/8/23 21:17 v0.0.5-dev
*/
private Anonymous anonymous;
/**
* 可选要禁言的匿名用户的 flag需从群消息上报的数据中获得
* @since 2024/8/23 21:17 v0.0.5-dev
*/
private String flag;
/**
* 禁言时长单位秒无法取消匿名用户禁言默认30 * 60
* @since 2024/8/23 21:17 v0.0.5-dev
*/
@JSONField(defaultValue = "1800")
private Long duration;
}
}

View File

@ -0,0 +1,61 @@
package cn.wzpmc.api.api.actions.message.set;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 群组单人禁言
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/23 20:03
*/
public class SetGroupBanAction extends Action<SetGroupBanAction.Params, Void> {
/**
* 群组单人禁言
* @author wzp
* @since 2024/8/23 21:20 v0.0.5-dev
* @param groupId 群号
* @param userId 要禁言的 QQ
* @param duration 禁言时长单位秒0 表示取消禁言
*/
public SetGroupBanAction(Long groupId, Long userId, Long duration){
super.setAction(Actions.SET_GROUP_BAN);
super.setParams(new Params(groupId, userId, duration));
}
/**
* 群组单人禁言
* @author wzp
* @since 2024/8/23 21:20 v0.0.5-dev
* @param groupId 群号
* @param userId 要禁言的 QQ
*/
public SetGroupBanAction(Long groupId, Long userId){
this(groupId, userId, 1800L);
}
@Data
@AllArgsConstructor
public static final class Params {
/**
* 群号
* @since 2024/8/23 21:20 v0.0.5-dev
*/
@JSONField(name = "group_id")
private Long groupId;
/**
* 要禁言的 QQ
* @since 2024/8/23 21:20 v0.0.5-dev
*/
@JSONField(name = "user_id")
private Long userId;
/**
* 禁言时长单位秒0 表示取消禁言默认30 * 60
* @since 2024/8/23 21:20 v0.0.5-dev
*/
@JSONField(defaultValue = "1800")
private Long duration;
}
}

View File

@ -0,0 +1,60 @@
package cn.wzpmc.api.api.actions.message.set;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 设置群名片群备注
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/23 20:59
*/
public class SetGroupCardAction extends Action<SetGroupCardAction.Params, Void> {
/**
* 设置群名片群备注
* @author wzp
* @since 2024/8/23 21:22 v0.0.5-dev
* @param groupId 群号
* @param userId 要设置的 QQ
* @param card 群名片内容不填或空字符串表示删除群名片
*/
public SetGroupCardAction(Long groupId, Long userId, String card) {
super.setAction(Actions.SET_GROUP_CARD);
super.setParams(new Params(groupId, userId, card));
}
/**
* 设置群名片群备注
* @author wzp
* @since 2024/8/23 21:22 v0.0.5-dev
* @param groupId 群号
* @param userId 要设置的 QQ
*/
public SetGroupCardAction(Long groupId, Long userId) {
this(groupId, userId, "");
}
@Data
@AllArgsConstructor
public static final class Params {
/**
* 群号
* @since 2024/8/23 21:23 v0.0.5-dev
*/
@JSONField(name = "group_id")
private Long groupId;
/**
* 要设置的 QQ
* @since 2024/8/23 21:23 v0.0.5-dev
*/
@JSONField(name = "user_id")
private Long userId;
/**
* 群名片内容不填或空字符串表示删除群名片默认为空
* @since 2024/8/23 21:23 v0.0.5-dev
*/
private String card;
}
}

View File

@ -0,0 +1,61 @@
package cn.wzpmc.api.api.actions.message.set;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 群组踢人
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/23 19:52
*/
public class SetGroupKickAction extends Action<SetGroupKickAction.Params, Void> {
/**
* 群组踢人
* @author wzp
* @since 2024/8/23 21:24 v0.0.5-dev
* @param groupId 群号
* @param userId 要踢的 QQ
* @param rejectAddRequest 拒绝此人的加群请求
*/
public SetGroupKickAction(Long groupId, Long userId, Boolean rejectAddRequest) {
super.setAction(Actions.SET_GROUP_KICK);
super.setParams(new Params(groupId, userId, rejectAddRequest));
}
/**
* 群组踢人
* @author wzp
* @since 2024/8/23 21:24 v0.0.5-dev
* @param groupId 群号
* @param userId 要踢的 QQ
*/
public SetGroupKickAction(Long groupId, Long userId) {
this(groupId, userId, false);
}
@Data
@AllArgsConstructor
public static final class Params {
/**
* 群号
* @since 2024/8/23 21:25 v0.0.5-dev
*/
@JSONField(name = "group_id")
private Long groupId;
/**
* 要踢的 QQ
* @since 2024/8/23 21:25 v0.0.5-dev
*/
@JSONField(name = "user_id")
private Long userId;
/**
* 拒绝此人的加群请求默认为false
* @since 2024/8/23 21:25 v0.0.5-dev
*/
@JSONField(name = "reject_add_request", defaultValue = "false")
private Boolean rejectAddRequest;
}
}

View File

@ -0,0 +1,53 @@
package cn.wzpmc.api.api.actions.message.set;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.Actions;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 群组全员禁言
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/23 20:06
*/
public class SetGroupWholeBanAction extends Action<SetGroupWholeBanAction.Params, Void> {
/**
* 群组全员禁言
* @author wzp
* @since 2024/8/23 21:27 v0.0.5-dev
* @param groupId 群号
* @param enable 是否禁言
*/
public SetGroupWholeBanAction(Long groupId, Boolean enable) {
super.setAction(Actions.SET_GROUP_WHOLE_BAN);
super.setParams(new Params(groupId, enable));
}
/**
* 群组全员禁言
* @author wzp
* @since 2024/8/23 21:28 v0.0.5-dev
* @param groupId 群号
*/
public SetGroupWholeBanAction(Long groupId) {
this(groupId, true);
}
@Data
@AllArgsConstructor
public static final class Params {
/**
* 群号
* @since 2024/8/23 21:28 v0.0.5-dev
*/
@JSONField(name = "group_id")
private Long groupId;
/**
* 是否禁言默认true
* @since 2024/8/23 21:28 v0.0.5-dev
*/
@JSONField(defaultValue = "true")
private Boolean enable;
}
}

View File

@ -10,6 +10,14 @@ import lombok.Data;
*/ */
@Data @Data
public class BotStatus { public class BotStatus {
/**
* bot是否在线
* @since 2024/8/23 21:33 v0.0.5-dev
*/
private boolean online; private boolean online;
/**
* bot健康程度
* @since 2024/8/23 21:34 v0.0.5-dev
*/
private boolean good; private boolean good;
} }

View File

@ -0,0 +1,49 @@
package cn.wzpmc.api.entities;
import cn.wzpmc.api.events.message.MessageType;
import cn.wzpmc.api.message.MessageComponent;
import cn.wzpmc.api.user.IUser;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.Data;
/**
* 获取消息操作返回
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/17 23:08
*/
@Data
public class MessageInformation {
/**
* 发送时间
* @since 2024/8/23 21:34 v0.0.5-dev
*/
private Integer time;
/**
* 消息类型
* @since 2024/8/23 21:34 v0.0.5-dev
*/
private MessageType type;
/**
* 消息 ID
* @since 2024/8/23 21:34 v0.0.5-dev
*/
@JSONField(name = "message_id")
private Integer messageId;
/**
* 消息真实 ID
* @since 2024/8/23 21:34 v0.0.5-dev
*/
@JSONField(name = "real_id")
private Integer realId;
/**
* 发送人信息
* @since 2024/8/23 21:35 v0.0.5-dev
*/
private IUser sender;
/**
* 消息内容
* @since 2024/8/23 21:35 v0.0.5-dev
*/
private MessageComponent message;
}

View File

@ -17,10 +17,24 @@ import java.util.stream.Collectors;
@Data @Data
public class JsonMessage implements MessageComponent { public class JsonMessage implements MessageComponent {
private final List<JsonMessagePart> messageParts = new ArrayList<>(); private final List<JsonMessagePart> messageParts = new ArrayList<>();
/**
* 将消息转为JSON文本
* @author wzp
* @since 2024/8/23 21:36 v0.0.5-dev
* @return json文本
*/
@Override @Override
public String toMessageString() { public String toMessageString() {
return JSON.toJSONString(messageParts); return JSON.toJSONString(messageParts);
} }
/**
* 将JSON消息转化为纯文本显示方式
* @author wzp
* @since 2024/8/23 21:35 v0.0.5-dev
* @return 文本
*/
public String toTextDisplay() { public String toTextDisplay() {
return this.messageParts.stream().map(JsonMessagePart::getTextDisplay).collect(Collectors.joining("")); return this.messageParts.stream().map(JsonMessagePart::getTextDisplay).collect(Collectors.joining(""));
} }

View File

@ -2,6 +2,7 @@ package cn.wzpmc.api.message.json.parts;
import cn.wzpmc.api.message.json.JsonMessagePart; import cn.wzpmc.api.message.json.JsonMessagePart;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@ -13,12 +14,13 @@ import lombok.NoArgsConstructor;
*/ */
@Data @Data
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor
public class At implements JsonMessagePart { public class At implements JsonMessagePart {
/** /**
* "@" QQ all 表示全体成员 * "@" QQ all 表示全体成员
* @since 2024/8/2 下午11:50 v0.0.3-dev * @since 2024/8/2 下午11:50 v0.0.3-dev
*/ */
private String qq; private Long qq;
@Override @Override
public PartType getPartType() { public PartType getPartType() {

View File

@ -6,6 +6,7 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
/** /**
* 掷骰子魔法表情
* @author MoYiJiangNan * @author MoYiJiangNan
* @version 0.0.3-dev * @version 0.0.3-dev
* @since 2024/8/2 下午11:26 * @since 2024/8/2 下午11:26

View File

@ -11,27 +11,108 @@ import cn.wzpmc.api.message.json.parts.poke.Poke;
* 消息段类型 * 消息段类型
* @author wzp * @author wzp
* @since 2024/8/3 下午6:18 * @since 2024/8/3 下午6:18
* @version 0.0.3-dev */ * @version 0.0.3-dev
*/
public enum PartType { public enum PartType {
/**
* 文本消息
* @since 2024/8/23 21:37 v0.0.5-dev
*/
TEXT(StringMessage.class), TEXT(StringMessage.class),
/**
* 表情消息
* @since 2024/8/23 21:37 v0.0.5-dev
*/
FACE(Face.class), FACE(Face.class),
/**
* 图片消息
* @since 2024/8/23 21:37 v0.0.5-dev
*/
IMAGE(Image.class), IMAGE(Image.class),
/**
* 语音
* @since 2024/8/23 21:37 v0.0.5-dev
*/
RECORD(Record.class), RECORD(Record.class),
/**
* 短视频
* @since 2024/8/23 21:37 v0.0.5-dev
*/
VIDEO(Video.class), VIDEO(Video.class),
/**
* "@"某人
* @since 2024/8/23 21:37 v0.0.5-dev
*/
AT(At.class), AT(At.class),
/**
* 拳魔法表情
* @since 2024/8/23 21:37 v0.0.5-dev
*/
RPS(cn.wzpmc.api.message.json.parts.RPS.class), RPS(cn.wzpmc.api.message.json.parts.RPS.class),
/**
* 掷骰子魔法表情
* @since 2024/8/23 21:38 v0.0.5-dev
*/
DICE(Dice.class), DICE(Dice.class),
/**
* 窗口抖动戳一戳
* @since 2024/8/23 21:38 v0.0.5-dev
*/
SHAKE(Shake.class), SHAKE(Shake.class),
/**
* 戳一戳
* @since 2024/8/23 21:38 v0.0.5-dev
*/
POKE(Poke.class), POKE(Poke.class),
/**
* 匿名发消息
* @since 2024/8/23 21:39 v0.0.5-dev
*/
ANONYMOUS(Anonymous.class), ANONYMOUS(Anonymous.class),
/**
* 链接分享
* @since 2024/8/23 21:39 v0.0.5-dev
*/
SHARE(Share.class), SHARE(Share.class),
/**
* 推荐好友/
* @since 2024/8/23 21:39 v0.0.5-dev
*/
CONTACT(Contact.class), CONTACT(Contact.class),
/**
* 位置
* @since 2024/8/23 21:40 v0.0.5-dev
*/
LOCATION(Location.class), LOCATION(Location.class),
/**
* 音乐分享
* @since 2024/8/23 21:40 v0.0.5-dev
*/
MUSIC(Music.class), MUSIC(Music.class),
/**
* 回复
* @since 2024/8/23 21:40 v0.0.5-dev
*/
REPLY(Reply.class), REPLY(Reply.class),
/**
* 合并转发
* @since 2024/8/23 21:40 v0.0.5-dev
*/
FORWARD(Forward.class), FORWARD(Forward.class),
/**
* 合并转发节点
* @since 2024/8/23 21:40 v0.0.5-dev
*/
NODE(Node.class), NODE(Node.class),
/**
* XML消息
* @since 2024/8/23 21:40 v0.0.5-dev
*/
XML(XMLMessage.class), XML(XMLMessage.class),
/**
* JSON消息
* @since 2024/8/23 21:40 v0.0.5-dev
*/
JSON(CustomJSONMessage.class); JSON(CustomJSONMessage.class);
public final Class<? extends JsonMessagePart> clazz; public final Class<? extends JsonMessagePart> clazz;
PartType(Class<? extends JsonMessagePart> clazz){ PartType(Class<? extends JsonMessagePart> clazz){

View File

@ -16,5 +16,5 @@ public enum ContactType {
* 推荐群 * 推荐群
* @since 2024/8/2 下午11:36 v0.0.3-dev * @since 2024/8/2 下午11:36 v0.0.3-dev
*/ */
GROUP; GROUP
} }

View File

@ -3,6 +3,9 @@ package cn.wzpmc.api.plugins;
import cn.wzpmc.api.user.IBot; import cn.wzpmc.api.user.IBot;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.InputStream;
/** /**
* 插件基类 * 插件基类
* @author wzp * @author wzp
@ -47,7 +50,57 @@ public interface BasePlugin {
*/ */
IPluginClassLoader getClassLoader(); IPluginClassLoader getClassLoader();
/**
* 当插件被加载时调用
* @author wzp
* @since 2024/8/16 13:14 v0.0.5-dev
*/
void onLoad(); void onLoad();
/**
* 当插件被卸载时调用
* @author wzp
* @since 2024/8/16 13:14 v0.0.5-dev
*/
void onUnload(); void onUnload();
/**
* 获取日志记录器
* @author wzp
* @since 2024/8/16 13:14 v0.0.5-dev
* @return 日志记录器
*/
Logger getLogger(); Logger getLogger();
/**
* 从插件中读取资源
* @author wzp
* @since 2024/8/16 13:14 v0.0.5-dev
* @param name 资源路径
* @return 资源流
*/
InputStream getResourceAsStream(String name);
/**
* 获取插件数据文件夹
* @author wzp
* @since 2024/8/16 13:16 v0.0.5-dev
* @return 插件数据文件夹
*/
File getDataFolder();
/**
* 获取默认配置文件
* @author wzp
* @since 2024/8/16 13:16 v0.0.5-dev
* @return 获取默认配置文件
*/
File getDefaultConfigFile();
/**
* 将插件默认配置文件保存到文件夹中
* @author wzp
* @since 2024/8/16 13:16 v0.0.5-dev
*/
void saveDefaultConfig();
} }

View File

@ -12,7 +12,12 @@ import java.net.URLClassLoader;
* @since 2024/7/31 下午6:59 * @since 2024/7/31 下午6:59
*/ */
public abstract class IPluginClassLoader extends URLClassLoader { public abstract class IPluginClassLoader extends URLClassLoader {
/**
* 创建插件类加载器
* @author wzp
* @since 2024/8/23 21:41 v0.0.5-dev
* @param urls jar文件路径
*/
public IPluginClassLoader(URL[] urls) { public IPluginClassLoader(URL[] urls) {
super(urls); super(urls);
} }

View File

@ -4,6 +4,7 @@ import java.lang.reflect.InvocationTargetException;
import java.util.List; import java.util.List;
/** /**
* 插件管理器
* @author wzp * @author wzp
* @version 0.0.4-dev * @version 0.0.4-dev
* @since 2024/8/6 下午3:19 * @since 2024/8/6 下午3:19
@ -11,7 +12,6 @@ import java.util.List;
public interface IPluginManager { public interface IPluginManager {
/** /**
* 初始化插件主类 * 初始化插件主类
*
* @param <T> 插件主类类型 * @param <T> 插件主类类型
* @param baseClass 插件主类 * @param baseClass 插件主类
* @param name 插件名称 * @param name 插件名称
@ -19,6 +19,10 @@ public interface IPluginManager {
* @return 这个插件的实例 * @return 这个插件的实例
* @author wzp * @author wzp
* @since 2024/8/5 上午12:58 v0.0.4-dev * @since 2024/8/5 上午12:58 v0.0.4-dev
* @throws NoSuchMethodException 初始化插件错误
* @throws InvocationTargetException 初始化插件错误
* @throws InstantiationException 初始化插件错误
* @throws IllegalAccessException 初始化插件错误
*/ */
<T extends BasePlugin> T initPlugin(Class<T> baseClass, String name, String version) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException; <T extends BasePlugin> T initPlugin(Class<T> baseClass, String name, String version) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException;
List<BasePlugin> getPlugins(); List<BasePlugin> getPlugins();

View File

@ -1,10 +1,17 @@
package cn.wzpmc.api.plugins; package cn.wzpmc.api.plugins;
import cn.wzpmc.api.user.IBot;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/** /**
* Java插件基类 * Java插件基类
* @author wzp * @author wzp
@ -13,7 +20,12 @@ import org.apache.logging.log4j.Logger;
*/ */
@Setter @Setter
@Getter @Getter
@Log4j2
public abstract class JavaPlugin implements BasePlugin { public abstract class JavaPlugin implements BasePlugin {
/**
* 日志处理器
* @since 2024/8/23 21:42 v0.0.5-dev
*/
private Logger logger; private Logger logger;
@Override @Override
public IPluginClassLoader getClassLoader() { public IPluginClassLoader getClassLoader() {
@ -35,4 +47,51 @@ public abstract class JavaPlugin implements BasePlugin {
} }
return this.logger; return this.logger;
} }
public InputStream getResourceAsStream(String name) {
return this.getClassLoader().getResourceAsStream(name);
}
@Override
public File getDataFolder() {
IBot bot = this.getClassLoader().getBot();
File pluginsFolder = bot.getPluginsFolder();
File file = new File(pluginsFolder, this.getClassLoader().getName());
if (!file.isDirectory()){
if (!file.mkdir()) {
log.error("Failed to create plugin data folder");
return null;
}
}
return file;
}
@Override
public File getDefaultConfigFile() {
File file = new File(this.getDataFolder(), "config.yml");
if (!file.isFile()){
try {
if (!file.createNewFile()){
log.error("cannot create default config file");
return null;
}
} catch (IOException e) {
log.error(e);
return null;
}
}
return file;
}
@Override
public void saveDefaultConfig() {
try(InputStream resourceAsStream = this.getResourceAsStream("config.yml")){
File defaultConfigFile = this.getDefaultConfigFile();
try(FileOutputStream fileOutputStream = new FileOutputStream(defaultConfigFile)){
resourceAsStream.transferTo(fileOutputStream);
}
} catch (IOException e) {
log.error(e);
}
}
} }

View File

@ -2,50 +2,76 @@ package cn.wzpmc.api.user;
import cn.wzpmc.api.message.MessageComponent; import cn.wzpmc.api.message.MessageComponent;
import cn.wzpmc.api.user.permission.Permissions; import cn.wzpmc.api.user.permission.Permissions;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/** /**
* 消息发送者 * 命令发送者
* @author wzp * @author wzp
* @version 0.0.1-dev * @version 0.0.1-dev
* @since 2024/7/31 上午2:32 * @since 2024/7/31 上午2:32
*/ */
@AllArgsConstructor public interface CommandSender {
@NoArgsConstructor
@Data
public abstract class CommandSender {
/**
* 用户ID
* @since 2024/7/30 下午11:48 v0.0.1-dev
*/
protected Long id;
/**
* 用户名
* @since 2024/7/30 下午11:48 v0.0.1-dev
*/
protected String name;
/**
* 权限
* @since 2024/8/1 下午8:24 v0.0.2-dev
*/
protected Permissions permissions;
/** /**
* 发送消息 * 发送消息
* @author wzp * @author wzp
* @since 2024/7/31 上午2:42 v0.0.1-dev * @since 2024/7/31 上午2:42 v0.0.1-dev
* @param messageComponent 消息组件 * @param messageComponent 消息组件
*/ */
public abstract void sendMessage(MessageComponent messageComponent); void sendMessage(MessageComponent messageComponent);
/**
* 获取用户ID
* @author wzp
* @since 2024/8/23 21:43 v0.0.5-dev
* @return 用户ID
*/
Long getId();
/**
* 获取用户名
* @author wzp
* @since 2024/8/23 21:43 v0.0.5-dev
* @return 用户名
*/
String getName();
/**
* 获取用户权限
* @author wzp
* @since 2024/8/23 21:43 v0.0.5-dev
* @return 权限
*/
Permissions getPermissions();
/**
* 设置用户ID
* @author wzp
* @since 2024/8/23 21:43 v0.0.5-dev
* @param id 用户ID
*/
void setId(Long id);
/**
* 设置用户名
* @author wzp
* @since 2024/8/23 21:43 v0.0.5-dev
* @param name 用户名
*/
void setName(String name);
/**
* 设置用户权限
* @author wzp
* @since 2024/8/23 21:44 v0.0.5-dev
* @param permissions 用户权限
*/
void setPermissions(Permissions permissions);
/** /**
* 指令发送者是否为管理员 * 指令发送者是否为管理员
* @author wzp * @author wzp
* @since 2024/8/1 下午4:50 v0.0.2-dev * @since 2024/8/1 下午4:50 v0.0.2-dev
* @return 是否为管理员 * @return 是否为管理员
*/ */
public boolean isAdmin(){ default boolean isAdmin(){
return Permissions.ADMIN.equals(this.permissions); return Permissions.ADMIN.equals(this.getPermissions());
} }
} }

View File

@ -1,10 +1,13 @@
package cn.wzpmc.api.user; package cn.wzpmc.api.user;
import cn.wzpmc.api.api.IMainApi;
import cn.wzpmc.api.api.actions.message.send.SendPrivateMessageAction;
import cn.wzpmc.api.message.MessageComponent; import cn.wzpmc.api.message.MessageComponent;
import cn.wzpmc.api.user.permission.Permissions; import cn.wzpmc.api.user.permission.Permissions;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;
/** /**
* 好友 * 好友
@ -15,12 +18,22 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Data @Data
@AllArgsConstructor @AllArgsConstructor
public class Friend extends IUser{ public class Friend extends IUser implements CommandSender{
public Friend(Long id, String name, Permissions permissions, String nickname, Sex sex, Integer age) { public Friend(Long id, String name, Permissions permissions, String nickname, Sex sex, Integer age) {
super(id, name, permissions, nickname, sex, age); super(id, name, permissions, nickname, sex, age);
} }
/**
* 发送消息
* @author wzp
* @since 2024/8/23 21:44 v0.0.5-dev
* @param messageComponent 消息组件
*/
@SneakyThrows
@Override @Override
public void sendMessage(MessageComponent messageComponent) { public void sendMessage(MessageComponent messageComponent) {
IBot instance = IBot.getInstance();
IMainApi mainApi = instance.getMainApi();
mainApi.doApiCall(new SendPrivateMessageAction(this.id, messageComponent));
} }
} }

View File

@ -1,9 +1,11 @@
package cn.wzpmc.api.user; package cn.wzpmc.api.user;
import cn.wzpmc.api.api.IMainApi;
import cn.wzpmc.api.events.Event; 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.io.File;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
/** /**
@ -12,7 +14,13 @@ import java.lang.reflect.InvocationTargetException;
* @version 0.0.1-dev * @version 0.0.1-dev
* @since 2024/7/31 上午2:31 * @since 2024/7/31 上午2:31
*/ */
public abstract class IBot extends CommandSender { public abstract class IBot extends MessageSender implements CommandSender {
private static IBot instance = null;
protected IBot(){
if (IBot.instance == null){
IBot.instance = this;
}
}
/** /**
* 获取配置文件 * 获取配置文件
* @author wzp * @author wzp
@ -49,6 +57,34 @@ public abstract class IBot extends CommandSender {
* @author wzp * @author wzp
* @since 2024/8/16 00:49 v0.0.4-dev * @since 2024/8/16 00:49 v0.0.4-dev
* @param event 事件 * @param event 事件
* @throws InvocationTargetException 处理时出现错误
* @throws IllegalAccessException 处理时出现错误
*/ */
public abstract void triggerEvent(Event event) throws InvocationTargetException, IllegalAccessException; public abstract void triggerEvent(Event event) throws InvocationTargetException, IllegalAccessException;
/**
* 获取插件文件夹
* @author wzp
* @since 2024/8/16 12:49 v0.0.5-dev
* @return 插件文件夹
*/
public abstract File getPluginsFolder();
/**
* 获取api接口
* @author wzp
* @since 2024/8/16 17:34 v0.0.5-dev
* @return api接口
*/
public abstract IMainApi getMainApi();
/**
* 获取bot实例
* @author wzp
* @since 2024/8/17 23:19 v0.0.5-dev
* @return 一个bot实例对象
*/
public static IBot getInstance(){
return IBot.instance;
}
} }

View File

@ -16,7 +16,7 @@ import lombok.NoArgsConstructor;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public abstract class IUser extends CommandSender { public abstract class IUser extends MessageSender {
/** /**
* 玩家昵称 * 玩家昵称
* @since 2024/8/1 下午8:34 v0.0.2-dev * @since 2024/8/1 下午8:34 v0.0.2-dev

View File

@ -0,0 +1,36 @@
package cn.wzpmc.api.user;
import cn.wzpmc.api.user.permission.Permissions;
import com.alibaba.fastjson2.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 消息发送者
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/18 00:01
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MessageSender {
/**
* 用户ID
* @since 2024/7/30 下午11:48 v0.0.1-dev
*/
@JSONField(name = "user_id")
protected Long id;
/**
* 用户名
* @since 2024/7/30 下午11:48 v0.0.1-dev
*/
@JSONField(name = "nickname")
protected String name;
/**
* 权限
* @since 2024/8/1 下午8:24 v0.0.2-dev
*/
protected Permissions permissions;
}

View File

@ -0,0 +1,73 @@
package cn.wzpmc.api.user.group;
import cn.wzpmc.api.api.IMainApi;
import cn.wzpmc.api.api.actions.message.send.SendGroupMessageAction;
import cn.wzpmc.api.events.message.group.GroupMessageEvent;
import cn.wzpmc.api.message.MessageComponent;
import cn.wzpmc.api.message.StringMessage;
import cn.wzpmc.api.message.json.JsonMessage;
import cn.wzpmc.api.message.json.JsonMessagePart;
import cn.wzpmc.api.message.json.parts.At;
import cn.wzpmc.api.user.CommandSender;
import cn.wzpmc.api.user.IBot;
import cn.wzpmc.api.user.Sex;
import cn.wzpmc.api.user.permission.Permissions;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.SneakyThrows;
import java.util.List;
/**
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/18 00:11
*/
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
public class GroupCommandSender extends GroupUser implements CommandSender {
public GroupCommandSender(Long id, String name, Permissions permissions, String nickname, Sex sex, Integer age, String card, String area, String level, GroupUserRole role, String title, Long groupId){
super(id, name, permissions, nickname, sex, age, card, area, level, role, title);
this.groupId = groupId;
}
private Long groupId;
@SneakyThrows
@Override
public void sendMessage(MessageComponent messageComponent) {
IBot instance = IBot.getInstance();
IMainApi mainApi = instance.getMainApi();
JsonMessage jsonMessage = new JsonMessage();
List<JsonMessagePart> messageParts = jsonMessage.getMessageParts();
messageParts.add(new At(this.getId()));
messageParts.add(StringMessage.text(messageComponent.toMessageString()));
SendGroupMessageAction sendGroupMessageAction = new SendGroupMessageAction(this.groupId, jsonMessage);
mainApi.doApiCall(sendGroupMessageAction);
}
/**
* 将一个群消息事件转为一个群指令执行者
* @author wzp
* @since 2024/8/23 21:42 v0.0.5-dev
* @param event 群消息事件
* @return 指令执行者对象
*/
public static GroupCommandSender of(GroupMessageEvent event){
GroupUser sender = event.getSender();
Long eventGroupId = event.getGroupId();
Long id = sender.getId();
String name = sender.getName();
Permissions permissions = sender.getPermissions();
String nickname = sender.getNickname();
Sex sex = sender.getSex();
Integer age = sender.getAge();
String card = sender.getCard();
String area = sender.getArea();
String level = sender.getLevel();
GroupUserRole role = sender.getRole();
String title = sender.getTitle();
return new GroupCommandSender(id, name, permissions, nickname, sex, age, card, area, level, role, title, eventGroupId);
}
}

View File

@ -1,7 +1,8 @@
package cn.wzpmc.api.user.group; package cn.wzpmc.api.user.group;
import cn.wzpmc.api.message.MessageComponent;
import cn.wzpmc.api.user.IUser; import cn.wzpmc.api.user.IUser;
import cn.wzpmc.api.user.Sex;
import cn.wzpmc.api.user.permission.Permissions;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@ -43,8 +44,12 @@ public class GroupUser extends IUser {
* @since 2024/8/1 下午8:53 v0.0.2-dev * @since 2024/8/1 下午8:53 v0.0.2-dev
*/ */
private String title; private String title;
@Override public GroupUser(Long id, String name, Permissions permissions, String nickname, Sex sex, Integer age, String card, String area, String level, GroupUserRole role, String title) {
public void sendMessage(MessageComponent messageComponent) { super(id, name, permissions, nickname, sex, age);
this.card = card;
this.area = area;
this.level = level;
this.role = role;
this.title = title;
} }
} }

View File

@ -1,8 +1,10 @@
package cn.wzpmc.console; package cn.wzpmc.console;
import cn.wzpmc.api.plugins.BasePlugin;
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.PluginManager;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
@ -44,8 +46,10 @@ public class MyBotConsole extends SimpleTerminalConsole {
@Override @Override
public void shutdown() { public void shutdown() {
running = false; PluginManager pluginManager = this.bot.getPluginManager();
pluginManager.getPlugins().forEach(BasePlugin::onUnload);
this.webSocketConnectionHandler.kill(); this.webSocketConnectionHandler.kill();
running = false;
} }
@Override @Override

View File

@ -2,13 +2,15 @@ package cn.wzpmc.console.logger;
import cn.wzpmc.api.plugins.BasePlugin; import cn.wzpmc.api.plugins.BasePlugin;
import cn.wzpmc.api.plugins.IPluginClassLoader; import cn.wzpmc.api.plugins.IPluginClassLoader;
import org.apache.logging.log4j.message.*; import org.apache.logging.log4j.message.Message;
import org.apache.logging.log4j.message.MessageFactory;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import static org.apache.logging.log4j.spi.AbstractLogger.DEFAULT_FLOW_MESSAGE_FACTORY_CLASS; import static org.apache.logging.log4j.spi.AbstractLogger.DEFAULT_FLOW_MESSAGE_FACTORY_CLASS;
/** /**
* 插件消息工厂
* @author wzp * @author wzp
* @version 0.0.4-dev * @version 0.0.4-dev
* @since 2024/8/9 00:35 * @since 2024/8/9 00:35

View File

@ -0,0 +1,27 @@
package cn.wzpmc.entities.api;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.ActionResponse;
import lombok.Data;
import java.util.concurrent.CompletableFuture;
/**
* api返回需求
* @author wzp
* @since 2024/8/16 22:08
* @version 0.0.5-dev
*/
@Data
public class ApiResponseRequired<REQUEST, RESPONSE> {
/**
* 请求返回Promise
* @since 2024/8/23 21:46 v0.0.5-dev
*/
private final CompletableFuture<ActionResponse<RESPONSE>> future;
/**
* 请求体
* @since 2024/8/23 21:47 v0.0.5-dev
*/
private final Action<REQUEST, RESPONSE> request;
}

View File

@ -5,12 +5,21 @@ import lombok.Data;
import java.lang.reflect.Method; import java.lang.reflect.Method;
/** /**
* 事件处理器
* @author wzp * @author wzp
* @version 0.0.4-dev * @version 0.0.4-dev
* @since 2024/8/15 23:53 * @since 2024/8/15 23:53
*/ */
@Data @Data
public class EventHandlerMethod { public class EventHandlerMethod {
/**
* 处理器类
* @since 2024/8/23 21:47 v0.0.5-dev
*/
private final Object object; private final Object object;
/**
* 处理的方法
* @since 2024/8/23 21:47 v0.0.5-dev
*/
private final Method method; private final Method method;
} }

View File

@ -1,5 +1,6 @@
package cn.wzpmc.entities.user.bot; package cn.wzpmc.entities.user.bot;
import cn.wzpmc.api.api.IMainApi;
import cn.wzpmc.api.events.Event; 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;
@ -11,13 +12,16 @@ 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.entities.event.EventHandlerMethod;
import cn.wzpmc.network.WebSocketConnectionHandler;
import cn.wzpmc.plugins.CommandManager; import cn.wzpmc.plugins.CommandManager;
import cn.wzpmc.plugins.PluginManager; import cn.wzpmc.plugins.PluginManager;
import cn.wzpmc.plugins.api.MainApi;
import cn.wzpmc.utils.ReflectionUtils; 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.io.File;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.List; import java.util.List;
@ -38,8 +42,12 @@ public class MyBot extends IBot {
private final CommandManager commandManager = new CommandManager(this); private final CommandManager commandManager = new CommandManager(this);
private final PluginManager pluginManager = new PluginManager(); private final PluginManager pluginManager = new PluginManager();
private final IncreasbleHashMap<Class<? extends Event>, EventHandlerMethod> events = new IncreasbleHashMap<>(); private final IncreasbleHashMap<Class<? extends Event>, EventHandlerMethod> events = new IncreasbleHashMap<>();
private File pluginsFolder;
@Setter @Setter
private MyBotConsole console = null; private MyBotConsole console = null;
@Getter
private IMainApi mainApi;
private WebSocketConnectionHandler connectionHandler;
public MyBot(Configuration configuration){ public MyBot(Configuration configuration){
this.configuration = configuration; this.configuration = configuration;
this.permissions = Permissions.ADMIN; this.permissions = Permissions.ADMIN;
@ -73,8 +81,22 @@ public class MyBot extends IBot {
@Override @Override
public void triggerEvent(Event event) throws InvocationTargetException, IllegalAccessException { public void triggerEvent(Event event) throws InvocationTargetException, IllegalAccessException {
List<EventHandlerMethod> eventHandlerMethods = this.events.get(event.getClass()); List<EventHandlerMethod> eventHandlerMethods = this.events.get(event.getClass());
if (eventHandlerMethods == null){
return;
}
for (EventHandlerMethod eventHandlerMethod : eventHandlerMethods) { for (EventHandlerMethod eventHandlerMethod : eventHandlerMethods) {
eventHandlerMethod.getMethod().invoke(eventHandlerMethod.getObject(), event); eventHandlerMethod.getMethod().invoke(eventHandlerMethod.getObject(), event);
} }
} }
public void setPluginsFolder(File pluginsFolder) {
if (this.pluginsFolder != null){
throw new IllegalStateException("This bot already initialized!");
}
this.pluginsFolder = pluginsFolder;
}
public void setConnectionHandler(WebSocketConnectionHandler connectionHandler) {
this.connectionHandler = connectionHandler;
this.mainApi = new MainApi(this, this.connectionHandler);
}
} }

View File

@ -4,9 +4,12 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker; import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import java.util.concurrent.CompletableFuture;
/** /**
* 握手包处理器 * 握手包处理器
* @author wzp * @author wzp
@ -17,6 +20,8 @@ import lombok.extern.log4j.Log4j2;
@RequiredArgsConstructor @RequiredArgsConstructor
public class HandshakePacketHandler extends SimpleChannelInboundHandler<FullHttpResponse> { public class HandshakePacketHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
private final WebSocketClientHandshaker handshaker; private final WebSocketClientHandshaker handshaker;
@Getter
private final CompletableFuture<Boolean> handshakeFuture = new CompletableFuture<>();
@Override @Override
public void channelActive(ChannelHandlerContext ctx) { public void channelActive(ChannelHandlerContext ctx) {
@ -28,6 +33,7 @@ public class HandshakePacketHandler extends SimpleChannelInboundHandler<FullHttp
protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpResponse fullHttpResponse) { protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpResponse fullHttpResponse) {
if (!handshaker.isHandshakeComplete()) { if (!handshaker.isHandshakeComplete()) {
handshaker.finishHandshake(channelHandlerContext.channel(), fullHttpResponse); handshaker.finishHandshake(channelHandlerContext.channel(), fullHttpResponse);
this.handshakeFuture.complete(true);
log.debug("握手成功"); log.debug("握手成功");
log.info("连接服务器成功!"); log.info("连接服务器成功!");
} }

View File

@ -1,7 +1,11 @@
package cn.wzpmc.network; package cn.wzpmc.network;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.ActionResponse;
import cn.wzpmc.api.events.Event; import cn.wzpmc.api.events.Event;
import cn.wzpmc.api.user.IBot; import cn.wzpmc.api.user.IBot;
import cn.wzpmc.entities.api.ApiResponseRequired;
import cn.wzpmc.utils.json.action.ActionReader;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.JSONObject;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
@ -11,6 +15,10 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/** /**
* websocket包处理器 * websocket包处理器
@ -22,30 +30,73 @@ import java.lang.reflect.InvocationTargetException;
@RequiredArgsConstructor @RequiredArgsConstructor
public class PacketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { public class PacketHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
private final IBot bot; private final IBot bot;
@Override @Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame webSocketFrame) { protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame webSocketFrame) {
String text = webSocketFrame.text(); String text = webSocketFrame.text();
System.out.println(text);
if (!JSON.isValidObject(text)){ if (!JSON.isValidObject(text)){
log.warn("收到了无法处理的WebSocket数据包{}", text); log.warn("收到了无法处理的WebSocket数据包{}", text);
return; return;
} }
JSONObject jsonObject = JSON.parseObject(text); JSONObject jsonObject = JSON.parseObject(text);
if (jsonObject.containsKey("echo")) { if (jsonObject.containsKey("echo")) {
handleApiEcho(jsonObject); handleApiEcho(text);
return; return;
} }
handleEvent(text); handleEvent(text);
} }
private final ExecutorService threadPool = Executors.newFixedThreadPool(4);
/**
* 处理事件
* @author wzp
* @since 2024/8/23 21:47 v0.0.5-dev
* @param text 事件json文本
*/
private void handleEvent(String text){ private void handleEvent(String text){
Event event = JSON.parseObject(text, Event.class); Event event = JSON.parseObject(text, Event.class);
try { threadPool.submit(() -> {
this.bot.triggerEvent(event); try {
} catch (InvocationTargetException | IllegalAccessException e) { this.bot.triggerEvent(event);
log.error(new RuntimeException(e)); } catch (InvocationTargetException | IllegalAccessException e) {
} log.error(new RuntimeException(e));
}
});
} }
private void handleApiEcho(JSONObject data){
/**
* 处理api回调
* @author wzp
* @since 2024/8/23 21:48 v0.0.5-dev
* @param dataString 返回json文本
* @param <REQUEST> 请求类型
* @param <RESPONSE> 返回类型
*/
private <REQUEST, RESPONSE> void handleApiEcho(String dataString){
//noinspection unchecked
ActionResponse<RESPONSE> actionResponse = JSON.parseObject(dataString, ActionResponse.class);
UUID echo = actionResponse.getEcho();
//noinspection unchecked
ApiResponseRequired<REQUEST, RESPONSE> apiResponseRequired = (ApiResponseRequired<REQUEST, RESPONSE>) ActionReader.tasks.get(echo);
if (apiResponseRequired == null) {
log.warn("收到了错误的请求返回:{}", echo);
return;
}
ActionReader.tasks.remove(echo);
apiResponseRequired.getFuture().complete(actionResponse);
}
/**
* 注册返回回调
* @author wzp
* @since 2024/8/23 21:48 v0.0.5-dev
* @param echo 回调ID
* @param responsePromise 返回Promise
* @param request 请求体
* @param <REQUEST> 请求体类型
* @param <RESPONSE> 返回类型
*/
public <REQUEST, RESPONSE> void registerResponse(UUID echo, CompletableFuture<ActionResponse<RESPONSE>> responsePromise, Action<REQUEST, RESPONSE> request) {
ActionReader.tasks.put(echo, new ApiResponseRequired<>(responsePromise, request));
} }
} }

View File

@ -1,12 +1,16 @@
package cn.wzpmc.network; package cn.wzpmc.network;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.ActionResponse;
import cn.wzpmc.api.user.IBot; import cn.wzpmc.api.user.IBot;
import com.alibaba.fastjson2.JSON;
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;
import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
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;
@ -14,6 +18,8 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import java.net.URI; import java.net.URI;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
/** /**
* 此类用于建立WebSocket连接 * 此类用于建立WebSocket连接
@ -26,21 +32,23 @@ import java.net.URI;
public class WebSocketConnectionHandler { public class WebSocketConnectionHandler {
private final EventLoopGroup eventLoopGroup = new NioEventLoopGroup(); private final EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
private final IBot bot; private final IBot bot;
private ChannelFuture channelFuture;
private PacketHandler packetHandler;
private HandshakePacketHandler handshakePacketHandler;
/** /**
* 建立连接 * 建立连接
* @author wzp * @author wzp
* @since 2024/7/30 下午11:55 v0.0.1-dev * @since 2024/7/30 下午11:55 v0.0.1-dev
* @param websocket websocket连接地址 * @param websocket websocket连接地址
* @return 一个ChannelFuture对象
*/ */
public ChannelFuture connect(URI websocket){ public void connect(URI websocket){
log.info("正在连接websocket"); log.info("正在连接websocket");
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); this.handshakePacketHandler = new HandshakePacketHandler(clientHandshaker);
PacketHandler handler = new PacketHandler(this.bot); this.packetHandler = new PacketHandler(this.bot);
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new WebSocketChannelInitializer(handler, handshakePacketHandler)); bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new WebSocketChannelInitializer(this.packetHandler, this.handshakePacketHandler));
return bootstrap.connect(websocket.getHost(), websocket.getPort()); this.channelFuture = bootstrap.connect(websocket.getHost(), websocket.getPort());
} }
/** /**
@ -52,4 +60,31 @@ public class WebSocketConnectionHandler {
log.info("结束连接..."); log.info("结束连接...");
this.eventLoopGroup.shutdownGracefully(); this.eventLoopGroup.shutdownGracefully();
} }
/**
* 发送请求
* @author wzp
* @since 2024/8/23 21:49 v0.0.5-dev
* @param request 请求
* @return 返回
* @param <REQUEST> 请求体类型
* @param <RESPONSE> 返回类型
* @throws InterruptedException 当请求进行时按下Ctrl+C时抛出
*/
public <REQUEST, RESPONSE> ActionResponse<RESPONSE> sendRequest(Action<REQUEST, RESPONSE> request) throws InterruptedException {
try {
this.handshakePacketHandler.getHandshakeFuture().get();
} catch (ExecutionException e) {
log.error(e);
}
CompletableFuture<ActionResponse<RESPONSE>> responsePromise = new CompletableFuture<>();
packetHandler.registerResponse(request.getEcho(), responsePromise, request);
channelFuture.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(request)));
try {
return responsePromise.get();
} catch (ExecutionException e) {
log.error(e);
}
return null;
}
} }

View File

@ -5,7 +5,6 @@ import cn.wzpmc.api.plugins.IPluginClassLoader;
import cn.wzpmc.api.user.IBot; import cn.wzpmc.api.user.IBot;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.Setter;
import lombok.ToString; import lombok.ToString;
import java.net.URL; import java.net.URL;

View File

@ -0,0 +1,24 @@
package cn.wzpmc.plugins.api;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.ActionResponse;
import cn.wzpmc.api.api.IMainApi;
import cn.wzpmc.api.user.IBot;
import cn.wzpmc.network.WebSocketConnectionHandler;
import lombok.RequiredArgsConstructor;
/**
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/16 17:32
*/
@RequiredArgsConstructor
public class MainApi implements IMainApi {
private final IBot bot;
private final WebSocketConnectionHandler handler;
@Override
public <REQUEST, RESPONSE> ActionResponse<RESPONSE> doApiCall(Action<REQUEST, RESPONSE> packet) throws InterruptedException {
return handler.sendRequest(packet);
}
}

View File

@ -1,5 +1,7 @@
package cn.wzpmc.utils; package cn.wzpmc.utils;
import cn.wzpmc.api.api.ActionResponse;
import cn.wzpmc.api.api.Actions;
import cn.wzpmc.api.events.Event; import cn.wzpmc.api.events.Event;
import cn.wzpmc.api.events.message.MessageEvent; import cn.wzpmc.api.events.message.MessageEvent;
import cn.wzpmc.api.events.meta.MetaEvent; import cn.wzpmc.api.events.meta.MetaEvent;
@ -8,10 +10,14 @@ import cn.wzpmc.api.events.notice.notify.NotifyEvent;
import cn.wzpmc.api.events.request.RequestEvent; import cn.wzpmc.api.events.request.RequestEvent;
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.user.IUser;
import cn.wzpmc.utils.json.action.ActionReader;
import cn.wzpmc.utils.json.action.ActionWriter;
import cn.wzpmc.utils.json.event.*; import cn.wzpmc.utils.json.event.*;
import cn.wzpmc.utils.json.message.JsonMessageReader; import cn.wzpmc.utils.json.message.JsonMessageReader;
import cn.wzpmc.utils.json.message.JsonMessageWriter; import cn.wzpmc.utils.json.message.JsonMessageWriter;
import cn.wzpmc.utils.json.message.StringMessageReader; import cn.wzpmc.utils.json.message.StringMessageReader;
import cn.wzpmc.utils.json.user.IUserReader;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
/** /**
@ -21,9 +27,21 @@ import com.alibaba.fastjson2.JSON;
* @since 2024/8/2 下午2:04 * @since 2024/8/2 下午2:04
*/ */
public class JsonUtils { public class JsonUtils {
/**
* 初始化JSON反序列化相关
* @author wzp
* @since 2024/8/23 21:50 v0.0.5-dev
*/
public static void initWriter() { public static void initWriter() {
JSON.register(JsonMessage.class, new JsonMessageWriter()); JSON.register(JsonMessage.class, new JsonMessageWriter());
JSON.register(Actions.class, new ActionWriter());
} }
/**
* 初始化JSON序列化相关
* @author wzp
* @since 2024/8/23 21:50 v0.0.5-dev
*/
public static void initReader() { public static void initReader() {
JSON.register(MessageEvent.class, new MessageEventReader()); JSON.register(MessageEvent.class, new MessageEventReader());
JSON.register(MetaEvent.class, new MetaEventReader()); JSON.register(MetaEvent.class, new MetaEventReader());
@ -33,6 +51,8 @@ public class JsonUtils {
JSON.register(Event.class, new EventReader()); JSON.register(Event.class, new EventReader());
JSON.register(JsonMessage.class, new JsonMessageReader()); JSON.register(JsonMessage.class, new JsonMessageReader());
JSON.register(StringMessage.class, new StringMessageReader()); JSON.register(StringMessage.class, new StringMessageReader());
JSON.register(ActionResponse.class, new ActionReader());
JSON.register(IUser.class, new IUserReader());
} }
} }

View File

@ -0,0 +1,39 @@
package cn.wzpmc.utils.json.action;
import cn.wzpmc.api.api.Action;
import cn.wzpmc.api.api.ActionResponse;
import cn.wzpmc.api.api.Actions;
import cn.wzpmc.entities.api.ApiResponseRequired;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.reader.ObjectReader;
import java.lang.reflect.Type;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/16 21:50
*/
public class ActionReader implements ObjectReader<ActionResponse<?>> {
public static final ConcurrentHashMap<UUID, ApiResponseRequired<?, ?>> tasks = new ConcurrentHashMap<>();
@Override
public ActionResponse<?> readObject(JSONReader jsonReader, Type type, Object o, long l) {
JSONObject jsonObject = jsonReader.readJSONObject();
UUID echo = jsonObject.getObject("echo", UUID.class);
ApiResponseRequired<?, ?> apiResponseRequired = tasks.get(echo);
Action<?, ?> request = apiResponseRequired.getRequest();
Actions action = request.getAction();
String status = jsonObject.getString("status");
short retcode = jsonObject.getShort("retcode");
JSONObject data = jsonObject.getJSONObject("data");
Object dataObj = null;
if (data != null){
dataObj = data.to(action.responseClass);
}
return new ActionResponse<>(status, retcode, dataObj, echo);
}
}

View File

@ -0,0 +1,20 @@
package cn.wzpmc.utils.json.action;
import cn.wzpmc.api.api.Actions;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.writer.ObjectWriter;
import java.lang.reflect.Type;
/**
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/17 22:05
*/
public class ActionWriter implements ObjectWriter<Actions> {
@Override
public void write(JSONWriter jsonWriter, Object o, Object fieldName, Type type, long l) {
Actions actions = (Actions) o;
jsonWriter.writeString(actions.name().toLowerCase());
}
}

View File

@ -0,0 +1,26 @@
package cn.wzpmc.utils.json.user;
import cn.wzpmc.api.user.Friend;
import cn.wzpmc.api.user.IUser;
import cn.wzpmc.api.user.group.GroupUser;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.reader.ObjectReader;
import java.lang.reflect.Type;
/**
* @author wzp
* @version 0.0.5-dev
* @since 2024/8/17 23:12
*/
public class IUserReader implements ObjectReader<IUser> {
@Override
public IUser readObject(JSONReader jsonReader, Type type, Object o, long l) {
JSONObject jsonObject = jsonReader.readJSONObject();
if (jsonObject.containsKey("role")) {
return jsonObject.to(GroupUser.class);
}
return jsonObject.to(Friend.class);
}
}

View File

@ -1,7 +1,3 @@
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 cn.wzpmc.utils.ReflectionUtils;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;