mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-20 17:54:52 +08:00
Merge branch 'dev'
This commit is contained in:
commit
713308331d
@ -1,5 +1,8 @@
|
||||
# Version 1.x
|
||||
|
||||
## `1.2.2` 2020/8/22
|
||||
- 修复依赖冲突问题 (#523)
|
||||
|
||||
## `1.2.1` 2020/8/19
|
||||
- 修复在 Java 调用 `group.uploadImage` 时编译出错的问题 (#511)
|
||||
- 为 `group.uploadVoice` 添加 Java 方法 (需要 [kotlin-jvm-blocking-bridge](https://github.com/mamoe/kotlin-jvm-blocking-bridge)) (#512)
|
||||
@ -8,7 +11,7 @@
|
||||
## `1.2.0` 2020/8/19
|
||||
|
||||
### 新特性
|
||||
- 初步语音支持: `Group.uploadVoice`, 支持 silk 或 arm 格式.
|
||||
- 初步语音支持: `Group.uploadVoice`, 支持 silk 或 amr 格式.
|
||||
**注意**: 现阶段语音实现仅为临时方案, 在将来 (`2.0.0`) 一定会变动. 使用时请评估可能带来的不兼容性.
|
||||
|
||||
- 新增将日志转换为 log4j, JDK Logger, SLF4J 等框架的方法: `LoggerAdapters` (#498 by [@Karlatemp](https://github.com/Karlatemp))
|
||||
|
@ -8,6 +8,12 @@ mirai 欢迎一切形式的代码贡献。你可以通过以下几种途径向 m
|
||||
|
||||
**阅读文档**: [docs/mirai.md](docs/mirai.md)
|
||||
|
||||
### 构建
|
||||
- 要构建项目, 请运行 `gradlew assemble`
|
||||
- 要运行测试, 请运行 `gradlew test`
|
||||
- 要构建项目并运行测试, 请运行 `gradlew build`
|
||||
- 若要添加一个 suspend 函数, 请务必考虑 Java 兼容性, 使用 [kotlin-jvm-blocking-bridge](https://github.com/mamoe/kotlin-jvm-blocking-bridge/blob/master/README-chs.md)
|
||||
|
||||
### 能做什么?
|
||||
|
||||
**请基于 `master` 分支进行文档修改; 基于 `dev` 分支进行其他修改 (否则你的修改可能被关闭或不会立即合并)**
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
object Versions {
|
||||
object Mirai {
|
||||
const val version = "1.2.1"
|
||||
const val version = "1.2.2"
|
||||
}
|
||||
|
||||
object Kotlin {
|
||||
|
@ -60,14 +60,12 @@ kotlin {
|
||||
|
||||
val commonMain by getting {
|
||||
dependencies {
|
||||
api(kotlinx("serialization-core", Versions.Kotlin.serialization))
|
||||
api1(kotlinx("serialization-core", Versions.Kotlin.serialization))
|
||||
api(kotlinx("coroutines-core", Versions.Kotlin.coroutines))
|
||||
implementation(kotlinx("serialization-protobuf", Versions.Kotlin.serialization))
|
||||
api("org.jetbrains.kotlinx:atomicfu:${Versions.Kotlin.atomicFU}")
|
||||
api(kotlinx("io", Versions.Kotlin.io)) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
}
|
||||
implementation(kotlinx("coroutines-io", Versions.Kotlin.coroutinesIo))
|
||||
implementation1(kotlinx("serialization-protobuf", Versions.Kotlin.serialization))
|
||||
api1("org.jetbrains.kotlinx:atomicfu:${Versions.Kotlin.atomicFU}")
|
||||
api1(kotlinx("io", Versions.Kotlin.io))
|
||||
implementation1(kotlinx("coroutines-io", Versions.Kotlin.coroutinesIo))
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,11 +95,8 @@ kotlin {
|
||||
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE
|
||||
implementation("org.bouncycastle:bcprov-jdk15on:1.64")
|
||||
api(kotlinx("io-jvm", Versions.Kotlin.io)) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
}
|
||||
api1(kotlinx("io-jvm", Versions.Kotlin.io))
|
||||
// api(kotlinx("coroutines-debug", Versions.Kotlin.coroutines))
|
||||
}
|
||||
}
|
||||
@ -112,14 +107,29 @@ kotlin {
|
||||
implementation(kotlin("test", Versions.Kotlin.compiler))
|
||||
implementation(kotlin("test-junit", Versions.Kotlin.compiler))
|
||||
implementation("org.pcap4j:pcap4j-distribution:1.8.2")
|
||||
|
||||
runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE
|
||||
runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.implementation1(dependencyNotation: String) =
|
||||
implementation(dependencyNotation) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-common")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-metadata")
|
||||
}
|
||||
|
||||
fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.api1(dependencyNotation: String) =
|
||||
api(dependencyNotation) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-common")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-metadata")
|
||||
}
|
||||
|
||||
apply(from = rootProject.file("gradle/publish.gradle"))
|
||||
|
||||
|
||||
|
@ -180,7 +180,7 @@ internal class MemberImpl constructor(
|
||||
check(this.id != bot.id) {
|
||||
"A bot can't mute itself."
|
||||
}
|
||||
checkBotPermissionHigherThanThis()
|
||||
checkBotPermissionHigherThanThis("mute")
|
||||
bot.network.run {
|
||||
TroopManagement.Mute(
|
||||
client = bot.client,
|
||||
@ -194,10 +194,10 @@ internal class MemberImpl constructor(
|
||||
net.mamoe.mirai.event.events.MemberMuteEvent(this@MemberImpl, durationSeconds, null).broadcast()
|
||||
}
|
||||
|
||||
private fun checkBotPermissionHigherThanThis() {
|
||||
private fun checkBotPermissionHigherThanThis(operationName: String) {
|
||||
check(group.botPermission > this.permission) {
|
||||
throw PermissionDeniedException(
|
||||
"`kick` operation requires bot to have a higher permission than the target member, " +
|
||||
"`$operationName` operation requires bot to have a higher permission than the target member, " +
|
||||
"but bot's is ${group.botPermission}, target's is ${this.permission}"
|
||||
)
|
||||
}
|
||||
@ -205,7 +205,7 @@ internal class MemberImpl constructor(
|
||||
|
||||
@JvmSynthetic
|
||||
override suspend fun unmute() {
|
||||
checkBotPermissionHigherThanThis()
|
||||
checkBotPermissionHigherThanThis("unmute")
|
||||
bot.network.run {
|
||||
TroopManagement.Mute(
|
||||
client = bot.client,
|
||||
@ -222,7 +222,7 @@ internal class MemberImpl constructor(
|
||||
|
||||
@JvmSynthetic
|
||||
override suspend fun kick(message: String) {
|
||||
checkBotPermissionHigherThanThis()
|
||||
checkBotPermissionHigherThanThis("kick")
|
||||
check(group.members.getOrNull(this.id) != null) {
|
||||
"Member ${this.id} had already been kicked from group ${group.id}"
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ internal class MsgSvc : ProtoBuf {
|
||||
@ProtoNumber(1) @JvmField val result: Int = 0,
|
||||
@ProtoNumber(2) @JvmField val errmsg: String = "",
|
||||
@ProtoNumber(3) @JvmField val syncCookie: ByteArray? = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(4) @JvmField val syncFlag: SyncFlag,
|
||||
@ProtoNumber(4) @JvmField val syncFlag: SyncFlag = SyncFlag.CONTINUE,
|
||||
@ProtoNumber(5) @JvmField val uinPairMsgs: List<MsgComm.UinPairMsg>? = null,
|
||||
@ProtoNumber(6) @JvmField val bindUin: Long = 0L,
|
||||
@ProtoNumber(7) @JvmField val msgRspType: Int = 0,
|
||||
|
@ -14,6 +14,7 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
|
||||
import kotlinx.atomicfu.loop
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
@ -43,6 +44,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.GroupInfoImpl
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.NewContact
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.qqandroid.utils._miraiContentToString
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.utils.read
|
||||
@ -56,6 +58,12 @@ import net.mamoe.mirai.utils.warning
|
||||
* 获取好友消息和消息记录
|
||||
*/
|
||||
internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Response>("MessageSvc.PbGetMsg") {
|
||||
|
||||
|
||||
private val msgUidQueue = ArrayDeque<Long>()
|
||||
private val msgUidSet = hashSetOf<Long>()
|
||||
private val msgQueueMutex = Mutex()
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
operator fun invoke(
|
||||
client: QQAndroidClient,
|
||||
@ -114,8 +122,9 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
||||
|
||||
private fun MsgComm.Msg.getNewMemberInfo(): MemberInfo {
|
||||
return object : MemberInfo {
|
||||
override val nameCard: String get() = msgHead.authNick.takeIf { it.isNotEmpty() }
|
||||
?: msgHead.fromNick
|
||||
override val nameCard: String
|
||||
get() = msgHead.authNick.takeIf { it.isNotEmpty() }
|
||||
?: msgHead.fromNick
|
||||
override val permission: MemberPermission get() = MemberPermission.MEMBER
|
||||
override val specialTitle: String get() = ""
|
||||
override val muteTimestamp: Int get() = 0
|
||||
@ -135,9 +144,23 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
||||
.warning { "MessageSvcPushNotify: result != 0, result = ${resp.result}, errorMsg=${resp.errmsg}" }
|
||||
return EmptyResponse
|
||||
}
|
||||
when (resp.msgRspType) {
|
||||
0 -> {
|
||||
bot.client.c2cMessageSync.syncCookie = resp.syncCookie
|
||||
bot.client.c2cMessageSync.pubAccountCookie = resp.pubAccountCookie
|
||||
}
|
||||
1 -> {
|
||||
bot.client.c2cMessageSync.syncCookie = resp.syncCookie
|
||||
}
|
||||
2 -> {
|
||||
bot.client.c2cMessageSync.pubAccountCookie = resp.pubAccountCookie
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// bot.logger.debug(resp.msgRspType._miraiContentToString())
|
||||
// bot.logger.debug(resp.syncCookie._miraiContentToString())
|
||||
|
||||
bot.client.c2cMessageSync.syncCookie = resp.syncCookie
|
||||
bot.client.c2cMessageSync.pubAccountCookie = resp.pubAccountCookie
|
||||
bot.client.c2cMessageSync.msgCtrlBuf = resp.msgCtrlBuf
|
||||
|
||||
if (resp.uinPairMsgs == null) {
|
||||
@ -151,10 +174,21 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
||||
.filter { msg: MsgComm.Msg -> msg.msgHead.msgTime > it.lastReadTime.toLong() and 4294967295L }
|
||||
}.also {
|
||||
MessageSvcPbDeleteMsg.delete(bot, it) // 删除消息
|
||||
// todo 实现一个锁来防止重复收到消息
|
||||
}
|
||||
.mapNotNull<MsgComm.Msg, Packet> { msg ->
|
||||
|
||||
msgQueueMutex.lock()
|
||||
val msgUid = msg.msgHead.msgUid
|
||||
if (msgUidSet.size > 50) {
|
||||
msgUidSet.remove(msgUidQueue.removeFirst())
|
||||
}
|
||||
if (!msgUidSet.add(msgUid)) {
|
||||
msgQueueMutex.unlock()
|
||||
return@mapNotNull null
|
||||
}
|
||||
msgQueueMutex.unlock()
|
||||
msgUidQueue.addLast(msgUid)
|
||||
|
||||
suspend fun createGroupForBot(groupUin: Long): Group? {
|
||||
val group = bot.getGroupByUinOrNull(groupUin)
|
||||
if (group != null) {
|
||||
@ -294,18 +328,15 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
if (friend.lastMessageSequence.compareAndSet(
|
||||
friend.lastMessageSequence.value,
|
||||
msg.msgHead.msgSeq
|
||||
)
|
||||
) {
|
||||
return@mapNotNull FriendMessageEvent(
|
||||
friend,
|
||||
msg.toMessageChain(bot, groupIdOrZero = 0, onlineSource = true),
|
||||
msg.msgHead.msgTime
|
||||
)
|
||||
friend.lastMessageSequence.loop {
|
||||
if (friend.lastMessageSequence.compareAndSet(it, msg.msgHead.msgSeq)) {
|
||||
return@mapNotNull FriendMessageEvent(
|
||||
friend,
|
||||
msg.toMessageChain(bot, groupIdOrZero = 0, onlineSource = true),
|
||||
msg.msgHead.msgTime
|
||||
)
|
||||
} else return@mapNotNull null
|
||||
}
|
||||
return@mapNotNull null
|
||||
}
|
||||
208 -> {
|
||||
// friend ptt
|
||||
@ -387,7 +418,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
||||
MessageSvcPbGetMsg(
|
||||
client,
|
||||
MsgSvc.SyncFlag.CONTINUE,
|
||||
packet.syncCookie
|
||||
bot.client.c2cMessageSync.syncCookie
|
||||
).sendAndExpect<Packet>()
|
||||
}
|
||||
return
|
||||
@ -398,7 +429,7 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
|
||||
MessageSvcPbGetMsg(
|
||||
client,
|
||||
MsgSvc.SyncFlag.CONTINUE,
|
||||
packet.syncCookie
|
||||
bot.client.c2cMessageSync.syncCookie
|
||||
).sendAndExpect<Packet>()
|
||||
}
|
||||
return
|
||||
|
@ -63,21 +63,17 @@ kotlin {
|
||||
api(kotlin("serialization"))
|
||||
api(kotlin("reflect"))
|
||||
|
||||
api(kotlinx("serialization-core", Versions.Kotlin.serialization))
|
||||
implementation(kotlinx("serialization-protobuf", Versions.Kotlin.serialization))
|
||||
api(kotlinx("io", Versions.Kotlin.io)) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
}
|
||||
api(kotlinx("coroutines-io", Versions.Kotlin.coroutinesIo)) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
}
|
||||
api1(kotlinx("serialization-core", Versions.Kotlin.serialization))
|
||||
implementation1(kotlinx("serialization-protobuf", Versions.Kotlin.serialization))
|
||||
api1(kotlinx("io", Versions.Kotlin.io))
|
||||
api1(kotlinx("coroutines-io", Versions.Kotlin.coroutinesIo))
|
||||
api(kotlinx("coroutines-core", Versions.Kotlin.coroutines))
|
||||
|
||||
implementation("org.jetbrains.kotlinx:atomicfu:${Versions.Kotlin.atomicFU}")
|
||||
implementation1("org.jetbrains.kotlinx:atomicfu:${Versions.Kotlin.atomicFU}")
|
||||
|
||||
api(ktor("client-cio"))
|
||||
api(ktor("client-core"))
|
||||
api(ktor("network"))
|
||||
api1(ktor("client-cio"))
|
||||
api1(ktor("client-core"))
|
||||
api1(ktor("network"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,14 +89,10 @@ kotlin {
|
||||
dependencies {
|
||||
api(kotlin("reflect"))
|
||||
|
||||
api(kotlinx("io-jvm", Versions.Kotlin.io)) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
}
|
||||
api(kotlinx("coroutines-io-jvm", Versions.Kotlin.coroutinesIo)) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
}
|
||||
api1(kotlinx("io-jvm", Versions.Kotlin.io))
|
||||
api1(kotlinx("coroutines-io-jvm", Versions.Kotlin.coroutinesIo))
|
||||
|
||||
api(ktor("client-android", Versions.Kotlin.ktor))
|
||||
api1(ktor("client-android", Versions.Kotlin.ktor))
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,21 +108,13 @@ kotlin {
|
||||
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
//api(kotlin("stdlib-jdk8"))
|
||||
//api(kotlin("stdlib-jdk7"))
|
||||
api(kotlin("reflect"))
|
||||
compileOnly("org.apache.logging.log4j:log4j-api:" + Versions.Logging.log4j)
|
||||
compileOnly("org.slf4j:slf4j-api:" + Versions.Logging.slf4j)
|
||||
|
||||
api(ktor("client-core-jvm", Versions.Kotlin.ktor))
|
||||
api(kotlinx("io-jvm", Versions.Kotlin.io)) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
}
|
||||
api(kotlinx("coroutines-io-jvm", Versions.Kotlin.coroutinesIo)) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
}
|
||||
|
||||
runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE
|
||||
api1(ktor("client-core-jvm", Versions.Kotlin.ktor))
|
||||
api1(kotlinx("io-jvm", Versions.Kotlin.io))
|
||||
api1(kotlinx("coroutines-io-jvm", Versions.Kotlin.coroutinesIo))
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,6 +130,24 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.implementation1(dependencyNotation: String) =
|
||||
implementation(dependencyNotation) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-common")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-metadata")
|
||||
}
|
||||
|
||||
fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.api1(dependencyNotation: String) =
|
||||
api(dependencyNotation) {
|
||||
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-common")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-jvm")
|
||||
exclude("org.jetbrains.kotlinx", "kotlinx-coroutines-core-metadata")
|
||||
}
|
||||
|
||||
apply(from = rootProject.file("gradle/publish.gradle"))
|
||||
|
||||
tasks.withType<com.jfrog.bintray.gradle.tasks.BintrayUploadTask> {
|
||||
|
@ -26,7 +26,7 @@ import kotlin.reflect.KClass
|
||||
internal fun <L : Listener<E>, E : Event> KClass<out E>.subscribeInternal(listener: L): L {
|
||||
with(GlobalEventListeners[listener.priority]) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val node = ListenerNode(listener as Listener<Event>, this@subscribeInternal)
|
||||
val node = ListenerRegistry(listener as Listener<Event>, this@subscribeInternal)
|
||||
addLast(node)
|
||||
listener.invokeOnCompletion {
|
||||
this.remove(node)
|
||||
@ -107,13 +107,13 @@ internal class Handler<in E : Event> internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
internal class ListenerNode(
|
||||
internal class ListenerRegistry(
|
||||
val listener: Listener<Event>,
|
||||
val owner: KClass<out Event>
|
||||
val type: KClass<out Event>
|
||||
)
|
||||
|
||||
internal expect object GlobalEventListeners {
|
||||
operator fun get(priority: Listener.EventPriority): LockFreeLinkedList<ListenerNode>
|
||||
operator fun get(priority: Listener.EventPriority): LockFreeLinkedList<ListenerRegistry>
|
||||
}
|
||||
|
||||
internal expect class MiraiAtomicBoolean(initial: Boolean) {
|
||||
@ -135,50 +135,50 @@ internal suspend inline fun AbstractEvent.broadcastInternal() {
|
||||
internal suspend inline fun <E : AbstractEvent> callAndRemoveIfRequired(
|
||||
event: E
|
||||
) {
|
||||
for (p in Listener.EventPriority.valuesExceptMonitor) {
|
||||
GlobalEventListeners[p].forEachNode { eventNode ->
|
||||
for (p in Listener.EventPriority.prioritiesExcludedMonitor) {
|
||||
GlobalEventListeners[p].forEachNode { registeredRegistryNode ->
|
||||
if (event.isIntercepted) {
|
||||
return
|
||||
}
|
||||
val node = eventNode.nodeValue
|
||||
if (!node.owner.isInstance(event)) return@forEachNode
|
||||
val listener = node.listener
|
||||
val listenerRegistry = registeredRegistryNode.nodeValue
|
||||
if (!listenerRegistry.type.isInstance(event)) return@forEachNode
|
||||
val listener = listenerRegistry.listener
|
||||
when (listener.concurrencyKind) {
|
||||
Listener.ConcurrencyKind.LOCKED -> {
|
||||
(listener as Handler).lock!!.withLock {
|
||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
||||
removeNode(eventNode)
|
||||
removeNode(registeredRegistryNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
Listener.ConcurrencyKind.CONCURRENT -> {
|
||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
||||
removeNode(eventNode)
|
||||
removeNode(registeredRegistryNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
coroutineScope {
|
||||
GlobalEventListeners[EventPriority.MONITOR].forEachNode { eventNode ->
|
||||
GlobalEventListeners[EventPriority.MONITOR].forEachNode { registeredRegistryNode ->
|
||||
if (event.isIntercepted) {
|
||||
return@coroutineScope
|
||||
}
|
||||
val node = eventNode.nodeValue
|
||||
if (!node.owner.isInstance(event)) return@forEachNode
|
||||
val listener = node.listener
|
||||
val listenerRegistry = registeredRegistryNode.nodeValue
|
||||
if (!listenerRegistry.type.isInstance(event)) return@forEachNode
|
||||
val listener = listenerRegistry.listener
|
||||
launch {
|
||||
when (listener.concurrencyKind) {
|
||||
Listener.ConcurrencyKind.LOCKED -> {
|
||||
(listener as Handler).lock!!.withLock {
|
||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
||||
removeNode(eventNode)
|
||||
removeNode(registeredRegistryNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
Listener.ConcurrencyKind.CONCURRENT -> {
|
||||
if (listener.onEvent(event) == ListeningStatus.STOPPED) {
|
||||
removeNode(eventNode)
|
||||
removeNode(registeredRegistryNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +110,9 @@ public interface Listener<in E : Event> : CompletableJob {
|
||||
|
||||
internal companion object {
|
||||
@JvmStatic
|
||||
internal val valuesExceptMonitor: Array<EventPriority> = arrayOf(HIGHEST, HIGH, NORMAL, LOW, LOWEST)
|
||||
internal val prioritiesExcludedMonitor: Array<EventPriority> = run {
|
||||
values().filter { it != MONITOR }.toTypedArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -844,7 +844,7 @@ internal open class LockFreeLinkedListNode<E>(
|
||||
* [Tail], is not being tested.
|
||||
*/
|
||||
inline fun allMatching(condition: (LockFreeLinkedListNode<E>) -> Boolean): Boolean =
|
||||
this.childIterateReturnsLastSatisfying({ it.nextNode }, condition) !is Tail
|
||||
this.childIterateReturnsLastSatisfying({ it.nextNode }, condition) is Tail
|
||||
|
||||
/**
|
||||
* Stop on and returns the former element of the element that is [equals] to the [element]
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.event.internal
|
||||
|
||||
import net.mamoe.mirai.event.Listener
|
||||
import net.mamoe.mirai.utils.LockFreeLinkedList
|
||||
import java.util.*
|
||||
|
||||
|
||||
internal actual object GlobalEventListeners {
|
||||
private val ALL_LEVEL_REGISTRIES: Map<Listener.EventPriority, LockFreeLinkedList<ListenerRegistry>>
|
||||
|
||||
init {
|
||||
val map = EnumMap<Listener.EventPriority, LockFreeLinkedList<ListenerRegistry>>(Listener.EventPriority::class.java)
|
||||
Listener.EventPriority.values().forEach {
|
||||
map[it] = LockFreeLinkedList()
|
||||
}
|
||||
this.ALL_LEVEL_REGISTRIES = map
|
||||
}
|
||||
|
||||
actual operator fun get(priority: Listener.EventPriority): LockFreeLinkedList<ListenerRegistry> = ALL_LEVEL_REGISTRIES[priority]!!
|
||||
|
||||
}
|
@ -9,16 +9,10 @@
|
||||
|
||||
package net.mamoe.mirai.event.internal
|
||||
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.event.Listener
|
||||
import net.mamoe.mirai.utils.LockFreeLinkedList
|
||||
import net.mamoe.mirai.utils.LockFreeLinkedListNode
|
||||
import net.mamoe.mirai.utils.isRemoved
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
internal actual class MiraiAtomicBoolean actual constructor(initial: Boolean) {
|
||||
private val delegate: AtomicBoolean = AtomicBoolean(initial)
|
||||
@ -33,42 +27,3 @@ internal actual class MiraiAtomicBoolean actual constructor(initial: Boolean) {
|
||||
delegate.set(value)
|
||||
}
|
||||
}
|
||||
|
||||
internal actual object GlobalEventListeners {
|
||||
private val map: Map<Listener.EventPriority, LockFreeLinkedList<ListenerNode>>
|
||||
|
||||
init {
|
||||
val map = EnumMap<Listener.EventPriority, LockFreeLinkedList<ListenerNode>>(Listener.EventPriority::class.java)
|
||||
Listener.EventPriority.values().forEach {
|
||||
map[it] = LockFreeLinkedList()
|
||||
}
|
||||
this.map = map
|
||||
}
|
||||
|
||||
actual operator fun get(priority: Listener.EventPriority): LockFreeLinkedList<ListenerNode> = map[priority]!!
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
internal actual class EventListeners<E : Event> actual constructor(clazz: KClass<E>) :
|
||||
LockFreeLinkedList<Listener<E>>() {
|
||||
@Suppress("UNCHECKED_CAST", "UNSUPPORTED", "NO_REFLECTION_IN_CLASS_PATH")
|
||||
actual val supertypes: Set<KClass<out Event>> by lazy {
|
||||
val supertypes = mutableSetOf<KClass<out Event>>()
|
||||
|
||||
fun addSupertypes(klass: KClass<out Event>) {
|
||||
klass.supertypes.forEach {
|
||||
val classifier = it.classifier as? KClass<out Event>
|
||||
if (classifier != null) {
|
||||
supertypes.add(classifier)
|
||||
addSupertypes(classifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
addSupertypes(clazz)
|
||||
|
||||
supertypes
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
@ -33,6 +33,14 @@ internal class LockFreeLinkedListTest {
|
||||
list.size shouldBeEqualTo 4
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isEmpty() {
|
||||
val list = LockFreeLinkedList<Int>()
|
||||
assertTrue { list.isEmpty() }
|
||||
list.addLast(1)
|
||||
assertFalse { list.isEmpty() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addAndGetConcurrent() = runBlocking {
|
||||
//withContext(Dispatchers.Default){
|
||||
|
Loading…
Reference in New Issue
Block a user