Merge remote-tracking branch 'origin/master'

This commit is contained in:
Him188 2020-02-24 10:26:44 +08:00
commit 577348ff32
10 changed files with 270 additions and 116 deletions

View File

@ -173,14 +173,16 @@ fun main() {
| ------------ | ------ | ----- | ----------- | -------------------------------- | | ------------ | ------ | ----- | ----------- | -------------------------------- |
| sessionKey | String | false | YourSession | 已经激活的Session | | sessionKey | String | false | YourSession | 已经激活的Session |
| target | Long | false | 987654321 | 发送消息目标好友的QQ号 | | target | Long | false | 987654321 | 发送消息目标好友的QQ号 |
| quote | Long | true | 135798642 | 引用一条消息的messageId进行回复 |
| messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 | | messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 |
#### 响应: 返回统一状态码 #### 响应: 返回统一状态码并携带messageId
```json5 ```json5
{ {
"code": 0, "code": 0,
"msg": "success" "msg": "success",
"messageId": 1234567890 // 一个Long类型属性标识本条消息用于撤回和引用回复
} }
``` ```
@ -211,52 +213,16 @@ fun main() {
| ------------ | ------ | ----- | ----------- | -------------------------------- | | ------------ | ------ | ----- | ----------- | -------------------------------- |
| sessionKey | String | false | YourSession | 已经激活的Session | | sessionKey | String | false | YourSession | 已经激活的Session |
| target | Long | false | 987654321 | 发送消息目标群的群号 | | target | Long | false | 987654321 | 发送消息目标群的群号 |
| quote | Long | true | 135798642 | 引用一条消息的messageId进行回复 |
| messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 | | messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 |
#### 响应: 返回统一状态码 #### 响应: 返回统一状态码并携带messageId
```json5 ```json5
{ {
"code": 0, "code": 0,
"msg": "success" "msg": "success",
} "messageId": 1234567890 // 一个Long类型属性标识本条消息用于撤回和引用回复
```
### 发送引用回复消息(仅支持群消息)
```
[POST] /sendQuoteMessage
```
使用此方法向指定的消息进行引用回复
#### 请求
```json5
{
"sessionKey": "YourSession",
"target": 987654321,
"messageChain": [
{ "type": "Plain", "text":"hello\n" },
{ "type": "Plain", "text":"world" }
]
}
```
| 名字 | 类型 | 可选 | 举例 | 说明 |
| ------------ | ------ | ----- | ----------- | -------------------------------- |
| sessionKey | String | false | YourSession | 已经激活的Session |
| target | Long | false | 987654321 | 引用消息的Message Source的Uid |
| messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 |
#### 响应: 返回统一状态码
```json5
{
"code": 0,
"msg": "success"
} }
``` ```
@ -331,6 +297,39 @@ Content-Typemultipart/form-data
### 撤回消息
```
[POST] /recall
```
使用此方法撤回指定消息。对于bot发送的消息又2分钟时间限制。对于撤回群聊中群员的消息需要有相应权限
#### 请求
```json5
{
"sessionKey": "YourSession",
"target": 987654321
}
```
| 名字 | 类型 | 可选 | 举例 | 说明 |
| ------------ | ------ | ----- | ----------- | -------------------------------- |
| sessionKey | String | false | YourSession | 已经激活的Session |
| target | Long | false | 987654321 | 需要撤回的消息的messageId |
#### 响应: 返回统一状态码
```json5
{
"code": 0,
"msg": "success"
}
```
### 获取Bot收到的消息和事件 ### 获取Bot收到的消息和事件
``` ```
@ -371,6 +370,9 @@ Content-Typemultipart/form-data
},{ },{
"type": "FriendMessage", // 消息类型GroupMessage或FriendMessage或各类Event "type": "FriendMessage", // 消息类型GroupMessage或FriendMessage或各类Event
"messageChain": [{ // 消息链,是一个消息对象构成的数组 "messageChain": [{ // 消息链,是一个消息对象构成的数组
"type": "Source",
"uid": 123456
},{
"type": "Plain", "type": "Plain",
"text": "Miral牛逼" "text": "Miral牛逼"
}], }],

View File

@ -12,7 +12,7 @@ import net.mamoe.mirai.utils.MiraiExperimentalAPI
sealed class BotEventDTO : EventDTO() sealed class BotEventDTO : EventDTO()
@UseExperimental(MiraiExperimentalAPI::class) @UseExperimental(MiraiExperimentalAPI::class)
fun BotEvent.toDTO() = when(this) { suspend fun BotEvent.toDTO() = when(this) {
is MessagePacket<*, *> -> toDTO() is MessagePacket<*, *> -> toDTO()
else -> when(this) { else -> when(this) {
is BotOnlineEvent -> BotOnlineEventDTO(bot.uin) is BotOnlineEvent -> BotOnlineEventDTO(bot.uin)

View File

@ -17,8 +17,9 @@ import net.mamoe.mirai.message.FriendMessage
import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.GroupMessage
import net.mamoe.mirai.message.MessagePacket import net.mamoe.mirai.message.MessagePacket
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.message.uploadImage
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import java.net.URL
/* /*
* DTO data class * DTO data class
@ -57,7 +58,7 @@ data class PlainDTO(val text: String) : MessageDTO()
@Serializable @Serializable
@SerialName("Image") @SerialName("Image")
data class ImageDTO(val imageId: String) : MessageDTO() data class ImageDTO(val imageId: String? = null, val url: String? = null) : MessageDTO()
@Serializable @Serializable
@SerialName("Xml") @SerialName("Xml")
@ -84,42 +85,49 @@ sealed class MessageDTO : DTO
/* /*
Extend function Extend function
*/ */
fun MessagePacket<*, *>.toDTO() = when (this) { suspend fun MessagePacket<*, *>.toDTO() = when (this) {
is FriendMessage -> FriendMessagePacketDTO(QQDTO(sender)) is FriendMessage -> FriendMessagePacketDTO(QQDTO(sender))
is GroupMessage -> GroupMessagePacketDTO(MemberDTO(sender)) is GroupMessage -> GroupMessagePacketDTO(MemberDTO(sender))
else -> IgnoreEventDTO else -> IgnoreEventDTO
}.apply { }.apply {
if (this is MessagePacketDTO) { messageChain = message.toDTOChain() } if (this is MessagePacketDTO) {
// 将MessagePacket中的所有Message转为DTO对象并添加到messageChain
// foreachContent会忽略MessageSource一次主动获取
messageChain = mutableListOf(messageDTO(message[MessageSource])).apply {
message.foreachContent { content -> messageDTO(content).takeUnless { it == UnknownMessageDTO }?.let(::add) }
}
// else: `this` is bot event // else: `this` is bot event
}
} }
fun MessageChain.toDTOChain() = mutableListOf(this[MessageSource].toDTO()).apply { suspend fun MessageChainDTO.toMessageChain(contact: Contact) =
foreachContent { content -> content.toDTO().takeUnless { it == UnknownMessageDTO }?.let(::add) } buildMessageChain { this@toMessageChain.forEach { it.toMessage(contact)?.let(::add) } }
}
fun MessageChainDTO.toMessageChain(contact: Contact) =
buildMessageChain { this@toMessageChain.forEach { add(it.toMessage(contact)) } }
@UseExperimental(ExperimentalUnsignedTypes::class, MiraiExperimentalAPI::class) @UseExperimental(ExperimentalUnsignedTypes::class)
fun Message.toDTO() = when (this) { suspend fun MessagePacket<*, *>.messageDTO(message: Message) = when (message) {
is MessageSource -> MessageSourceDTO(id) is MessageSource -> MessageSourceDTO(message.id)
is At -> AtDTO(target, display) is At -> AtDTO(message.target, message.display)
is AtAll -> AtAllDTO(0L) is AtAll -> AtAllDTO(0L)
is Face -> FaceDTO(id) is Face -> FaceDTO(message.id)
is PlainText -> PlainDTO(stringValue) is PlainText -> PlainDTO(message.stringValue)
is Image -> ImageDTO(imageId) is Image -> ImageDTO(message.imageId, message.url())
is XMLMessage -> XmlDTO(stringValue) is XMLMessage -> XmlDTO(message.stringValue)
else -> UnknownMessageDTO else -> UnknownMessageDTO
} }
@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class, MiraiExperimentalAPI::class) @UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
fun MessageDTO.toMessage(contact: Contact) = when (this) { suspend fun MessageDTO.toMessage(contact: Contact) = when (this) {
is AtDTO -> At((contact as Group)[target]) is AtDTO -> At((contact as Group)[target])
is AtAllDTO -> AtAll is AtAllDTO -> AtAll
is FaceDTO -> Face(faceId) is FaceDTO -> Face(faceId)
is PlainDTO -> PlainText(text) is PlainDTO -> PlainText(text)
is ImageDTO -> Image(imageId) is ImageDTO -> when {
!imageId.isNullOrBlank() -> Image(imageId)
!url.isNullOrBlank() -> contact.uploadImage(URL(url))
else -> null
}
is XmlDTO -> XMLMessage(xml) is XmlDTO -> XMLMessage(xml)
is MessageSourceDTO, is UnknownMessageDTO -> PlainText("assert cannot reach") is MessageSourceDTO, is UnknownMessageDTO -> null
} }

View File

@ -13,17 +13,17 @@ import net.mamoe.mirai.api.http.data.common.EventDTO
import net.mamoe.mirai.api.http.data.common.IgnoreEventDTO import net.mamoe.mirai.api.http.data.common.IgnoreEventDTO
import net.mamoe.mirai.api.http.data.common.toDTO import net.mamoe.mirai.api.http.data.common.toDTO
import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.MessagePacket
import net.mamoe.mirai.message.data.MessageSource import net.mamoe.mirai.message.data.MessageSource
import net.mamoe.mirai.utils.firstKey import net.mamoe.mirai.utils.firstKey
import java.util.concurrent.ConcurrentLinkedDeque import java.util.concurrent.ConcurrentLinkedDeque
class MessageQueue : ConcurrentLinkedDeque<BotEvent>() { class MessageQueue : ConcurrentLinkedDeque<BotEvent>() {
val quoteCacheSize = 4096 val cacheSize = 4096
val quoteCache = LinkedHashMap<Long, GroupMessage>() val cache = LinkedHashMap<Long, MessagePacket<*, *>>()
fun fetch(size: Int): List<EventDTO> { suspend fun fetch(size: Int): List<EventDTO> {
var count = size var count = size
val ret = ArrayList<EventDTO>(count) val ret = ArrayList<EventDTO>(count)
@ -37,18 +37,20 @@ class MessageQueue : ConcurrentLinkedDeque<BotEvent>() {
} }
} }
// TODO: 等FriendMessage支持quote if (event is MessagePacket<*, *>) {
if (event is GroupMessage) {
addQuoteCache(event) addQuoteCache(event)
} }
} }
return ret return ret
} }
private fun addQuoteCache(msg: GroupMessage) { fun cache(messageId: Long) =
quoteCache[msg.message[MessageSource].id] = msg cache[messageId] ?: throw NoSuchElementException()
if (quoteCache.size > quoteCacheSize) {
quoteCache.remove(quoteCache.firstKey()) fun addQuoteCache(msg: MessagePacket<*, *>) {
cache[msg.message[MessageSource].id] = msg
if (cache.size > cacheSize) {
cache.remove(cache.firstKey())
} }
} }
} }

View File

@ -20,15 +20,19 @@ import io.ktor.response.respondText
import io.ktor.routing.post import io.ktor.routing.post
import io.ktor.routing.routing import io.ktor.routing.routing
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import net.mamoe.mirai.api.http.AuthedSession import net.mamoe.mirai.api.http.AuthedSession
import net.mamoe.mirai.api.http.SessionManager import net.mamoe.mirai.api.http.SessionManager
import net.mamoe.mirai.api.http.data.* import net.mamoe.mirai.api.http.data.*
import net.mamoe.mirai.api.http.data.common.DTO
import net.mamoe.mirai.api.http.data.common.MessageChainDTO import net.mamoe.mirai.api.http.data.common.MessageChainDTO
import net.mamoe.mirai.api.http.data.common.VerifyDTO import net.mamoe.mirai.api.http.data.common.VerifyDTO
import net.mamoe.mirai.api.http.data.common.toMessageChain import net.mamoe.mirai.api.http.data.common.toMessageChain
import net.mamoe.mirai.api.http.util.toJson import net.mamoe.mirai.api.http.util.toJson
import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.message.FriendMessage
import net.mamoe.mirai.message.GroupMessage
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.uploadImage import net.mamoe.mirai.message.uploadImage
import java.net.URL import java.net.URL
@ -42,23 +46,47 @@ fun Application.messageModule() {
call.respondJson(fetch.toJson()) call.respondJson(fetch.toJson())
} }
suspend fun <C : Contact> sendMessage(
quote: QuoteReplyToSend?,
messageChain: MessageChain,
target: C
): MessageReceipt<out Contact> {
val send = if (quote == null) {
messageChain
} else {
(quote + messageChain).toChain()
}
return target.sendMessage(send)
}
miraiVerify<SendDTO>("/sendFriendMessage") { miraiVerify<SendDTO>("/sendFriendMessage") {
val quote = it.quote?.let { q ->
it.session.messageQueue.cache(q).run {
this[MessageSource].quote(sender)
}}
it.session.bot.getFriend(it.target).apply { it.session.bot.getFriend(it.target).apply {
sendMessage(it.messageChain.toMessageChain(this)) // this aka QQ val receipt = sendMessage(quote, it.messageChain.toMessageChain(this), this)
receipt.source.ensureSequenceIdAvailable()
it.session.messageQueue.addQuoteCache(FriendMessage(bot.selfQQ, receipt.source.toChain()))
call.respondDTO(SendRetDTO(messageId = receipt.source.id))
} }
} }
miraiVerify<SendDTO>("/sendGroupMessage") { miraiVerify<SendDTO>("/sendGroupMessage") {
it.session.bot.getGroup(it.target).apply { val quote = it.quote?.let { q ->
sendMessage(it.messageChain.toMessageChain(this)) // this aka Group it.session.messageQueue.cache(q).run {
} this[MessageSource].quote(sender)
} }}
miraiVerify<SendDTO>("/sendQuoteMessage") { it.session.bot.getGroup(it.target).apply {
it.session.messageQueue.quoteCache[it.target]?.apply { val receipt = sendMessage(quote, it.messageChain.toMessageChain(this), this)
quoteReply(it.messageChain.toMessageChain(group)) receipt.source.ensureSequenceIdAvailable()
} ?: throw NoSuchElementException()
call.respondStateCode(StateCode.Success) it.session.messageQueue.addQuoteCache(GroupMessage("", botPermission, botAsMember, receipt.source.toChain()))
call.respondDTO(SendRetDTO(messageId = receipt.source.id))
}
} }
miraiVerify<SendImageDTO>("sendImageMessage") { miraiVerify<SendImageDTO>("sendImageMessage") {
@ -101,8 +129,10 @@ fun Application.messageModule() {
} }
miraiVerify<RecallDTO>("recall") { miraiVerify<RecallDTO>("recall") {
// TODO it.session.messageQueue.cache(it.target).apply {
call.respond(HttpStatusCode.NotFound, "未完成") it.session.bot.recall(get(MessageSource))
}
call.respondStateCode(StateCode.Success)
} }
} }
} }
@ -110,6 +140,7 @@ fun Application.messageModule() {
@Serializable @Serializable
private data class SendDTO( private data class SendDTO(
override val sessionKey: String, override val sessionKey: String,
val quote: Long? = null,
val target: Long, val target: Long,
val messageChain: MessageChainDTO val messageChain: MessageChainDTO
) : VerifyDTO() ) : VerifyDTO()
@ -125,13 +156,13 @@ private data class SendImageDTO(
@Serializable @Serializable
private class SendRetDTO( private class SendRetDTO(
val messageId: Long, val code: Int = 0,
@Transient val stateCode: StateCode = Success val msg: String = "success",
) : StateCode(stateCode.code, stateCode.msg) val messageId: Long
) : DTO
@Serializable @Serializable
private data class RecallDTO( private data class RecallDTO(
override val sessionKey: String, override val sessionKey: String,
val target: Long, val target: Long
val sender: Long
) : VerifyDTO() ) : VerifyDTO()

View File

@ -17,8 +17,11 @@ import com.moandjiezana.toml.Toml
import com.moandjiezana.toml.TomlWriter import com.moandjiezana.toml.TomlWriter
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.UnstableDefault import kotlinx.serialization.UnstableDefault
import net.mamoe.mirai.utils.io.encodeToString
import org.yaml.snakeyaml.Yaml import org.yaml.snakeyaml.Yaml
import tornadofx.c
import java.io.File import java.io.File
import java.io.InputStream
import java.util.* import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.LinkedHashMap import kotlin.collections.LinkedHashMap
@ -69,6 +72,9 @@ interface Config {
) )
} }
/**
* create a read-write config
* */
fun load(file: File): Config { fun load(file: File): Config {
if (!file.exists()) { if (!file.exists()) {
file.createNewFile() file.createNewFile()
@ -86,6 +92,32 @@ interface Config {
else -> error("Unsupported file config type ${file.extension.toLowerCase()}") 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( abstract class FileConfigImpl internal constructor(
private val file: File private val rawContent: String
) : FileConfig, ) : FileConfig,
ConfigSection { ConfigSection {
private val content by lazy { internal var file: File? = null
deserialize(file.readText())
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 size: Int get() = content.size
override val entries: MutableSet<MutableMap.MutableEntry<String, Any>> get() = content.entries override val entries: MutableSet<MutableMap.MutableEntry<String, Any>> get() = content.entries
override val keys: MutableSet<String> get() = content.keys 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 remove(key: String): Any? = content.remove(key)
override fun save() { override fun save() {
if (!file.exists()) { if (isReadOnly()) {
file.createNewFile() 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 { override fun contains(key: String): Boolean {
return content.contains(key) return content.contains(key)
@ -409,8 +455,12 @@ abstract class FileConfigImpl internal constructor(
} }
class JsonConfig internal constructor( class JsonConfig internal constructor(
file: File content: String
) : FileConfigImpl(file) { ) : FileConfigImpl(content) {
constructor(file: File) : this(file.readText()) {
this.file = file
}
@UnstableDefault @UnstableDefault
override fun deserialize(content: String): ConfigSection { override fun deserialize(content: String): ConfigSection {
if (content.isEmpty() || content.isBlank() || content == "{}") { 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 { override fun deserialize(content: String): ConfigSection {
if (content.isEmpty() || content.isBlank()) { if (content.isEmpty() || content.isBlank()) {
return ConfigSectionImpl() 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 { override fun deserialize(content: String): ConfigSection {
if (content.isEmpty() || content.isBlank()) { if (content.isEmpty() || content.isBlank()) {
return ConfigSectionImpl() 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.SimpleLogger
import net.mamoe.mirai.utils.io.encodeToString import net.mamoe.mirai.utils.io.encodeToString
import java.io.File import java.io.File
import java.io.InputStream
import java.net.URL import java.net.URL
import java.net.URLClassLoader import java.net.URLClassLoader
import java.util.jar.JarFile import java.util.jar.JarFile
@ -91,6 +92,13 @@ abstract class PluginBase(coroutineContext: CoroutineContext) : CoroutineScope {
val logger: MiraiLogger by lazy { val logger: MiraiLogger by lazy {
DefaultLogger(pluginDescription.name) DefaultLogger(pluginDescription.name)
} }
fun getResources(fileName: String): InputStream? {
return PluginManager.getFileInJarByName(
this.pluginDescription.name,
fileName
)
}
} }
class PluginDescription( class PluginDescription(
@ -325,6 +333,47 @@ object PluginManager {
it.disable(throwable) 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

@ -31,7 +31,7 @@ import net.mamoe.mirai.utils.unsafeWeakRef
* @see QQ.sendMessage 发送群消息, 返回回执此对象 * @see QQ.sendMessage 发送群消息, 返回回执此对象
*/ */
open class MessageReceipt<C : Contact>( open class MessageReceipt<C : Contact>(
private val source: MessageSource, val source: MessageSource,
target: C target: C
) { ) {
init { init {

View File

@ -161,7 +161,7 @@ internal class LockFreeLinkedListTest {
println("Check value") println("Check value")
value shouldBeEqualTo 6 value shouldBeEqualTo 6
println("Check size") println("Check size")
println(list.getLinkStructure()) // println(list.getLinkStructure())
list.size shouldBeEqualTo 6 list.size shouldBeEqualTo 6
} }
@ -174,7 +174,7 @@ internal class LockFreeLinkedListTest {
println("Check value") println("Check value")
value shouldBeEqualTo 2 value shouldBeEqualTo 2
println("Check size") println("Check size")
println(list.getLinkStructure()) // println(list.getLinkStructure())
list.size shouldBeEqualTo 5 list.size shouldBeEqualTo 5
} }
@ -198,7 +198,7 @@ internal class LockFreeLinkedListTest {
println("Check value") println("Check value")
value shouldBeEqualTo 2 value shouldBeEqualTo 2
println("Check size") println("Check size")
println(list.getLinkStructure()) // println(list.getLinkStructure())
list.size shouldBeEqualTo 1 list.size shouldBeEqualTo 1
} }
/* /*

View File

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