1
0
mirror of https://github.com/mamoe/mirai.git synced 2025-04-25 13:03:35 +08:00

update docs

This commit is contained in:
Him188 2019-10-28 20:12:39 +08:00
parent e7725bdcaa
commit ead17724b6
6 changed files with 79 additions and 199 deletions
mirai-core/src/commonMain/kotlin/net.mamoe.mirai
mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman

View File

@ -34,10 +34,10 @@ abstract class SenderAndMessage<S : Contact>(
* 对于好友消息事件, 这个方法将会给好友 ([subject]) 发送消息
* 对于群消息事件, 这个方法将会给群 ([subject]) 发送消息
*/
suspend fun reply(message: MessageChain) = subject.sendMessage(message)
suspend inline fun reply(message: MessageChain) = subject.sendMessage(message)
suspend fun reply(message: Message) = reply(message.toChain())
suspend fun reply(plain: String) = reply(PlainText(plain))
suspend fun reply(message: Message) = subject.sendMessage(message.toChain())
suspend fun reply(plain: String) = subject.sendMessage(plain.toMessage())
// region Send to subject
@ -71,8 +71,8 @@ class GroupSenderAndMessage(
/**
* 订阅来自所有 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话.
*/
@MessageListenerDsl
suspend inline fun subscribeMessages(noinline listeners: suspend MessageSubscribersBuilder<SenderAndMessage<*>>.() -> Unit) {
@MessageDsl
suspend inline fun subscribeMessages(crossinline listeners: suspend MessageSubscribersBuilder<SenderAndMessage<*>>.() -> Unit) {
MessageSubscribersBuilder<SenderAndMessage<*>> { listener ->
subscribeAlways<BotEvent> {
when (it) {
@ -86,8 +86,8 @@ suspend inline fun subscribeMessages(noinline listeners: suspend MessageSubscrib
/**
* 订阅来自所有 [Bot] 的所有群消息事件
*/
@MessageListenerDsl
suspend inline fun subscribeGroupMessages(noinline listeners: suspend MessageSubscribersBuilder<GroupSenderAndMessage>.() -> Unit) {
@MessageDsl
suspend inline fun subscribeGroupMessages(crossinline listeners: suspend MessageSubscribersBuilder<GroupSenderAndMessage>.() -> Unit) {
MessageSubscribersBuilder<GroupSenderAndMessage> { listener ->
subscribeAlways<GroupMessageEvent> {
listener(GroupSenderAndMessage(it.group, it.sender, it.message))
@ -98,8 +98,8 @@ suspend inline fun subscribeGroupMessages(noinline listeners: suspend MessageSub
/**
* 订阅来自所有 [Bot] 的所有好友消息事件
*/
@MessageListenerDsl
suspend inline fun subscribeFriendMessages(noinline listeners: suspend MessageSubscribersBuilder<FriendSenderAndMessage>.() -> Unit) {
@MessageDsl
suspend inline fun subscribeFriendMessages(crossinline listeners: suspend MessageSubscribersBuilder<FriendSenderAndMessage>.() -> Unit) {
MessageSubscribersBuilder<FriendSenderAndMessage> { listener ->
subscribeAlways<FriendMessageEvent> {
listener(FriendSenderAndMessage(it.sender, it.message))
@ -110,8 +110,8 @@ suspend inline fun subscribeFriendMessages(noinline listeners: suspend MessageSu
/**
* 订阅来自这个 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话.
*/
@MessageListenerDsl
suspend inline fun Bot.subscribeMessages(noinline listeners: suspend MessageSubscribersBuilder<SenderAndMessage<*>>.() -> Unit) {
@MessageDsl
suspend inline fun Bot.subscribeMessages(crossinline listeners: suspend MessageSubscribersBuilder<SenderAndMessage<*>>.() -> Unit) {
MessageSubscribersBuilder<SenderAndMessage<*>> { listener ->
this.subscribeAlways<BotEvent> {
when (it) {
@ -125,8 +125,8 @@ suspend inline fun Bot.subscribeMessages(noinline listeners: suspend MessageSubs
/**
* 订阅来自这个 [Bot] 的所有群消息事件
*/
@MessageListenerDsl
suspend inline fun Bot.subscribeGroupMessages(noinline listeners: suspend MessageSubscribersBuilder<GroupSenderAndMessage>.() -> Unit) {
@MessageDsl
suspend inline fun Bot.subscribeGroupMessages(crossinline listeners: suspend MessageSubscribersBuilder<GroupSenderAndMessage>.() -> Unit) {
MessageSubscribersBuilder<GroupSenderAndMessage> { listener ->
this.subscribeAlways<GroupMessageEvent> {
listener(GroupSenderAndMessage(it.group, it.sender, it.message))
@ -137,8 +137,8 @@ suspend inline fun Bot.subscribeGroupMessages(noinline listeners: suspend Messag
/**
* 订阅来自这个 [Bot] 的所有好友消息事件.
*/
@MessageListenerDsl
suspend inline fun Bot.subscribeFriendMessages(noinline listeners: suspend MessageSubscribersBuilder<FriendSenderAndMessage>.() -> Unit) {
@MessageDsl
suspend inline fun Bot.subscribeFriendMessages(crossinline listeners: suspend MessageSubscribersBuilder<FriendSenderAndMessage>.() -> Unit) {
MessageSubscribersBuilder<FriendSenderAndMessage> { listener ->
this.subscribeAlways<FriendMessageEvent> {
listener(FriendSenderAndMessage(it.sender, it.message))
@ -146,23 +146,17 @@ suspend inline fun Bot.subscribeFriendMessages(noinline listeners: suspend Messa
}.apply { listeners() }
}
internal typealias MessageListener<T> = @MessageListenerDsl suspend T.(String) -> Unit
internal typealias MessageReplier<T> = @MessageDsl suspend T.(String) -> Message
internal typealias MessageReplier<T> = @MessageListenerDsl suspend T.(String) -> Message
internal typealias StringReplier<T> = @MessageDsl suspend T.(String) -> String
internal typealias StringReplier<T> = @MessageListenerDsl suspend T.(String) -> String
internal suspend inline operator fun <T : SenderAndMessage<*>> MessageListener<T>.invoke(t: T) =
internal suspend inline operator fun <T : SenderAndMessage<*>> (@MessageDsl suspend T.(String) -> Unit).invoke(t: T) =
this.invoke(t, t.message.stringValue)
@JvmName("invoke1") //Avoid Platform declaration clash
internal suspend inline operator fun <T : SenderAndMessage<*>> StringReplier<T>.invoke(t: T): String =
this.invoke(t, t.message.stringValue)
@JvmName("invoke2") //Avoid Platform declaration clash
internal suspend inline operator fun <T : SenderAndMessage<*>> MessageReplier<T>.invoke(t: T): Message =
this.invoke(t, t.message.stringValue)
/**
* 消息订阅构造器
*
@ -170,71 +164,81 @@ internal suspend inline operator fun <T : SenderAndMessage<*>> MessageReplier<T>
* @sample demo.subscribe.messageDSL
*/
@Suppress("unused")
@MessageListenerDsl
//TODO 将这个类 inline 后会导致 kotlin 编译错误. 等待修复后再 inline
@MessageDsl
class MessageSubscribersBuilder<T : SenderAndMessage<*>>(
val handlerConsumer: suspend (MessageListener<T>) -> Unit
inline val subscriber: suspend (@MessageDsl suspend T.(String) -> Unit) -> Unit
) {
suspend inline fun case(equals: String, trim: Boolean = true, noinline listener: MessageListener<T>) =
content({ equals == if (trim) it.trim() else it }, listener)
/**
* 如果消息内容 `==` [equals], 就执行 [onEvent]
* @param trim `true` 则删除首尾空格后比较
* @param ignoreCase `true` 则不区分大小写
*/
suspend fun case(equals: String, trim: Boolean = true, ignoreCase: Boolean = false, onEvent: @MessageDsl suspend T.(String) -> Unit) =
content({ equals.equals(if (trim) it.trim() else it, ignoreCase = ignoreCase) }, onEvent)
suspend inline fun contains(value: String, noinline listener: MessageListener<T>) =
content({ value in it }, listener)
/**
* 如果消息内容包含 [sub], 就执行 [onEvent]
*/
suspend fun contains(sub: String, onEvent: @MessageDsl suspend T.(String) -> Unit) = content({ sub in it }, onEvent)
suspend inline fun startsWith(
prefix: String,
removePrefix: Boolean = false,
noinline listener: MessageListener<T>
) =
/**
* 如果消息的前缀是 [prefix], 就执行 [onEvent]
* @param
*/
suspend fun startsWith(prefix: String, removePrefix: Boolean = false, onEvent: @MessageDsl suspend T.(String) -> Unit) =
content({ it.startsWith(prefix) }) {
if (removePrefix) listener.invoke(
this,
this.message.stringValue.substringAfter(prefix)
) else listener(this)
if (removePrefix) this.onEvent(this.message.stringValue.substringAfter(prefix))
else onEvent(this)
}
suspend inline fun endsWith(start: String, noinline listener: MessageListener<T>) =
content({ it.endsWith(start) }, listener)
/**
* 如果消息的结尾是 [suffix], 就执行 [onEvent]
*/
suspend fun endsWith(suffix: String, onEvent: @MessageDsl suspend T.(String) -> Unit) =
content({ it.endsWith(suffix) }, onEvent)
/**
* 如果是这个人发的消息. 可以好友消息也可以是群消息
* 如果是这个人发的消息, 就执行 [onEvent]. 消息可以好友消息也可以是群消息
*/
suspend inline fun sentBy(qqId: UInt, noinline listener: MessageListener<T>) = content({ sender.id == qqId }, listener)
suspend fun sentBy(qqId: UInt, onEvent: @MessageDsl suspend T.(String) -> Unit) = content({ sender.id == qqId }, onEvent)
/**
* 如果是这个人发的消息. 可以好友消息也可以是群消息
* 如果是这个人发的消息, 就执行 [onEvent]. 消息可以好友消息也可以是群消息
*/
suspend inline fun sentBy(qqId: Long, noinline listener: MessageListener<T>) = sentBy(qqId.toUInt(), listener)
suspend fun sentBy(qqId: Long, onEvent: @MessageDsl suspend T.(String) -> Unit) = sentBy(qqId.toUInt(), onEvent)
/**
* 如果是来自这个群的消息
* 如果是来自这个群的消息, 就执行 [onEvent]
*/
suspend inline fun sentFrom(id: UInt, noinline listener: MessageListener<T>) = content({ if (this is GroupSenderAndMessage) group.id == id else false }, listener)
suspend fun sentFrom(id: UInt, onEvent: @MessageDsl suspend T.(String) -> Unit) =
content({ if (this is GroupSenderAndMessage) group.id == id else false }, onEvent)
/**
* 如果是来自这个群的消息
* 如果是来自这个群的消息, 就执行 [onEvent]
*/
suspend inline fun sentFrom(id: Long, noinline listener: MessageListener<T>) = sentFrom(id.toUInt(), listener)
suspend fun sentFrom(id: Long, onEvent: @MessageDsl suspend T.(String) -> Unit) = sentFrom(id.toUInt(), onEvent)
suspend inline fun <reified M : Message> has(noinline listener: MessageListener<T>) =
handlerConsumer { if (message.any<M>()) listener(this) }
/**
* 如果消息内容包含 [M] 类型的 [Message], 就执行 [onEvent]
*/
suspend inline fun <reified M : Message> has(noinline onEvent: @MessageDsl suspend T.(String) -> Unit) =
subscriber { if (message.any<M>()) onEvent(this) }
suspend inline fun content(noinline filter: T.(String) -> Boolean, noinline listener: MessageListener<T>) =
handlerConsumer { if (this.filter(message.stringValue)) listener(this) }
/**
* 如果 [filter] 返回 `true` 就执行 `onEvent`
*/
suspend fun content(filter: T.(String) -> Boolean, onEvent: @MessageDsl suspend T.(String) -> Unit) =
subscriber { if (this.filter(message.stringValue)) onEvent(this) }
suspend infix fun String.caseReply(replier: String) = case(this, true) { this@case.reply(replier) }
suspend infix fun String.caseReply(replier: StringReplier<T>) = case(this, true) { this@case.reply(replier(this)) }
suspend infix fun String.containsReply(replier: String) =
content({ this@containsReply in it }) { this@content.reply(replier) }
suspend infix fun String.containsReply(replier: String) = content({ this@containsReply in it }) { this@content.reply(replier) }
suspend infix fun String.containsReply(replier: StringReplier<T>) =
content({ this@containsReply in it }) { replier(this) }
suspend infix fun String.containsReply(replier: StringReplier<T>) = content({ this@containsReply in it }) { replier(this) }
suspend infix fun String.startsWithReply(replier: StringReplier<T>) =
content({ it.startsWith(this@startsWithReply) }) { replier(this) }
suspend infix fun String.startsWithReply(replier: StringReplier<T>) = content({ it.startsWith(this@startsWithReply) }) { replier(this) }
suspend infix fun String.endswithReply(replier: StringReplier<T>) =
content({ it.endsWith(this@endswithReply) }) { replier(this) }
suspend infix fun String.endswithReply(replier: StringReplier<T>) = content({ it.endsWith(this@endswithReply) }) { replier(this) }
suspend infix fun String.reply(reply: String) = case(this) { this@case.reply(reply) }
suspend infix fun String.reply(reply: StringReplier<T>) = case(this) { this@case.reply(reply(this)) }
@ -254,4 +258,4 @@ class MessageSubscribersBuilder<T : SenderAndMessage<*>>(
*/
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS, AnnotationTarget.TYPE)
@DslMarker
internal annotation class MessageListenerDsl
internal annotation class MessageDsl

View File

@ -83,14 +83,14 @@ interface Message {
if (tail is MessageChain) tail.concat(this)/*MessageChainImpl(this).also { tail.forEach { child -> it.concat(child) } }*/
else MessageChainImpl(this, tail)
infix operator fun plus(another: Message): MessageChain = this.concat(another)
infix operator fun plus(another: String): MessageChain = this.concat(another.toMessage())
operator fun plus(another: Message): MessageChain = this.concat(another)
operator fun plus(another: String): MessageChain = this.concat(another.toMessage())
}
/**
* [this] 发送给指定联系人
*/
suspend fun Message.sendTo(contact: Contact) = contact.sendMessage(this)
suspend inline fun Message.sendTo(contact: Contact) = contact.sendMessage(this)
// endregion
// region PlainText
@ -172,7 +172,7 @@ inline class Face(val id: FaceID) : Message {
// region MessageChain
// ==================================== MessageChain ====================================
// region constructors
// region constructor functions
/**
* 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 8
*/

View File

@ -5,8 +5,6 @@ package net.mamoe.mirai.network.protocol.tim.packet.action
import kotlinx.io.core.*
import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.message.internal.toPacket
import net.mamoe.mirai.message.toChain
import net.mamoe.mirai.message.toMessage
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
@ -15,10 +13,6 @@ import net.mamoe.mirai.network.protocol.tim.packet.ResponsePacket
import net.mamoe.mirai.utils.io.*
import net.mamoe.mirai.utils.md5
fun main() {
println("牛逼".toMessage().toChain().toPacket(true).readBytes().toUHexString())
}
@PacketId(0x00_CDu)
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2.21173")
class SendFriendMessagePacket(

View File

@ -83,7 +83,10 @@ class LoginResponseSuccessPacket(input: ByteReadPacket) : ServerLoginResponsePac
discardExact(60)//00 20 01 60 C5 A1 39 7A 12 8E BC 34 C3 56 70 E3 1A ED 20 67 ED A9 DB 06 C1 70 81 3C 01 69 0D FF 63 DA 00 00 01 03 00 14 00 01 00 10 60 C9 5D A7 45 70 04 7F 21 7D 84 50 5C 66 A5 C6
discardExact(when (readUByte().toUInt()) {
0x00u -> if (readUByte().toUInt() == 0x33u) 28 else null
0x00u -> when (readUByte().toUInt()) {
0x33u -> 28
else -> null
}
0x01u -> when (readUByte().toUInt()) {
0x07u -> 0
0x10u -> 64

View File

@ -75,7 +75,7 @@ suspend fun ExternalImage.upload(contact: Contact): Image = when (contact) {
/**
* 将图片发送给 [this]
*/
suspend fun Contact.sendImage(image: ExternalImage) = image.sendTo(this)
suspend inline fun Contact.sendImage(image: ExternalImage) = image.sendTo(this)
private operator fun ByteArray.get(range: IntRange): String = buildString {
range.forEach {

View File

@ -1,23 +1,10 @@
package demo.gentleman
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.Channel
import net.mamoe.ex.content.RandomAccessHDImage
import net.mamoe.ex.network.ExNetwork
import net.mamoe.ex.network.connections.defaults.DownloadHDImageStreamSpider
import net.mamoe.ex.network.connections.defaults.ExIPWhiteListSpider
import kotlinx.coroutines.launch
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.message.sendTo
import net.mamoe.mirai.message.uploadImage
import net.mamoe.robot.AsyncTaskPool
import java.io.Closeable
import java.io.InputStream
import java.util.*
import java.util.concurrent.ExecutionException
import java.util.concurrent.Future
/**
@ -37,103 +24,6 @@ object Gentlemen : MutableMap<UInt, Gentleman> by mutableMapOf() {
}
private val sessionMap = LinkedHashMap<Long, HPictureSession>()
val ERROR_LINK = "https://i.loli.net/2019/08/05/usINjXSiZxrQJkT.jpg"
val TITLE_PICTURE_LINK = "https://i.loli.net/2019/08/04/B5ZMw1rdzVQI7Yv.jpg"
var minstar = 100
class HPictureSession constructor(private val group: Group, private val sender: QQ, val keyword: String) : Closeable {
private var hdImage: RandomAccessHDImage? = null
var sentCount: Int = 0
set(sentCount) {
field = this.sentCount
}//已经发送了几个 ImageSet
private var fetchTask: Future<RandomAccessHDImage>? = null
init {
AsyncTaskPool.submit {
try {
Thread.sleep((1000 * 60 * 10).toLong())//10min
} catch (ignored: InterruptedException) {
}
close()
}
}
init {
GlobalScope.launch { reloadImage() }
}
private suspend fun reloadImage() {
if (keyword.isEmpty()) {
group.sendMessage("正在搜寻随机色图")
} else {
group.sendMessage("正在搜寻有关 $keyword 的色图")
}
try {
withContext(IO) {
if (!ExNetwork.doSpider(ExIPWhiteListSpider()).get()) {
group.sendMessage("无法连接EX")
close()
return@withContext
}
}
} catch (e: InterruptedException) {
e.printStackTrace()
close()
return
} catch (e: ExecutionException) {
e.printStackTrace()
close()
return
}
this.fetchTask = ExNetwork.getRandomImage(keyword, minstar) { value ->
this.hdImage = value
if (this.hdImage == null) {
runBlocking { group.sendMessage("没找到") }
close()
} else {
with(this.hdImage!!) {
if (this.picId != null) {
runBlocking {
group.sendMessage(picId)
}
} else {
AsyncTaskPool.submit {
try {
runBlocking {
group.uploadImage(ExNetwork.doSpider(DownloadHDImageStreamSpider(this@with)).get() as InputStream).sendTo(group)
}
} catch (var7: Exception) {
var7.printStackTrace()
}
}
}
}
}
}
}
override fun close() {
this.hdImage = null
if (this.fetchTask != null) {
if (!this.fetchTask!!.isCancelled && !this.fetchTask!!.isDone) {
this.fetchTask!!.cancel(true)
}
}
this.fetchTask = null
sessionMap.entries.removeIf { longHPictureSessionEntry -> longHPictureSessionEntry.value === this }
}
}
@ExperimentalCoroutinesApi
class Gentleman(private val contact: Contact) : Channel<GentleImage> by Channel(IMAGE_BUFFER_CAPACITY) {
init {
@ -179,15 +69,4 @@ class Gentleman(private val contact: Contact) : Channel<GentleImage> by Channel(
}
}
}
}
object ForbiddenKeyWords : List<String> by listOf(
"miku",
"vocaloid",
"kuriyama",
"mirai"
) {
override fun contains(element: String): Boolean {
return this.stream().anyMatch { element.contains(it, ignoreCase = true) }
}
}