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
22175eaa
Commit
22175eaa
authored
Dec 23, 2019
by
Him188
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rewrite events
parent
e56ef7ba
Changes
8
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
269 additions
and
449 deletions
+269
-449
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt
...onMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt
+60
-69
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt
...c/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt
+3
-30
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
...rc/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
+107
-121
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/SubscribersWithBot.kt
...onMain/kotlin/net.mamoe.mirai/event/SubscribersWithBot.kt
+0
-103
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt
.../net.mamoe.mirai/event/internal/InternalEventListeners.kt
+33
-92
mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt
...re/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt
+44
-0
mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt
...i-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt
+13
-28
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt
...rai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt
+9
-6
No files found.
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt
View file @
22175eaa
This diff is collapsed.
Click to expand it.
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt
View file @
22175eaa
...
@@ -3,9 +3,6 @@
...
@@ -3,9 +3,6 @@
package
net.mamoe.mirai.event
package
net.mamoe.mirai.event
import
net.mamoe.mirai.event.internal.broadcastInternal
import
net.mamoe.mirai.event.internal.broadcastInternal
import
net.mamoe.mirai.utils.DefaultLogger
import
net.mamoe.mirai.utils.MiraiLogger
import
net.mamoe.mirai.utils.withSwitch
/**
/**
* 可被监听的.
* 可被监听的.
...
@@ -13,9 +10,7 @@ import net.mamoe.mirai.utils.withSwitch
...
@@ -13,9 +10,7 @@ import net.mamoe.mirai.utils.withSwitch
* 可以是任何 class 或 object.
* 可以是任何 class 或 object.
*
*
* @see subscribeAlways
* @see subscribeAlways
* @see subscribeOnce
* @see subscribeWhile
* @see subscribeWhile
* @see subscribeAll
*
*
* @see subscribeMessages
* @see subscribeMessages
*/
*/
...
@@ -47,19 +42,6 @@ abstract class Event : Subscribable {
...
@@ -47,19 +42,6 @@ abstract class Event : Subscribable {
fun
cancel
()
{
fun
cancel
()
{
cancelled
=
true
cancelled
=
true
}
}
init
{
if
(
EventDebuggingFlag
)
{
EventDebugLogger
.
debug
(
this
::
class
.
simpleName
+
" created"
)
}
}
}
internal
object
EventDebugLogger
:
MiraiLogger
by
DefaultLogger
(
"Event"
).
withSwitch
(
EventDebuggingFlag
)
private
val
EventDebuggingFlag
:
Boolean
by
lazy
{
// avoid 'Condition is always true'
false
}
}
/**
/**
...
@@ -74,19 +56,10 @@ interface Cancellable : Subscribable {
...
@@ -74,19 +56,10 @@ interface Cancellable : Subscribable {
/**
/**
* 广播一个事件的唯一途径.
* 广播一个事件的唯一途径.
*/
*/
@Suppress
(
"UNCHECKED_CAST"
)
suspend
fun
<
E
:
Subscribable
>
E
.
broadcast
():
E
{
suspend
fun
<
E
:
Subscribable
>
E
.
broadcast
():
E
{
if
(
EventDebuggingFlag
)
{
EventDebugLogger
.
debug
(
this
::
class
.
simpleName
+
" pre broadcast"
)
}
try
{
@Suppress
(
"EXPERIMENTAL_API_USAGE"
)
@Suppress
(
"EXPERIMENTAL_API_USAGE"
)
return
this
@
broadcast
.
broadcastInternal
()
this
@
broadcast
.
broadcastInternal
()
// inline, no extra cost
}
finally
{
return
this
if
(
EventDebuggingFlag
)
{
EventDebugLogger
.
debug
(
this
::
class
.
simpleName
+
" after broadcast"
)
}
}
}
}
/**
/**
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
View file @
22175eaa
This diff is collapsed.
Click to expand it.
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/SubscribersWithBot.kt
deleted
100644 → 0
View file @
e56ef7ba
@
file
:
Suppress
(
"unused"
)
package
net.mamoe.mirai.event
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.event.internal.HandlerWithSession
import
net.mamoe.mirai.event.internal.Listener
import
net.mamoe.mirai.event.internal.subscribeInternal
import
kotlin.reflect.KClass
/**
* 该文件为所有的含 Bot 的事件的订阅方法
*
* 与不含 bot 的相比, 在监听时将会有 `this: Bot`
* 在 demo 中找到实例可很快了解区别.
*/
// region 顶层方法
suspend
inline
fun
<
reified
E
:
Subscribable
>
Bot
.
subscribe
(
noinline
handler
:
suspend
Bot
.(
E
)
->
ListeningStatus
):
Listener
<
E
>
=
E
::
class
.
subscribe
(
this
,
handler
)
suspend
inline
fun
<
reified
E
:
Subscribable
>
Bot
.
subscribeAlways
(
noinline
listener
:
suspend
Bot
.(
E
)
->
Unit
):
Listener
<
E
>
=
E
::
class
.
subscribeAlways
(
this
,
listener
)
suspend
inline
fun
<
reified
E
:
Subscribable
>
Bot
.
subscribeOnce
(
noinline
listener
:
suspend
Bot
.(
E
)
->
Unit
):
Listener
<
E
>
=
E
::
class
.
subscribeOnce
(
this
,
listener
)
suspend
inline
fun
<
reified
E
:
Subscribable
,
T
>
Bot
.
subscribeUntil
(
valueIfStop
:
T
,
noinline
listener
:
suspend
Bot
.(
E
)
->
T
):
Listener
<
E
>
=
E
::
class
.
subscribeUntil
(
this
,
valueIfStop
,
listener
)
suspend
inline
fun
<
reified
E
:
Subscribable
>
Bot
.
subscribeUntilFalse
(
noinline
listener
:
suspend
Bot
.(
E
)
->
Boolean
):
Listener
<
E
>
=
E
::
class
.
subscribeUntilFalse
(
this
,
listener
)
suspend
inline
fun
<
reified
E
:
Subscribable
>
Bot
.
subscribeUntilTrue
(
noinline
listener
:
suspend
Bot
.(
E
)
->
Boolean
):
Listener
<
E
>
=
E
::
class
.
subscribeUntilTrue
(
this
,
listener
)
suspend
inline
fun
<
reified
E
:
Subscribable
>
Bot
.
subscribeUntilNull
(
noinline
listener
:
suspend
Bot
.(
E
)
->
Any
?):
Listener
<
E
>
=
E
::
class
.
subscribeUntilNull
(
this
,
listener
)
suspend
inline
fun
<
reified
E
:
Subscribable
,
T
>
Bot
.
subscribeWhile
(
valueIfContinue
:
T
,
noinline
listener
:
suspend
Bot
.(
E
)
->
T
):
Listener
<
E
>
=
E
::
class
.
subscribeWhile
(
this
,
valueIfContinue
,
listener
)
suspend
inline
fun
<
reified
E
:
Subscribable
>
Bot
.
subscribeWhileFalse
(
noinline
listener
:
suspend
Bot
.(
E
)
->
Boolean
):
Listener
<
E
>
=
E
::
class
.
subscribeWhileFalse
(
this
,
listener
)
suspend
inline
fun
<
reified
E
:
Subscribable
>
Bot
.
subscribeWhileTrue
(
noinline
listener
:
suspend
Bot
.(
E
)
->
Boolean
):
Listener
<
E
>
=
E
::
class
.
subscribeWhileTrue
(
this
,
listener
)
suspend
inline
fun
<
reified
E
:
Subscribable
>
Bot
.
subscribeWhileNull
(
noinline
listener
:
suspend
Bot
.(
E
)
->
Any
?):
Listener
<
E
>
=
E
::
class
.
subscribeWhileNull
(
this
,
listener
)
// endregion
// region KClass 的扩展方法 (仅内部使用)
@PublishedApi
internal
suspend
fun
<
E
:
Subscribable
>
KClass
<
E
>.
subscribe
(
bot
:
Bot
,
handler
:
suspend
Bot
.(
E
)
->
ListeningStatus
)
=
this
.
subscribeInternal
(
HandlerWithSession
(
bot
,
handler
))
@PublishedApi
internal
suspend
fun
<
E
:
Subscribable
>
KClass
<
E
>.
subscribeAlways
(
bot
:
Bot
,
listener
:
suspend
Bot
.(
E
)
->
Unit
)
=
this
.
subscribeInternal
(
HandlerWithSession
(
bot
)
{
listener
(
it
);
ListeningStatus
.
LISTENING
})
@PublishedApi
internal
suspend
fun
<
E
:
Subscribable
>
KClass
<
E
>.
subscribeOnce
(
bot
:
Bot
,
listener
:
suspend
Bot
.(
E
)
->
Unit
)
=
this
.
subscribeInternal
(
HandlerWithSession
(
bot
)
{
listener
(
it
);
ListeningStatus
.
STOPPED
})
@PublishedApi
internal
suspend
fun
<
E
:
Subscribable
,
T
>
KClass
<
E
>.
subscribeUntil
(
bot
:
Bot
,
valueIfStop
:
T
,
listener
:
suspend
Bot
.(
E
)
->
T
)
=
subscribeInternal
(
HandlerWithSession
(
bot
)
{
if
(
listener
(
it
)
===
valueIfStop
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
})
@PublishedApi
internal
suspend
inline
fun
<
E
:
Subscribable
>
KClass
<
E
>.
subscribeUntilFalse
(
bot
:
Bot
,
noinline
listener
:
suspend
Bot
.(
E
)
->
Boolean
)
=
subscribeUntil
(
bot
,
false
,
listener
)
@PublishedApi
internal
suspend
inline
fun
<
E
:
Subscribable
>
KClass
<
E
>.
subscribeUntilTrue
(
bot
:
Bot
,
noinline
listener
:
suspend
Bot
.(
E
)
->
Boolean
)
=
subscribeUntil
(
bot
,
true
,
listener
)
@PublishedApi
internal
suspend
inline
fun
<
E
:
Subscribable
>
KClass
<
E
>.
subscribeUntilNull
(
bot
:
Bot
,
noinline
listener
:
suspend
Bot
.(
E
)
->
Any
?)
=
subscribeUntil
(
bot
,
null
,
listener
)
@PublishedApi
internal
suspend
fun
<
E
:
Subscribable
,
T
>
KClass
<
E
>.
subscribeWhile
(
bot
:
Bot
,
valueIfContinue
:
T
,
listener
:
suspend
Bot
.(
E
)
->
T
)
=
subscribeInternal
(
HandlerWithSession
(
bot
)
{
if
(
listener
(
it
)
!==
valueIfContinue
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
})
@PublishedApi
internal
suspend
inline
fun
<
E
:
Subscribable
>
KClass
<
E
>.
subscribeWhileFalse
(
bot
:
Bot
,
noinline
listener
:
suspend
Bot
.(
E
)
->
Boolean
)
=
subscribeWhile
(
bot
,
false
,
listener
)
@PublishedApi
internal
suspend
inline
fun
<
E
:
Subscribable
>
KClass
<
E
>.
subscribeWhileTrue
(
bot
:
Bot
,
noinline
listener
:
suspend
Bot
.(
E
)
->
Boolean
)
=
subscribeWhile
(
bot
,
true
,
listener
)
@PublishedApi
internal
suspend
inline
fun
<
E
:
Subscribable
>
KClass
<
E
>.
subscribeWhileNull
(
bot
:
Bot
,
noinline
listener
:
suspend
Bot
.(
E
)
->
Any
?)
=
subscribeWhile
(
bot
,
null
,
listener
)
// endregion
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt
View file @
22175eaa
package
net.mamoe.mirai.event.internal
package
net.mamoe.mirai.event.internal
import
kotlinx.coroutines.CompletableJob
import
kotlinx.coroutines.CompletableJob
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.sync.Mutex
import
kotlinx.coroutines.sync.withLock
import
kotlinx.coroutines.withContext
import
kotlinx.coroutines.withContext
import
net.mamoe.mirai.
Bot
import
net.mamoe.mirai.
event.Listener
import
net.mamoe.mirai.event.ListeningStatus
import
net.mamoe.mirai.event.ListeningStatus
import
net.mamoe.mirai.event.Subscribable
import
net.mamoe.mirai.event.Subscribable
import
net.mamoe.mirai.event.events.BotEvent
import
net.mamoe.mirai.utils.LockFreeLinkedList
import
net.mamoe.mirai.utils.LockFreeLinkedList
import
net.mamoe.mirai.utils.io.logStacktrace
import
net.mamoe.mirai.utils.io.logStacktrace
import
net.mamoe.mirai.utils.unsafeWeakRef
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
import
kotlin.reflect.KFunction
/**
/**
* 设置为 `true` 以关闭事件.
* 设置为 `true` 以关闭事件.
...
@@ -24,15 +19,8 @@ import kotlin.reflect.KFunction
...
@@ -24,15 +19,8 @@ import kotlin.reflect.KFunction
*/
*/
var
EventDisabled
=
false
var
EventDisabled
=
false
/**
@PublishedApi
* 监听和广播实现.
internal
fun
<
L
:
Listener
<
E
>,
E
:
Subscribable
>
KClass
<
out
E
>.
subscribeInternal
(
listener
:
L
):
L
{
* 它会首先检查这个事件是否正在被广播
* - 如果是, 则将新的监听者放入缓存中. 在当前广播结束后转移到主列表 (通过一个协程完成)
* - 如果不是, 则直接将新的监听者放入主列表
*
* @author Him188moe
*/
// inline to avoid a Continuation creation
internal
suspend
inline
fun
<
L
:
Listener
<
E
>,
E
:
Subscribable
>
KClass
<
E
>.
subscribeInternal
(
listener
:
L
):
L
{
this
.
listeners
().
addLast
(
listener
)
this
.
listeners
().
addLast
(
listener
)
return
listener
return
listener
}
}
...
@@ -40,18 +28,15 @@ internal suspend inline fun <L : Listener<E>, E : Subscribable> KClass<E>.subscr
...
@@ -40,18 +28,15 @@ internal suspend inline fun <L : Listener<E>, E : Subscribable> KClass<E>.subscr
/**
/**
* 事件监听器.
* 事件监听器.
*
*
* 它实现 [CompletableJob] 接口,
* 可通过 [CompletableJob.complete] 来正常结束监听, 或 [CompletableJob.completeExceptionally] 来异常地结束监听.
*
* @author Him188moe
* @author Him188moe
*/
*/
sealed
class
Listener
<
in
E
:
Subscribable
>
:
CompletableJob
{
internal
sealed
class
ListenerImpl
<
in
E
:
Subscribable
>
:
Listener
<
E
>
{
abstract
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
abstract
override
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
}
}
@PublishedApi
@PublishedApi
@Suppress
(
"FunctionName"
)
@Suppress
(
"FunctionName"
)
internal
suspend
inline
fun
<
E
:
Subscribable
>
Handler
(
noinline
handler
:
suspend
(
E
)
->
ListeningStatus
):
Handler
<
E
>
{
internal
fun
<
E
:
Subscribable
>
CoroutineScope
.
Handler
(
handler
:
suspend
(
E
)
->
ListeningStatus
):
Handler
<
E
>
{
return
Handler
(
coroutineContext
[
Job
],
coroutineContext
,
handler
)
return
Handler
(
coroutineContext
[
Job
],
coroutineContext
,
handler
)
}
}
...
@@ -60,14 +45,15 @@ internal suspend inline fun <E : Subscribable> Handler(noinline handler: suspend
...
@@ -60,14 +45,15 @@ internal suspend inline fun <E : Subscribable> Handler(noinline handler: suspend
*/
*/
@PublishedApi
@PublishedApi
internal
class
Handler
<
in
E
:
Subscribable
>
internal
class
Handler
<
in
E
:
Subscribable
>
@PublishedApi
internal
constructor
(
parentJob
:
Job
?,
private
val
c
ontext
:
CoroutineContext
,
@JvmField
val
handler
:
suspend
(
E
)
->
ListeningStatus
)
:
@PublishedApi
internal
constructor
(
parentJob
:
Job
?,
private
val
subscriberC
ontext
:
CoroutineContext
,
@JvmField
val
handler
:
suspend
(
E
)
->
ListeningStatus
)
:
Listener
<
E
>(),
CompletableJob
by
Job
(
parentJob
)
{
Listener
Impl
<
E
>(),
CompletableJob
by
Job
(
parentJob
)
{
override
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
{
override
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
{
if
(
isCompleted
||
isCancelled
)
return
ListeningStatus
.
STOPPED
if
(
isCompleted
||
isCancelled
)
return
ListeningStatus
.
STOPPED
if
(!
isActive
)
return
ListeningStatus
.
LISTENING
if
(!
isActive
)
return
ListeningStatus
.
LISTENING
return
try
{
return
try
{
withContext
(
context
)
{
handler
.
invoke
(
event
)
}.
also
{
if
(
it
==
ListeningStatus
.
STOPPED
)
this
.
complete
()
}
// Inherit context.
withContext
(
subscriberContext
)
{
handler
.
invoke
(
event
)
}.
also
{
if
(
it
==
ListeningStatus
.
STOPPED
)
this
.
complete
()
}
}
catch
(
e
:
Throwable
)
{
}
catch
(
e
:
Throwable
)
{
e
.
logStacktrace
()
e
.
logStacktrace
()
//this.completeExceptionally(e)
//this.completeExceptionally(e)
...
@@ -76,96 +62,51 @@ internal class Handler<in E : Subscribable>
...
@@ -76,96 +62,51 @@ internal class Handler<in E : Subscribable>
}
}
}
}
@PublishedApi
@Suppress
(
"FunctionName"
)
internal
suspend
inline
fun
<
E
:
Subscribable
>
HandlerWithSession
(
bot
:
Bot
,
noinline
handler
:
suspend
Bot
.(
E
)
->
ListeningStatus
):
HandlerWithSession
<
E
>
{
return
HandlerWithSession
(
bot
,
coroutineContext
[
Job
],
coroutineContext
,
handler
)
}
/**
* 带有 bot 筛选的监听器.
* 所有的非 [BotEvent] 的事件都不会被处理
* 所有的 [BotEvent.bot] `!==` `bot` 的事件都不会被处理
*/
@PublishedApi
internal
class
HandlerWithSession
<
E
:
Subscribable
>
@PublishedApi
internal
constructor
(
bot
:
Bot
,
parentJob
:
Job
?,
private
val
context
:
CoroutineContext
,
@JvmField
val
handler
:
suspend
Bot
.(
E
)
->
ListeningStatus
)
:
Listener
<
E
>(),
CompletableJob
by
Job
(
parentJob
)
{
val
bot
:
Bot
by
bot
.
unsafeWeakRef
()
override
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
{
if
(
isCompleted
||
isCancelled
)
return
ListeningStatus
.
STOPPED
if
(!
isActive
)
return
ListeningStatus
.
LISTENING
if
(
event
!
is
BotEvent
||
event
.
bot
!==
bot
)
return
ListeningStatus
.
LISTENING
return
try
{
withContext
(
context
)
{
bot
.
handler
(
event
)
}.
also
{
if
(
it
==
ListeningStatus
.
STOPPED
)
complete
()
}
}
catch
(
e
:
Throwable
)
{
e
.
logStacktrace
()
//completeExceptionally(e)
complete
()
ListeningStatus
.
STOPPED
}
}
}
/**
/**
* 这个事件类的监听器 list
* 这个事件类的监听器 list
*/
*/
internal
suspend
fun
<
E
:
Subscribable
>
KClass
<
out
E
>.
listeners
():
EventListeners
<
E
>
=
EventListenerManger
.
get
(
this
)
internal
fun
<
E
:
Subscribable
>
KClass
<
out
E
>.
listeners
():
EventListeners
<
E
>
=
EventListenerManger
.
get
(
this
)
internal
class
EventListeners
<
E
:
Subscribable
>
:
LockFreeLinkedList
<
Listener
<
E
>>()
{
internal
class
EventListeners
<
E
:
Subscribable
>
:
LockFreeLinkedList
<
Listener
<
E
>>()
init
{
this
::
class
.
members
.
filterIsInstance
<
KFunction
<
*
>>().
forEach
{
if
(
it
.
name
==
"add"
)
{
it
.
isExternal
}
}
}
}
/**
/**
* 管理每个事件 class 的 [EventListeners].
* 管理每个事件 class 的 [EventListeners].
* [EventListeners] 是 lazy 的: 它们只会在被需要的时候才创建和存储.
* [EventListeners] 是 lazy 的: 它们只会在被需要的时候才创建和存储.
*/
*/
internal
object
EventListenerManger
{
internal
object
EventListenerManger
{
private
val
registries
:
MutableMap
<
KClass
<
out
Subscribable
>,
EventListeners
<
*
>>
=
mutableMapOf
()
private
data class
Registry
<
E
:
Subscribable
>(
val
clazz
:
KClass
<
E
>,
val
listeners
:
EventListeners
<
E
>)
private
val
registriesMutex
=
Mutex
()
private
val
registries
=
LockFreeLinkedList
<
Registry
<
*
>>()
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
internal
suspend
fun
<
E
:
Subscribable
>
get
(
clazz
:
KClass
<
out
E
>):
EventListeners
<
E
>
=
internal
fun
<
E
:
Subscribable
>
get
(
clazz
:
KClass
<
out
E
>):
EventListeners
<
E
>
{
if
(
registries
.
containsKey
(
clazz
))
registries
[
clazz
]
as
EventListeners
<
E
>
return
registries
.
filteringGetOrAdd
({
it
.
clazz
==
clazz
})
{
else
registriesMutex
.
withLock
{
Registry
(
EventListeners
<
E
>().
let
{
clazz
,
registries
[
clazz
]
=
it
EventListeners
()
return
it
)
}.
listeners
as
EventListeners
<
E
>
}
}
}
}
}
// inline: NO extra Continuation
// inline: NO extra Continuation
internal
suspend
inline
fun
<
E
:
Subscribable
>
E
.
broadcastInternal
():
E
{
internal
suspend
inline
fun
Subscribable
.
broadcastInternal
()
{
if
(
EventDisabled
)
return
this
if
(
EventDisabled
)
return
callAndRemoveIfRequired
(
this
::
class
.
listeners
())
callAndRemoveIfRequired
(
this
::
class
.
listeners
())
this
::
class
.
supertypes
.
forEach
{
superType
->
this
::
class
.
supertypes
.
forEach
{
superType
->
if
(
Subscribable
::
class
.
isInstance
(
superType
))
{
val
superListeners
=
// the super type is a child of Subscribable, then we can cast.
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
callAndRemoveIfRequired
((
superType
.
classifier
as
KClass
<
out
Subscribable
>).
listeners
())
(
superType
.
classifier
as
?
KClass
<
out
Subscribable
>)
?.
listeners
()
?:
return
// return if super type is not Subscribable
}
callAndRemoveIfRequired
(
superListeners
)
}
}
return
this
return
}
}
private
suspend
inline
fun
<
E
:
Subscribable
>
E
.
callAndRemoveIfRequired
(
listeners
:
EventListeners
<
E
>)
{
private
suspend
inline
fun
<
E
:
Subscribable
>
E
.
callAndRemoveIfRequired
(
listeners
:
EventListeners
<
E
>)
{
// atomic foreach
listeners
.
forEach
{
listeners
.
forEach
{
if
(
it
.
onEvent
(
this
)
==
ListeningStatus
.
STOPPED
)
{
if
(
it
.
onEvent
(
this
)
==
ListeningStatus
.
STOPPED
)
{
listeners
.
remove
(
it
)
// atomic remove
listeners
.
remove
(
it
)
// atomic remove
...
...
mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/EventTests.kt
0 → 100644
View file @
22175eaa
package
net.mamoe.mirai.event
import
kotlinx.coroutines.runBlocking
import
net.mamoe.mirai.test.shouldBeEqualTo
import
kotlin.system.exitProcess
import
kotlin.test.Test
class
TestEvent
:
Subscribable
{
var
triggered
=
false
}
class
EventTests
{
@Test
fun
testSubscribeInplace
()
{
runBlocking
{
val
subscriber
=
subscribeAlways
<
TestEvent
>
{
triggered
=
true
println
(
"Triggered"
)
}
TestEvent
().
broadcast
().
triggered
shouldBeEqualTo
true
subscriber
.
complete
()
println
(
"finished"
)
}
}
@Test
fun
testSubscribeGlobalScope
()
{
runBlocking
{
TestEvent
().
broadcast
().
triggered
shouldBeEqualTo
true
println
(
"finished"
)
}
}
companion
object
{
@JvmStatic
fun
main
(
args
:
Array
<
String
>)
{
EventTests
().
testSubscribeGlobalScope
()
exitProcess
(
0
)
}
}
}
\ No newline at end of file
mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt
View file @
22175eaa
...
@@ -51,17 +51,6 @@ suspend fun main() {
...
@@ -51,17 +51,6 @@ suspend fun main() {
bot
.
messageDSL
()
bot
.
messageDSL
()
directlySubscribe
(
bot
)
directlySubscribe
(
bot
)
//DSL 监听
subscribeAll
<
FriendMessage
>
{
always
{
//获取第一个纯文本消息
val
firstText
=
it
.
message
.
firstOrNull
<
PlainText
>()
}
}
demo2
()
bot
.
network
.
awaitDisconnection
()
//等到直到断开连接
bot
.
network
.
awaitDisconnection
()
//等到直到断开连接
}
}
...
@@ -199,9 +188,22 @@ suspend fun Bot.messageDSL() {
...
@@ -199,9 +188,22 @@ suspend fun Bot.messageDSL() {
*/
*/
@Suppress
(
"UNUSED_VARIABLE"
)
@Suppress
(
"UNUSED_VARIABLE"
)
suspend
fun
directlySubscribe
(
bot
:
Bot
)
{
suspend
fun
directlySubscribe
(
bot
:
Bot
)
{
// 在当前协程作用域 (CoroutineScope) 下创建一个子 Job, 监听一个事件.
//
// 手动处理消息
// 手动处理消息
// 使用 Bot 的扩展方法监听, 将在处理事件时得到一个 this: Bot.
// 使用 Bot 的扩展方法监听, 将在处理事件时得到一个 this: Bot.
// 这样可以调用 Bot 内的一些扩展方法如 UInt.qq():QQ
// 这样可以调用 Bot 内的一些扩展方法如 UInt.qq():QQ
//
// 这个函数返回 Listener, Listener 是一个 CompletableJob. 如果不手动 close 它, 它会一直阻止当前 CoroutineScope 结束.
// 例如:
// ```kotlin
// runBlocking {// this: CoroutineScope
// bot.subscribeAlways<FriendMessage> {
// }
// }
// ```
// 则这个 `runBlocking` 永远不会结束, 因为 `subscribeAlways` 在 `runBlocking` 的 `CoroutineScope` 下创建了一个 Job.
// 正确的用法为:
bot
.
subscribeAlways
<
FriendMessage
>
{
bot
.
subscribeAlways
<
FriendMessage
>
{
// this: Bot
// this: Bot
// it: FriendMessageEvent
// it: FriendMessageEvent
...
@@ -246,20 +248,3 @@ suspend fun directlySubscribe(bot: Bot) {
...
@@ -246,20 +248,3 @@ suspend fun directlySubscribe(bot: Bot) {
}
}
}
}
}
}
\ No newline at end of file
/**
* 实现功能:
* 对机器人说 "记笔记", 机器人记录之后的所有消息.
* 对机器人说 "停止", 机器人停止
*/
suspend
fun
demo2
()
{
subscribeAlways
<
FriendMessage
>
{
event
->
if
(
event
.
message
eq
"记笔记"
)
{
subscribeUntilFalse
<
FriendMessage
>
{
it
.
reply
(
"你发送了 ${it.message}"
)
it
.
message
eq
"停止"
}
}
}
}
\ No newline at end of file
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt
View file @
22175eaa
...
@@ -37,7 +37,7 @@ private fun readTestAccount(): BotAccount? {
...
@@ -37,7 +37,7 @@ private fun readTestAccount(): BotAccount? {
val
lines
=
file
.
readLines
()
val
lines
=
file
.
readLines
()
return
try
{
return
try
{
BotAccount
(
lines
[
0
].
toLong
(),
lines
[
1
])
BotAccount
(
lines
[
0
].
toLong
(),
lines
[
1
])
}
catch
(
e
:
Exception
)
{
}
catch
(
e
:
Throwable
)
{
null
null
}
}
}
}
...
@@ -54,16 +54,15 @@ suspend fun main() {
...
@@ -54,16 +54,15 @@ suspend fun main() {
/**
/**
* 监听所有事件
* 监听所有事件
*/
*/
subscribeAlways
<
Subscribable
>
{
GlobalScope
.
subscribeAlways
<
Subscribable
>
{
bot
.
logger
.
verbose
(
"收到了一个事件: $this"
)
//bot.logger.verbose("收到了一个事件: ${it::class.simpleName}")
}
}
subscribeAlways
<
ReceiveFriendAddRequestEvent
>
{
GlobalScope
.
subscribeAlways
<
ReceiveFriendAddRequestEvent
>
{
it
.
approve
()
it
.
approve
()
}
}
bot
.
subscribeGroupMessages
{
GlobalScope
.
subscribeGroupMessages
{
"群资料"
reply
{
"群资料"
reply
{
group
.
updateGroupInfo
().
toString
().
reply
()
group
.
updateGroupInfo
().
toString
().
reply
()
}
}
...
@@ -85,7 +84,11 @@ suspend fun main() {
...
@@ -85,7 +84,11 @@ suspend fun main() {
}
}
bot
.
subscribeMessages
{
bot
.
subscribeMessages
{
always
{
}
case
(
"at me"
)
{
At
(
sender
).
reply
()
}
case
(
"at me"
)
{
At
(
sender
).
reply
()
}
// 等同于 "at me" reply { At(sender) }
"你好"
reply
"你好!"
"你好"
reply
"你好!"
...
...
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