mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-09 01:30:17 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
577348ff32
@ -173,14 +173,16 @@ fun main() {
|
||||
| ------------ | ------ | ----- | ----------- | -------------------------------- |
|
||||
| sessionKey | String | false | YourSession | 已经激活的Session |
|
||||
| target | Long | false | 987654321 | 发送消息目标好友的QQ号 |
|
||||
| quote | Long | true | 135798642 | 引用一条消息的messageId进行回复 |
|
||||
| messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 |
|
||||
|
||||
#### 响应: 返回统一状态码
|
||||
#### 响应: 返回统一状态码(并携带messageId)
|
||||
|
||||
```json5
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "success"
|
||||
"msg": "success",
|
||||
"messageId": 1234567890 // 一个Long类型属性,标识本条消息,用于撤回和引用回复
|
||||
}
|
||||
```
|
||||
|
||||
@ -211,52 +213,16 @@ fun main() {
|
||||
| ------------ | ------ | ----- | ----------- | -------------------------------- |
|
||||
| sessionKey | String | false | YourSession | 已经激活的Session |
|
||||
| target | Long | false | 987654321 | 发送消息目标群的群号 |
|
||||
| quote | Long | true | 135798642 | 引用一条消息的messageId进行回复 |
|
||||
| messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 |
|
||||
|
||||
#### 响应: 返回统一状态码
|
||||
#### 响应: 返回统一状态码(并携带messageId)
|
||||
|
||||
```json5
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "success"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 发送引用回复消息(仅支持群消息)
|
||||
|
||||
```
|
||||
[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"
|
||||
"msg": "success",
|
||||
"messageId": 1234567890 // 一个Long类型属性,标识本条消息,用于撤回和引用回复
|
||||
}
|
||||
```
|
||||
|
||||
@ -331,6 +297,39 @@ Content-Type:multipart/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收到的消息和事件
|
||||
|
||||
```
|
||||
@ -370,7 +369,10 @@ Content-Type:multipart/form-data
|
||||
}
|
||||
},{
|
||||
"type": "FriendMessage", // 消息类型:GroupMessage或FriendMessage或各类Event
|
||||
"messageChain": [{ // 消息链,是一个消息对象构成的数组
|
||||
"messageChain": [{ // 消息链,是一个消息对象构成的数组
|
||||
"type": "Source",
|
||||
"uid": 123456
|
||||
},{
|
||||
"type": "Plain",
|
||||
"text": "Miral牛逼"
|
||||
}],
|
||||
|
@ -12,7 +12,7 @@ import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||
sealed class BotEventDTO : EventDTO()
|
||||
|
||||
@UseExperimental(MiraiExperimentalAPI::class)
|
||||
fun BotEvent.toDTO() = when(this) {
|
||||
suspend fun BotEvent.toDTO() = when(this) {
|
||||
is MessagePacket<*, *> -> toDTO()
|
||||
else -> when(this) {
|
||||
is BotOnlineEvent -> BotOnlineEventDTO(bot.uin)
|
||||
|
@ -17,8 +17,9 @@ import net.mamoe.mirai.message.FriendMessage
|
||||
import net.mamoe.mirai.message.GroupMessage
|
||||
import net.mamoe.mirai.message.MessagePacket
|
||||
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 java.net.URL
|
||||
|
||||
/*
|
||||
* DTO data class
|
||||
@ -57,7 +58,7 @@ data class PlainDTO(val text: String) : MessageDTO()
|
||||
|
||||
@Serializable
|
||||
@SerialName("Image")
|
||||
data class ImageDTO(val imageId: String) : MessageDTO()
|
||||
data class ImageDTO(val imageId: String? = null, val url: String? = null) : MessageDTO()
|
||||
|
||||
@Serializable
|
||||
@SerialName("Xml")
|
||||
@ -84,42 +85,49 @@ sealed class MessageDTO : DTO
|
||||
/*
|
||||
Extend function
|
||||
*/
|
||||
fun MessagePacket<*, *>.toDTO() = when (this) {
|
||||
suspend fun MessagePacket<*, *>.toDTO() = when (this) {
|
||||
is FriendMessage -> FriendMessagePacketDTO(QQDTO(sender))
|
||||
is GroupMessage -> GroupMessagePacketDTO(MemberDTO(sender))
|
||||
else -> IgnoreEventDTO
|
||||
}.apply {
|
||||
if (this is MessagePacketDTO) { messageChain = message.toDTOChain() }
|
||||
// else: `this` is bot event
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
fun MessageChain.toDTOChain() = mutableListOf(this[MessageSource].toDTO()).apply {
|
||||
foreachContent { content -> content.toDTO().takeUnless { it == UnknownMessageDTO }?.let(::add) }
|
||||
}
|
||||
suspend fun MessageChainDTO.toMessageChain(contact: Contact) =
|
||||
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)
|
||||
fun Message.toDTO() = when (this) {
|
||||
is MessageSource -> MessageSourceDTO(id)
|
||||
is At -> AtDTO(target, display)
|
||||
@UseExperimental(ExperimentalUnsignedTypes::class)
|
||||
suspend fun MessagePacket<*, *>.messageDTO(message: Message) = when (message) {
|
||||
is MessageSource -> MessageSourceDTO(message.id)
|
||||
is At -> AtDTO(message.target, message.display)
|
||||
is AtAll -> AtAllDTO(0L)
|
||||
is Face -> FaceDTO(id)
|
||||
is PlainText -> PlainDTO(stringValue)
|
||||
is Image -> ImageDTO(imageId)
|
||||
is XMLMessage -> XmlDTO(stringValue)
|
||||
is Face -> FaceDTO(message.id)
|
||||
is PlainText -> PlainDTO(message.stringValue)
|
||||
is Image -> ImageDTO(message.imageId, message.url())
|
||||
is XMLMessage -> XmlDTO(message.stringValue)
|
||||
else -> UnknownMessageDTO
|
||||
}
|
||||
|
||||
@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class, MiraiExperimentalAPI::class)
|
||||
fun MessageDTO.toMessage(contact: Contact) = when (this) {
|
||||
@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
|
||||
suspend fun MessageDTO.toMessage(contact: Contact) = when (this) {
|
||||
is AtDTO -> At((contact as Group)[target])
|
||||
is AtAllDTO -> AtAll
|
||||
is FaceDTO -> Face(faceId)
|
||||
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 MessageSourceDTO, is UnknownMessageDTO -> PlainText("assert cannot reach")
|
||||
is MessageSourceDTO, is UnknownMessageDTO -> null
|
||||
}
|
||||
|
||||
|
@ -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.toDTO
|
||||
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.utils.firstKey
|
||||
import java.util.concurrent.ConcurrentLinkedDeque
|
||||
|
||||
class MessageQueue : ConcurrentLinkedDeque<BotEvent>() {
|
||||
|
||||
val quoteCacheSize = 4096
|
||||
val quoteCache = LinkedHashMap<Long, GroupMessage>()
|
||||
val cacheSize = 4096
|
||||
val cache = LinkedHashMap<Long, MessagePacket<*, *>>()
|
||||
|
||||
fun fetch(size: Int): List<EventDTO> {
|
||||
suspend fun fetch(size: Int): List<EventDTO> {
|
||||
var count = size
|
||||
|
||||
val ret = ArrayList<EventDTO>(count)
|
||||
@ -37,18 +37,20 @@ class MessageQueue : ConcurrentLinkedDeque<BotEvent>() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 等FriendMessage支持quote
|
||||
if (event is GroupMessage) {
|
||||
if (event is MessagePacket<*, *>) {
|
||||
addQuoteCache(event)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
private fun addQuoteCache(msg: GroupMessage) {
|
||||
quoteCache[msg.message[MessageSource].id] = msg
|
||||
if (quoteCache.size > quoteCacheSize) {
|
||||
quoteCache.remove(quoteCache.firstKey())
|
||||
fun cache(messageId: Long) =
|
||||
cache[messageId] ?: throw NoSuchElementException()
|
||||
|
||||
fun addQuoteCache(msg: MessagePacket<*, *>) {
|
||||
cache[msg.message[MessageSource].id] = msg
|
||||
if (cache.size > cacheSize) {
|
||||
cache.remove(cache.firstKey())
|
||||
}
|
||||
}
|
||||
}
|
@ -20,15 +20,19 @@ import io.ktor.response.respondText
|
||||
import io.ktor.routing.post
|
||||
import io.ktor.routing.routing
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.Transient
|
||||
import net.mamoe.mirai.api.http.AuthedSession
|
||||
import net.mamoe.mirai.api.http.SessionManager
|
||||
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.VerifyDTO
|
||||
import net.mamoe.mirai.api.http.data.common.toMessageChain
|
||||
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 java.net.URL
|
||||
|
||||
@ -42,23 +46,47 @@ fun Application.messageModule() {
|
||||
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") {
|
||||
val quote = it.quote?.let { q ->
|
||||
it.session.messageQueue.cache(q).run {
|
||||
this[MessageSource].quote(sender)
|
||||
}}
|
||||
|
||||
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") {
|
||||
it.session.bot.getGroup(it.target).apply {
|
||||
sendMessage(it.messageChain.toMessageChain(this)) // this aka Group
|
||||
}
|
||||
}
|
||||
val quote = it.quote?.let { q ->
|
||||
it.session.messageQueue.cache(q).run {
|
||||
this[MessageSource].quote(sender)
|
||||
}}
|
||||
|
||||
miraiVerify<SendDTO>("/sendQuoteMessage") {
|
||||
it.session.messageQueue.quoteCache[it.target]?.apply {
|
||||
quoteReply(it.messageChain.toMessageChain(group))
|
||||
} ?: throw NoSuchElementException()
|
||||
call.respondStateCode(StateCode.Success)
|
||||
it.session.bot.getGroup(it.target).apply {
|
||||
val receipt = sendMessage(quote, it.messageChain.toMessageChain(this), this)
|
||||
receipt.source.ensureSequenceIdAvailable()
|
||||
|
||||
it.session.messageQueue.addQuoteCache(GroupMessage("", botPermission, botAsMember, receipt.source.toChain()))
|
||||
call.respondDTO(SendRetDTO(messageId = receipt.source.id))
|
||||
}
|
||||
}
|
||||
|
||||
miraiVerify<SendImageDTO>("sendImageMessage") {
|
||||
@ -101,8 +129,10 @@ fun Application.messageModule() {
|
||||
}
|
||||
|
||||
miraiVerify<RecallDTO>("recall") {
|
||||
// TODO
|
||||
call.respond(HttpStatusCode.NotFound, "未完成")
|
||||
it.session.messageQueue.cache(it.target).apply {
|
||||
it.session.bot.recall(get(MessageSource))
|
||||
}
|
||||
call.respondStateCode(StateCode.Success)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -110,6 +140,7 @@ fun Application.messageModule() {
|
||||
@Serializable
|
||||
private data class SendDTO(
|
||||
override val sessionKey: String,
|
||||
val quote: Long? = null,
|
||||
val target: Long,
|
||||
val messageChain: MessageChainDTO
|
||||
) : VerifyDTO()
|
||||
@ -125,13 +156,13 @@ private data class SendImageDTO(
|
||||
|
||||
@Serializable
|
||||
private class SendRetDTO(
|
||||
val messageId: Long,
|
||||
@Transient val stateCode: StateCode = Success
|
||||
) : StateCode(stateCode.code, stateCode.msg)
|
||||
val code: Int = 0,
|
||||
val msg: String = "success",
|
||||
val messageId: Long
|
||||
) : DTO
|
||||
|
||||
@Serializable
|
||||
private data class RecallDTO(
|
||||
override val sessionKey: String,
|
||||
val target: Long,
|
||||
val sender: Long
|
||||
val target: Long
|
||||
) : VerifyDTO()
|
||||
|
@ -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,12 +425,17 @@ 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()
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,7 +31,7 @@ import net.mamoe.mirai.utils.unsafeWeakRef
|
||||
* @see QQ.sendMessage 发送群消息, 返回回执(此对象)
|
||||
*/
|
||||
open class MessageReceipt<C : Contact>(
|
||||
private val source: MessageSource,
|
||||
val source: MessageSource,
|
||||
target: C
|
||||
) {
|
||||
init {
|
||||
|
@ -161,7 +161,7 @@ internal class LockFreeLinkedListTest {
|
||||
println("Check value")
|
||||
value shouldBeEqualTo 6
|
||||
println("Check size")
|
||||
println(list.getLinkStructure())
|
||||
// println(list.getLinkStructure())
|
||||
list.size shouldBeEqualTo 6
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ internal class LockFreeLinkedListTest {
|
||||
println("Check value")
|
||||
value shouldBeEqualTo 2
|
||||
println("Check size")
|
||||
println(list.getLinkStructure())
|
||||
// println(list.getLinkStructure())
|
||||
list.size shouldBeEqualTo 5
|
||||
}
|
||||
|
||||
@ -198,7 +198,7 @@ internal class LockFreeLinkedListTest {
|
||||
println("Check value")
|
||||
value shouldBeEqualTo 2
|
||||
println("Check size")
|
||||
println(list.getLinkStructure())
|
||||
// println(list.getLinkStructure())
|
||||
list.size shouldBeEqualTo 1
|
||||
}
|
||||
/*
|
||||
|
@ -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() {
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user