Commit 09524da1 authored by Him188's avatar Him188

Add docs, rearrange implementations

parent 716e3ade
......@@ -24,10 +24,7 @@ import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.json.int
import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotImpl
import net.mamoe.mirai.LowLevelAPI
import net.mamoe.mirai.ThisApiMustBeUsedInWithConnectionLockBlock
import net.mamoe.mirai.*
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.*
import net.mamoe.mirai.event.broadcast
......@@ -82,10 +79,18 @@ internal class QQAndroidBot constructor(
@OptIn(LowLevelAPI::class)
override suspend fun acceptNewFriendRequest(event: NewFriendRequestEvent) {
check(event.bot === this) {
"the request $event is from Bot ${event.bot.id} but you are responding with bot ${this.id}"
}
check(event.responded.compareAndSet(false, true)) {
"the request $this has already been responded"
}
check(!friends.contains(event.fromId)) {
"the request $event is outdated: You had already responded it on another device."
}
network.run {
NewContact.SystemMsgNewFriend.Action(
bot.client,
......@@ -100,8 +105,16 @@ internal class QQAndroidBot constructor(
}
override suspend fun rejectNewFriendRequest(event: NewFriendRequestEvent, blackList: Boolean) {
check(event.bot === this) {
"the request $event is from Bot ${event.bot.id} but you are responding with bot ${this.id}"
}
check(event.responded.compareAndSet(false, true)) {
"the request $this has already been responded"
"the request $event has already been responded"
}
check(!friends.contains(event.fromId)) {
"the request $event is outdated: You had already responded it on another device."
}
network.run {
......@@ -116,10 +129,16 @@ internal class QQAndroidBot constructor(
@OptIn(LowLevelAPI::class)
override suspend fun acceptMemberJoinRequest(event: MemberJoinRequestEvent) {
@Suppress("DuplicatedCode")
checkGroupPermission(event.bot, event.group) { event::class.simpleName ?: "<anonymous class>" }
check(event.responded.compareAndSet(false, true)) {
"the request $this has already been responded"
}
check(!event.group.members.contains(event.fromId)) {
"the request $this is outdated: Another operator has already responded it."
}
network.run {
NewContact.SystemMsgNewGroup.Action(
bot.client,
......@@ -137,11 +156,17 @@ internal class QQAndroidBot constructor(
}
}
@Suppress("DuplicatedCode")
@OptIn(LowLevelAPI::class)
override suspend fun rejectMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean) {
checkGroupPermission(event.bot, event.group) { event::class.simpleName ?: "<anonymous class>" }
check(event.responded.compareAndSet(false, true)) {
"the request $this has already been responded"
}
check(!event.group.members.contains(event.fromId)) {
"the request $this is outdated: Another operator has already responded it."
}
network.run {
NewContact.SystemMsgNewGroup.Action(
bot.client,
......@@ -152,7 +177,22 @@ internal class QQAndroidBot constructor(
}
}
private inline fun checkGroupPermission(eventBot: Bot, eventGroup: Group, eventName: () -> String) {
val group = this.getGroupOrNull(eventGroup.id)
?: kotlin.run {
if (this == eventBot) {
error("A ${eventName()} is outdated. Group ${eventGroup.id} not found for bot ${this.id}. " +
"This is because bot isn't in the group anymore")
} else {
error("A ${eventName()} is from bot ${eventBot.id}, but you are trying to respond it using bot ${this.id} who isn't a member of the group ${eventGroup.id}")
}
}
group.checkBotPermissionOperator()
}
override suspend fun ignoreMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean) {
checkGroupPermission(event.bot, event.group) { event::class.simpleName ?: "<anonymous class>" }
check(event.responded.compareAndSet(false, true)) {
"the request $this has already been responded"
}
......
......@@ -44,7 +44,7 @@ import kotlin.jvm.JvmSynthetic
@OptIn(MiraiInternalAPI::class)
open class MessageReceipt<out C : Contact>(
/**
* 指代发送出去的消息
* 指代发送出去的消息.
*/
val source: OnlineMessageSource.Outgoing,
/**
......
......@@ -12,11 +12,9 @@
package net.mamoe.mirai.message.data
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.SinceMirai
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
private const val displayA = "@全体成员"
......@@ -50,15 +48,6 @@ object AtAll :
}
// 自动为消息补充 " "
@OptIn(MiraiInternalAPI::class)
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_FUNCTION_RETURN_TYPE")
@JvmName("followedBy")
@JvmSynthetic
override fun followedBy1(tail: Message): CombinedMessage {
return followedByInternalForBinaryCompatibility(tail)
}
override fun followedBy(tail: Message): MessageChain {
if (tail is PlainText && tail.stringValue.startsWith(' ')) {
return super.followedBy(tail)
......
......@@ -8,6 +8,8 @@
*/
@file:Suppress("unused", "NOTHING_TO_INLINE")
@file:JvmMultifileClass
@file:JvmName("MessageUtils") // since 0.39.1
package net.mamoe.mirai.message.data
......@@ -15,10 +17,7 @@ import net.mamoe.mirai.message.data.PokeMessage.Types
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.SinceMirai
import kotlin.jvm.JvmField
import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic
import kotlin.jvm.JvmSynthetic
import kotlin.jvm.*
/**
* 一些特殊的消息
......
......@@ -19,7 +19,6 @@ import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotImpl
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.SinceMirai
......@@ -38,7 +37,7 @@ import kotlin.jvm.JvmSynthetic
*
* ### [toString] 和 [contentToString]
* - [toString] 固定返回 `[mirai:image:<ID>]` 格式字符串, 其中 `<ID>` 代表 [imageId].
* - [contentToString] 固定返回 `"[图片]"`
* - [contentToString] 固定返回 ```"[图片]"```
*
* ### 上传和发送图片
* @see Contact.uploadImage 上传 [图片文件][ExternalImage] 并得到 [Image] 消息
......
......@@ -8,6 +8,8 @@
*/
@file:Suppress("MemberVisibilityCanBePrivate", "unused", "EXPERIMENTAL_API_USAGE", "NOTHING_TO_INLINE")
@file:JvmMultifileClass
@file:JvmName("MessageUtils")
package net.mamoe.mirai.message.data
......@@ -17,6 +19,7 @@ import net.mamoe.mirai.message.data.Message.Key
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.SinceMirai
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
......@@ -313,6 +316,8 @@ interface SingleMessage : Message, CharSequence, Comparable<String> {
/**
* 消息元数据, 即不含内容的元素.
*
* 所有子类的 [contentToString] 都应该返回空字符串.
*
* @see MessageSource 消息源
* @see QuoteReply 引用回复
* @see CustomMessageMetadata 自定义元数据
......@@ -328,11 +333,12 @@ interface MessageMetadata : SingleMessage {
/**
* 约束一个 [MessageChain] 中只存在这一种类型的元素. 新元素将会替换旧元素, 保持原顺序.
*
* 实现此接口的元素将会在连接时自动处理替换.
*/
@SinceMirai("0.34.0")
interface ConstrainSingle<out M : Message> : MessageMetadata {
val key: Message.Key<M>
val key: Key<M>
}
/**
......
......@@ -142,9 +142,7 @@ inline fun MessageChain.allContent(block: (MessageContent) -> Boolean): Boolean
this.forEach {
if (it !is MessageMetadata) {
check(it is MessageContent) { "internal error: Message must be either MessageMetaData or MessageContent" }
if (!block(it)) {
return false
}
if (!block(it)) return false
}
}
return true
......@@ -158,9 +156,7 @@ inline fun MessageChain.noneContent(block: (MessageContent) -> Boolean): Boolean
this.forEach {
if (it !is MessageMetadata) {
check(it is MessageContent) { "internal error: Message must be either MessageMetaData or MessageContent" }
if (block(it)) {
return false
}
if (block(it)) return false
}
}
return true
......
......@@ -25,6 +25,9 @@ import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
/**
* 将在线消息源转换为离线消息源.
*/
@SinceMirai("0.39.0")
@JvmName("toOfflineMessageSource")
fun OnlineMessageSource.toOffline(): OfflineMessageSource =
......@@ -60,6 +63,14 @@ interface MessageSourceAmender {
var internalId: Int
var originalMessage: MessageChain
/** 从另一个 [MessageSource] 中复制 [id], [internalId], [time]*/
@SinceMirai("0.39.2")
fun metadataFrom(another: MessageSource) {
this.id = another.id
this.internalId = another.internalId
this.time = another.time
}
}
......
......@@ -15,7 +15,6 @@ package net.mamoe.mirai.message.data
import kotlinx.coroutines.Job
import net.mamoe.mirai.Bot
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.SinceMirai
import kotlin.coroutines.CoroutineContext
......@@ -29,10 +28,19 @@ import kotlin.jvm.JvmSynthetic
/**
* 引用回复.
*
* 可以引用一条群消息并发送给一个好友, 或是引用好友消息发送给群.
* 可以引用自己发出的消息. 详见 [MessageReceipt.quote]
* 支持引用任何一条消息发送给任何人.
*
* @see MessageSource 获取更多信息
* #### [source] 的类型:
* - 在发送引用回复时, [source] 类型为 [OnlineMessageSource] 或 [OfflineMessageSource]
* - 在接收引用回复时, [source] 类型一定为 [OfflineMessageSource]
*
* #### 原消息内容
* 引用回复的原消息内容完全由 [source] 中 [MessageSource.originalMessage] 控制, 客户端不会自行寻找原消息.
*
* #### 客户端内跳转
* 客户端在跳转原消息时, 会通过 [MessageSource.id] 等 metadata
*
* @see MessageSource 获取有关消息源的更多信息
*/
@OptIn(MiraiExperimentalAPI::class)
@SinceMirai("0.33.0")
......@@ -50,26 +58,52 @@ class QuoteReply(val source: MessageSource) : Message, MessageMetadata, Constrai
override fun hashCode(): Int = source.hashCode()
}
/**
* @see MessageSource.id
*/
@get:JvmSynthetic
inline val QuoteReply.id: Int
get() = source.id
/**
* @see MessageSource.internalId
*/
@SinceMirai("0.39.2")
@get:JvmSynthetic
inline val QuoteReply.internalId: Int
get() = source.internalId
/**
* @see MessageSource.fromId
*/
@get:JvmSynthetic
inline val QuoteReply.fromId: Long
get() = source.fromId
/**
* @see MessageSource.targetId
*/
@get:JvmSynthetic
inline val QuoteReply.targetId: Long
get() = source.targetId
/**
* @see MessageSource.originalMessage
*/
@get:JvmSynthetic
inline val QuoteReply.originalMessage: MessageChain
get() = source.originalMessage
/**
* @see MessageSource.time
*/
@get:JvmSynthetic
inline val QuoteReply.time: Int
get() = source.time
/**
* @see MessageSource.bot
*/
@get:JvmSynthetic
inline val QuoteReply.bot: Bot
get() = source.bot
......@@ -78,6 +112,9 @@ inline val QuoteReply.bot: Bot
@JvmSynthetic
suspend inline fun QuoteReply.recall() = this.source.recall()
/**
* 在一段时间后撤回这条消息.
*/
@JvmOverloads
inline fun QuoteReply.recallIn(
millis: Long,
......
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:JvmName("HummerMessageKt")
@file:Suppress("NOTHING_TO_INLINE")
package net.mamoe.mirai.message.data
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.SinceMirai
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
/*
因为文件改名为做的兼容
*/
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("flash")
@SinceMirai("0.33.0")
inline fun Image.flash2(): FlashImage = FlashImage(this)
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("flash")
@JvmSynthetic
@SinceMirai("0.33.0")
inline fun GroupImage.flash2(): GroupFlashImage = FlashImage(this) as GroupFlashImage
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("flash")
@JvmSynthetic
@SinceMirai("0.33.0")
inline fun FriendImage.flash2(): FriendFlashImage = FlashImage(this) as FriendFlashImage
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:JvmName("MessageKt")
@file:Suppress("NOTHING_TO_INLINE")
package net.mamoe.mirai.message.data
import net.mamoe.mirai.utils.PlannedRemoval
import kotlin.jvm.JvmName
/*
因为文件改名为做的兼容
*/
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("isPlain")
inline fun Message.isPlain2(): Boolean = this is PlainText
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("isNotPlain")
inline fun Message.isNotPlain2(): Boolean = this !is PlainText
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("repeat")
// inline: for future removal
inline fun Message.repeat2(count: Int): MessageChain {
if (this is ConstrainSingle<*>) {
// fast-path
return this.asMessageChain()
}
return buildMessageChain(count) {
add(this@repeat2)
}
}
......@@ -42,6 +42,8 @@ inline fun buildMessageChain(initialSize: Int, block: MessageChainBuilder.() ->
/**
* [MessageChain] 构建器.
* 多个连续的 [String] 会被连接为单个 [PlainText] 以优化性能.
*
*
* **注意:** 无并发安全性.
*
* @see buildMessageChain 推荐使用
......@@ -91,6 +93,7 @@ open class MessageChainBuilder private constructor(
return addAll(elements.flatten())
}
@JvmSynthetic
operator fun Message.unaryPlus() {
checkBuilt()
flushCache()
......@@ -98,22 +101,26 @@ open class MessageChainBuilder private constructor(
}
@JvmSynthetic
operator fun String.unaryPlus() {
checkBuilt()
add(this)
}
@JvmSynthetic // they should use add
operator fun plusAssign(plain: String) {
checkBuilt()
withCache { append(plain) }
}
@JvmSynthetic // they should use add
operator fun plusAssign(message: Message) {
checkBuilt()
flushCache()
this.add(message)
}
@JvmSynthetic // they should use add
operator fun plusAssign(message: SingleMessage) { // avoid resolution ambiguity
checkBuilt()
flushCache()
......@@ -125,6 +132,7 @@ open class MessageChainBuilder private constructor(
withCache { append(plain) }
}
@JvmSynthetic // they should use add
operator fun plusAssign(charSequence: CharSequence) {
checkBuilt()
withCache { append(charSequence) }
......
......@@ -311,9 +311,11 @@ internal class SingleMessageChainImpl constructor(
@SharedImmutable
@get:JvmSynthetic
internal val EMPTY_BYTE_ARRAY = ByteArray(0)
@JvmSynthetic
@Suppress("NOTHING_TO_INLINE") // no stack waste
internal inline fun Char.hexDigitToByte(): Int {
return when (this) {
......@@ -324,6 +326,7 @@ internal inline fun Char.hexDigitToByte(): Int {
}
}
@JvmSynthetic
internal fun String.skipToSecondHyphen(): Int {
var count = 0
this.forEachIndexed { index, c ->
......@@ -332,6 +335,7 @@ internal fun String.skipToSecondHyphen(): Int {
error("cannot find two hyphens")
}
@JvmSynthetic
internal fun String.imageIdToMd5(offset: Int): ByteArray {
val result = ByteArray(16)
var cur = 0
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment