Http api fix conflict

This commit is contained in:
ryoii 2020-02-23 22:53:56 +08:00
commit 1660e5b938
20 changed files with 264 additions and 126 deletions

View File

@ -103,6 +103,7 @@ suspend fun MessagePacket<*, *>.toDTO() = when (this) {
suspend fun MessageChainDTO.toMessageChain(contact: Contact) =
buildMessageChain { this@toMessageChain.forEach { it.toMessage(contact)?.let(::add) } }
@UseExperimental(ExperimentalUnsignedTypes::class)
suspend fun MessagePacket<*, *>.messageDTO(message: Message) = when (message) {
is MessageSource -> MessageSourceDTO(message.id)

View File

@ -17,8 +17,11 @@ import com.moandjiezana.toml.Toml
import com.moandjiezana.toml.TomlWriter
import kotlinx.serialization.Serializable
import kotlinx.serialization.UnstableDefault
import net.mamoe.mirai.utils.io.encodeToString
import org.yaml.snakeyaml.Yaml
import tornadofx.c
import java.io.File
import java.io.InputStream
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.LinkedHashMap
@ -69,6 +72,9 @@ interface Config {
)
}
/**
* create a read-write config
* */
fun load(file: File): Config {
if (!file.exists()) {
file.createNewFile()
@ -86,6 +92,32 @@ interface Config {
else -> error("Unsupported file config type ${file.extension.toLowerCase()}")
}
}
/**
* create a read-only config
*/
fun load(content: String, type: String): Config {
return when (type.toLowerCase()) {
"json" -> JsonConfig(content)
"yml" -> YamlConfig(content)
"yaml" -> YamlConfig(content)
"mirai" -> YamlConfig(content)
"ini" -> TomlConfig(content)
"toml" -> TomlConfig(content)
"properties" -> TomlConfig(content)
"property" -> TomlConfig(content)
"data" -> TomlConfig(content)
else -> error("Unsupported file config type $content")
}
}
/**
* create a read-only config
*/
fun load(inputStream: InputStream, type: String): Config {
return load(inputStream.readBytes().encodeToString(), type)
}
}
}
@ -363,14 +395,23 @@ interface FileConfig : Config {
abstract class FileConfigImpl internal constructor(
private val file: File
private val rawContent: String
) : FileConfig,
ConfigSection {
private val content by lazy {
deserialize(file.readText())
internal var file: File? = null
constructor(file: File) : this(file.readText()) {
this.file = file
}
private val content by lazy {
deserialize(rawContent)
}
override val size: Int get() = content.size
override val entries: MutableSet<MutableMap.MutableEntry<String, Any>> get() = content.entries
override val keys: MutableSet<String> get() = content.keys
@ -384,11 +425,16 @@ abstract class FileConfigImpl internal constructor(
override fun remove(key: String): Any? = content.remove(key)
override fun save() {
if (!file.exists()) {
file.createNewFile()
if (isReadOnly()) {
error("Config is readonly")
}
file.writeText(serialize(content))
if (!((file?.exists())!!)) {
file?.createNewFile()
}
file?.writeText(serialize(content))
}
fun isReadOnly() = file == null
override fun contains(key: String): Boolean {
return content.contains(key)
@ -409,8 +455,12 @@ abstract class FileConfigImpl internal constructor(
}
class JsonConfig internal constructor(
file: File
) : FileConfigImpl(file) {
content: String
) : FileConfigImpl(content) {
constructor(file: File) : this(file.readText()) {
this.file = file
}
@UnstableDefault
override fun deserialize(content: String): ConfigSection {
if (content.isEmpty() || content.isBlank() || content == "{}") {
@ -429,7 +479,11 @@ class JsonConfig internal constructor(
}
}
class YamlConfig internal constructor(file: File) : FileConfigImpl(file) {
class YamlConfig internal constructor(content: String) : FileConfigImpl(content) {
constructor(file: File) : this(file.readText()) {
this.file = file
}
override fun deserialize(content: String): ConfigSection {
if (content.isEmpty() || content.isBlank()) {
return ConfigSectionImpl()
@ -447,7 +501,11 @@ class YamlConfig internal constructor(file: File) : FileConfigImpl(file) {
}
class TomlConfig internal constructor(file: File) : FileConfigImpl(file) {
class TomlConfig internal constructor(content: String) : FileConfigImpl(content) {
constructor(file: File) : this(file.readText()) {
this.file = file
}
override fun deserialize(content: String): ConfigSection {
if (content.isEmpty() || content.isBlank()) {
return ConfigSectionImpl()

View File

@ -17,6 +17,7 @@ import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.SimpleLogger
import net.mamoe.mirai.utils.io.encodeToString
import java.io.File
import java.io.InputStream
import java.net.URL
import java.net.URLClassLoader
import java.util.jar.JarFile
@ -91,6 +92,13 @@ abstract class PluginBase(coroutineContext: CoroutineContext) : CoroutineScope {
val logger: MiraiLogger by lazy {
DefaultLogger(pluginDescription.name)
}
fun getResources(fileName: String): InputStream? {
return PluginManager.getFileInJarByName(
this.pluginDescription.name,
fileName
)
}
}
class PluginDescription(
@ -325,6 +333,47 @@ object PluginManager {
it.disable(throwable)
}
}
/**
* 根据插件名字找Jar的文件
* null => 没找到
*/
fun getJarPath(pluginName: String): File? {
File(pluginsPath).listFiles()?.forEach { file ->
if (file != null && file.extension == "jar") {
val jar = JarFile(file)
val pluginYml =
jar.entries().asSequence().filter { it.name.toLowerCase().contains("plugin.yml") }.firstOrNull()
if (pluginYml != null) {
val description =
PluginDescription.readFromContent(
URL("jar:file:" + file.absoluteFile + "!/" + pluginYml.name).openConnection().inputStream.use {
it.readBytes().encodeToString()
})
if (description.name.toLowerCase() == pluginName.toLowerCase()) {
return file
}
}
}
}
return null
}
/**
* 根据插件名字找Jar resources中的文件
* null => 没找到
*/
fun getFileInJarByName(pluginName: String, toFind: String): InputStream? {
val jarFile = getJarPath(pluginName)
if (jarFile == null) {
return null
}
val jar = JarFile(jarFile)
val toFindFile =
jar.entries().asSequence().filter { it.name == toFind }.firstOrNull() ?: return null
return URL("jar:file:" + jarFile.absoluteFile + "!/" + toFindFile.name).openConnection().inputStream
}
}

View File

@ -326,7 +326,7 @@ internal class NotOnlineImageFromServer(
internal fun MsgComm.Msg.toMessageChain(): MessageChain {
val elements = this.msgBody.richText.elems
val message = ArrayList<Message>(elements.size + 1)
val message = MessageChainBuilder(elements.size + 1)
message.add(MessageSourceFromMsg(delegate = this))
elements.joinToMessageChain(message)
return message.asMessageChain()
@ -338,7 +338,7 @@ internal fun MsgComm.Msg.toMessageChain(): MessageChain {
internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain {
val elements = this.elems!!
val message = ArrayList<Message>(elements.size + 1)
val message = MessageChainBuilder(elements.size + 1)
message.add(MessageSourceFromServer(delegate = this))
elements.joinToMessageChain(message)
return message.asMessageChain()
@ -346,7 +346,7 @@ internal fun ImMsgBody.SourceMsg.toMessageChain(): MessageChain {
@UseExperimental(MiraiInternalAPI::class, ExperimentalUnsignedTypes::class, MiraiDebugAPI::class)
internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MutableList<Message>) {
internal fun List<ImMsgBody.Elem>.joinToMessageChain(message: MessageChainBuilder) {
this.forEach {
when {
it.srcMsg != null -> message.add(QuoteReply(MessageSourceFromServer(it.srcMsg)))

View File

@ -285,7 +285,7 @@ internal class MessageSvc {
@UseExperimental(MiraiExperimentalAPI::class)
fun startWaitingSequenceId(contact: Contact) {
sequenceIdDeferred = contact.subscribingGetAsync<OnlinePush.PbPushGroupMsg.SendGroupMessageReceipt, Int> {
sequenceIdDeferred = contact.subscribingGetAsync<OnlinePush.PbPushGroupMsg.SendGroupMessageReceipt, Int>(timeoutMillis = 3000) {
if (it.messageRandom == this@MessageSourceFromSend.messageRandom) {
it.sequenceId
} else null

View File

@ -138,9 +138,5 @@ suspend inline fun <C : Contact> C.sendMessage(message: Message): MessageReceipt
/**
* @see Contact.sendMessage
*/
@Suppress("UNCHECKED_CAST")
suspend inline fun <C : Contact> C.sendMessage(plain: String): MessageReceipt<C> = sendMessage(plain.toMessage())
/**
* @see Contact.sendMessage
*/
suspend inline fun <C : Contact> C.sendMessage(plain: CombinedMessage): MessageReceipt<C> = sendMessage(MessageChain(plain as Message)) as MessageReceipt<C>

View File

@ -26,7 +26,8 @@ import kotlin.jvm.JvmName
*
* @see AtAll 全体成员
*/
class At @MiraiInternalAPI constructor(val target: Long, val display: String) : Message {
class At
@MiraiInternalAPI constructor(val target: Long, val display: String) : Message, MessageContent {
@UseExperimental(MiraiInternalAPI::class)
constructor(member: Member) : this(member.id, "@${member.nameCardOrNick}")
@ -38,9 +39,9 @@ class At @MiraiInternalAPI constructor(val target: Long, val display: String) :
override fun followedBy(tail: Message): CombinedMessage {
if (tail is PlainText && tail.stringValue.startsWith(' ')) {
return super.followedBy(tail)
return super<MessageContent>.followedBy(tail)
}
return super.followedBy(PlainText(" ")) + tail
return super<MessageContent>.followedBy(PlainText(" ")) + tail
}
}

View File

@ -22,15 +22,15 @@ import kotlin.jvm.JvmName
*
* @see At at 单个群成员
*/
object AtAll : Message, Message.Key<AtAll> {
object AtAll : Message, Message.Key<AtAll>, MessageContent {
override fun toString(): String = "@全体成员"
// 自动为消息补充 " "
override fun followedBy(tail: Message): CombinedMessage {
if (tail is PlainText && tail.stringValue.startsWith(' ')) {
return super.followedBy(tail)
return super<MessageContent>.followedBy(tail)
}
return super.followedBy(PlainText(" ")) + tail
return super<MessageContent>.followedBy(PlainText(" ")) + tail
}
}

View File

@ -7,8 +7,14 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:JvmMultifileClass
@file:JvmName("MessageUtils")
package net.mamoe.mirai.message.data
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
/**
* Left-biased list
*/
@ -16,6 +22,8 @@ class CombinedMessage(
val left: Message,
val element: Message
) : Iterable<Message>, Message {
// 不要把它用作 local function, 会编译错误
private suspend fun SequenceScope<Message>.yieldCombinedOrElements(message: Message) {
when (message) {
is CombinedMessage -> {
@ -36,6 +44,6 @@ class CombinedMessage(
}
override fun toString(): String {
return left.toString() + element.toString()
return element.toString() + left.toString()
}
}

View File

@ -18,7 +18,7 @@ import kotlin.jvm.JvmName
/**
* QQ 自带表情
*/
class Face(val id: Int) : Message {
class Face(val id: Int) : Message, MessageContent {
override fun toString(): String = "[mirai:face$id]"
/**

View File

@ -25,7 +25,7 @@ import kotlin.jvm.JvmStatic
/**
* 自定义表情 (收藏的表情), 图片
*/
sealed class Image : Message {
sealed class Image : Message, MessageContent {
companion object Key : Message.Key<Image> {
@JvmStatic
@JsName("fromId")

View File

@ -20,6 +20,12 @@ import kotlin.jvm.JvmSynthetic
* 可发送的或从服务器接收的消息.
* 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 [纯文本][PlainText], [图片][Image] .
*
* [消息][Message] 分为
* - [MessageMetadata] 消息元数据, 包括: [消息来源][MessageSource]
* - [MessageContent] 单个消息, 包括: [纯文本][PlainText], [@群员][At], [@全体成员][AtAll] .
* - [CombinedMessage] 通过 [plus] 连接的两个消息. 可通过 [asMessageChain] 转换为 [MessageChain]
* - [MessageChain] 不可变消息链, [List] 形式链接的多个 [Message] 实例.
*
* ** Kotlin 使用 [Message]**
* 这与使用 [String] 的使用非常类似.
*
@ -44,7 +50,12 @@ import kotlin.jvm.JvmSynthetic
* @see PlainText 纯文本
* @see Image 图片
* @see Face 表情
* @see At 引用一个群成员
* @see AtAll 引用全体成员
* @see QuoteReply 引用一条消息
*
* @see MessageChain 消息链( `List<Message>`)
* @see buildMessageChain 构造一个 [MessageChain]
*
* @see Contact.sendMessage 发送消息
*/
@ -86,8 +97,6 @@ interface Message {
*/
@JvmSynthetic // in java they should use `plus` instead
fun followedBy(tail: Message): CombinedMessage {
require(tail !is SingleOnly) { "SingleOnly Message cannot follow another message" }
require(this !is SingleOnly) { "SingleOnly Message cannot be followed" }
return CombinedMessage(tail, this)
}
@ -100,12 +109,37 @@ interface Message {
operator fun plus(another: CharSequence): CombinedMessage = this.followedBy(another.toString().toMessage())
}
suspend fun <C : Contact> Message.sendTo(contact: C): MessageReceipt<C> {
return contact.sendMessage(this)
}
interface SingleMessage : Message
/**
* 表示这个 [Message] 仅能单个存在, 无法被连接.
* 消息元数据, 即不含内容的元素.
* 包括: [MessageSource]
*/
interface SingleOnly : Message
interface MessageMetadata : SingleMessage {
/*
fun iterator(): Iterator<Message> {
return object : Iterator<Message> {
var visited: Boolean = false
override fun hasNext(): Boolean = !visited
override fun next(): Message {
if (visited) throw NoSuchElementException()
return this@MessageMetadata.also { visited = true }
}
}
}*/
}
/**
* 消息内容
*/
interface MessageContent : SingleMessage
/**
* [this] 发送给指定联系人
*/
suspend inline fun <C : Contact> Message.sendTo(contact: C): MessageReceipt<C> = contact.sendMessage(this)
@Suppress("UNCHECKED_CAST")
suspend inline fun <C : Contact> MessageChain.sendTo(contact: C): MessageReceipt<C> = contact.sendMessage(this) as MessageReceipt<C>

View File

@ -16,27 +16,19 @@ import net.mamoe.mirai.message.data.NullMessageChain.toString
import kotlin.js.JsName
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
import kotlin.reflect.KProperty
/**
* 消息链. MutableList<Message>.
* 消息链.
* 它的一般实现为 [MessageChainImpl], `null` 实现为 [NullMessageChain]
*
* 有关 [MessageChain] 的创建和连接:
* - 当任意两个不是 [MessageChain] [Message] 相连接后, 将会产生一个 [MessageChain].
* - 若两个 [MessageChain] 连接, 后一个将会被合并到第一个内.
* - 若一个 [MessageChain] 与一个其他 [Message] 连接, [Message] 将会被添加入 [MessageChain].
* - 若一个 [Message] 与一个 [MessageChain] 连接, [Message] 将会被添加入 [MessageChain].
*
* 要获取更多信息, 请查看 [Message]
*
* @see buildMessageChain
* @see buildMessageChain 构造一个 [MessageChain]
*/
interface MessageChain : Message, List<Message> {
// region Message override
interface MessageChain : Message, Iterable<SingleMessage> {
override operator fun contains(sub: String): Boolean
// endregion
override fun toString(): String
/**
@ -51,29 +43,16 @@ interface MessageChain : Message, List<Message> {
* 遍历每一个有内容的消息, [At], [AtAll], [PlainText], [Image], [Face], [XMLMessage]
*/
inline fun MessageChain.foreachContent(block: (Message) -> Unit) {
this.forEachIndexed { index: Int, message: Message ->
var last: Message? = null
this.forEach { message: Message ->
if (message is At) {
if (index == 0 || this[index - 1] !is QuoteReply) {
if (last != null || last !is QuoteReply) {
block(message)
}
} else if (message.hasContent()) {
} else if (message is MessageContent) {
block(message)
}
}
}
/**
* 判断这个 [Message] 是否含有内容, 即是否为 [At], [AtAll], [PlainText], [Image], [Face], [XMLMessage]
*/
fun Message.hasContent(): Boolean {
return when (this) {
is At,
is AtAll,
is PlainText,
is Image,
is Face,
is XMLMessage -> true
else -> false
last = message
}
}
@ -99,7 +78,7 @@ fun MessageChain(): MessageChain = EmptyMessageChain
@Suppress("FunctionName")
fun MessageChain(vararg messages: Message): MessageChain =
if (messages.isEmpty()) EmptyMessageChain
else MessageChainImpl(messages.toMutableList())
else MessageChainImpl(messages.asSequence().flatten())
/**
* 构造 [MessageChain] 的快速途径 ( [Array] 创建)
@ -109,7 +88,10 @@ fun MessageChain(vararg messages: Message): MessageChain =
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(message: Message): MessageChain =
MessageChainImpl(listOf(message))
when (message) {
is SingleMessage -> SingleMessageChainImpl(message)
else -> MessageChainImpl(message.flatten().asIterable())
}
/**
* 构造 [MessageChain]
@ -118,7 +100,7 @@ fun MessageChain(message: Message): MessageChain =
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(messages: Iterable<Message>): MessageChain =
MessageChainImpl(messages.toList())
MessageChainImpl(messages.flatten().asIterable())
/**
* 构造 [MessageChain]
@ -127,7 +109,7 @@ fun MessageChain(messages: Iterable<Message>): MessageChain =
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(messages: List<Message>): MessageChain =
MessageChainImpl(messages)
MessageChainImpl(messages.flatten().asIterable())
/**
@ -135,14 +117,34 @@ fun MessageChain(messages: List<Message>): MessageChain =
* [this] [MessageChain] 将直接返回 this
* 否则将调用 [MessageChain] 构造一个 [MessageChainImpl]
*/
@Suppress("NOTHING_TO_INLINE")
inline fun Message.toChain(): MessageChain = if (this is MessageChain) this else MessageChain(this)
@Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST")
@JvmSynthetic
fun Message.toChain(): MessageChain = when (this) {
is MessageChain -> this
is CombinedMessage -> MessageChainImpl((this as Iterable<Message>).flatten().asIterable())
else -> SingleMessageChainImpl(this as SingleMessage)
}
/**
* 构造 [MessageChain]
*/
@JvmName("asMessageChain1")
@JvmSynthetic
@Suppress("unused", "NOTHING_TO_INLINE")
inline fun List<Message>.asMessageChain(): MessageChain = MessageChain(this)
fun Iterable<SingleMessage>.asMessageChain(): MessageChain = MessageChainImpl(this)
@JvmSynthetic
@Suppress("unused", "NOTHING_TO_INLINE")
fun Iterable<Message>.asMessageChain(): MessageChain = MessageChainImpl(this.flatten())
fun Iterable<Message>.flatten(): Sequence<SingleMessage> = asSequence().flatten()
fun Sequence<Message>.flatten(): Sequence<SingleMessage> = flatMap { it.flatten() }
fun Message.flatten(): Sequence<SingleMessage> {
return when (this) {
is MessageChain -> this.asSequence()
is CombinedMessage -> this.asSequence().flatten()
else -> sequenceOf(this as SingleMessage)
}
}
/**
* 获取第一个 [M] 类型的 [Message] 实例
@ -189,9 +191,7 @@ fun <M : Message> MessageChain.first(key: Message.Key<M>): M = firstOrNull(key)
@Suppress("UNCHECKED_CAST")
fun <M : Message> MessageChain.any(key: Message.Key<M>): Boolean = firstOrNull(key) != null
object EmptyMessageChain : MessageChain by {
MessageChainImpl(emptyList())
}()
object EmptyMessageChain : MessageChain by MessageChainImpl(emptyList())
/**
* Null [MessageChain].
@ -200,45 +200,27 @@ object EmptyMessageChain : MessageChain by {
* [toString] , 其他方法均 [error]
*/
object NullMessageChain : MessageChain {
override fun subList(fromIndex: Int, toIndex: Int): MutableList<Message> = error("accessing NullMessageChain")
override fun toString(): String = "null"
override fun contains(sub: String): Boolean = error("accessing NullMessageChain")
override fun contains(element: Message): Boolean = error("accessing NullMessageChain")
override fun followedBy(tail: Message): CombinedMessage = CombinedMessage(left = EmptyMessageChain, element = tail)
override val size: Int get() = error("accessing NullMessageChain")
override fun containsAll(elements: Collection<Message>): Boolean = error("accessing NullMessageChain")
override fun get(index: Int): Message = error("accessing NullMessageChain")
override fun indexOf(element: Message): Int = error("accessing NullMessageChain")
override fun isEmpty(): Boolean = error("accessing NullMessageChain")
override fun iterator(): MutableIterator<Message> = error("accessing NullMessageChain")
override fun lastIndexOf(element: Message): Int = error("accessing NullMessageChain")
override fun listIterator(): MutableListIterator<Message> = error("accessing NullMessageChain")
override fun listIterator(index: Int): MutableListIterator<Message> = error("accessing NullMessageChain")
override fun iterator(): MutableIterator<SingleMessage> = error("accessing NullMessageChain")
}
/**
* [MessageChain] 实现
* 它是一个特殊的 [Message], 实现 [MutableList] 接口, 但将所有的接口调用都转到内部维护的另一个 [MutableList].
*/
@PublishedApi
internal class MessageChainImpl constructor(
/**
* Elements will not be instances of [MessageChain]
*/
private val delegate: List<Message>
) : Message, List<Message> by delegate, MessageChain {
override fun toString(): String = this.delegate.joinToString("") { it.toString() }
private val delegate: Iterable<SingleMessage>
) : Message, Iterable<SingleMessage> by delegate, MessageChain {
constructor(delegate: Sequence<SingleMessage>) : this(delegate.asIterable())
override fun toString(): String = this.delegate.joinToString("") { it.toString() }
override operator fun contains(sub: String): Boolean = delegate.any { it.contains(sub) }
override fun followedBy(tail: Message): CombinedMessage {
require(tail !is SingleOnly) { "SingleOnly Message cannot follow another message" }
// if (tail is MessageChain) tail.forEach { child -> this.followedBy(child) }
// else this.delegate.add(tail)
return CombinedMessage(tail, this)
}
}
@PublishedApi
internal class SingleMessageChainImpl constructor(
private val delegate: SingleMessage
) : Message, Iterable<SingleMessage> by listOf(delegate), MessageChain {
override fun toString(): String = this.delegate.toString()
override operator fun contains(sub: String): Boolean = sub in delegate
}

View File

@ -23,7 +23,7 @@ import kotlin.jvm.JvmName
*
* @see MessageSource.quote 引用这条消息, 创建 [MessageChain]
*/
interface MessageSource : Message {
interface MessageSource : Message, MessageMetadata {
companion object Key : Message.Key<MessageSource>
/**

View File

@ -21,7 +21,7 @@ import kotlin.jvm.JvmStatic
*
* 一般不需要主动构造 [PlainText], [Message] 可直接与 [String] 相加. Java 用户请使用 [MessageChain.plus]
*/
inline class PlainText(val stringValue: String) : Message {
inline class PlainText(val stringValue: String) : Message, MessageContent {
constructor(charSequence: CharSequence) : this(charSequence.toString())
override operator fun contains(sub: String): Boolean = sub in stringValue

View File

@ -21,25 +21,27 @@ import kotlin.jvm.JvmName
/**
* 群内的或好友的引用回复.
* 从服务器接收的或客户端构造用来发送的群内的或好友的引用回复.
*
* 可以引用一条群消息并发送给一个好友, 或是引用好友消息发送给群.
* 可以引用自己发出的消息. 详见 [MessageReceipt.quote]
*
* 总是使用 [quote] 来构造这个实例.
*/
open class QuoteReply @MiraiInternalAPI constructor(val source: MessageSource) : Message {
open class QuoteReply
@MiraiInternalAPI constructor(val source: MessageSource) : Message, MessageContent {
companion object Key : Message.Key<QuoteReply>
override fun toString(): String = ""
}
/**
* 群内的引用回复.
* 用于发送的引用回复.
* 总是使用 [quote] 来构造实例.
*/
@UseExperimental(MiraiInternalAPI::class)
class QuoteReplyToSend @MiraiInternalAPI constructor(source: MessageSource, val sender: QQ) : QuoteReply(source) {
class QuoteReplyToSend
@MiraiInternalAPI constructor(source: MessageSource, val sender: QQ) : QuoteReply(source) {
fun createAt(): At = At(sender as Member)
}

View File

@ -23,8 +23,8 @@ import kotlin.jvm.JvmName
*
* @see buildXMLMessage
*/
inline class XMLMessage(val stringValue: String) : Message,
SingleOnly {
@MiraiExperimentalAPI
inline class XMLMessage(val stringValue: String) : Message, MessageContent {
override fun followedBy(tail: Message): Nothing = error("XMLMessage Message cannot be followed")
override fun toString(): String = stringValue
}

View File

@ -22,8 +22,10 @@ inline fun buildMessageChain(block: MessageChainBuilder.() -> Unit): MessageChai
}
class MessageChainBuilder @JvmOverloads constructor(
private val container: MutableList<Message> = mutableListOf()
) : MutableList<Message> by container, Appendable {
private val container: MutableCollection<Message> = mutableListOf()
) : MutableCollection<Message> by container, Appendable {
constructor(initialSize: Int) : this(ArrayList<Message>(initialSize))
operator fun Message.unaryPlus() {
add(this)
}

View File

@ -56,6 +56,7 @@ internal class LockFreeLinkedListTest {
//}
}
@Suppress("UNREACHABLE_CODE", "DeferredResultUnused")
@Test
fun `so many concurrent add remove and foreach`() = runBlocking {
return@runBlocking // 测试通过了, 加快速度. 因为 kotlin 一些其他 bug

View File

@ -12,17 +12,17 @@ package net.mamoe.mirai.imageplugin
import kotlinx.coroutines.*
import net.mamoe.mirai.console.plugins.Config
import net.mamoe.mirai.console.plugins.ConfigSection
import net.mamoe.mirai.console.plugins.PluginBase
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.event.events.BotOnlineEvent
import net.mamoe.mirai.event.subscribeAlways
import net.mamoe.mirai.event.subscribeMessages
import net.mamoe.mirai.console.plugins.PluginBase
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.uploadAsImage
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import org.jsoup.Jsoup
import java.io.File
import kotlin.random.Random
import java.net.URL
class ImageSenderMain : PluginBase() {
@ -60,7 +60,6 @@ class ImageSenderMain : PluginBase() {
reply(e.message ?: "unknown error")
}
}
}
}
}
@ -84,16 +83,21 @@ class ImageSenderMain : PluginBase() {
override fun onLoad() {
logger.info("loading local image data")
try {
images = Config.load(this.javaClass.classLoader.getResource("data.yml")!!.path!!)
images = Config.load(getResources(fileName = "data.yml")!!, "yml")
} catch (e: Exception) {
e.printStackTrace()
logger.info("无法加载本地图片")
}
logger.info("本地图片版本" + images.getString("version"))
logger.info("Normal * " + images.getList("normal").size)
logger.info("R18 * " + images.getList("R18").size)
r18 = images.getConfigSectionList("R18")
normal = images.getConfigSectionList("normal")
logger.info("Normal * " + normal.size)
logger.info("R18 * " + r18.size)
}
override fun onDisable() {
}