From 5ebbaa4d55a9721cee53785ada5a3251ea0b8df9 Mon Sep 17 00:00:00 2001 From: cnlimiter Date: Thu, 18 Jan 2024 20:02:44 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- .../cn/evole/onebot/mirai/OneBotMirai.java | 102 +++++++++++++++--- .../onebot/mirai/core/session/BotSession.java | 41 +++++-- .../evole/onebot/mirai/util/ActionUtils.java | 7 +- .../cn/evole/onebot/mirai/util/BaseUtils.java | 25 +++-- .../cn/evole/onebot/mirai/util/ImgUtils.java | 20 +++- .../evole/onebot/mirai/config/PluginConfig.kt | 5 +- src/main/resources/plugin.yml | 2 +- 8 files changed, 161 insertions(+), 43 deletions(-) diff --git a/build.gradle b/build.gradle index a801910..d437d30 100644 --- a/build.gradle +++ b/build.gradle @@ -33,7 +33,7 @@ dependencies { implementation("cn.evole.bot:OneBot-SDK:0.2.7") "shadowLink"("cn.evole.bot:OneBot-SDK") implementation("io.github.pcmind:leveldb:1.2") - "shadowLink"("io.github.pcmind:leveldb") + "shadowLink"("io.github.pcmind:leveldb"){transitive = false} implementation("com.google.code.gson:gson:2.10.1") diff --git a/src/main/java/cn/evole/onebot/mirai/OneBotMirai.java b/src/main/java/cn/evole/onebot/mirai/OneBotMirai.java index 416f20b..43e183d 100644 --- a/src/main/java/cn/evole/onebot/mirai/OneBotMirai.java +++ b/src/main/java/cn/evole/onebot/mirai/OneBotMirai.java @@ -4,14 +4,22 @@ import cn.evole.onebot.mirai.core.SessionManager; import cn.evole.onebot.mirai.util.BaseUtils; import cn.evole.onebot.mirai.util.DBUtils; +import cn.evole.onebot.mirai.util.HttpUtils; import cn.evole.onebot.sdk.util.FileUtils; +import cn.evole.onebot.sdk.util.NetUtils; import lombok.val; import net.mamoe.mirai.Bot; +import net.mamoe.mirai.Mirai; import net.mamoe.mirai.console.plugin.jvm.JavaPlugin; +import net.mamoe.mirai.contact.Friend; +import net.mamoe.mirai.contact.Group; +import net.mamoe.mirai.contact.Member; import net.mamoe.mirai.event.Event; import net.mamoe.mirai.event.GlobalEventChannel; import net.mamoe.mirai.event.Listener; import net.mamoe.mirai.event.events.*; +import net.mamoe.mirai.message.data.Image; +import net.mamoe.mirai.message.data.OnlineAudio; import net.mamoe.mirai.utils.MiraiLogger; import org.iq80.leveldb.DB; import org.iq80.leveldb.Options; @@ -24,6 +32,9 @@ import java.util.List; import java.util.Objects; +import static cn.evole.onebot.mirai.util.ImgUtils.constructCacheImageMeta; +import static cn.evole.onebot.mirai.util.ImgUtils.getImageType; + public final class OneBotMirai extends JavaPlugin { public static String VERSION; public static final OneBotMirai INSTANCE = new OneBotMirai(); @@ -36,8 +47,8 @@ private OneBotMirai() { VERSION = getDescription().getVersion().toString(); } - private File imageFolder = new File(getDataFolder(), "image"); - private File recordFolder = new File(getDataFolder(), "record"); + private final File imageFolder = new File(getDataFolder(), "image"); + private final File recordFolder = new File(getDataFolder(), "record"); public DB db = null; @Override @@ -65,9 +76,9 @@ public void onEnable() { instances.forEach(bot -> { logger.info(String.format("bot : %d", bot.getId())); if (!SessionManager.getSessions().containsKey(bot.getId())) { - var botId = String.valueOf(bot.getId()); + val botId = String.valueOf(bot.getId()); if (Objects.requireNonNull(PluginConfig.INSTANCE.getBots()).containsKey(botId)){ - var mapConfig = PluginConfig.INSTANCE.getBots().get(botId); + val mapConfig = PluginConfig.INSTANCE.getBots().get(botId); SessionManager.createBotSession(bot, mapConfig); logger.info(String.format("创建配置: %d", bot.getId())); } @@ -86,23 +97,24 @@ public void onEnable() { } if (event instanceof BotOnlineEvent onlineEvent){ if (!SessionManager.containsSession(onlineEvent.getBot().getId())){ - var botId = String.valueOf(onlineEvent.getBot().getId()); + val botId = String.valueOf(onlineEvent.getBot().getId()); if (Objects.requireNonNull(PluginConfig.INSTANCE.getBots()).containsKey(String.valueOf(event.getBot().getId()))){ - var mapConfig = PluginConfig.INSTANCE.getBots().get(botId); - SessionManager.createBotSession(onlineEvent.getBot(), mapConfig); - logger.warning(String.format("%s 创建OneBot Session", event.getBot().getId())); - + val mapConfig = PluginConfig.INSTANCE.getBots().get(botId); + val session = SessionManager.createBotSession(onlineEvent.getBot(), mapConfig); + logger.info(String.format("机器人 %s 创建 OneBot Session", event.getBot().getId())); } else { - logger.warning(String.format("%s 未进行OneBot配置,请在setting.yml中进行配置", event.getBot().getId())); + logger.warning(String.format("机器人 %s 未进行OneBot配置,请在setting.yml中进行配置", event.getBot().getId())); } } } else if (event instanceof MessageEvent messageEvent){ - if (SessionManager.containsSession(messageEvent.getBot().getId())) { + val bot = messageEvent.getBot(); + val botId = bot.getId(); + if (SessionManager.containsSession(botId)) { DBUtils.saveMessageToDB(messageEvent);//存入数据库 - var session = SessionManager.get(messageEvent.getBot().getId()); + val session = SessionManager.get(botId); if (messageEvent instanceof GroupMessageEvent groupMessageEvent){ session.getApiImpl().getCachedSourceQueue().add(groupMessageEvent.getSource()); } @@ -110,23 +122,73 @@ else if (messageEvent instanceof GroupTempMessageEvent groupTempMessageEvent){ session.getApiImpl().getCachedTempContact() .put(groupTempMessageEvent.getSender().getId(), groupTempMessageEvent.getGroup().getId()); } + if (session.getBotConfig().getCacheImage()){ + messageEvent.getMessage().stream() + .filter(singleMessage -> singleMessage instanceof Image) + .forEach(singleMessage -> { + val img = (Image) singleMessage; + long imageSize; + val imageMD5 = BaseUtils.bytesToHexString(img.getMd5()); + val subject = messageEvent.getSubject(); + if (subject instanceof Member || subject instanceof Friend){ + val imageHeight = img.getHeight(); + val imageWidth = img.getWidth(); + imageSize = (long) imageHeight * imageWidth; + } + else if (subject instanceof Group){ + imageSize = img.getSize(); + } + else imageSize = 0; + + val imgMetaContent = constructCacheImageMeta( + imageMD5, + imageSize, + Mirai.getInstance().queryImageUrl(bot, img), + getImageType(img) + ); + saveImageOrRecord( + img.getImageId() + ".cqimg", + imgMetaContent, + true + ); + + }); + } + if (session.getBotConfig().getCacheRecord()){ + messageEvent.getMessage().stream() + .filter(singleMessage -> singleMessage instanceof OnlineAudio) + .forEach(singleMessage -> { + val audio = (OnlineAudio) singleMessage; + val voiceUrl = audio.getUrlForDownload(); + val voiceBytes = HttpUtils.getBytesFromHttpUrl(voiceUrl); + if (voiceBytes != null) { + saveImageOrRecord( + BaseUtils.bytesToHexString(audio.getFileMd5()) + ".cqrecord", + voiceBytes, + false + ); + } + }); + } + + } } else if (event instanceof NewFriendRequestEvent requestEvent) { if (SessionManager.containsSession(requestEvent.getBot().getId())) { - var session = SessionManager.get(requestEvent.getBot().getId()); + val session = SessionManager.get(requestEvent.getBot().getId()); session.getApiImpl().getCacheRequestQueue().add(requestEvent); } } else if (event instanceof MemberJoinRequestEvent requestEvent) { if (SessionManager.containsSession(requestEvent.getBot().getId())) { - var session = SessionManager.get(requestEvent.getBot().getId()); + val session = SessionManager.get(requestEvent.getBot().getId()); session.getApiImpl().getCacheRequestQueue().add(requestEvent); } } else if (event instanceof BotInvitedJoinGroupRequestEvent requestEvent) { if (SessionManager.containsSession(requestEvent.getBot().getId())) { - var session = SessionManager.get(requestEvent.getBot().getId()); + val session = SessionManager.get(requestEvent.getBot().getId()); session.getApiImpl().getCacheRequestQueue().add(requestEvent); } } @@ -149,6 +211,16 @@ private File record(String recordName){ return new File(this.recordFolder, recordName); } + public void saveImageOrRecord(String name, String data, boolean img){ + BaseUtils.safeRun(() -> { + if(data != null) { + try { + Files.writeString(img ? image(name).toPath() : record(name).toPath(), data, StandardOpenOption.WRITE); + } catch (IOException ignored) {} + } + }); + } + public void saveImageOrRecord(String name, byte[] data, boolean img){ BaseUtils.safeRun(() -> { if(data != null) { diff --git a/src/main/java/cn/evole/onebot/mirai/core/session/BotSession.java b/src/main/java/cn/evole/onebot/mirai/core/session/BotSession.java index ac33df3..2eef258 100644 --- a/src/main/java/cn/evole/onebot/mirai/core/session/BotSession.java +++ b/src/main/java/cn/evole/onebot/mirai/core/session/BotSession.java @@ -34,6 +34,18 @@ public class BotSession { private final List websocketClient = new ArrayList<>(); private final MiraiLogger miraiLogger = MiraiLogger.Factory.INSTANCE.create(BotSession.class); + + @Override + public String toString() { + return """ + Bot Id: %s, + Bot Config: %s, + OneBot Clients: %s, + OneBot Server: %s + """.formatted(bot.getBot().getId(), botConfig.toString(), websocketClient.size(), websocketServer.getAddress()) + ; + } + public BotSession(Bot bot, BotConfig botConfig){ this.bot = bot; this.apiImpl = new ApiMap(bot); @@ -68,21 +80,28 @@ public void triggerEvent(BotEvent event){ var e = EventMap.toDTO(event); var json = GsonUtils.getGson().toJson(e); if (!(e instanceof IgnoreEvent)) { + var debug = PluginConfig.INSTANCE.getDebug(); if (this.botConfig.getWs().getEnable()){ - OneBotMirai.logger.info("将广播正向websocket事件"); + if (debug) OneBotMirai.logger.info("将广播正向websocket事件"); websocketServer.broadcast(json); } - long sendCount = websocketClient.stream().filter(client -> { - try{ - if (client.isOpen()) { - client.send(json); - } - }catch (Exception ex){ - OneBotMirai.logger.warning("error sending msg", ex); + + for(PluginConfig.WSReverseConfig ws_re : botConfig.getWsReverse()){ + if (ws_re.getEnable()){ + long sendCount = websocketClient.stream().filter(client -> { + try{ + if (client.isOpen()) { + client.send(json); + } + }catch (Exception ex){ + OneBotMirai.logger.warning("error sending msg", ex); + } + return client.isOpen(); + }).count(); + if (debug) OneBotMirai.logger.info(String.format("将广播反向websocket事件, 共计发送 :%d", sendCount)); } - return client.isOpen(); - }).count(); - OneBotMirai.logger.info(String.format("广播反向websocket事件, 共计发送 :%d", sendCount)); + } + } } diff --git a/src/main/java/cn/evole/onebot/mirai/util/ActionUtils.java b/src/main/java/cn/evole/onebot/mirai/util/ActionUtils.java index 6813f0e..b46dde3 100644 --- a/src/main/java/cn/evole/onebot/mirai/util/ActionUtils.java +++ b/src/main/java/cn/evole/onebot/mirai/util/ActionUtils.java @@ -1,6 +1,7 @@ package cn.evole.onebot.mirai.util; import cn.evole.onebot.mirai.OneBotMirai; +import cn.evole.onebot.mirai.config.PluginConfig; import cn.evole.onebot.mirai.core.ApiMap; import com.google.gson.JsonObject; import org.java_websocket.WebSocket; @@ -15,7 +16,9 @@ public class ActionUtils { public static void handleWebSocketActions(WebSocket session, ApiMap api, JsonObject json){ try { - OneBotMirai.logger.info(String.format("WebSocket收到操作请求: %s", GsonUtils.getGson().toJson(json))); + var debug = PluginConfig.INSTANCE.getDebug(); + if (debug) OneBotMirai.logger.info(String.format("WebSocket收到操作请求: %s", GsonUtils.getGson().toJson(json))); + var echo = json.get("echo").getAsString(); var action = json.get("action").getAsString(); @@ -23,8 +26,8 @@ public static void handleWebSocketActions(WebSocket session, ApiMap api, JsonObj responseDTO.setEcho(echo); var jsonToSend = GsonUtils.getGson().toJson(responseDTO); - OneBotMirai.logger.info(String.format("WebSocket将返回结果: %s" ,jsonToSend)); session.send(jsonToSend); + if (debug) OneBotMirai.logger.info(String.format("WebSocket将返回结果: %s" ,jsonToSend)); } catch (Exception e) { OneBotMirai.logger.error(e.getMessage()); } diff --git a/src/main/java/cn/evole/onebot/mirai/util/BaseUtils.java b/src/main/java/cn/evole/onebot/mirai/util/BaseUtils.java index 4d71813..7e0c8a8 100644 --- a/src/main/java/cn/evole/onebot/mirai/util/BaseUtils.java +++ b/src/main/java/cn/evole/onebot/mirai/util/BaseUtils.java @@ -71,26 +71,33 @@ else if (new File(systemDataFolder + name).getAbsoluteFile().exists()){ } } - public static String byteToHex(byte[] bytes){ - String strHex = ""; - StringBuilder sb = new StringBuilder(); - for (int n = bytes.length-1; n >=0; n--) { - strHex = Integer.toHexString(bytes[n] & 0xFF); - sb.append((strHex.length() == 1) ? "0" + strHex : strHex); // 每个字节由两个字符表示,位数不够,高位补0 + /** + * 更加高效 + * @param bytes 数据 + * @return 字符 + */ + public static String bytesToHexString(byte[] bytes) { + final char[] hexArray = "0123456789ABCDEF".toCharArray();//通过对一个只读数组hexArray进行读取来实现 + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } - return sb.toString().trim(); + return new String(hexChars); } public static String bytesToString(byte[] str) { String keyword = null; try { - keyword = new String(str,"GBK"); + keyword = new String(str, "GBK"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return keyword; } + public static int byteToInt(byte[] b) { int s = 0; int s0 = b[0] & 0xff;// 最低位 @@ -103,4 +110,6 @@ public static int byteToInt(byte[] b) { s = s0 | s1 | s2 | s3; return s; } + + } diff --git a/src/main/java/cn/evole/onebot/mirai/util/ImgUtils.java b/src/main/java/cn/evole/onebot/mirai/util/ImgUtils.java index 01f2c0e..e40bc96 100644 --- a/src/main/java/cn/evole/onebot/mirai/util/ImgUtils.java +++ b/src/main/java/cn/evole/onebot/mirai/util/ImgUtils.java @@ -1,6 +1,7 @@ package cn.evole.onebot.mirai.util; import lombok.val; +import net.mamoe.mirai.message.data.Image; import org.jetbrains.annotations.Nullable; import java.io.File; @@ -19,7 +20,7 @@ public class ImgUtils { - public static String constructCacheImageMeta(String md5, int size, String url, String imageType){ + public static String constructCacheImageMeta(String md5, long size, String url, String imageType){ return """ [image] md5=%s @@ -30,6 +31,17 @@ public static String constructCacheImageMeta(String md5, int size, String url, S """.formatted(md5, size, url, System.currentTimeMillis(), imageType); } + + public static String getImageType(Image image){ + val parts = image.getImageId().split("\\.", 2); + if (parts.length == 2){ + return parts[1]; + } + else { + return "unknown"; + } + } + public static String getImageType(byte[] bytes){ byte[] b1 = new byte[8]; System.arraycopy(bytes, 0, b1, 0, 8); @@ -119,10 +131,12 @@ else if (name.endsWith(".image")){ val bytes = Files.readAllBytes(cacheFile.toPath()); byte[] b1 = new byte[16]; System.arraycopy(bytes, 0, b1, 0, 16); - md5[0] = BaseUtils.bytesToString(b1); - byte[] b2 = new byte[16]; + md5[0] = BaseUtils.bytesToHexString(b1); + + byte[] b2 = new byte[4]; System.arraycopy(bytes, 16, b2, 0, 4); size[0] = BaseUtils.byteToInt(b2); + url[0] = "https://c2cpicdw.qpic.cn/offpic_new//0/0-00-$md5/0?term=2"; } catch (IOException ignored){} diff --git a/src/main/kotlin/cn/evole/onebot/mirai/config/PluginConfig.kt b/src/main/kotlin/cn/evole/onebot/mirai/config/PluginConfig.kt index 7b7b280..eeb2293 100644 --- a/src/main/kotlin/cn/evole/onebot/mirai/config/PluginConfig.kt +++ b/src/main/kotlin/cn/evole/onebot/mirai/config/PluginConfig.kt @@ -8,11 +8,12 @@ import net.mamoe.mirai.console.data.value object PluginConfig : AutoSavePluginConfig("setting"){ val bots: MutableMap? by value(mutableMapOf("12345654321" to BotConfig())) val db by value(DBSettings()) + val debug : Boolean = false @Serializable data class BotConfig( - var cacheImage: Boolean = false, - var cacheRecord: Boolean = false, + var cacheImage: Boolean = true, + var cacheRecord: Boolean = true, var heartbeat: HeartbeatConfig = HeartbeatConfig(), var http: HTTPConfig = HTTPConfig(), @SerialName("ws_reverse") diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 0279381..9bf8b9a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ id: cn.evole.mirai.onebot main: cn.evole.mirai.onebot.OneBotMirai -version: 0.1.7 +version: 0.2.0 name: OneBot_Mirai author: cnlimiter dependencies: [ ]