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 class Main {
|
||||||
public static void main(String[] args) {
|
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);
|
Javalin app = Javalin.create().start(7070);
|
||||||
var bot = new MiniOneBot(app, "HelloOneBot");
|
var bot = new MiniOneBot(app, "HelloOneBot");
|
||||||
bot.startWsServer("/openchat");
|
bot.startWsServer("/openchat");
|
||||||
@ -35,17 +16,21 @@ public class Main {
|
|||||||
} catch (URISyntaxException ignored) {
|
} catch (URISyntaxException ignored) {
|
||||||
System.out.println("Uri Syntax error!");
|
System.out.println("Uri Syntax error!");
|
||||||
}
|
}
|
||||||
bot.subscribeGroupMessageEvent(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.println(event.message));
|
bot.subscribeGuildChannelMessageEvent(event -> System.out.printf("[Cl]<%s> %s%n", event.senderName(), event.message()));
|
||||||
|
|
||||||
var scanner = new Scanner(System.in);
|
var scanner = new Scanner(System.in);
|
||||||
while (true) {
|
while (true) {
|
||||||
var input = scanner.nextLine();
|
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;
|
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;
|
package top.jie65535.minionebot;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
import io.javalin.Javalin;
|
import io.javalin.Javalin;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import top.jie65535.minionebot.events.GroupMessage;
|
||||||
import top.jie65535.minionebot.events.GroupMessageHandler;
|
import top.jie65535.minionebot.events.GroupMessageHandler;
|
||||||
|
import top.jie65535.minionebot.events.GuildChannelMessage;
|
||||||
import top.jie65535.minionebot.events.GuildChannelMessageHandler;
|
import top.jie65535.minionebot.events.GuildChannelMessageHandler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class MiniOneBot implements WsStream.WsMessageHandler {
|
public class MiniOneBot implements WsStream.WsMessageHandler {
|
||||||
private final Logger logger = LoggerFactory.getLogger("Console");
|
private final Logger logger = LoggerFactory.getLogger("Console");
|
||||||
@ -14,11 +21,11 @@ public class MiniOneBot implements WsStream.WsMessageHandler {
|
|||||||
private final String token;
|
private final String token;
|
||||||
private MiniOneBotWsServer server;
|
private MiniOneBotWsServer server;
|
||||||
private MiniOneBotWsClient client;
|
private MiniOneBotWsClient client;
|
||||||
|
private final Gson gson = new Gson();
|
||||||
|
|
||||||
public MiniOneBot(Javalin javalin, String token) {
|
public MiniOneBot(Javalin javalin, String token) {
|
||||||
this.javalin = javalin;
|
this.javalin = javalin;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
logger.info("Test");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// region WebSocket
|
// 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) {
|
private void sendMessageToAll(String message) {
|
||||||
|
logger.info("Sending... message=\"{}\"", message);
|
||||||
server.send(message);
|
server.send(message);
|
||||||
client.send(message);
|
client.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region OneBot message
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(String message) {
|
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
|
// endregion
|
||||||
|
|
||||||
// region Message API
|
// region Message API
|
||||||
|
|
||||||
public void sendMessage(String sender, String message) {
|
// region Models
|
||||||
// TODO
|
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;
|
GroupMessageHandler groupMessageHandler;
|
||||||
|
|
||||||
|
GuildChannelMessageHandler guildChannelMessageHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订阅群消息事件
|
||||||
|
* @param handler 群消息处理器
|
||||||
|
*/
|
||||||
public void subscribeGroupMessageEvent(GroupMessageHandler handler) {
|
public void subscribeGroupMessageEvent(GroupMessageHandler handler) {
|
||||||
groupMessageHandler = handler;
|
groupMessageHandler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
GuildChannelMessageHandler guildChannelMessageHandler;
|
/**
|
||||||
|
* 订阅频道消息事件
|
||||||
|
* @param handler 频道消息处理器
|
||||||
|
*/
|
||||||
public void subscribeGuildChannelMessageEvent(GuildChannelMessageHandler handler) {
|
public void subscribeGuildChannelMessageEvent(GuildChannelMessageHandler handler) {
|
||||||
guildChannelMessageHandler = handler;
|
guildChannelMessageHandler = handler;
|
||||||
}
|
}
|
||||||
@ -71,6 +226,33 @@ public class MiniOneBot implements WsStream.WsMessageHandler {
|
|||||||
|
|
||||||
// region Utils
|
// 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) {
|
private static String escape(String msg) {
|
||||||
return msg.replace("&", "&")
|
return msg.replace("&", "&")
|
||||||
.replace("[", "[")
|
.replace("[", "[")
|
||||||
|
@ -5,10 +5,12 @@ import io.javalin.websocket.*;
|
|||||||
import org.eclipse.jetty.websocket.api.CloseStatus;
|
import org.eclipse.jetty.websocket.api.CloseStatus;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class MiniOneBotWsServer implements WsStream {
|
public class MiniOneBotWsServer implements WsStream, Closeable {
|
||||||
|
|
||||||
private final String token;
|
private final String token;
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
@ -70,31 +72,6 @@ public class MiniOneBotWsServer implements WsStream {
|
|||||||
logger.debug("onMessage: {}", ctx.message());
|
logger.debug("onMessage: {}", ctx.message());
|
||||||
|
|
||||||
callback.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;
|
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;
|
package top.jie65535.minionebot.events;
|
||||||
|
|
||||||
public class GroupMessage {
|
public record GroupMessage(
|
||||||
public String message;
|
long groupId,
|
||||||
|
String message,
|
||||||
|
long senderId,
|
||||||
|
String senderCardOrNickname,
|
||||||
|
String senderLevel,
|
||||||
|
String senderRole,
|
||||||
|
String senderTitle
|
||||||
|
) {
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package top.jie65535.minionebot.events;
|
package top.jie65535.minionebot.events;
|
||||||
|
|
||||||
public class GuildChannelMessage {
|
public record GuildChannelMessage(
|
||||||
public String message;
|
String guildId,
|
||||||
|
String channelId,
|
||||||
|
String message,
|
||||||
|
String senderId,
|
||||||
|
String senderName
|
||||||
|
) {
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user