소스 검색

Merge branch 'dev' of https://github.com/mamoe/mirai into dev

sandtechnology 5 년 전
부모
커밋
410f371c74
16개의 변경된 파일289개의 추가작업 그리고 84개의 파일을 삭제
  1. 4 0
      buildSrc/src/main/kotlin/Versions.kt
  2. 8 8
      java-test/src/test/java/net/mamoe/mirai/javatest/SimpleListenerHostTest.java
  3. 70 36
      mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt
  4. 2 3
      mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
  5. 0 2
      mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt
  6. 8 14
      mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt
  7. 5 6
      mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/voice/PttStore.kt
  8. 2 0
      mirai-core/build.gradle.kts
  9. 15 4
      mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt
  10. 5 2
      mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.common.kt
  11. 4 4
      mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/EventInternalJvm.kt
  12. 16 5
      mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/SendImageUtilsJvm.kt
  13. 32 0
      mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/LoggerAdapters.kt
  14. 40 0
      mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/internal/logging/JdkLogger.kt
  15. 40 0
      mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/internal/logging/Log4jLogger.kt
  16. 38 0
      mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/internal/logging/Slf4jLogger.kt

+ 4 - 0
buildSrc/src/main/kotlin/Versions.kt

@@ -36,6 +36,10 @@ object Versions {
         const val bintray = "1.8.5"
     }
 
+    object Logging {
+        const val slf4j = "1.7.30"
+        const val log4j = "2.13.3"
+    }
 }
 
 @Suppress("unused")

+ 8 - 8
java-test/src/test/java/net/mamoe/mirai/javatest/SimpleListenerHostTest.java

@@ -8,33 +8,33 @@
 
 package net.mamoe.mirai.javatest;
 
-import kotlin.coroutines.CoroutineContext;
 import kotlin.coroutines.EmptyCoroutineContext;
 import kotlinx.coroutines.CoroutineScope;
 import kotlinx.coroutines.CoroutineScopeKt;
 import net.mamoe.mirai.event.*;
-import org.jetbrains.annotations.NotNull;
 import org.junit.Test;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 public class SimpleListenerHostTest {
     @Test
-    public void test() {
+    public void testJavaSimpleListenerHostWork() {
+        AtomicBoolean called = new AtomicBoolean();
         final SimpleListenerHost host = new SimpleListenerHost() {
             @EventHandler
             public void testListen(
                     AbstractEvent event
             ) {
                 System.out.println(event);
-            }
-
-            @Override
-            public void handleException(@NotNull CoroutineContext context, @NotNull Throwable exception) {
-                exception.printStackTrace();
+                called.set(true);
             }
         };
         CoroutineScope scope = CoroutineScopeKt.CoroutineScope(EmptyCoroutineContext.INSTANCE);
         Events.registerEvents(scope, host);
         EventKt.broadcast(new AbstractEvent() {
         });
+        if (!called.get()) {
+            throw new AssertionError("JavaTest: SimpleListenerHost Failed.");
+        }
     }
 }

+ 70 - 36
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/GroupImpl.kt

@@ -12,9 +12,7 @@
 
 package net.mamoe.mirai.qqandroid.contact
 
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.*
 import kotlinx.io.core.Closeable
 import net.mamoe.mirai.LowLevelAPI
 import net.mamoe.mirai.contact.*
@@ -33,9 +31,13 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
 import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
 import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
 import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.createToGroup
+import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.voice.PttStore
 import net.mamoe.mirai.qqandroid.network.protocol.packet.list.ProfileService
+import net.mamoe.mirai.qqandroid.utils.MiraiPlatformUtils
 import net.mamoe.mirai.qqandroid.utils.estimateLength
+import net.mamoe.mirai.qqandroid.utils.toUHexString
 import net.mamoe.mirai.utils.*
+import java.io.InputStream
 import kotlin.contracts.contract
 import kotlin.coroutines.CoroutineContext
 import kotlin.jvm.JvmSynthetic
@@ -130,18 +132,18 @@ internal class GroupImpl(
             set(newValue) {
                 checkBotPermission(MemberPermission.ADMINISTRATOR)
                 //if (_announcement != newValue) {
-                    val oldValue = _announcement
-                    _announcement = newValue
-                    launch {
-                        bot.network.run {
-                            TroopManagement.GroupOperation.memo(
-                                client = bot.client,
-                                groupCode = id,
-                                newMemo = newValue
-                            ).sendWithoutExpect()
-                        }
-                        GroupEntranceAnnouncementChangeEvent(oldValue, newValue, this@GroupImpl, null).broadcast()
+                val oldValue = _announcement
+                _announcement = newValue
+                launch {
+                    bot.network.run {
+                        TroopManagement.GroupOperation.memo(
+                            client = bot.client,
+                            groupCode = id,
+                            newMemo = newValue
+                        ).sendWithoutExpect()
                     }
+                    GroupEntranceAnnouncementChangeEvent(oldValue, newValue, this@GroupImpl, null).broadcast()
+                }
                 //}
             }
 
@@ -151,18 +153,18 @@ internal class GroupImpl(
             set(newValue) {
                 checkBotPermission(MemberPermission.ADMINISTRATOR)
                 //if (_allowMemberInvite != newValue) {
-                    val oldValue = _allowMemberInvite
-                    _allowMemberInvite = newValue
-                    launch {
-                        bot.network.run {
-                            TroopManagement.GroupOperation.allowMemberInvite(
-                                client = bot.client,
-                                groupCode = id,
-                                switch = newValue
-                            ).sendWithoutExpect()
-                        }
-                        GroupAllowMemberInviteEvent(oldValue, newValue, this@GroupImpl, null).broadcast()
+                val oldValue = _allowMemberInvite
+                _allowMemberInvite = newValue
+                launch {
+                    bot.network.run {
+                        TroopManagement.GroupOperation.allowMemberInvite(
+                            client = bot.client,
+                            groupCode = id,
+                            switch = newValue
+                        ).sendWithoutExpect()
                     }
+                    GroupAllowMemberInviteEvent(oldValue, newValue, this@GroupImpl, null).broadcast()
+                }
                 //}
             }
 
@@ -208,18 +210,18 @@ internal class GroupImpl(
             set(newValue) {
                 checkBotPermission(MemberPermission.ADMINISTRATOR)
                 //if (_muteAll != newValue) {
-                    val oldValue = _muteAll
-                    _muteAll = newValue
-                    launch {
-                        bot.network.run {
-                            TroopManagement.GroupOperation.muteAll(
-                                client = bot.client,
-                                groupCode = id,
-                                switch = newValue
-                            ).sendWithoutExpect()
-                        }
-                        GroupMuteAllEvent(oldValue, newValue, this@GroupImpl, null).broadcast()
+                val oldValue = _muteAll
+                _muteAll = newValue
+                launch {
+                    bot.network.run {
+                        TroopManagement.GroupOperation.muteAll(
+                            client = bot.client,
+                            groupCode = id,
+                            switch = newValue
+                        ).sendWithoutExpect()
                     }
+                    GroupMuteAllEvent(oldValue, newValue, this@GroupImpl, null).broadcast()
+                }
                 //}
             }
     }
@@ -443,5 +445,37 @@ internal class GroupImpl(
         (image.input as? Closeable)?.close()
     }
 
+    /**
+     * 上传一个语音消息以备发送.
+     * 请注意,这是一个实验性api且随时会被删除
+     * @throws EventCancelledException 当发送消息事件被取消
+     * @throws OverFileSizeMaxException 当图片文件过大而被服务器拒绝上传时. (最大大小约为 1 MB)
+     */
+    @JvmSynthetic
+    @MiraiExperimentalAPI
+    override suspend fun uploadGroupVoice(input: InputStream): Voice {
+        val content = ByteArray(input.available())
+        input.read(content)
+        if (content.size > 1048576) {
+            throw  OverFileSizeMaxException()
+        }
+        val md5 = MiraiPlatformUtils.md5(content)
+        return bot.network.run {
+            val response: PttStore.GroupPttUp.Response.RequireUpload =
+                PttStore.GroupPttUp(bot.client, bot.id, 0L, md5, content.size.toLong()).sendAndExpect()
+            HighwayHelper.uploadPttToServers(
+                bot,
+                response.uploadIpList.zip(response.uploadPortList),
+                content,
+                md5,
+                response.uKey,
+                response.fileKey
+            )
+            Voice("${md5.toUHexString("")}.amr", md5, content.size.toLong(), "")
+        }
+
+    }
+
+
     override fun toString(): String = "Group($id)"
 }

+ 2 - 3
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt

@@ -413,9 +413,8 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
         logger.info { "Syncing friend message history..." }
         withTimeoutOrNull(30000) {
             launch(CoroutineName("Syncing friend message history")) { syncFromEvent<MessageSvcPbGetMsg.GetMsgSuccess, Unit> { Unit } }
-            // 别问我为什么要发两个 我也不知道 反正它能用
-            MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, null, firstSync = true).sendAndExpect<Packet>()
-            MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, null, firstSync = true).sendAndExpect<Packet>()
+            MessageSvcPbGetMsg(bot.client, MsgSvc.SyncFlag.START, null).sendAndExpect<Packet>()
+
         } ?: error("timeout syncing friend message history")
         logger.info { "Syncing friend message history: Success" }
     }

+ 0 - 2
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt

@@ -128,8 +128,6 @@ internal open class QQAndroidClient(
 
     lateinit var fileStoragePushFSSvcList: FileStoragePushFSSvcListFuckKotlin
 
-    internal val firstSyncPackets: AtomicInt = atomic(0)  // 启动时候仅将所有好友信息设为已读的包
-
     internal suspend inline fun useNextServers(crossinline block: suspend (host: String, port: Int) -> Unit) {
         if (bot.client.serverList.isEmpty()) {
             throw NoServerAvailableException(null)

+ 8 - 14
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt

@@ -61,14 +61,10 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
         client: QQAndroidClient,
         syncFlag: MsgSvc.SyncFlag = MsgSvc.SyncFlag.START,
         syncCookie: ByteArray?, //PbPushMsg.msg.msgHead.msgTime
-        firstSync: Boolean = false
     ): OutgoingPacket = buildOutgoingUniPacket(
         client
     ) {
         //println("syncCookie=${client.c2cMessageSync.syncCookie?.toUHexString()}")
-        if (firstSync) {
-            client.firstSyncPackets.getAndAdd(1)
-        }
         writeProtoBuf(
             MsgSvc.PbGetMsgReq.serializer(),
             MsgSvc.PbGetMsgReq(
@@ -150,10 +146,13 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
 
         val messages = resp.uinPairMsgs.asFlow()
             .filterNot { it.msg == null }
-            .flatMapConcat { it.msg!!.asFlow() }
-            .also {
-                MessageSvcPbDeleteMsg.delete(bot, it)
-            } // 删除消息
+            .flatMapConcat {
+                it.msg!!.asFlow()
+                    .filter { msg: MsgComm.Msg -> msg.msgHead.msgTime > it.lastReadTime.toLong() and 4294967295L }
+            }.also {
+                MessageSvcPbDeleteMsg.delete(bot, it) // 删除消息
+                // todo 实现一个锁来防止重复收到消息
+            }
             .mapNotNull<MsgComm.Msg, Packet> { msg ->
 
                 suspend fun createGroupForBot(groupUin: Long): Group? {
@@ -277,9 +276,6 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
                     */
 
                     166 -> {
-                        if (bot.client.firstSyncPackets.value != 0) {
-                            return@mapNotNull null
-                        }
                         if (msg.msgHead.fromUin == bot.id) {
                             loop@ while (true) {
                                 val instance = bot.client.getFriendSeq()
@@ -383,9 +379,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
     override suspend fun QQAndroidBot.handle(packet: Response) {
         when (packet.syncFlagFromServer) {
             MsgSvc.SyncFlag.STOP -> {
-                if (client.firstSyncPackets.value != 0) {
-                    client.firstSyncPackets.getAndDecrement()
-                }
+
             }
 
             MsgSvc.SyncFlag.START -> {

+ 5 - 6
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/voice/PttStore.kt

@@ -37,9 +37,8 @@ internal class PttStore {
             uin: Long,
             groupCode: Long,
             md5: ByteArray,
-            size: Long = 0,
-            voiceLength: Int = 0,
-            fileId: Long = 0
+            size: Long,
+            codec: Int = 0
         ): OutgoingPacket {
             val pack = Cmd0x388.ReqBody(
                 netType = 3, // wifi
@@ -48,7 +47,7 @@ internal class PttStore {
                     Cmd0x388.TryUpPttReq(
                         srcUin = uin,
                         groupCode = groupCode,
-                        fileId = fileId,
+                        fileId = 0,
                         fileSize = size,
                         fileMd5 = md5,
                         fileName = md5,
@@ -57,8 +56,8 @@ internal class PttStore {
                         buType = 4,
                         innerIp = 0,
                         buildVer = "6.5.5.663".encodeToByteArray(),
-                        voiceLength = voiceLength,
-                        codec = 0,
+                        voiceLength = 1,
+                        codec = codec,
                         voiceType = 1,
                         boolNewUpChan = true
                     )

+ 2 - 0
mirai-core/build.gradle.kts

@@ -108,6 +108,8 @@ kotlin {
                 //api(kotlin("stdlib-jdk8"))
                 //api(kotlin("stdlib-jdk7"))
                 api(kotlin("reflect"))
+                compileOnly("org.apache.logging.log4j:log4j-api:" + Versions.Logging.log4j)
+                compileOnly("org.slf4j:slf4j-api:" + Versions.Logging.slf4j)
 
                 api(ktor("client-core-jvm", Versions.Kotlin.ktor))
                 implementation(kotlinx("io-jvm", Versions.Kotlin.io))

+ 15 - 4
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt

@@ -18,13 +18,11 @@ import net.mamoe.mirai.LowLevelAPI
 import net.mamoe.mirai.data.MemberInfo
 import net.mamoe.mirai.event.events.*
 import net.mamoe.mirai.message.MessageReceipt
-import net.mamoe.mirai.message.data.Image
-import net.mamoe.mirai.message.data.Message
-import net.mamoe.mirai.message.data.isContentEmpty
-import net.mamoe.mirai.message.data.toMessage
+import net.mamoe.mirai.message.data.*
 import net.mamoe.mirai.message.recall
 import net.mamoe.mirai.utils.*
 import net.mamoe.mirai.utils.internal.runBlocking
+import java.io.InputStream
 import kotlin.jvm.JvmName
 import kotlin.jvm.JvmStatic
 import kotlin.jvm.JvmSynthetic
@@ -174,6 +172,19 @@ public abstract class Group : Contact(), CoroutineScope {
     @JvmSynthetic
     public abstract override suspend fun uploadImage(image: ExternalImage): Image
 
+    /**
+     * 上传一个语音消息以备发送.
+     * 请手动关闭输入流
+     * 请使用mar格式
+     * 请注意,这是一个实验性api且随时会被删除
+     * @throws EventCancelledException 当发送消息事件被取消
+     * @throws OverFileSizeMaxException 当图片文件过大而被服务器拒绝上传时. (最大大小约为 1 MB)
+     */
+    @JvmSynthetic
+    @MiraiExperimentalAPI
+    public abstract suspend fun uploadGroupVoice(input: InputStream): Voice
+
+
     public companion object {
         /**
          * 使用 groupCode 计算 groupUin. 这两个值仅在 mirai 内部协议区分, 一般人使用时无需在意.

+ 5 - 2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.common.kt

@@ -159,8 +159,11 @@ public open class BotConfigurationBase internal constructor() {
     @MiraiExperimentalAPI
     public var json: Json = kotlin.runCatching {
         @OptIn(UnstableDefault::class)
-        Json(JsonConfiguration(isLenient = true, ignoreUnknownKeys = true))
-    }.getOrElse { Json(JsonConfiguration.Stable) }
+        Json {
+            isLenient = true
+            ignoreUnknownKeys = true
+        }
+    }.getOrElse { Json {} }
 
     /**
      * 不显示网络日志. 不推荐.

+ 4 - 4
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/EventInternalJvm.kt

@@ -161,11 +161,11 @@ internal fun Method.registerEvent(
                     if (annotation.ignoreCancelled) {
                         if ((this as? CancellableEvent)?.isCancelled != true) {
                             withContext(Dispatchers.IO) {
-                                [email protected](owner, this)
+                                [email protected](owner, this@subscribeAlways)
                             }
                         }
                     } else withContext(Dispatchers.IO) {
-                        [email protected](owner, this)
+                        [email protected](owner, this@subscribeAlways)
                     }
                 }
             }
@@ -179,11 +179,11 @@ internal fun Method.registerEvent(
                     if (annotation.ignoreCancelled) {
                         if ((this as? CancellableEvent)?.isCancelled != true) {
                             withContext(Dispatchers.IO) {
-                                [email protected](owner, this) as ListeningStatus
+                                [email protected](owner, this@subscribe) as ListeningStatus
                             }
                         } else ListeningStatus.LISTENING
                     } else withContext(Dispatchers.IO) {
-                        [email protected](owner, this) as ListeningStatus
+                        [email protected](owner, this@subscribe) as ListeningStatus
                     }
 
                 }

+ 16 - 5
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/message/SendImageUtilsJvm.kt

@@ -12,14 +12,12 @@
 package net.mamoe.mirai.message
 
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
 import kotlinx.io.core.Input
 import net.mamoe.mirai.contact.Contact
+import net.mamoe.mirai.contact.Group
 import net.mamoe.mirai.message.data.Image
-import net.mamoe.mirai.utils.OverFileSizeMaxException
-import net.mamoe.mirai.utils.sendTo
-import net.mamoe.mirai.utils.toExternalImage
-import net.mamoe.mirai.utils.upload
+import net.mamoe.mirai.message.data.Voice
+import net.mamoe.mirai.utils.*
 import java.awt.image.BufferedImage
 import java.io.File
 import java.io.InputStream
@@ -120,6 +118,19 @@ public suspend fun File.uploadAsImage(contact: Contact): Image {
     return toExternalImage().upload(contact)
 }
 
+/**
+ * 在 [Dispatchers.IO] 中将文件作为语音上传后构造 [Image]
+ * 请手动关闭输入流
+ * 请使用mar格式
+ * 注意,这只是个实验性功能且随时可能会删除
+ * @throws OverFileSizeMaxException
+ */
+@Throws(OverFileSizeMaxException::class)
+@MiraiExperimentalAPI
+public suspend fun InputStream.uploadAsGroupVoice(group: Group): Voice {
+    return group.uploadGroupVoice(this)
+}
+
 // endregion
 
 // region Contact.sendImage(IMAGE)

+ 32 - 0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/LoggerAdapters.kt

@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019-2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+package net.mamoe.mirai.utils
+
+import net.mamoe.mirai.utils.internal.logging.JdkLogger
+import net.mamoe.mirai.utils.internal.logging.Log4jLogger
+import net.mamoe.mirai.utils.internal.logging.Slf4jLogger
+
+@SinceMirai("1.2.0")
+public object LoggerAdapters {
+    @JvmStatic
+    public fun java.util.logging.Logger.asMiraiLogger(): MiraiLogger {
+        return JdkLogger(this)
+    }
+
+    @JvmStatic
+    public fun org.apache.logging.log4j.Logger.asMiraiLogger(): MiraiLogger {
+        return Log4jLogger(this);
+    }
+
+    @JvmStatic
+    public fun org.slf4j.Logger.asMiraiLogger(): MiraiLogger {
+        return Slf4jLogger(this)
+    }
+}

+ 40 - 0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/internal/logging/JdkLogger.kt

@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019-2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+package net.mamoe.mirai.utils.internal.logging
+
+import net.mamoe.mirai.utils.MiraiLoggerPlatformBase
+import java.util.logging.Level
+import java.util.logging.Logger
+
+internal class JdkLogger(private val logger: Logger) : MiraiLoggerPlatformBase() {
+    override fun verbose0(message: String?, e: Throwable?) {
+        logger.log(Level.FINER, message, e)
+    }
+
+    override fun debug0(message: String?, e: Throwable?) {
+        logger.log(Level.FINEST, message, e)
+
+    }
+
+    override fun info0(message: String?, e: Throwable?) {
+        logger.log(Level.INFO, message, e)
+    }
+
+    override fun warning0(message: String?, e: Throwable?) {
+        logger.log(Level.WARNING, message, e)
+    }
+
+    override fun error0(message: String?, e: Throwable?) {
+        logger.log(Level.SEVERE, message, e)
+    }
+
+    override val identity: String?
+        get() = logger.name
+}

+ 40 - 0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/internal/logging/Log4jLogger.kt

@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019-2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+package net.mamoe.mirai.utils.internal.logging
+
+import net.mamoe.mirai.utils.MiraiLoggerPlatformBase
+import org.apache.logging.log4j.Logger
+
+internal class Log4jLogger(private val logger: Logger) : MiraiLoggerPlatformBase() {
+
+    override fun verbose0(message: String?, e: Throwable?) {
+        logger.trace(message, e)
+    }
+
+    override fun debug0(message: String?, e: Throwable?) {
+        logger.debug(message, e)
+    }
+
+    override fun info0(message: String?, e: Throwable?) {
+        logger.info(message, e)
+    }
+
+    override fun warning0(message: String?, e: Throwable?) {
+        logger.warn(message, e)
+    }
+
+    override fun error0(message: String?, e: Throwable?) {
+        logger.error(message, e)
+    }
+
+    override val identity: String?
+        get() = logger.name
+
+}

+ 38 - 0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/internal/logging/Slf4jLogger.kt

@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019-2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+package net.mamoe.mirai.utils.internal.logging
+
+import net.mamoe.mirai.utils.MiraiLoggerPlatformBase
+import org.slf4j.Logger
+
+internal class Slf4jLogger(private val logger: Logger) : MiraiLoggerPlatformBase() {
+    override fun verbose0(message: String?, e: Throwable?) {
+        logger.trace(message, e)
+    }
+
+    override fun debug0(message: String?, e: Throwable?) {
+        logger.debug(message, e)
+    }
+
+    override fun info0(message: String?, e: Throwable?) {
+        logger.info(message, e)
+    }
+
+    override fun warning0(message: String?, e: Throwable?) {
+        logger.warn(message, e)
+    }
+
+    override fun error0(message: String?, e: Throwable?) {
+        logger.error(message, e)
+    }
+
+    override val identity: String?
+        get() = logger.name
+}