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
2322387f
Commit
2322387f
authored
Feb 19, 2020
by
Him188
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add `bot.subscribe`, close #61
parent
385b36b0
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
60 additions
and
76 deletions
+60
-76
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt
...c/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
...rc/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
+59
-75
No files found.
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt
View file @
2322387f
...
@@ -20,7 +20,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
...
@@ -20,7 +20,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
* 若监听这个类, 监听器将会接收所有事件的广播.
* 若监听这个类, 监听器将会接收所有事件的广播.
*
*
* @see subscribeAlways
* @see subscribeAlways
* @see subscribe
Whil
e
* @see subscribe
Onc
e
*
*
* @see subscribeMessages
* @see subscribeMessages
*
*
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
View file @
2322387f
...
@@ -14,6 +14,7 @@ import kotlinx.coroutines.CoroutineExceptionHandler
...
@@ -14,6 +14,7 @@ import kotlinx.coroutines.CoroutineExceptionHandler
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.GlobalScope
import
kotlinx.coroutines.GlobalScope
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
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
...
@@ -21,6 +22,7 @@ import kotlin.contracts.ExperimentalContracts
...
@@ -21,6 +22,7 @@ import kotlin.contracts.ExperimentalContracts
import
kotlin.contracts.InvocationKind
import
kotlin.contracts.InvocationKind
import
kotlin.contracts.contract
import
kotlin.contracts.contract
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.CoroutineContext
import
kotlin.jvm.JvmName
/*
/*
* 该文件为所有的订阅事件的方法.
* 该文件为所有的订阅事件的方法.
...
@@ -71,15 +73,16 @@ interface Listener<in E : Event> : CompletableJob {
...
@@ -71,15 +73,16 @@ interface Listener<in E : Event> : CompletableJob {
*
`runBlocking`
不会结束
,
也就是下一行
`foo
()
`
不会被执行
.
直到监听时创建的
`Listener`
被停止
.
*
`runBlocking`
不会结束
,
也就是下一行
`foo
()
`
不会被执行
.
直到监听时创建的
`Listener`
被停止
.
*
*
*
*
*
要创建一个全局都存在的监听
,
即守护协程
,
请在
[
GlobalScope
]
下调用本函数
:
*
要创建一个仅在某个机器人在线时的监听
,
请在
[
Bot
]
下调用本函数
(
因为
[
Bot
]
也实现
[
CoroutineScope
]).
*
这种方式创建的监听会自动筛选
[
Bot
].
*
``
`kotlin
*
``
`kotlin
*
GlobalScope
.
subscribe
<
Event
>
{
/* 一些处理
*/
}
*
bot1
.
subscribe
<
BotEvent
>
{
/* 只会处理来自 bot1 的事件
*/
}
*
```
*
```
*
*
*
*
*
要创建一个
仅在某个机器人在线时的监听
,
请在
[
Bot
]
下调用本函数
(
因为
[
Bot
]
也实现
[
CoroutineScope
])
:
*
要创建一个
全局都存在的监听
,
即守护协程
,
请在
[
GlobalScope
]
下调用本函数
:
*
``
`kotlin
*
``
`kotlin
*
bot
.
subscribe
<
Subscribe
>
{
/* 一些处理
*/
}
*
GlobalScope
.
subscribe
<
Event
>
{
/* 会收到来自全部 Bot 的事件和与 Bot 不相关的事件
*/
}
*
```
*
```
*
*
*
*
...
@@ -89,31 +92,34 @@ interface Listener<in E : Event> : CompletableJob {
...
@@ -89,31 +92,34 @@ interface Listener<in E : Event> : CompletableJob {
*
若
[
this
]
没有
[
CoroutineExceptionHandler
],
则在事件广播方的
[
CoroutineExceptionHandler
]
处理
*
若
[
this
]
没有
[
CoroutineExceptionHandler
],
则在事件广播方的
[
CoroutineExceptionHandler
]
处理
*
若均找不到
,
则会触发
logger
warning
.
*
若均找不到
,
则会触发
logger
warning
.
*
-
事件处理时抛出异常不会停止监听器
.
*
-
事件处理时抛出异常不会停止监听器
.
*
-
建议在事件处理中
,
即
[
handler
]
里处理异常
,
或在
[
this
]
指定
[
CoroutineExceptionHandler
].
*
-
建议在事件处理中
(
即
[
handler
]
里
)
处理异常
,
*
或在
[
this
]
的
[
CoroutineScope
.
coroutineContext
]
中添加
[
CoroutineExceptionHandler
].
*
*
*
*
*
**
注意
:**
事件处理是
`suspend`
的
,
请
严格控制
JVM
阻塞方法的使用
.
若致事件处理阻塞
,
则会导致一些逻辑无法进行
.
*
**
注意
:**
事件处理是
`suspend`
的
,
请
规范处理
JVM
阻塞方法
.
*
*
*
// TODO: 2020/2/13 在 bot 下监听时同时筛选对应 bot 实例
*
@
see
subscribeAlways
一直监听
*
@
see
subscribeOnce
只监听一次
*
*
*
@
see
subscribeMessages
监听消息
DSL
*
@
see
subscribeMessages
监听消息
DSL
*
@
see
subscribeGroupMessages
监听群消息
DSL
*
@
see
subscribeGroupMessages
监听群消息
DSL
*
@
see
subscribeFriendMessages
监听好友消息
DSL
*
@
see
subscribeFriendMessages
监听好友消息
DSL
*/
*/
@UseExperimental
(
MiraiInternalAPI
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribe
(
cross
inline
handler
:
suspend
E
.(
E
)
->
ListeningStatus
):
Listener
<
E
>
=
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribe
(
no
inline
handler
:
suspend
E
.(
E
)
->
ListeningStatus
):
Listener
<
E
>
=
E
::
class
.
subscribeInternal
(
Handler
{
it
.
handler
(
it
);
})
E
::
class
.
subscribeInternal
(
Handler
{
it
.
handler
(
it
);
})
/**
/**
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行.
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行.
*
*
* 仅当 [Listener.complete] 或 [Listener.cancel] 时结束.
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
*
*
* @see subscribe 获取更多说明
* @see subscribe 获取更多说明
*/
*/
@UseExperimental
(
MiraiInternalAPI
::
class
,
ExperimentalContracts
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
,
ExperimentalContracts
::
class
)
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribeAlways
(
cross
inline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
{
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribeAlways
(
no
inline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
{
contract
{
contract
{
callsInPlace
(
listener
,
InvocationKind
.
UNKNOWN
)
callsInPlace
(
listener
,
InvocationKind
.
UNKNOWN
)
}
}
...
@@ -124,91 +130,69 @@ inline fun <reified E : Event> CoroutineScope.subscribeAlways(crossinline listen
...
@@ -124,91 +130,69 @@ inline fun <reified E : Event> CoroutineScope.subscribeAlways(crossinline listen
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行.
* 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行.
*
*
* 在这之前, 可通过 [Listener.complete] 来停止监听.
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
*
*
* @see subscribe 获取更多说明
* @see subscribe 获取更多说明
*/
*/
@UseExperimental
(
MiraiInternalAPI
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribeOnce
(
cross
inline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
inline
fun
<
reified
E
:
Event
>
CoroutineScope
.
subscribeOnce
(
no
inline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
E
::
class
.
subscribeInternal
(
Handler
{
it
.
listener
(
it
);
ListeningStatus
.
STOPPED
})
E
::
class
.
subscribeInternal
(
Handler
{
it
.
listener
(
it
);
ListeningStatus
.
STOPPED
})
//
// 以下为带筛选 Bot 的监听
//
/**
/**
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行, 直到 [listener] 的返回值 [equals] 于 [valueIfStop]
* 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行,
* 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听
*
*
* 可在任意时刻通过 [Listener.complete] 来停止监听.
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
*
*
* @see subscribe 获取更多说明
* @see subscribe 获取更多说明
*/
*/
@JvmName
(
"subscribeAlwaysForBot"
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
inline
fun
<
reified
E
:
Event
,
T
>
CoroutineScope
.
subscribeUntil
(
valueIfStop
:
T
,
crossinline
listener
:
suspend
E
.(
E
)
->
T
):
Listener
<
E
>
=
inline
fun
<
reified
E
:
BotEvent
>
Bot
.
subscribe
(
noinline
handler
:
suspend
E
.(
E
)
->
ListeningStatus
):
Listener
<
E
>
=
E
::
class
.
subscribeInternal
(
Handler
{
if
(
it
.
listener
(
it
)
==
valueIfStop
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
})
E
::
class
.
subscribeInternal
(
Handler
{
if
(
it
.
bot
===
this
)
it
.
handler
(
it
)
else
ListeningStatus
.
LISTENING
})
/**
/**
* 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行,
* 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行.
* 如果 [listener] 的返回值 [equals] 于 [valueIfContinue], 则继续监听, 否则停止
*
*
* 可在任意时刻通过 [Listener.complete] 来停止监听.
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
*
*
* @see subscribe 获取更多说明
* @see subscribe 获取更多说明
*/
*/
@JvmName
(
"subscribeAlwaysForBot"
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
@UseExperimental
(
MiraiInternalAPI
::
class
)
inline
fun
<
reified
E
:
Event
,
T
>
CoroutineScope
.
subscribeWhile
(
valueIfContinue
:
T
,
crossinline
listener
:
suspend
E
.(
E
)
->
T
):
Listener
<
E
>
=
inline
fun
<
reified
E
:
BotEvent
>
Bot
.
subscribeAlways
(
noinline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
{
E
::
class
.
subscribeInternal
(
Handler
{
if
(
it
.
listener
(
it
)
!=
valueIfContinue
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
})
return
E
::
class
.
subscribeInternal
(
Handler
{
if
(
it
.
bot
===
this
)
it
.
listener
(
it
);
ListeningStatus
.
LISTENING
})
}
// endregion
// region ListenerBuilder DSL
/*
/**
/**
* 监听构建器. 可同时进行多种方式的监听
* 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件.
* 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行.
*
*
* ```kotlin
* 可在任意时候通过 [Listener.complete] 来主动停止监听.
* FriendMessageEvent.subscribe {
* [Bot] 被关闭后事件监听会被 [取消][Listener.cancel].
* always{
* it.reply("永远发生")
* }
*
*
* untilFalse {
* @see subscribe 获取更多说明
* it.reply("你发送了 ${it.event}")
* it.event eq "停止"
* }
* }
* ```
*/
*/
@ListenersBuilderDsl
@JvmName
(
"subscribeOnceForBot"
)
@Suppress("MemberVisibilityCanBePrivate", "unused")
@UseExperimental
(
MiraiInternalAPI
::
class
)
inline class ListenerBuilder<out E : Event>(
inline
fun
<
reified
E
:
BotEvent
>
Bot
.
subscribeOnce
(
noinline
listener
:
suspend
E
.(
E
)
->
Unit
):
Listener
<
E
>
=
@PublishedApi internal inline val handlerConsumer: CoroutineCoroutineScope.(Listener<E>) -> Unit
E
::
class
.
subscribeInternal
(
Handler
{
) {
if
(
it
.
bot
===
this
)
{
fun CoroutineCoroutineScope.handler(listener: suspend E.(E) -> ListeningStatus) {
it
.
listener
(
it
)
handlerConsumer(Handler { it.listener(it) })
ListeningStatus
.
STOPPED
}
}
else
ListeningStatus
.
LISTENING
})
fun CoroutineCoroutineScope.always(listener: suspend E.(E) -> Unit) = handler { listener(it); ListeningStatus.LISTENING }
fun <T> CoroutineCoroutineScope.until(until: T, listener: suspend E.(E) -> T) =
handler { if (listener(it) == until) ListeningStatus.STOPPED else ListeningStatus.LISTENING }
fun CoroutineCoroutineScope.untilFalse(listener: suspend E.(E) -> Boolean) = until(false, listener)
fun CoroutineCoroutineScope.untilTrue(listener: suspend E.(E) -> Boolean) = until(true, listener)
fun CoroutineCoroutineScope.untilNull(listener: suspend E.(E) -> Any?) = until(null, listener)
fun <T> CoroutineCoroutineScope.`while`(until: T, listener: suspend E.(E) -> T) =
handler { if (listener(it) !== until) ListeningStatus.STOPPED else ListeningStatus.LISTENING }
fun CoroutineCoroutineScope.whileFalse(listener: suspend E.(E) -> Boolean) = `while`(false, listener)
fun CoroutineCoroutineScope.whileTrue(listener: suspend E.(E) -> Boolean) = `while`(true, listener)
fun CoroutineCoroutineScope.whileNull(listener: suspend E.(E) -> Any?) = `while`(null, listener)
fun CoroutineCoroutineScope.once(listener: suspend E.(E) -> Unit) = handler { listener(it); ListeningStatus.STOPPED }
}
@DslMarker
annotation class ListenersBuilderDsl
*/
// endregion
// endregion
\ No newline at end of file
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