Commit 90185490 authored by Him188's avatar Him188

Implementations rearrangement

parent 2b0165d8
......@@ -21,12 +21,10 @@ package net.mamoe.mirai.message
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.event.subscribe
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.sendTo
import net.mamoe.mirai.utils.upload
import kotlin.jvm.JvmMultifileClass
......@@ -46,7 +44,7 @@ import kotlin.jvm.JvmSynthetic
* @see isContextIdenticalWith 判断语境是否相同
*/
@Suppress("DEPRECATION_ERROR")
public abstract class MessageEvent : @PlannedRemoval("1.2.0") ContactMessage(),
public abstract class MessageEvent : ContactMessage(),
BotEvent, MessageEventExtensions<User, Contact> {
/**
......@@ -167,112 +165,3 @@ internal expect interface MessageEventPlatformExtensions<out TSender : User, out
val message: MessageChain
val bot: Bot
}
/**
* 已废弃, 请使用 [MessageEvent]
*/
@PlannedRemoval("1.2.0")
@Deprecated(
message = "use MessageEvent",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
level = DeprecationLevel.HIDDEN
)
public abstract class MessagePacketBase<out TSender : User, out TSubject : Contact> : Packet, BotEvent,
AbstractEvent() {
abstract override val bot: Bot
public abstract val sender: User
public abstract val subject: Contact
public abstract val message: MessageChain
public abstract val time: Int
public abstract val source: OnlineMessageSource.Incoming
public abstract val senderName: String
}
@PlannedRemoval("1.2.0")
@Deprecated(
message = "Ambiguous name. Use MessageEvent instead",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
public abstract class MessagePacket : MessagePacketBase<User, Contact>(),
BotEvent, MessageEventExtensions<User, Contact> {
abstract override val bot: Bot
abstract override val sender: User
abstract override val subject: Contact
abstract override val message: MessageChain
abstract override val time: Int
abstract override val source: OnlineMessageSource.Incoming
abstract override val senderName: String
}
@PlannedRemoval("1.2.0")
@Deprecated(
message = "Ambiguous name. Use MessageEvent instead",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
public abstract class ContactMessage : MessagePacket(),
BotEvent, MessageEventExtensions<User, Contact> {
abstract override val bot: Bot
abstract override val sender: User
abstract override val subject: Contact
abstract override val message: MessageChain
abstract override val time: Int
abstract override val source: OnlineMessageSource.Incoming
abstract override val senderName: String
}
@PlannedRemoval("1.2.0")
@Deprecated(
message = "Ambiguous name. Use FriendMessageEvent instead",
replaceWith = ReplaceWith("FriendMessageEvent", "net.mamoe.mirai.message.FriendMessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
public abstract class FriendMessage : MessageEvent() {
abstract override val bot: Bot
abstract override val sender: Friend
abstract override val subject: Friend
abstract override val message: MessageChain
abstract override val time: Int
abstract override val source: OnlineMessageSource.Incoming.FromFriend
abstract override val senderName: String
}
@PlannedRemoval("1.2.0")
@Deprecated(
message = "Ambiguous name. Use GroupMessageEvent instead",
replaceWith = ReplaceWith("GroupMessageEvent", "net.mamoe.mirai.message.GroupMessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
public abstract class GroupMessage : MessageEvent() {
public abstract val group: Group
abstract override val bot: Bot
abstract override val sender: Member
abstract override val subject: Group
abstract override val message: MessageChain
abstract override val time: Int
abstract override val source: OnlineMessageSource.Incoming.FromGroup
abstract override val senderName: String
}
@PlannedRemoval("1.2.0")
@Deprecated(
message = "Ambiguous name. Use TempMessageEvent instead",
replaceWith = ReplaceWith("TempMessageEvent", "net.mamoe.mirai.message.TempMessageEvent"),
level = DeprecationLevel.HIDDEN
)
public abstract class TempMessage : MessageEvent() {
abstract override val bot: Bot
abstract override val sender: Member
abstract override val subject: Member
abstract override val message: MessageChain
abstract override val time: Int
abstract override val source: OnlineMessageSource.Incoming.FromTemp
public abstract val group: Group
abstract override val senderName: String
}
\ No newline at end of file
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress(
"EXPERIMENTAL_UNSIGNED_LITERALS",
"EXPERIMENTAL_API_USAGE",
"unused",
"DECLARATION_CANT_BE_INLINED", "UNCHECKED_CAST", "NOTHING_TO_INLINE"
)
@file:JvmMultifileClass
@file:JvmName("MessageEventKt")
package net.mamoe.mirai.message
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.OnlineMessageSource
import net.mamoe.mirai.qqandroid.network.Packet
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
/**
* 已废弃, 请使用 [MessageEvent]
*/
@Deprecated(
message = "use MessageEvent",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
level = DeprecationLevel.HIDDEN
)
public abstract class MessagePacketBase<out TSender : User, out TSubject : Contact> : Packet, BotEvent,
AbstractEvent() {
abstract override val bot: Bot
public abstract val sender: User
public abstract val subject: Contact
public abstract val message: MessageChain
public abstract val time: Int
public abstract val source: OnlineMessageSource.Incoming
public abstract val senderName: String
}
@Deprecated(
message = "Ambiguous name. Use MessageEvent instead",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
public abstract class MessagePacket : MessagePacketBase<User, Contact>(),
BotEvent, MessageEventExtensions<User, Contact> {
abstract override val bot: Bot
abstract override val sender: User
abstract override val subject: Contact
abstract override val message: MessageChain
abstract override val time: Int
abstract override val source: OnlineMessageSource.Incoming
abstract override val senderName: String
}
@Deprecated(
message = "Ambiguous name. Use MessageEvent instead",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
public abstract class ContactMessage : MessagePacket(),
BotEvent, MessageEventExtensions<User, Contact> {
abstract override val bot: Bot
abstract override val sender: User
abstract override val subject: Contact
abstract override val message: MessageChain
abstract override val time: Int
abstract override val source: OnlineMessageSource.Incoming
abstract override val senderName: String
}
@Deprecated(
message = "Ambiguous name. Use FriendMessageEvent instead",
replaceWith = ReplaceWith("FriendMessageEvent", "net.mamoe.mirai.message.FriendMessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
public abstract class FriendMessage : MessageEvent() {
abstract override val bot: Bot
abstract override val sender: Friend
abstract override val subject: Friend
abstract override val message: MessageChain
abstract override val time: Int
abstract override val source: OnlineMessageSource.Incoming.FromFriend
abstract override val senderName: String
}
@Deprecated(
message = "Ambiguous name. Use GroupMessageEvent instead",
replaceWith = ReplaceWith("GroupMessageEvent", "net.mamoe.mirai.message.GroupMessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
public abstract class GroupMessage : MessageEvent() {
public abstract val group: Group
abstract override val bot: Bot
abstract override val sender: Member
abstract override val subject: Group
abstract override val message: MessageChain
abstract override val time: Int
abstract override val source: OnlineMessageSource.Incoming.FromGroup
abstract override val senderName: String
}
@Deprecated(
message = "Ambiguous name. Use TempMessageEvent instead",
replaceWith = ReplaceWith("TempMessageEvent", "net.mamoe.mirai.message.TempMessageEvent"),
level = DeprecationLevel.HIDDEN
)
public abstract class TempMessage : MessageEvent() {
abstract override val bot: Bot
abstract override val sender: Member
abstract override val subject: Member
abstract override val message: MessageChain
abstract override val time: Int
abstract override val source: OnlineMessageSource.Incoming.FromTemp
public abstract val group: Group
abstract override val senderName: String
}
\ No newline at end of file
......@@ -14,15 +14,9 @@
package net.mamoe.mirai.event
import kotlinx.coroutines.*
import java.lang.reflect.Method
import net.mamoe.mirai.event.internal.registerEvent
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KClass
import kotlin.reflect.full.IllegalCallableAccessException
import kotlin.reflect.full.callSuspend
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.kotlinFunction
/**
* 标注一个函数为事件监听器.
......@@ -227,154 +221,13 @@ public fun <T> T.registerEvents(coroutineContext: CoroutineContext = EmptyCorout
* @see EventHandler 获取更多信息
*/
@JvmOverloads
public fun CoroutineScope.registerEvents(host: ListenerHost, coroutineContext: CoroutineContext = EmptyCoroutineContext) {
public fun CoroutineScope.registerEvents(
host: ListenerHost,
coroutineContext: CoroutineContext = EmptyCoroutineContext
) {
for (method in host.javaClass.declaredMethods) {
method.getAnnotation(EventHandler::class.java)?.let {
method.registerEvent(host, this, it, coroutineContext)
}
}
}
\ No newline at end of file
@Suppress("UNCHECKED_CAST")
private fun Method.registerEvent(
owner: Any,
scope: CoroutineScope,
annotation: EventHandler,
coroutineContext: CoroutineContext
): Listener<Event> {
this.isAccessible = true
val kotlinFunction = kotlin.runCatching { this.kotlinFunction }.getOrNull()
return if (kotlinFunction != null) {
// kotlin functions
val param = kotlinFunction.parameters
when (param.size) {
3 -> { // ownerClass, receiver, event
check(param[1].type == param[2].type) { "Illegal kotlin function ${kotlinFunction.name}. Receiver and param must have same type" }
check((param[1].type.classifier as? KClass<*>)?.isSubclassOf(Event::class) == true) {
"Illegal kotlin function ${kotlinFunction.name}. First param or receiver must be subclass of Event, but found ${param[1].type.classifier}"
}
}
2 -> { // ownerClass, event
check((param[1].type.classifier as? KClass<*>)?.isSubclassOf(Event::class) == true) {
"Illegal kotlin function ${kotlinFunction.name}. First param or receiver must be subclass of Event, but found ${param[1].type.classifier}"
}
}
else -> error("function ${kotlinFunction.name} must have one Event param")
}
lateinit var listener: Listener<*>
kotlin.runCatching {
kotlinFunction.isAccessible = true
}
suspend fun callFunction(event: Event): Any? {
try {
return when (param.size) {
3 -> {
if (kotlinFunction.isSuspend) {
kotlinFunction.callSuspend(owner, event, event)
} else withContext(Dispatchers.IO) { // for safety
kotlinFunction.call(owner, event, event)
}
}
2 -> {
if (kotlinFunction.isSuspend) {
kotlinFunction.callSuspend(owner, event)
} else withContext(Dispatchers.IO) { // for safety
kotlinFunction.call(owner, event)
}
}
else -> error("stub")
}
} catch (e: IllegalCallableAccessException) {
listener.completeExceptionally(e)
return ListeningStatus.STOPPED
}
}
require(!kotlinFunction.returnType.isMarkedNullable) {
"Kotlin event handlers cannot have nullable return type."
}
require(kotlinFunction.parameters.any { it.type.isMarkedNullable }) {
"Kotlin event handlers cannot have nullable parameter type."
}
when (kotlinFunction.returnType.classifier) {
Unit::class, Nothing::class -> {
scope.subscribeAlways(
param[1].type.classifier as KClass<out Event>,
priority = annotation.priority,
concurrency = annotation.concurrency,
coroutineContext = coroutineContext
) {
if (annotation.ignoreCancelled) {
if ((this as? CancellableEvent)?.isCancelled != true) {
callFunction(this)
}
} else callFunction(this)
}.also { listener = it }
}
ListeningStatus::class -> {
scope.subscribe(
param[1].type.classifier as KClass<out Event>,
priority = annotation.priority,
concurrency = annotation.concurrency,
coroutineContext = coroutineContext
) {
if (annotation.ignoreCancelled) {
if ((this as? CancellableEvent)?.isCancelled != true) {
callFunction(this) as ListeningStatus
} else ListeningStatus.LISTENING
} else callFunction(this) as ListeningStatus
}.also { listener = it }
}
else -> error("Illegal method return type. Required Void, Nothing or ListeningStatus, found ${kotlinFunction.returnType.classifier}")
}
} else {
// java methods
val paramType = this.parameters[0].type
check(this.parameterCount == 1 && Event::class.java.isAssignableFrom(paramType)) {
"Illegal method parameter. Required one exact Event subclass. found $paramType"
}
when (this.returnType) {
Void::class.java, Void.TYPE, Nothing::class.java -> {
scope.subscribeAlways(
paramType.kotlin as KClass<out Event>,
priority = annotation.priority,
concurrency = annotation.concurrency,
coroutineContext = coroutineContext
) {
if (annotation.ignoreCancelled) {
if ((this as? CancellableEvent)?.isCancelled != true) {
withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this)
}
}
} else withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this)
}
}
}
ListeningStatus::class.java -> {
scope.subscribe(
paramType.kotlin as KClass<out Event>,
priority = annotation.priority,
concurrency = annotation.concurrency,
coroutineContext = coroutineContext
) {
if (annotation.ignoreCancelled) {
if ((this as? CancellableEvent)?.isCancelled != true) {
withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this) as ListeningStatus
}
} else ListeningStatus.LISTENING
} else withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this) as ListeningStatus
}
}
}
else -> error("Illegal method return type. Required Void or ListeningStatus, but found ${this.returnType.canonicalName}")
}
}
}
\ No newline at end of file
......@@ -14,12 +14,18 @@ package net.mamoe.mirai.event.internal
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import net.mamoe.mirai.event.Event
import net.mamoe.mirai.event.Listener
import net.mamoe.mirai.event.ListeningStatus
import net.mamoe.mirai.event.*
import java.lang.reflect.Method
import java.util.function.Consumer
import java.util.function.Function
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.reflect.KClass
import kotlin.reflect.full.IllegalCallableAccessException
import kotlin.reflect.full.callSuspend
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.kotlinFunction
@Suppress("FunctionName")
internal fun <E : Event> Class<E>._subscribeEventForJaptOnly(
......@@ -41,3 +47,148 @@ internal fun <E : Event> Class<E>._subscribeEventForJaptOnly(scope: CoroutineSco
Listener.ConcurrencyKind.LOCKED
) { withContext(Dispatchers.IO) { onEvent.accept(it) }; ListeningStatus.LISTENING; })
}
@Suppress("UNCHECKED_CAST")
internal fun Method.registerEvent(
owner: Any,
scope: CoroutineScope,
annotation: EventHandler,
coroutineContext: CoroutineContext
): Listener<Event> {
this.isAccessible = true
val kotlinFunction = kotlin.runCatching { this.kotlinFunction }.getOrNull()
return if (kotlinFunction != null) {
// kotlin functions
val param = kotlinFunction.parameters
when (param.size) {
3 -> { // ownerClass, receiver, event
check(param[1].type == param[2].type) { "Illegal kotlin function ${kotlinFunction.name}. Receiver and param must have same type" }
check((param[1].type.classifier as? KClass<*>)?.isSubclassOf(Event::class) == true) {
"Illegal kotlin function ${kotlinFunction.name}. First param or receiver must be subclass of Event, but found ${param[1].type.classifier}"
}
}
2 -> { // ownerClass, event
check((param[1].type.classifier as? KClass<*>)?.isSubclassOf(Event::class) == true) {
"Illegal kotlin function ${kotlinFunction.name}. First param or receiver must be subclass of Event, but found ${param[1].type.classifier}"
}
}
else -> error("function ${kotlinFunction.name} must have one Event param")
}
lateinit var listener: Listener<*>
kotlin.runCatching {
kotlinFunction.isAccessible = true
}
suspend fun callFunction(event: Event): Any? {
try {
return when (param.size) {
3 -> {
if (kotlinFunction.isSuspend) {
kotlinFunction.callSuspend(owner, event, event)
} else withContext(Dispatchers.IO) { // for safety
kotlinFunction.call(owner, event, event)
}
}
2 -> {
if (kotlinFunction.isSuspend) {
kotlinFunction.callSuspend(owner, event)
} else withContext(Dispatchers.IO) { // for safety
kotlinFunction.call(owner, event)
}
}
else -> error("stub")
}
} catch (e: IllegalCallableAccessException) {
listener.completeExceptionally(e)
return ListeningStatus.STOPPED
}
}
require(!kotlinFunction.returnType.isMarkedNullable) {
"Kotlin event handlers cannot have nullable return type."
}
require(kotlinFunction.parameters.any { it.type.isMarkedNullable }) {
"Kotlin event handlers cannot have nullable parameter type."
}
when (kotlinFunction.returnType.classifier) {
Unit::class, Nothing::class -> {
scope.subscribeAlways(
param[1].type.classifier as KClass<out Event>,
priority = annotation.priority,
concurrency = annotation.concurrency,
coroutineContext = coroutineContext
) {
if (annotation.ignoreCancelled) {
if ((this as? CancellableEvent)?.isCancelled != true) {
callFunction(this)
}
} else callFunction(this)
}.also { listener = it }
}
ListeningStatus::class -> {
scope.subscribe(
param[1].type.classifier as KClass<out Event>,
priority = annotation.priority,
concurrency = annotation.concurrency,
coroutineContext = coroutineContext
) {
if (annotation.ignoreCancelled) {
if ((this as? CancellableEvent)?.isCancelled != true) {
callFunction(this) as ListeningStatus
} else ListeningStatus.LISTENING
} else callFunction(this) as ListeningStatus
}.also { listener = it }
}
else -> error("Illegal method return type. Required Void, Nothing or ListeningStatus, found ${kotlinFunction.returnType.classifier}")
}
} else {
// java methods
val paramType = this.parameters[0].type
check(this.parameterCount == 1 && Event::class.java.isAssignableFrom(paramType)) {
"Illegal method parameter. Required one exact Event subclass. found $paramType"
}
when (this.returnType) {
Void::class.java, Void.TYPE, Nothing::class.java -> {
scope.subscribeAlways(
paramType.kotlin as KClass<out Event>,
priority = annotation.priority,
concurrency = annotation.concurrency,
coroutineContext = coroutineContext
) {
if (annotation.ignoreCancelled) {
if ((this as? CancellableEvent)?.isCancelled != true) {
withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this)
}
}
} else withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this)
}
}
}
ListeningStatus::class.java -> {
scope.subscribe(
paramType.kotlin as KClass<out Event>,
priority = annotation.priority,
concurrency = annotation.concurrency,
coroutineContext = coroutineContext
) {
if (annotation.ignoreCancelled) {
if ((this as? CancellableEvent)?.isCancelled != true) {
withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this) as ListeningStatus
}
} else ListeningStatus.LISTENING
} else withContext(Dispatchers.IO) {
this@registerEvent.invoke(owner, this) as ListeningStatus
}
}
}
else -> error("Illegal method return type. Required Void or ListeningStatus, but found ${this.returnType.canonicalName}")
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment