mirror of
https://github.com/jie65535/MiniOneBot.git
synced 2025-06-01 17:29:14 +08:00
Implement Onebot Group message
This commit is contained in:
parent
e4037549b4
commit
cefd69c6f8
@ -8,25 +8,6 @@ import java.util.Scanner;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
// System.out.println("Hello world!");
|
||||
//
|
||||
// // {"group_id":685816675,"raw_message":"Go","sender":{"area":"","role":"member","level":"108","user_id":840465812,"sex":"unknown","nickname":"筱傑","title":"加油啊5号马","age":22,"card":""},"sub_type":"normal","user_id":840465812,"self_id":1379892815,"message_id":-518394285,"message_type":"group","post_type":"message","time":1677306537,"message":"Go","font":0}
|
||||
// var gson = new Gson();
|
||||
// var json = "{\"type\":\"message\",\"data\":{\"type\":\"text\",\"data\":\"Hello world!\"}}";
|
||||
// var obj = gson.fromJson(json, JsonObject.class);
|
||||
// System.out.println(obj.get("type").getAsString());
|
||||
// var data = obj.get("data").getAsJsonObject();
|
||||
// System.out.println(data.get("type").getAsString());
|
||||
// System.out.println(data.get("data").getAsString());
|
||||
//
|
||||
// var map = gson.fromJson(json, Map.class);
|
||||
// System.out.println(map);
|
||||
// System.out.println(Objects.equals(map.get("type"), "message"));
|
||||
// var dataMap = (Map<?,?>) map.get("data");
|
||||
// System.out.println(Objects.equals(dataMap.get("type"), "text"));
|
||||
// System.out.println((String)dataMap.get("data"));
|
||||
|
||||
|
||||
Javalin app = Javalin.create().start(7070);
|
||||
var bot = new MiniOneBot(app, "HelloOneBot");
|
||||
bot.startWsServer("/openchat");
|
||||
@ -35,17 +16,21 @@ public class Main {
|
||||
} catch (URISyntaxException ignored) {
|
||||
System.out.println("Uri Syntax error!");
|
||||
}
|
||||
bot.subscribeGroupMessageEvent(event -> System.out.println(event.message));
|
||||
bot.subscribeGuildChannelMessageEvent(event -> System.out.println(event.message));
|
||||
bot.subscribeGroupMessageEvent(event -> System.out.printf("[QQ]<%s> %s%n", event.senderCardOrNickname(), event.message()));
|
||||
bot.subscribeGuildChannelMessageEvent(event -> System.out.printf("[Cl]<%s> %s%n", event.senderName(), event.message()));
|
||||
|
||||
var scanner = new Scanner(System.in);
|
||||
while (true) {
|
||||
var input = scanner.nextLine();
|
||||
if (input.isEmpty() || input.equals("exit") || input.equals("quit")) {
|
||||
if (input.isEmpty() || input.equals("stop") || input.equals("exit") || input.equals("quit")) {
|
||||
break;
|
||||
}
|
||||
|
||||
bot.sendMessage("Console", input);
|
||||
}
|
||||
bot.sendGroupMessage(0, "[MOB] Console: " + input);
|
||||
}
|
||||
System.out.println("Ending...");
|
||||
bot.stop();
|
||||
app.stop();
|
||||
System.out.println("Ended...");
|
||||
}
|
||||
}
|
@ -1,12 +1,19 @@
|
||||
package top.jie65535.minionebot;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import io.javalin.Javalin;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import top.jie65535.minionebot.events.GroupMessage;
|
||||
import top.jie65535.minionebot.events.GroupMessageHandler;
|
||||
import top.jie65535.minionebot.events.GuildChannelMessage;
|
||||
import top.jie65535.minionebot.events.GuildChannelMessageHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class MiniOneBot implements WsStream.WsMessageHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger("Console");
|
||||
@ -14,11 +21,11 @@ public class MiniOneBot implements WsStream.WsMessageHandler {
|
||||
private final String token;
|
||||
private MiniOneBotWsServer server;
|
||||
private MiniOneBotWsClient client;
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
public MiniOneBot(Javalin javalin, String token) {
|
||||
this.javalin = javalin;
|
||||
this.token = token;
|
||||
logger.info("Test");
|
||||
}
|
||||
|
||||
// region WebSocket
|
||||
@ -39,30 +46,178 @@ public class MiniOneBot implements WsStream.WsMessageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (client != null) {
|
||||
client.close();
|
||||
}
|
||||
if (server != null) {
|
||||
try {
|
||||
server.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("Stop MiniOneBot WebSocket Server Failed!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMessageToAll(String message) {
|
||||
logger.info("Sending... message=\"{}\"", message);
|
||||
server.send(message);
|
||||
client.send(message);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region OneBot message
|
||||
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
// TODO
|
||||
var map = gson.fromJson(message, JsonObject.class);
|
||||
if (!map.has("post_type")) return;
|
||||
var postType = map.get("post_type").getAsString();
|
||||
// 消息事件上报
|
||||
if (Objects.equals(postType, "message")) {
|
||||
var messageType = map.get("message_type").getAsString();
|
||||
var subType = map.get("sub_type").getAsString();
|
||||
|
||||
// 发送者信息 https://docs.go-cqhttp.org/reference/data_struct.html#post-message-messagesender
|
||||
var sender = map.get("sender").getAsJsonObject();
|
||||
var senderId = sender.get("user_id").getAsLong();
|
||||
var senderNickname = sender.get("nickname").getAsString();
|
||||
|
||||
// 群消息上报 https://docs.go-cqhttp.org/event/#%E7%BE%A4%E6%B6%88%E6%81%AF
|
||||
if (Objects.equals(messageType, "group")
|
||||
&& Objects.equals(subType, "normal")) {
|
||||
var groupId = map.get("group_id").getAsLong();
|
||||
// var message = (List<Map<?, ?>>)map.get("message");
|
||||
var rawMessage = map.get("raw_message").getAsString();
|
||||
|
||||
var senderCard = sender.get("card").getAsString();
|
||||
var senderLevel = sender.get("level").getAsString();
|
||||
var senderRole = sender.get("role").getAsString();
|
||||
var senderCardOrNickname = senderCard == null || senderCard.isEmpty() ? senderNickname : senderCard;
|
||||
var senderTitle = sender.get("title").getAsString();
|
||||
onGroupMessage(groupId, handleRawMessage(rawMessage), senderId, senderCardOrNickname, senderLevel, senderRole, senderTitle);
|
||||
}
|
||||
// 频道消息上报 https://docs.go-cqhttp.org/event/guild.html#%E6%94%B6%E5%88%B0%E9%A2%91%E9%81%93%E6%B6%88%E6%81%AF
|
||||
else if (Objects.equals(messageType, "guild")
|
||||
&& Objects.equals(subType, "channel")) {
|
||||
var guildId = map.get("guild_id").getAsString();
|
||||
var channelId = map.get("channel_id").getAsString();
|
||||
var rawMessage = map.get("message").getAsString(); // 需要 Message 消息链类型处理
|
||||
var tinyId = map.get("user_id").getAsString();
|
||||
onGuildMessage(guildId, channelId, handleRawMessage(rawMessage), tinyId, senderNickname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当收到群消息时触发
|
||||
* @param groupId 群号
|
||||
* @param message 消息
|
||||
* @param senderId 发送者ID
|
||||
* @param senderCardOrNickname 发送者群名片或昵称,名片为空时是昵称
|
||||
* @param senderLevel 发送者群等级
|
||||
* @param senderRole 发送者群身份
|
||||
* @param senderTitle 发送者群专属头衔
|
||||
*/
|
||||
private void onGroupMessage(long groupId,
|
||||
String message,
|
||||
long senderId,
|
||||
String senderCardOrNickname,
|
||||
String senderLevel,
|
||||
String senderRole,
|
||||
String senderTitle) {
|
||||
logger.info("groupId={}, message={}, senderId={}, senderCardOrNickname={}, senderLevel={}, senderRole={}, senderTitle={}",
|
||||
groupId, message, senderId, senderCardOrNickname, senderLevel, senderRole, senderTitle);
|
||||
groupMessageHandler.handleGroupMessage(new GroupMessage(groupId, message, senderId, senderCardOrNickname, senderLevel, senderRole, senderTitle));
|
||||
}
|
||||
|
||||
/**
|
||||
* 当收到频道消息时触发
|
||||
* @param guildId 频道Id
|
||||
* @param channelId 子频道Id
|
||||
* @param message 消息
|
||||
* @param senderId 发送者Id
|
||||
* @param senderName 发送者昵称
|
||||
*/
|
||||
private void onGuildMessage(String guildId, String channelId, String message, String senderId, String senderName) {
|
||||
logger.info("guildId={}, channelId={}, message={}, senderId={}, senderNickname={}",
|
||||
guildId, channelId, message, senderId, senderName);
|
||||
guildChannelMessageHandler.handleGuildChannelMessage(new GuildChannelMessage(guildId, channelId, message, senderId, senderName));
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Message API
|
||||
|
||||
public void sendMessage(String sender, String message) {
|
||||
// TODO
|
||||
// region Models
|
||||
private static class Action {
|
||||
public String action;
|
||||
public Object params;
|
||||
public Action(String action, Object params) {
|
||||
this.action = action;
|
||||
this.params = params;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SendGroupMsgArgs {
|
||||
public long group_id;
|
||||
public String message;
|
||||
public boolean auto_escape = true;
|
||||
public SendGroupMsgArgs(long groupId, String message) {
|
||||
this.group_id = groupId;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SendGuildChannelMsgArgs {
|
||||
public String guild_id;
|
||||
public String channel_id;
|
||||
public String message;
|
||||
public boolean auto_escape = true;
|
||||
public SendGuildChannelMsgArgs(String guildId, String channelId, String message) {
|
||||
this.guild_id = guildId;
|
||||
this.channel_id = channelId;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* 发送消息到群
|
||||
* @param groupId 群号
|
||||
* @param message 消息
|
||||
*/
|
||||
public void sendGroupMessage(long groupId, String message) {
|
||||
sendMessageToAll(gson.toJson(new Action("send_group_msg", new SendGroupMsgArgs(groupId, message))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息到子频道
|
||||
* @param guildId 频道ID
|
||||
* @param channelId 子频道ID
|
||||
* @param message 消息
|
||||
*/
|
||||
public void sendGuildChannelMessage(String guildId, String channelId, String message) {
|
||||
sendMessageToAll(gson.toJson(new Action("send_guild_channel_msg", new SendGuildChannelMsgArgs(guildId, channelId, message))));
|
||||
}
|
||||
|
||||
GroupMessageHandler groupMessageHandler;
|
||||
|
||||
GuildChannelMessageHandler guildChannelMessageHandler;
|
||||
|
||||
/**
|
||||
* 订阅群消息事件
|
||||
* @param handler 群消息处理器
|
||||
*/
|
||||
public void subscribeGroupMessageEvent(GroupMessageHandler handler) {
|
||||
groupMessageHandler = handler;
|
||||
}
|
||||
|
||||
GuildChannelMessageHandler guildChannelMessageHandler;
|
||||
/**
|
||||
* 订阅频道消息事件
|
||||
* @param handler 频道消息处理器
|
||||
*/
|
||||
public void subscribeGuildChannelMessageEvent(GuildChannelMessageHandler handler) {
|
||||
guildChannelMessageHandler = handler;
|
||||
}
|
||||
@ -71,6 +226,33 @@ public class MiniOneBot implements WsStream.WsMessageHandler {
|
||||
|
||||
// region Utils
|
||||
|
||||
private static final Pattern cqCodePattern = Pattern.compile("\\[CQ:(\\w+).*?]");
|
||||
|
||||
private static String handleRawMessage(String rawMessage) {
|
||||
if (rawMessage.indexOf('[') == -1)
|
||||
return unescape(rawMessage);
|
||||
var message = new StringBuilder();
|
||||
var matcher = cqCodePattern.matcher(rawMessage);
|
||||
while (matcher.find()) {
|
||||
var type = matcher.group(1);
|
||||
var replacement = switch (type) {
|
||||
case "image" -> "[图片]";
|
||||
case "reply" -> "[回复]";
|
||||
case "at" -> "[@]";
|
||||
case "record" -> "[语音]";
|
||||
case "forward" -> "[合并转发]";
|
||||
case "video" -> "[视频]";
|
||||
case "music" -> "[音乐]";
|
||||
case "redbag" -> "[红包]";
|
||||
case "poke" -> "[戳一戳]";
|
||||
default -> "";
|
||||
};
|
||||
matcher.appendReplacement(message, replacement);
|
||||
}
|
||||
matcher.appendTail(message);
|
||||
return unescape(message.toString());
|
||||
}
|
||||
|
||||
private static String escape(String msg) {
|
||||
return msg.replace("&", "&")
|
||||
.replace("[", "[")
|
||||
|
@ -5,10 +5,12 @@ import io.javalin.websocket.*;
|
||||
import org.eclipse.jetty.websocket.api.CloseStatus;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class MiniOneBotWsServer implements WsStream {
|
||||
public class MiniOneBotWsServer implements WsStream, Closeable {
|
||||
|
||||
private final String token;
|
||||
private final Logger logger;
|
||||
@ -70,31 +72,6 @@ public class MiniOneBotWsServer implements WsStream {
|
||||
logger.debug("onMessage: {}", ctx.message());
|
||||
|
||||
callback.onMessage(ctx.message());
|
||||
// var map = JsonUtils.decode(ctx.message(), Map.class);
|
||||
// // 消息事件上报
|
||||
// if (Objects.equals(map.get("post_type"), "message")) {
|
||||
// // 群消息上报 https://docs.go-cqhttp.org/event/#%E7%BE%A4%E6%B6%88%E6%81%AF
|
||||
// if (Objects.equals(map.get("message_type"), "group")
|
||||
// && Objects.equals(map.get("sub_type"), "normal")) {
|
||||
// // 检查群号
|
||||
// var groupId = (Long)map.get("group_id");
|
||||
// if (Objects.equals(config.groupId, groupId)) {
|
||||
//// var message = (List<Map<?, ?>>)map.get("message");
|
||||
// var rawMessage = map.get("raw_message").toString();
|
||||
//
|
||||
// // 发送者信息 https://docs.go-cqhttp.org/reference/data_struct.html#post-message-messagesender
|
||||
// var sender = (Map<?, ?>) map.get("sender");
|
||||
// var senderId = sender.get("user_id").toString();
|
||||
// var senderNickname = sender.get("nickname").toString();
|
||||
// var senderCard = sender.get("card").toString();
|
||||
// chatSystem.broadcastChatMessage(config.groupToGameFormat
|
||||
// .replace("{card}", senderCard)
|
||||
// .replace("{id}", senderId)
|
||||
// .replace("{nickname}", senderNickname)
|
||||
// .replace("{message}", rawMessage));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
private WsMessageHandler callback;
|
||||
@ -113,4 +90,15 @@ public class MiniOneBotWsServer implements WsStream {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (connections.isEmpty()) return;
|
||||
for (var ctx : connections.keySet()) {
|
||||
if (ctx.session.isOpen()) {
|
||||
ctx.session.close(1001, "Service stopped");
|
||||
}
|
||||
}
|
||||
connections.clear();
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
package top.jie65535.minionebot.events;
|
||||
|
||||
public class GroupMessage {
|
||||
public String message;
|
||||
public record GroupMessage(
|
||||
long groupId,
|
||||
String message,
|
||||
long senderId,
|
||||
String senderCardOrNickname,
|
||||
String senderLevel,
|
||||
String senderRole,
|
||||
String senderTitle
|
||||
) {
|
||||
}
|
||||
|
@ -1,5 +1,10 @@
|
||||
package top.jie65535.minionebot.events;
|
||||
|
||||
public class GuildChannelMessage {
|
||||
public String message;
|
||||
public record GuildChannelMessage(
|
||||
String guildId,
|
||||
String channelId,
|
||||
String message,
|
||||
String senderId,
|
||||
String senderName
|
||||
) {
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user