Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mirai
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Mirai
Commits
9924d37e
Commit
9924d37e
authored
May 01, 2020
by
Him188
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Misc improvements
parent
20af1fc3
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
243 additions
and
159 deletions
+243
-159
mirai-core-qqandroid/src/jvmTest/kotlin/net/mamoe/mirai/qqandroid/utils/AtomicResizeCacheListTest.kt
.../mamoe/mirai/qqandroid/utils/AtomicResizeCacheListTest.kt
+2
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt
...core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt
+31
-26
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt
.../net.mamoe.mirai/event/internal/InternalEventListeners.kt
+52
-42
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt
...src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt
+140
-70
mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt
...re/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt
+18
-20
No files found.
mirai-core-qqandroid/src/jvmTest/kotlin/net/mamoe/mirai/qqandroid/utils/AtomicResizeCacheListTest.kt
View file @
9924d37e
...
@@ -15,6 +15,7 @@ import kotlin.test.Test
...
@@ -15,6 +15,7 @@ import kotlin.test.Test
import
kotlin.test.assertFalse
import
kotlin.test.assertFalse
import
kotlin.test.assertTrue
import
kotlin.test.assertTrue
/*
internal class AtomicResizeCacheListTest {
internal class AtomicResizeCacheListTest {
@Test
@Test
...
@@ -38,4 +39,4 @@ internal class AtomicResizeCacheListTest {
...
@@ -38,4 +39,4 @@ internal class AtomicResizeCacheListTest {
assertTrue { list.ensureNoDuplication(1) }
assertTrue { list.ensureNoDuplication(1) }
}
}
}
}
}
}*/
\ No newline at end of file
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt
View file @
9924d37e
...
@@ -13,10 +13,12 @@ package net.mamoe.mirai.event
...
@@ -13,10 +13,12 @@ package net.mamoe.mirai.event
import
kotlinx.atomicfu.atomic
import
kotlinx.atomicfu.atomic
import
net.mamoe.mirai.event.internal.broadcastInternal
import
net.mamoe.mirai.event.internal.broadcastInternal
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.PlannedRemoval
import
net.mamoe.mirai.utils.PlannedRemoval
import
net.mamoe.mirai.utils.SinceMirai
import
net.mamoe.mirai.utils.SinceMirai
import
kotlin.jvm.JvmSynthetic
import
kotlin.jvm.JvmSynthetic
import
kotlin.jvm.Volatile
/**
/**
* 可被监听的类, 可以是任何 class 或 object.
* 可被监听的类, 可以是任何 class 或 object.
...
@@ -34,6 +36,20 @@ import kotlin.jvm.JvmSynthetic
...
@@ -34,6 +36,20 @@ import kotlin.jvm.JvmSynthetic
* @see [subscribe] 监听事件
* @see [subscribe] 监听事件
*/
*/
interface
Event
{
interface
Event
{
/**
* 事件是否已被拦截.
*
* 所有事件都可以被拦截, 拦截后低优先级的监听器将不会处理到这个事件.
*/
@SinceMirai
(
"1.0.0"
)
val
isIntercepted
:
Boolean
/**
* 拦截这个事件
*/
@SinceMirai
(
"1.0.0"
)
fun
intercept
()
@Deprecated
(
@Deprecated
(
"""
"""
...
@@ -47,6 +63,8 @@ interface Event {
...
@@ -47,6 +63,8 @@ interface Event {
/**
/**
* 所有实现了 [Event] 接口的类都应该继承的父类.
* 所有实现了 [Event] 接口的类都应该继承的父类.
*
* 在使用事件时应使用类型 [Event]. 在实现自定义事件时应继承 [AbstractEvent].
*/
*/
@SinceMirai
(
"1.0.0"
)
@SinceMirai
(
"1.0.0"
)
abstract
class
AbstractEvent
:
Event
{
abstract
class
AbstractEvent
:
Event
{
...
@@ -56,40 +74,20 @@ abstract class AbstractEvent : Event {
...
@@ -56,40 +74,20 @@ abstract class AbstractEvent : Event {
final
override
val
DoNotImplementThisClassButExtendAbstractEvent
:
Nothing
final
override
val
DoNotImplementThisClassButExtendAbstractEvent
:
Nothing
get
()
=
throw
Error
(
"Shouldn't be reached"
)
get
()
=
throw
Error
(
"Shouldn't be reached"
)
@Volatile
private
var
_intercepted
=
false
private
var
_intercepted
=
false
private
val
_cancelled
=
atomic
(
false
)
private
val
_cancelled
=
atomic
(
false
)
/**
// 实现 Event
* 事件是否已被拦截.
override
val
isIntercepted
:
Boolean
get
()
=
_intercepted
*
* 所有事件都可以被拦截, 拦截后低优先级的监听器将不会处理到这个事件.
*/
@SinceMirai
(
"1.0.0"
)
val
isIntercepted
:
Boolean
get
()
=
_intercepted
/**
* 拦截这个事件.
* 重复拦截时不会抛出异常.
*/
@SinceMirai
(
"1.0.0"
)
@SinceMirai
(
"1.0.0"
)
fun
intercept
()
{
override
fun
intercept
()
{
_intercepted
=
true
_intercepted
=
true
}
}
// 实现 CancellableEvent
/**
* 事件是否已取消.
*
* 事件需实现 [CancellableEvent] 接口才可以被取消,
* 否则此属性固定返回 false.
*/
val
isCancelled
:
Boolean
get
()
=
_cancelled
.
value
val
isCancelled
:
Boolean
get
()
=
_cancelled
.
value
/**
* 取消这个事件.
* 重复取消时不会抛出异常.
*/
fun
cancel
()
{
fun
cancel
()
{
check
(
this
is
CancellableEvent
)
{
check
(
this
is
CancellableEvent
)
{
"Event $this is not cancellable"
"Event $this is not cancellable"
...
@@ -103,12 +101,18 @@ abstract class AbstractEvent : Event {
...
@@ -103,12 +101,18 @@ abstract class AbstractEvent : Event {
*/
*/
interface
CancellableEvent
:
Event
{
interface
CancellableEvent
:
Event
{
/**
/**
* 事件是否已取消.
* 事件是否已被取消.
*
* 事件需实现 [CancellableEvent] 接口才可以被取消,
* 否则此属性固定返回 false.
*/
*/
val
isCancelled
:
Boolean
val
isCancelled
:
Boolean
/**
/**
* 取消这个事件.
* 取消这个事件.
* 事件需实现 [CancellableEvent] 接口才可以被取消
*
* @throws IllegalStateException 当事件未实现接口 [CancellableEvent] 时抛出
*/
*/
fun
cancel
()
fun
cancel
()
}
}
...
@@ -128,6 +132,7 @@ suspend fun <E : Event> E.broadcast(): E = apply {
...
@@ -128,6 +132,7 @@ suspend fun <E : Event> E.broadcast(): E = apply {
* 设置为 `true` 以关闭事件.
* 设置为 `true` 以关闭事件.
* 所有的 `subscribe` 都能正常添加到监听器列表, 但所有的广播都会直接返回.
* 所有的 `subscribe` 都能正常添加到监听器列表, 但所有的广播都会直接返回.
*/
*/
@MiraiExperimentalAPI
var
EventDisabled
=
false
var
EventDisabled
=
false
/**
/**
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt
View file @
9924d37e
...
@@ -14,14 +14,17 @@ import kotlinx.coroutines.*
...
@@ -14,14 +14,17 @@ import kotlinx.coroutines.*
import
kotlinx.coroutines.sync.Mutex
import
kotlinx.coroutines.sync.Mutex
import
kotlinx.coroutines.sync.withLock
import
kotlinx.coroutines.sync.withLock
import
net.mamoe.mirai.event.*
import
net.mamoe.mirai.event.*
import
net.mamoe.mirai.utils.*
import
net.mamoe.mirai.event.events.BotEvent
import
net.mamoe.mirai.utils.LockFreeLinkedList
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.MiraiLogger
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.coroutineContext
import
kotlin.coroutines.coroutineContext
import
kotlin.jvm.JvmField
import
kotlin.jvm.JvmField
import
kotlin.reflect.KClass
import
kotlin.reflect.KClass
@PublishedApi
internal
fun
<
L
:
Listener
<
E
>,
E
:
Event
>
KClass
<
out
E
>.
subscribeInternal
(
listener
:
L
):
L
{
internal
fun
<
L
:
Listener
<
E
>,
E
:
Event
>
KClass
<
out
E
>.
subscribeInternal
(
listener
:
L
):
L
{
with
(
GlobalEventListeners
[
listener
.
priority
])
{
with
(
GlobalEventListeners
[
listener
.
priority
])
{
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
...
@@ -37,7 +40,6 @@ internal fun <L : Listener<E>, E : Event> KClass<out E>.subscribeInternal(listen
...
@@ -37,7 +40,6 @@ internal fun <L : Listener<E>, E : Event> KClass<out E>.subscribeInternal(listen
}
}
@PublishedApi
@Suppress
(
"FunctionName"
)
@Suppress
(
"FunctionName"
)
internal
fun
<
E
:
Event
>
CoroutineScope
.
Handler
(
internal
fun
<
E
:
Event
>
CoroutineScope
.
Handler
(
coroutineContext
:
CoroutineContext
,
coroutineContext
:
CoroutineContext
,
...
@@ -53,9 +55,7 @@ internal fun <E : Event> CoroutineScope.Handler(
...
@@ -53,9 +55,7 @@ internal fun <E : Event> CoroutineScope.Handler(
/**
/**
* 事件处理器.
* 事件处理器.
*/
*/
@PublishedApi
internal
class
Handler
<
in
E
:
Event
>
internal
constructor
(
internal
class
Handler
<
in
E
:
Event
>
@PublishedApi
internal
constructor
(
parentJob
:
Job
?,
parentJob
:
Job
?,
subscriberContext
:
CoroutineContext
,
subscriberContext
:
CoroutineContext
,
@JvmField
val
handler
:
suspend
(
E
)
->
ListeningStatus
,
@JvmField
val
handler
:
suspend
(
E
)
->
ListeningStatus
,
...
@@ -65,8 +65,6 @@ internal class Handler<in E : Event>
...
@@ -65,8 +65,6 @@ internal class Handler<in E : Event>
private
val
subscriberContext
:
CoroutineContext
=
subscriberContext
+
this
// override Job.
private
val
subscriberContext
:
CoroutineContext
=
subscriberContext
+
this
// override Job.
@MiraiInternalAPI
val
lock
:
Mutex
?
=
when
(
concurrencyKind
)
{
val
lock
:
Mutex
?
=
when
(
concurrencyKind
)
{
Listener
.
ConcurrencyKind
.
LOCKED
->
Mutex
()
Listener
.
ConcurrencyKind
.
LOCKED
->
Mutex
()
else
->
null
else
->
null
...
@@ -84,10 +82,11 @@ internal class Handler<in E : Event>
...
@@ -84,10 +82,11 @@ internal class Handler<in E : Event>
?:
coroutineContext
[
CoroutineExceptionHandler
]
?.
handleException
(
subscriberContext
,
e
)
?:
coroutineContext
[
CoroutineExceptionHandler
]
?.
handleException
(
subscriberContext
,
e
)
?:
kotlin
.
run
{
?:
kotlin
.
run
{
@Suppress
(
"DEPRECATION"
)
@Suppress
(
"DEPRECATION"
)
MiraiLogger
.
warning
(
(
if
(
event
is
BotEvent
)
event
.
bot
.
logger
else
MiraiLogger
)
"""Event processing: An exception occurred but no CoroutineExceptionHandler found,
.
warning
(
"""Event processing: An exception occurred but no CoroutineExceptionHandler found,
either in coroutineContext from Handler job, or in subscriberContext"""
.
trimIndent
(),
e
either in coroutineContext from Handler job, or in subscriberContext"""
.
trimIndent
(),
e
)
)
}
}
// this.complete() // do not `completeExceptionally`, otherwise parentJob will fai`l.
// this.complete() // do not `completeExceptionally`, otherwise parentJob will fai`l.
// ListeningStatus.STOPPED
// ListeningStatus.STOPPED
...
@@ -102,6 +101,7 @@ internal class ListenerNode(
...
@@ -102,6 +101,7 @@ internal class ListenerNode(
val
listener
:
Listener
<
Event
>,
val
listener
:
Listener
<
Event
>,
val
owner
:
KClass
<
out
Event
>
val
owner
:
KClass
<
out
Event
>
)
)
internal
expect
object
GlobalEventListeners
{
internal
expect
object
GlobalEventListeners
{
operator
fun
get
(
priority
:
Listener
.
EventPriority
):
LockFreeLinkedList
<
ListenerNode
>
operator
fun
get
(
priority
:
Listener
.
EventPriority
):
LockFreeLinkedList
<
ListenerNode
>
}
}
...
@@ -116,51 +116,61 @@ internal expect class MiraiAtomicBoolean(initial: Boolean) {
...
@@ -116,51 +116,61 @@ internal expect class MiraiAtomicBoolean(initial: Boolean) {
// inline: NO extra Continuation
// inline: NO extra Continuation
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
internal
suspend
inline
fun
Event
.
broadcastInternal
()
=
coroutineScope
{
internal
suspend
inline
fun
Event
.
broadcastInternal
()
{
if
(
EventDisabled
)
return
@
coroutineScope
@OptIn
(
MiraiExperimentalAPI
::
class
)
if
(
EventDisabled
)
return
callAndRemoveIfRequired
(
this
@
broadcastInternal
as
?
AbstractEvent
?:
error
(
"Events must extends AbstractEvent"
))
callAndRemoveIfRequired
(
this
@
broadcastInternal
as
?
AbstractEvent
?:
error
(
"Events must extends AbstractEvent"
))
}
}
@Suppress
(
"DuplicatedCode"
)
@OptIn
(
MiraiInternalAPI
::
class
)
@OptIn
(
MiraiInternalAPI
::
class
)
private
suspend
fun
<
E
:
AbstractEvent
>
callAndRemoveIfRequired
(
internal
suspend
fun
<
E
:
AbstractEvent
>
callAndRemoveIfRequired
(
event
:
E
event
:
E
)
{
)
{
coroutineScope
{
for
(
p
in
Listener
.
EventPriority
.
valuesExceptMonitor
)
{
for
(
p
in
Listener
.
EventPriority
.
values
())
{
GlobalEventListeners
[
p
].
forEachNode
{
eventNode
->
GlobalEventListeners
[
p
].
forEachNode
{
eventNode
->
if
(
event
.
isIntercepted
)
{
if
(
event
.
isIntercepted
)
{
return
return
@
coroutineScope
}
val
node
=
eventNode
.
nodeValue
if
(!
node
.
owner
.
isInstance
(
event
))
return
@
forEachNode
val
listener
=
node
.
listener
when
(
listener
.
concurrencyKind
)
{
Listener
.
ConcurrencyKind
.
LOCKED
->
{
(
listener
as
Handler
).
lock
!!
.
withLock
{
if
(
listener
.
onEvent
(
event
)
==
ListeningStatus
.
STOPPED
)
{
removeNode
(
eventNode
)
}
}
}
Listener
.
ConcurrencyKind
.
CONCURRENT
->
{
if
(
listener
.
onEvent
(
event
)
==
ListeningStatus
.
STOPPED
)
{
removeNode
(
eventNode
)
}
}
}
val
node
=
eventNode
.
nodeValue
}
if
(!
node
.
owner
.
isInstance
(
event
))
return
@
forEachNode
}
val
listener
=
node
.
listener
}
coroutineScope
{
GlobalEventListeners
[
Listener
.
EventPriority
.
MONITOR
].
forEachNode
{
eventNode
->
if
(
event
.
isIntercepted
)
{
return
@
coroutineScope
}
val
node
=
eventNode
.
nodeValue
if
(!
node
.
owner
.
isInstance
(
event
))
return
@
forEachNode
val
listener
=
node
.
listener
launch
{
when
(
listener
.
concurrencyKind
)
{
when
(
listener
.
concurrencyKind
)
{
Listener
.
ConcurrencyKind
.
LOCKED
->
{
Listener
.
ConcurrencyKind
.
LOCKED
->
{
(
listener
as
Handler
).
lock
!!
.
withLock
{
(
listener
as
Handler
).
lock
!!
.
withLock
{
kotlin
.
runCatching
{
if
(
listener
.
onEvent
(
event
)
==
ListeningStatus
.
STOPPED
)
{
when
(
listener
.
onEvent
(
event
))
{
removeNode
(
eventNode
)
ListeningStatus
.
STOPPED
->
{
removeNode
(
eventNode
)
}
else
->
{
}
}
}.
onFailure
{
// TODO("Exception catching")
}
}
}
}
}
}
Listener
.
ConcurrencyKind
.
CONCURRENT
->
{
Listener
.
ConcurrencyKind
.
CONCURRENT
->
{
kotlin
.
runCatching
{
if
(
listener
.
onEvent
(
event
)
==
ListeningStatus
.
STOPPED
)
{
when
(
listener
.
onEvent
(
event
))
{
removeNode
(
eventNode
)
ListeningStatus
.
STOPPED
->
{
removeNode
(
eventNode
)
}
else
->
{
}
}
}.
onFailure
{
// TODO("Exception catching")
}
}
}
}
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/subscriber.kt
View file @
9924d37e
...
@@ -7,22 +7,28 @@
...
@@ -7,22 +7,28 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
*/
@
file
:
Suppress
(
"unused"
)
package
net.mamoe.mirai.event
package
net.mamoe.mirai.event
import
kotlinx.coroutines.CompletableJob
import
kotlinx.coroutines.CompletableJob
import
kotlinx.coroutines.CoroutineExceptionHandler
import
kotlinx.coroutines.CoroutineExceptionHandler
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.
GlobalScope
import
kotlinx.coroutines.
Job
import
kotlinx.coroutines.sync.Mutex
import
kotlinx.coroutines.sync.Mutex
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.event.Listener.EventPriority.*
import
net.mamoe.mirai.event.events.BotEvent
import
net.mamoe.mirai.event.events.BotEvent
import
net.mamoe.mirai.event.internal.Handler
import
net.mamoe.mirai.event.internal.Handler
import
net.mamoe.mirai.event.internal.subscribeInternal
import
net.mamoe.mirai.event.internal.subscribeInternal
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.MiraiLogger
import
net.mamoe.mirai.utils.PlannedRemoval
import
net.mamoe.mirai.utils.SinceMirai
import
net.mamoe.mirai.utils.SinceMirai
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.EmptyCoroutineContext
import
kotlin.coroutines.EmptyCoroutineContext
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmStatic
import
kotlin.jvm.JvmSynthetic
import
kotlin.jvm.JvmSynthetic
import
kotlin.reflect.KClass
import
kotlin.reflect.KClass
...
@@ -40,7 +46,12 @@ enum class ListeningStatus {
...
@@ -40,7 +46,12 @@ enum class ListeningStatus {
LISTENING
,
LISTENING
,
/**
/**
* 表示已停止
* 表示已停止.
*
* - 若监听器使用 [Listener.ConcurrencyKind.LOCKED],
* 在这之后监听器将会被从监听器列表中删除, 因此不再能接收到事件.
* - 若使用 [Listener.ConcurrencyKind.CONCURRENT],
* 在这之后无法保证立即停止监听.
*/
*/
STOPPED
STOPPED
}
}
...
@@ -70,15 +81,45 @@ interface Listener<in E : Event> : CompletableJob {
...
@@ -70,15 +81,45 @@ interface Listener<in E : Event> : CompletableJob {
*/
*/
val
concurrencyKind
:
ConcurrencyKind
val
concurrencyKind
:
ConcurrencyKind
/**
* 事件优先级.
*
* 在广播时, 事件监听器的调用顺序为 (从左到右):
* `[HIGHEST]` -> `[HIGH]` -> `[NORMAL]` -> `[LOW]` -> `[LOWEST]` -> `[MONITOR]`
*
* - 使用 [MONITOR] 优先级的监听器将会被**并行**调用.
* - 使用其他优先级的监听器都将会**按顺序**调用.
* 因此一个监听器的挂起可以阻塞事件处理过程而导致低优先级的监听器较晚处理.
*/
@SinceMirai
(
"1.0.0"
)
enum
class
EventPriority
{
enum
class
EventPriority
{
MONITOR
,
HIGHEST
,
HIGH
,
NORMAL
,
LOW
,
LOWEST
HIGHEST
,
HIGH
,
NORMAL
,
LOW
,
LOWEST
,
/**
* 最低的优先级.
*
* 只监听事件而不拦截事件的监听器应使用此监听器.
*/
MONITOR
;
companion
object
{
@JvmStatic
internal
val
valuesExceptMonitor
:
Array
<
EventPriority
>
=
arrayOf
(
HIGHEST
,
HIGH
,
NORMAL
,
LOW
,
LOWEST
)
}
}
}
val
priority
:
EventPriority
get
()
=
EventPriority
.
NORMAL
/**
* 事件优先级
* @see [EventPriority]
*/
val
priority
:
EventPriority
get
()
=
NORMAL
/**
* 这个方法将会调用 [subscribe] 时提供的参数 `noinline handler: suspend E.(E) -> ListeningStatus`.
* 并捕捉其异常.
*/
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
}
}
// region 顶层方法 创建当前 coroutineContext 下的子 Job
// region 顶层方法 创建当前 coroutineContext 下的子 Job
...
@@ -87,50 +128,59 @@ interface Listener<in E : Event> : CompletableJob {
...
@@ -87,50 +128,59 @@ interface Listener<in E : Event> : CompletableJob {
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行.
* 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行.
*
*
* 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听.
* 或 [Listener.complete] 后结束.
*
* 这个函数返回 [Listener], 它是一个 [CompletableJob]. 请注意它除非被 [Listener.complete] 或 [Listener.cancel], 则不会完成.
* 例:
* ```kotlin
* runBlocking { // this: CoroutineScope
* subscribe<Event> { /* 一些处理 */
}
// 返回 Listener, 即 CompletableJob
*
}
*
foo
()
*
```
*
`runBlocking`
不会结束
,
也就是下一行
`foo
()
`
不会被执行
.
直到监听时创建的
`Listener`
被停止
.
*
*
* ### 创建监听
*
*
* #### 单个 [Bot] 的事件监听
* 要创建一个仅在某个机器人在线时的监听, 请在 [Bot] 下调用本函数 (因为 [Bot] 也实现 [CoroutineScope]).
* 要创建一个仅在某个机器人在线时的监听, 请在 [Bot] 下调用本函数 (因为 [Bot] 也实现 [CoroutineScope]).
* 这种方式创建的监听会自动筛选 [Bot].
* 这种方式创建的监听会自动筛选 [Bot].
*
``
`
kotlin
* ```
* bot1.subscribe<BotEvent> { /* 只会处理来自 bot1 的事件 */
}
* bot1.subscribe<BotEvent> { /* 只会处理来自 bot1 的事件 */
}
*
```
*
```
*
*
*
*
####
全局范围监听
*
要创建一个全局都存在的监听(不推荐)
,
即守护协程
,
请在
[
GlobalScope
]
下
调用本函数
:
*
要创建一个全局都存在的监听(不推荐)
,
请使用除
[
Bot
]
外的任意
[
协程作用域
][
CoroutineScope
]
调用本函数
:
*
``
`
kotlin
*
```
*
GlobalScope
.
subscribe
<
Event
>
{
/* 会收到来自全部 Bot 的事件和与 Bot 不相关的事件 */
}
*
GlobalScope
.
subscribe
<
Event
>
{
/* 会收到来自全部 Bot 的事件和与 Bot 不相关的事件 */
}
*
```
*
```
*
*
*
*
*
###
异常处理
*
事件处理时的
[
CoroutineContext
]
为调用本函数时的
[
receiver
][
this
]
的
[
CoroutineScope
.
coroutineContext
].
*
事件处理时的
[
CoroutineContext
]
为调用本函数时的
[
receiver
][
this
]
的
[
CoroutineScope
.
coroutineContext
].
*
因此
:
*
因此
:
*
-
事件处理时抛出的异常将会在
[
this
]
的
[
CoroutineExceptionHandler
]
中处理
*
-
当参数
[
handler
]
处理抛出异常时
,
将会按如下顺序寻找
[
CoroutineExceptionHandler
]
处理异常
:
*
若
[
this
]
没有
[
CoroutineExceptionHandler
],
则在事件广播方的
[
CoroutineExceptionHandler
]
处理
*
1
.
参数
[
coroutineContext
]
*
若均找不到
,
则会触发
logger
warning
.
*
2
.
接收者
[
this
]
的
[
CoroutineScope
.
coroutineContext
]
*
3
.
[
Event
.
broadcast
]
调用者的
[
coroutineContext
]
*
4
.
若事件为
[
BotEvent
],
则从
[
BotEvent
.
bot
]
获取到
[
Bot
],
进而在
[
Bot
.
coroutineContext
]
中寻找
*
5
.
若以上四个步骤均无法获取
[
CoroutineExceptionHandler
],
则使用
[
MiraiLogger
.
Companion
]
通过日志记录
.
但这种情况理论上不应发生
.
*
-
事件处理时抛出异常不会停止监听器
.
*
-
事件处理时抛出异常不会停止监听器
.
*
-
建议在事件处理中
(
即
[
handler
]
里
)
处理异常
,
*
-
建议在事件处理中
(
即
[
handler
]
里
)
处理异常
,
*
或在
[
this
]
的
[
CoroutineScope
.
coroutineContext
]
中添加
[
CoroutineExceptionHandler
].
*
或在参数
[
coroutineContext
]
中添加
[
CoroutineExceptionHandler
].
*
*
*
###
停止监听
*
当
[
handler
]
返回
[
ListeningStatus
.
STOPPED
]
时停止监听
.
*
或
[
Listener
.
complete
]
后结束
.
*
*
这个函数返回
[
Listener
],
它是一个
[
CompletableJob
].
它会成为
[
CoroutineScope
]
的一个
[
子任务
][
Job
]
*
例
:
*
```
*
runBlocking
{
// this: CoroutineScope
*
subscribe
<
Event
>
{
/* 一些处理 */
}
// 返回 Listener, 即 CompletableJob
*
}
*
foo
()
*
```
*
`runBlocking`
不会结束
,
也就是下一行
`foo
()
`
不会被执行
.
直到监听时创建的
`Listener`
被停止
.
*
*
*
*
*
**
注意
:**
事件处理是
`suspend`
的
,
请规范处理
JVM
阻塞方法
.
*
*
*
@
param
coroutineContext
给事件监听协程的额外的
[
CoroutineContext
].
*
@
param
coroutineContext
给事件监听协程的额外的
[
CoroutineContext
].
*
@
param
concurrency
并发类型
.
查看
[
Listener
.
ConcurrencyKind
]
*
@
param
concurrency
并发类型
.
查看
[
Listener
.
ConcurrencyKind
]
*
@
param
priority
监听优先级,优先级越高越先执行
*
@
param
priority
监听优先级,优先级越高越先执行
*
@
param
handler
事件处理器
.
在接收到事件时会调用这个处理器
.
其返回值意义参考
[
ListeningStatus
].
其异常处理参考上文
*
*
*
@
see
syncFromEvent
监听一个事件
,
并尝试从这个事件中获取一个值
.
*
@
see
syncFromEvent
挂起当前协程
,
监听一个事件
,
并尝试从这个事件中
**
同步
**
一个值
*
@
see
asyncFromEvent
异步监听一个事件
,
并尝试从这个事件中获取一个值
.
*
@
see
asyncFromEvent
异步监听一个事件
,
并尝试从这个事件中获取一个值
.
*
*
*
@
see
selectMessages
以
`when`
的语法
'选择'
即将到来的一条消息
.
*
@
see
selectMessages
以
`when`
的语法
'选择'
即将到来的一条消息
.
...
@@ -142,15 +192,18 @@ interface Listener<in E : Event> : CompletableJob {
...
@@ -142,15 +192,18 @@ interface Listener<in E : Event> : CompletableJob {
*
@
see
subscribeMessages
监听消息
DSL
*
@
see
subscribeMessages
监听消息
DSL
*
@
see
subscribeGroupMessages
监听群消息
DSL
*
@
see
subscribeGroupMessages
监听群消息
DSL
*
@
see
subscribeFriendMessages
监听好友消息
DSL
*
@
see
subscribeFriendMessages
监听好友消息
DSL
*
@
see
subscribeTempMessages
监听临时会话消息
DSL
*/
*/
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribe
(
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribe
(
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
noinline
handler
:
suspend
E
.(
E
)
->
ListeningStatus
noinline
handler
:
suspend
E
.(
E
)
->
ListeningStatus
):
Listener
<
E
>
=
subscribe
(
E
::
class
,
coroutineContext
,
concurrency
,
priority
,
handler
)
):
Listener
<
E
>
=
subscribe
(
E
::
class
,
coroutineContext
,
concurrency
,
priority
,
handler
)
/**
/**
* 与 [subscribe] 的区别是接受 [eventClass] 参数, 而不使用 `reified` 泛型
*
* @see CoroutineScope.subscribe
* @see CoroutineScope.subscribe
*/
*/
@SinceMirai
(
"0.38.0"
)
@SinceMirai
(
"0.38.0"
)
...
@@ -158,7 +211,7 @@ fun <E : Event> CoroutineScope.subscribe(
...
@@ -158,7 +211,7 @@ fun <E : Event> CoroutineScope.subscribe(
eventClass
:
KClass
<
E
>,
eventClass
:
KClass
<
E
>,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
handler
:
suspend
E
.(
E
)
->
ListeningStatus
handler
:
suspend
E
.(
E
)
->
ListeningStatus
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
Handler
(
coroutineContext
,
concurrency
,
priority
)
{
it
.
handler
(
it
);
})
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
Handler
(
coroutineContext
,
concurrency
,
priority
)
{
it
.
handler
(
it
);
})
...
@@ -167,7 +220,7 @@ fun <E : Event> CoroutineScope.subscribe(
...
@@ -167,7 +220,7 @@ fun <E : Event> CoroutineScope.subscribe(
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行.
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行.
*
*
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [
Bot
] 被关闭后事件监听会被 [取消][Listener.cancel].
* [
CoroutineScope
] 被关闭后事件监听会被 [取消][Listener.cancel].
*
*
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @param priority 处理优先级, 优先级高的先执行
* @param priority 处理优先级, 优先级高的先执行
...
@@ -177,7 +230,7 @@ fun <E : Event> CoroutineScope.subscribe(
...
@@ -177,7 +230,7 @@ fun <E : Event> CoroutineScope.subscribe(
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribeAlways
(
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribeAlways
(
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
noinline
listener
:
suspend
E
.(
E
)
->
Unit
noinline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
subscribeAlways
(
E
::
class
,
coroutineContext
,
concurrency
,
priority
,
listener
)
):
Listener
<
E
>
=
subscribeAlways
(
E
::
class
,
coroutineContext
,
concurrency
,
priority
,
listener
)
...
@@ -190,7 +243,7 @@ fun <E : Event> CoroutineScope.subscribeAlways(
...
@@ -190,7 +243,7 @@ fun <E : Event> CoroutineScope.subscribeAlways(
eventClass
:
KClass
<
E
>,
eventClass
:
KClass
<
E
>,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
listener
:
suspend
E
.(
E
)
->
Unit
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
Handler
(
coroutineContext
,
concurrency
,
priority
)
{
it
.
listener
(
it
);
ListeningStatus
.
LISTENING
}
Handler
(
coroutineContext
,
concurrency
,
priority
)
{
it
.
listener
(
it
);
ListeningStatus
.
LISTENING
}
...
@@ -201,7 +254,7 @@ fun <E : Event> CoroutineScope.subscribeAlways(
...
@@ -201,7 +254,7 @@ fun <E : Event> CoroutineScope.subscribeAlways(
* 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行.
* 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行.
*
*
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [
Bot
] 被关闭后事件监听会被 [取消][Listener.cancel].
* [
CoroutineScope
] 被关闭后事件监听会被 [取消][Listener.cancel].
*
*
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @param priority 处理优先级, 优先级高的先执行
* @param priority 处理优先级, 优先级高的先执行
...
@@ -211,7 +264,7 @@ fun <E : Event> CoroutineScope.subscribeAlways(
...
@@ -211,7 +264,7 @@ fun <E : Event> CoroutineScope.subscribeAlways(
@JvmSynthetic
@JvmSynthetic
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribeOnce
(
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribeOnce
(
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
noinline
listener
:
suspend
E
.(
E
)
->
Unit
noinline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
subscribeOnce
(
E
::
class
,
coroutineContext
,
priority
,
listener
)
):
Listener
<
E
>
=
subscribeOnce
(
E
::
class
,
coroutineContext
,
priority
,
listener
)
...
@@ -222,7 +275,7 @@ inline fun <reified E : Event> CoroutineScope.subscribeOnce(
...
@@ -222,7 +275,7 @@ inline fun <reified E : Event> CoroutineScope.subscribeOnce(
fun
<
E
:
Event
>
CoroutineScope
.
subscribeOnce
(
fun
<
E
:
Event
>
CoroutineScope
.
subscribeOnce
(
eventClass
:
KClass
<
E
>,
eventClass
:
KClass
<
E
>,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
listener
:
suspend
E
.(
E
)
->
Unit
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
Handler
(
coroutineContext
,
Listener
.
ConcurrencyKind
.
LOCKED
,
priority
)
{
it
.
listener
(
it
);
ListeningStatus
.
STOPPED
}
Handler
(
coroutineContext
,
Listener
.
ConcurrencyKind
.
LOCKED
,
priority
)
{
it
.
listener
(
it
);
ListeningStatus
.
STOPPED
}
...
@@ -234,17 +287,10 @@ fun <E : Event> CoroutineScope.subscribeOnce(
...
@@ -234,17 +287,10 @@ fun <E : Event> CoroutineScope.subscribeOnce(
/**
/**
* 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行,
* [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
* 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听
*
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
*
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @param priority 事件优先级, 优先级高的先处理
*
*
* @see subscribe 获取更多说明
* @see
CoroutineScope.
subscribe 获取更多说明
*/
*/
@JvmSynthetic
@JvmSynthetic
@JvmName
(
"subscribeAlwaysForBot"
)
@JvmName
(
"subscribeAlwaysForBot"
)
...
@@ -252,11 +298,14 @@ fun <E : Event> CoroutineScope.subscribeOnce(
...
@@ -252,11 +298,14 @@ fun <E : Event> CoroutineScope.subscribeOnce(
inline
fun
<
reified
E
:
BotEvent
>
Bot
.
subscribe
(
inline
fun
<
reified
E
:
BotEvent
>
Bot
.
subscribe
(
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
noinline
handler
:
suspend
E
.(
E
)
->
ListeningStatus
noinline
handler
:
suspend
E
.(
E
)
->
ListeningStatus
):
Listener
<
E
>
=
this
.
subscribe
(
E
::
class
,
coroutineContext
,
concurrency
,
priority
,
handler
)
):
Listener
<
E
>
=
this
.
subscribe
(
E
::
class
,
coroutineContext
,
concurrency
,
priority
,
handler
)
/**
/**
* **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
*
* @see Bot.subscribe
* @see Bot.subscribe
*/
*/
@SinceMirai
(
"0.38.0"
)
@SinceMirai
(
"0.38.0"
)
...
@@ -264,7 +313,7 @@ fun <E : BotEvent> Bot.subscribe(
...
@@ -264,7 +313,7 @@ fun <E : BotEvent> Bot.subscribe(
eventClass
:
KClass
<
E
>,
eventClass
:
KClass
<
E
>,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
LOCKED
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
handler
:
suspend
E
.(
E
)
->
ListeningStatus
handler
:
suspend
E
.(
E
)
->
ListeningStatus
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
Handler
(
Handler
(
...
@@ -275,16 +324,10 @@ fun <E : BotEvent> Bot.subscribe(
...
@@ -275,16 +324,10 @@ fun <E : BotEvent> Bot.subscribe(
)
)
/**
/**
* 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行.
* [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
*
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
*
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @param priority 事件优先级, 优先级高的先处理
*
*
* @see
subscribe
获取更多说明
* @see
CoroutineScope.subscribeAlways
获取更多说明
*/
*/
@JvmSynthetic
@JvmSynthetic
@JvmName
(
"subscribeAlwaysForBot1"
)
@JvmName
(
"subscribeAlwaysForBot1"
)
...
@@ -292,11 +335,14 @@ fun <E : BotEvent> Bot.subscribe(
...
@@ -292,11 +335,14 @@ fun <E : BotEvent> Bot.subscribe(
inline
fun
<
reified
E
:
BotEvent
>
Bot
.
subscribeAlways
(
inline
fun
<
reified
E
:
BotEvent
>
Bot
.
subscribeAlways
(
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
CONCURRENT
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
CONCURRENT
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
noinline
listener
:
suspend
E
.(
E
)
->
Unit
noinline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
subscribeAlways
(
E
::
class
,
coroutineContext
,
concurrency
,
priority
,
listener
)
):
Listener
<
E
>
=
subscribeAlways
(
E
::
class
,
coroutineContext
,
concurrency
,
priority
,
listener
)
/**
/**
* **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
*
* @see Bot.subscribeAlways
* @see Bot.subscribeAlways
*/
*/
@SinceMirai
(
"0.38.0"
)
@SinceMirai
(
"0.38.0"
)
...
@@ -304,40 +350,37 @@ fun <E : BotEvent> Bot.subscribeAlways(
...
@@ -304,40 +350,37 @@ fun <E : BotEvent> Bot.subscribeAlways(
eventClass
:
KClass
<
E
>,
eventClass
:
KClass
<
E
>,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
CONCURRENT
,
concurrency
:
Listener
.
ConcurrencyKind
=
Listener
.
ConcurrencyKind
.
CONCURRENT
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
listener
:
suspend
E
.(
E
)
->
Unit
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
Handler
(
coroutineContext
,
concurrency
,
priority
)
{
if
(
it
.
bot
===
this
)
it
.
listener
(
it
);
ListeningStatus
.
LISTENING
}
Handler
(
coroutineContext
,
concurrency
,
priority
)
{
if
(
it
.
bot
===
this
)
it
.
listener
(
it
);
ListeningStatus
.
LISTENING
}
)
)
/**
/**
* 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行.
* [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
*
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
*
*
* @param coroutineContext 给事件监听协程的额外的 [CoroutineContext]
* @see subscribeOnce 获取更多说明
* @param priority 事件优先级, 高的先处理
*
* @see subscribe 获取更多说明
*/
*/
@JvmSynthetic
@JvmSynthetic
@JvmName
(
"subscribeOnceForBot2"
)
@JvmName
(
"subscribeOnceForBot2"
)
inline
fun
<
reified
E
:
BotEvent
>
Bot
.
subscribeOnce
(
inline
fun
<
reified
E
:
BotEvent
>
Bot
.
subscribeOnce
(
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
noinline
listener
:
suspend
E
.(
E
)
->
Unit
noinline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
subscribeOnce
(
E
::
class
,
coroutineContext
,
priority
,
listener
)
):
Listener
<
E
>
=
subscribeOnce
(
E
::
class
,
coroutineContext
,
priority
,
listener
)
/**
/**
* **注意:** 与 [CoroutineScope.subscribe] 不同的是,
* [Bot.subscribe] 会筛选事件来源 [Bot], 只监听来自 [this] 的事件.
*
* @see Bot.subscribeOnce
* @see Bot.subscribeOnce
*/
*/
@SinceMirai
(
"0.38.0"
)
@SinceMirai
(
"0.38.0"
)
fun
<
E
:
BotEvent
>
Bot
.
subscribeOnce
(
fun
<
E
:
BotEvent
>
Bot
.
subscribeOnce
(
eventClass
:
KClass
<
E
>,
eventClass
:
KClass
<
E
>,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
priority
:
Listener
.
EventPriority
=
Listener
.
EventPriority
.
NORMAL
,
priority
:
Listener
.
EventPriority
=
NORMAL
,
listener
:
suspend
E
.(
E
)
->
Unit
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
):
Listener
<
E
>
=
eventClass
.
subscribeInternal
(
Handler
(
coroutineContext
,
Listener
.
ConcurrencyKind
.
LOCKED
,
priority
)
{
eventClass
.
subscribeInternal
(
Handler
(
coroutineContext
,
Listener
.
ConcurrencyKind
.
LOCKED
,
priority
)
{
...
@@ -351,6 +394,7 @@ fun <E : BotEvent> Bot.subscribeOnce(
...
@@ -351,6 +394,7 @@ fun <E : BotEvent> Bot.subscribeOnce(
// region 为了兼容旧版本的方法
// region 为了兼容旧版本的方法
@PlannedRemoval
(
"1.2.0"
)
@JvmName
(
"subscribe"
)
@JvmName
(
"subscribe"
)
@JvmSynthetic
@JvmSynthetic
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -362,9 +406,11 @@ inline fun <reified E : Event> CoroutineScope.subscribeDeprecated(
...
@@ -362,9 +406,11 @@ inline fun <reified E : Event> CoroutineScope.subscribeDeprecated(
):
Listener
<
E
>
=
subscribe
(
):
Listener
<
E
>
=
subscribe
(
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
concurrency
=
concurrency
,
concurrency
=
concurrency
,
priority
=
MONITOR
,
handler
=
handler
handler
=
handler
)
)
@PlannedRemoval
(
"1.2.0"
)
@JvmName
(
"subscribe"
)
@JvmName
(
"subscribe"
)
@JvmSynthetic
@JvmSynthetic
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -378,9 +424,11 @@ fun <E : Event> CoroutineScope.subscribeDeprecated(
...
@@ -378,9 +424,11 @@ fun <E : Event> CoroutineScope.subscribeDeprecated(
eventClass
=
eventClass
,
eventClass
=
eventClass
,
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
concurrency
=
concurrency
,
concurrency
=
concurrency
,
priority
=
MONITOR
,
handler
=
handler
handler
=
handler
)
)
@PlannedRemoval
(
"1.2.0"
)
@JvmName
(
"subscribeAlways"
)
@JvmName
(
"subscribeAlways"
)
@JvmSynthetic
@JvmSynthetic
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -392,9 +440,11 @@ inline fun <reified E : Event> CoroutineScope.subscribeAlwaysDeprecated(
...
@@ -392,9 +440,11 @@ inline fun <reified E : Event> CoroutineScope.subscribeAlwaysDeprecated(
):
Listener
<
E
>
=
subscribeAlways
(
):
Listener
<
E
>
=
subscribeAlways
(
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
concurrency
=
concurrency
,
concurrency
=
concurrency
,
priority
=
MONITOR
,
listener
=
listener
listener
=
listener
)
)
@PlannedRemoval
(
"1.2.0"
)
@JvmName
(
"subscribeAlways"
)
@JvmName
(
"subscribeAlways"
)
@JvmSynthetic
@JvmSynthetic
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -408,9 +458,11 @@ fun <E : Event> CoroutineScope.subscribeAlwaysDeprecated(
...
@@ -408,9 +458,11 @@ fun <E : Event> CoroutineScope.subscribeAlwaysDeprecated(
eventClass
=
eventClass
,
eventClass
=
eventClass
,
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
concurrency
=
concurrency
,
concurrency
=
concurrency
,
priority
=
MONITOR
,
listener
=
listener
listener
=
listener
)
)
@PlannedRemoval
(
"1.2.0"
)
@JvmName
(
"subscribeOnce"
)
@JvmName
(
"subscribeOnce"
)
@JvmSynthetic
@JvmSynthetic
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -418,8 +470,13 @@ fun <E : Event> CoroutineScope.subscribeAlwaysDeprecated(
...
@@ -418,8 +470,13 @@ fun <E : Event> CoroutineScope.subscribeAlwaysDeprecated(
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribeOnceDeprecated
(
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribeOnceDeprecated
(
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
,
noinline
listener
:
suspend
E
.(
E
)
->
Unit
noinline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
subscribeOnce
(
coroutineContext
=
coroutineContext
,
listener
=
listener
)
):
Listener
<
E
>
=
subscribeOnce
(
coroutineContext
=
coroutineContext
,
priority
=
MONITOR
,
listener
=
listener
)
@PlannedRemoval
(
"1.2.0"
)
@JvmName
(
"subscribeOnce"
)
@JvmName
(
"subscribeOnce"
)
@JvmSynthetic
@JvmSynthetic
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -431,9 +488,11 @@ fun <E : Event> CoroutineScope.subscribeOnceDeprecated(
...
@@ -431,9 +488,11 @@ fun <E : Event> CoroutineScope.subscribeOnceDeprecated(
):
Listener
<
E
>
=
subscribeOnce
(
):
Listener
<
E
>
=
subscribeOnce
(
eventClass
=
eventClass
,
eventClass
=
eventClass
,
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
priority
=
MONITOR
,
listener
=
listener
listener
=
listener
)
)
@PlannedRemoval
(
"1.2.0"
)
@JvmSynthetic
@JvmSynthetic
@JvmName
(
"subscribeAlwaysForBot"
)
@JvmName
(
"subscribeAlwaysForBot"
)
@OptIn
(
MiraiInternalAPI
::
class
)
@OptIn
(
MiraiInternalAPI
::
class
)
...
@@ -446,9 +505,11 @@ inline fun <reified E : BotEvent> Bot.subscribeDeprecated(
...
@@ -446,9 +505,11 @@ inline fun <reified E : BotEvent> Bot.subscribeDeprecated(
):
Listener
<
E
>
=
this
.
subscribe
(
):
Listener
<
E
>
=
this
.
subscribe
(
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
concurrency
=
concurrency
,
concurrency
=
concurrency
,
priority
=
MONITOR
,
handler
=
handler
handler
=
handler
)
)
@PlannedRemoval
(
"1.2.0"
)
@JvmSynthetic
@JvmSynthetic
@JvmName
(
"subscribe"
)
@JvmName
(
"subscribe"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -462,9 +523,11 @@ fun <E : BotEvent> Bot.subscribeDeprecated(
...
@@ -462,9 +523,11 @@ fun <E : BotEvent> Bot.subscribeDeprecated(
eventClass
=
eventClass
,
eventClass
=
eventClass
,
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
concurrency
=
concurrency
,
concurrency
=
concurrency
,
priority
=
MONITOR
,
handler
=
handler
handler
=
handler
)
)
@PlannedRemoval
(
"1.2.0"
)
@JvmSynthetic
@JvmSynthetic
@JvmName
(
"subscribeAlwaysForBot1"
)
@JvmName
(
"subscribeAlwaysForBot1"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -477,9 +540,11 @@ inline fun <reified E : BotEvent> Bot.subscribeAlwaysDeprecated(
...
@@ -477,9 +540,11 @@ inline fun <reified E : BotEvent> Bot.subscribeAlwaysDeprecated(
):
Listener
<
E
>
=
subscribeAlways
(
):
Listener
<
E
>
=
subscribeAlways
(
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
concurrency
=
concurrency
,
concurrency
=
concurrency
,
priority
=
MONITOR
,
listener
=
listener
listener
=
listener
)
)
@PlannedRemoval
(
"1.2.0"
)
@JvmSynthetic
@JvmSynthetic
@JvmName
(
"subscribeAlways"
)
@JvmName
(
"subscribeAlways"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -493,9 +558,11 @@ fun <E : BotEvent> Bot.subscribeAlwaysDeprecated(
...
@@ -493,9 +558,11 @@ fun <E : BotEvent> Bot.subscribeAlwaysDeprecated(
eventClass
=
eventClass
,
eventClass
=
eventClass
,
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
concurrency
=
concurrency
,
concurrency
=
concurrency
,
priority
=
MONITOR
,
listener
=
listener
listener
=
listener
)
)
@PlannedRemoval
(
"1.2.0"
)
@JvmSynthetic
@JvmSynthetic
@JvmName
(
"subscribeOnceForBot2"
)
@JvmName
(
"subscribeOnceForBot2"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -505,9 +572,11 @@ inline fun <reified E : BotEvent> Bot.subscribeOnceDeprecated(
...
@@ -505,9 +572,11 @@ inline fun <reified E : BotEvent> Bot.subscribeOnceDeprecated(
noinline
listener
:
suspend
E
.(
E
)
->
Unit
noinline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
subscribeOnce
(
):
Listener
<
E
>
=
subscribeOnce
(
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
priority
=
MONITOR
,
listener
=
listener
listener
=
listener
)
)
@PlannedRemoval
(
"1.2.0"
)
@JvmSynthetic
@JvmSynthetic
@JvmName
(
"subscribeOnce"
)
@JvmName
(
"subscribeOnce"
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
@Deprecated
(
"for binary compatibility"
,
level
=
DeprecationLevel
.
HIDDEN
)
...
@@ -519,6 +588,7 @@ fun <E : BotEvent> Bot.subscribeOnceDeprecated(
...
@@ -519,6 +588,7 @@ fun <E : BotEvent> Bot.subscribeOnceDeprecated(
):
Listener
<
E
>
=
subscribeOnce
(
):
Listener
<
E
>
=
subscribeOnce
(
eventClass
=
eventClass
,
eventClass
=
eventClass
,
coroutineContext
=
coroutineContext
,
coroutineContext
=
coroutineContext
,
priority
=
MONITOR
,
listener
=
listener
listener
=
listener
)
)
// endregion
// endregion
\ No newline at end of file
mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt
View file @
9924d37e
...
@@ -9,8 +9,6 @@
...
@@ -9,8 +9,6 @@
package
net.mamoe.mirai.event
package
net.mamoe.mirai.event
import
kotlinx.atomicfu.AtomicInt
import
kotlinx.atomicfu.atomic
import
kotlinx.coroutines.*
import
kotlinx.coroutines.*
import
net.mamoe.mirai.event.internal.GlobalEventListeners
import
net.mamoe.mirai.event.internal.GlobalEventListeners
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
...
@@ -18,7 +16,6 @@ import net.mamoe.mirai.utils.StepUtil
...
@@ -18,7 +16,6 @@ import net.mamoe.mirai.utils.StepUtil
import
net.mamoe.mirai.utils.internal.runBlocking
import
net.mamoe.mirai.utils.internal.runBlocking
import
java.util.concurrent.Executor
import
java.util.concurrent.Executor
import
java.util.concurrent.atomic.AtomicInteger
import
java.util.concurrent.atomic.AtomicInteger
import
kotlin.concurrent.thread
import
kotlin.test.Test
import
kotlin.test.Test
import
kotlin.test.assertTrue
import
kotlin.test.assertTrue
...
@@ -67,7 +64,6 @@ class EventTests {
...
@@ -67,7 +64,6 @@ class EventTests {
}
}
kotlinx
.
coroutines
.
runBlocking
{
kotlinx
.
coroutines
.
runBlocking
{
ParentEvent
().
broadcast
()
ParentEvent
().
broadcast
()
delay
(
5000L
)
// ?
}
}
val
called
=
counter
.
get
()
val
called
=
counter
.
get
()
println
(
"Registered $listeners listeners and $called called"
)
println
(
"Registered $listeners listeners and $called called"
)
...
@@ -109,37 +105,39 @@ class EventTests {
...
@@ -109,37 +105,39 @@ class EventTests {
}
}
@Test
@Test
fun
`test
concurrent
listening
2
`
()
{
fun
`test
concurrent
listening
2
`
()
=
runBlocking
{
resetEventListeners
()
resetEventListeners
()
val
registered
=
AtomicInteger
()
val
registered
=
AtomicInteger
()
val
called
=
AtomicInteger
()
val
called
=
AtomicInteger
()
val
threads
=
mutableListOf
<
Thread
>()
repeat
(
50
)
{
val
supervisor
=
CoroutineScope
(
SupervisorJob
())
threads
.
add
(
thread
{
repeat
(
444
)
{
coroutineScope
{
registered
.
getAndIncrement
()
repeat
(
50
)
{
GlobalScope
.
launch
{
launch
{
subscribeAlways
<
ParentEvent
>
{
repeat
(
444
)
{
registered
.
getAndIncrement
()
supervisor
.
subscribeAlways
<
ParentEvent
>
{
called
.
getAndIncrement
()
called
.
getAndIncrement
()
}
}
}
}
}
}
})
}
}
Thread
.
sleep
(
5000L
)
// Wait all thread started.
threads
.
forEach
{
it
.
join
()
// Wait all finished
}
}
println
(
"All listeners registered"
)
println
(
"All listeners registered"
)
val
postCount
=
3
val
postCount
=
3
kotlinx
.
coroutines
.
runBlocking
{
coroutineScope
{
repeat
(
postCount
)
{
repeat
(
postCount
)
{
ParentEvent
().
broadcast
()
launch
{
ParentEvent
().
broadcast
()
}
}
}
delay
(
5000L
)
}
}
val
calledCount
=
called
.
get
()
val
calledCount
=
called
.
get
()
val
shouldCalled
=
registered
.
get
()
*
postCount
val
shouldCalled
=
registered
.
get
()
*
postCount
println
(
"Should call $shouldCalled times and $called called"
)
println
(
"Should call $shouldCalled times and $called called"
)
if
(
shouldCalled
!=
calledCount
)
{
if
(
shouldCalled
!=
calledCount
)
{
throw
IllegalStateException
(
"?"
)
throw
IllegalStateException
(
"?"
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment