Merge remote-tracking branch 'origin/master'

# Conflicts:
#	mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
This commit is contained in:
jiahua.liu 2020-02-18 15:01:53 +08:00
commit 49673262ad
34 changed files with 318 additions and 97 deletions

View File

@ -2,6 +2,14 @@
开发版本. 频繁更新, 不保证高稳定性
## `0.15.2` 2020/2/18
### mirai-core
- 尝试修复 `atomicfu` 编译错误的问题
### mirai-core-qqandroid
- 查询群信息失败后重试
## `0.15.1` 2020/2/15
### mirai-core

View File

@ -57,6 +57,10 @@ TIM PC 2.3.2 版本2019 年 8 月)协议的实现,相较于 core
## Use as a library
**mirai-core 为独立设计, 可以作为库内置于任意 Java(JVM)/Android 项目中使用.**
请将 `VERSION` 替换为最新的版本(如 `0.15.0`):
[![Download](https://api.bintray.com/packages/him188moe/mirai/mirai-core/images/download.svg)](https://bintray.com/him188moe/mirai/mirai-core/)
**Mirai 目前还处于实验性阶段, 我们无法保证任何稳定性, API 也可能会随时修改.**
### Maven
Kotlin 在 Maven 上只支持 JVM 平台.
```xml
@ -71,7 +75,7 @@ Kotlin 在 Maven 上只支持 JVM 平台.
<dependencies>
<dependency>
<groupId>net.mamoe</groupId>
<artifactId>mirai-core-qqandroid-jvm</artifactId>
<artifactId>mirai-core-qqandroid</artifactId>
<version>0.15.1</version> <!-- 替换版本为最新版本 -->
</dependency>
</dependencies>
@ -85,25 +89,21 @@ repositories{
}
```
若您需要使用在跨平台项目, 则要对各个目标平台添加不同的依赖,这与 kotlin 相关多平台库的依赖是类似的。
**若您只需要使用在单一平台, 则只需要添加一项该平台的依赖. 如只在 JVM 运行则只需要`-jvm`的依赖**
请将 `VERSION` 替换为最新的版本(如 `0.15.0`):
[![Download](https://api.bintray.com/packages/him188moe/mirai/mirai-core/images/download.svg)](https://bintray.com/him188moe/mirai/mirai-core/)
**Mirai 目前还处于实验性阶段, 我们无法保证任何稳定性, API 也可能会随时修改.**
**若您只需要使用在单一平台, 则只需要添加一项该平台的依赖.**
**注意:**
Mirai 核心由 API 模块(`mirai-core`)和协议模块组成。
只添加 API 模块将无法正常工作。
现在只推荐使用 QQAndroid 协议,请参照下文选择对应目标平台的依赖添加。
**jvm** (JVM 平台)
```kotlin
implementation("net.mamoe:mirai-core-qqandroid:VERSION")
```
**common** (通用平台)
```kotlin
implementation("net.mamoe:mirai-core-qqandroid-common:VERSION")
```
**jvm** (JVM 平台)
```kotlin
implementation("net.mamoe:mirai-core-qqandroid-jvm:VERSION")
```
**android** (Android 平台)
```kotlin
implementation("net.mamoe:mirai-core-qqandroid-android:VERSION")

View File

@ -1,7 +1,7 @@
# style guide
kotlin.code.style=official
# config
mirai_version=0.15.1
mirai_version=0.15.2
mirai_japt_version=1.0.1
kotlin.incremental.multiplatform=true
kotlin.parallel.tasks.in.project=true

View File

@ -1,4 +1,5 @@
// kotlinx.coroutines
// Source code from kotlinx.coroutines
def pomConfig = {
licenses {
@ -12,6 +13,7 @@ def pomConfig = {
developer {
id "mamoe"
name "Mamoe Technologies"
email "support@mamoe.net"
}
}
scm {

View File

@ -6,7 +6,7 @@ plugins {
}
javafx {
version = "11"
version = "13.0.2"
modules = listOf("javafx.controls")
//mainClassName = "Application"
}

View File

@ -24,8 +24,8 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
val botList = observableListOf<BotModel>()
val consoleInfo = ConsoleInfo()
fun login(qq: String, psd: String) {
MiraiConsole.CommandListener.commandChannel.offer("/login $qq $psd")
suspend fun login(qq: String, psd: String) {
MiraiConsole.CommandListener.commandChannel.send("/login $qq $psd")
}
override fun pushLog(identity: Long, message: String) = Platform.runLater {

View File

@ -1,7 +1,7 @@
package net.mamoe.mirai.console.graphical.view
import com.jfoenix.controls.JFXTextField
import javafx.beans.property.SimpleStringProperty
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController
import net.mamoe.mirai.console.graphical.util.jfxButton
import net.mamoe.mirai.console.graphical.util.jfxPasswordfield
@ -24,7 +24,9 @@ class LoginFragment : Fragment() {
}
}
jfxButton("登录").action {
controller.login(qq.value, psd.value)
runBlocking {
controller.login(qq.value, psd.value)
}
close()
}
}

View File

@ -10,7 +10,6 @@ import com.googlecode.lanterna.terminal.DefaultTerminalFactory
import com.googlecode.lanterna.terminal.Terminal
import com.googlecode.lanterna.terminal.TerminalResizeListener
import com.googlecode.lanterna.terminal.swing.SwingTerminal
import com.googlecode.lanterna.terminal.swing.SwingTerminalFontConfiguration
import com.googlecode.lanterna.terminal.swing.SwingTerminalFrame
import kotlinx.coroutines.*
import kotlinx.coroutines.io.close
@ -23,7 +22,6 @@ import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.redrawLogs
import net.mamoe.mirai.utils.LoginSolver
import net.mamoe.mirai.utils.createCharImg
import net.mamoe.mirai.utils.writeChannel
import java.awt.Font
import java.io.File
import java.io.OutputStream
import java.io.PrintStream
@ -126,12 +124,12 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
}
fun provideInput(input: String) {
suspend fun provideInput(input: String) {
if (requesting) {
requestResult = input
requesting = false
} else {
MiraiConsole.CommandListener.commandChannel.offer(
MiraiConsole.CommandListener.commandChannel.send(
commandBuilder.toString()
)
}
@ -336,7 +334,9 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
update()
}
KeyType.Enter -> {
provideInput(commandBuilder.toString())
runBlocking {
provideInput(commandBuilder.toString())
}
emptyCommand()
}
KeyType.Escape -> {

View File

@ -6,9 +6,9 @@
| 名字 | 介绍 |
| --- | --- |
| Mirai-Console-Pure | 最纯净版, CLI环境, 通过标准输入与标准输出 交互 |
| Mirai-Console-Terminal | (UNIX)Terminal环境 提供简介好用的富文本控制台 |
| Mirai-Console-Terminal | (UNIX)Terminal环境 提供简的富文本控制台 |
| Mirai-Console-Android | 安卓APP (TODO) |
| Mirai-Console-Graphical | JavaFX的图形化界面, 有Native版本(.jar/.exe/.dmg) |
| Mirai-Console-Graphical | JavaFX的图形化界面 (.jar/.exe/.dmg) |
| Mirai-Console-WebPanel | Web Panel操作(TODO) |
| Mirai-Console-Ios | IOS APP (TODO) |

View File

@ -42,7 +42,7 @@ object CommandManager {
registeredCommand.remove(commandName)
}
fun runCommand(fullCommand: String): Boolean {
suspend fun runCommand(fullCommand: String): Boolean {
val blocks = fullCommand.split(" ")
val commandHead = blocks[0].replace("/", "")
if (!registeredCommand.containsKey(commandHead)) {
@ -66,7 +66,7 @@ interface ICommand {
val name: String
val alias: List<String>
val description: String
fun onCommand(args: List<String>): Boolean
suspend fun onCommand(args: List<String>): Boolean
fun register()
}
@ -77,9 +77,9 @@ abstract class Command(
) : ICommand {
/**
* 最高优先级监听器
* 如果return [false] 这次指令不会被[PluginBase]的全局onCommand监听器监听
* 如果 return `false` 这次指令不会被 [PluginBase] 的全局 onCommand 监听器监听
* */
open override fun onCommand(args: List<String>): Boolean {
open override suspend fun onCommand(args: List<String>): Boolean {
return true
}
@ -92,9 +92,9 @@ class AnonymousCommand internal constructor(
override val name: String,
override val alias: List<String>,
override val description: String,
val onCommand: ICommand.(args: List<String>) -> Boolean
val onCommand: suspend ICommand.(args: List<String>) -> Boolean
) : ICommand {
override fun onCommand(args: List<String>): Boolean {
override suspend fun onCommand(args: List<String>): Boolean {
return onCommand.invoke(this, args)
}
@ -107,9 +107,9 @@ class CommandBuilder internal constructor() {
var name: String? = null
var alias: List<String>? = null
var description: String = ""
var onCommand: (ICommand.(args: List<String>) -> Boolean)? = null
var onCommand: (suspend ICommand.(args: List<String>) -> Boolean)? = null
fun onCommand(commandProcess: ICommand.(args: List<String>) -> Boolean) {
fun onCommand(commandProcess: suspend ICommand.(args: List<String>) -> Boolean) {
onCommand = commandProcess
}

View File

@ -9,20 +9,20 @@ package net.mamoe.mirai.console
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import net.mamoe.mirai.Bot
import net.mamoe.mirai.api.http.MiraiHttpAPIServer
import net.mamoe.mirai.api.http.generateSessionKey
import net.mamoe.mirai.console.MiraiConsole.CommandListener.processNextCommandLine
import net.mamoe.mirai.console.plugins.PluginManager
import net.mamoe.mirai.console.plugins.loadAsConfig
import net.mamoe.mirai.console.plugins.withDefaultWrite
import net.mamoe.mirai.console.plugins.withDefaultWriteSave
import net.mamoe.mirai.contact.sendMessage
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.SimpleLogger
import java.io.File
import java.util.*
import java.util.concurrent.LinkedBlockingQueue
import kotlin.concurrent.thread
object MiraiConsole {
@ -130,37 +130,35 @@ object MiraiConsole {
val qqPassword = it[1]
logger("[Bot Login]", 0, "login...")
try {
runBlocking {
frontEnd.prePushBot(qqNumber)
val bot = Bot(qqNumber, qqPassword) {
this.loginSolver = frontEnd.createLoginSolver()
this.botLoggerSupplier = {
SimpleLogger("BOT $qqNumber]") { _, message, e ->
logger("[BOT $qqNumber]", qqNumber, message)
if (e != null) {
logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ
e.printStackTrace()
}
}
}
this.networkLoggerSupplier = {
SimpleLogger("BOT $qqNumber") { _, message, e ->
logger("[NETWORK]", qqNumber, message)//因为在一页 所以可以不打QQ
if (e != null) {
logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ
e.printStackTrace()
}
frontEnd.prePushBot(qqNumber)
val bot = Bot(qqNumber, qqPassword) {
this.loginSolver = frontEnd.createLoginSolver()
this.botLoggerSupplier = {
SimpleLogger("BOT $qqNumber]") { _, message, e ->
logger("[BOT $qqNumber]", qqNumber, message)
if (e != null) {
logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ
e.printStackTrace()
}
}
}
this.networkLoggerSupplier = {
SimpleLogger("BOT $qqNumber") { _, message, e ->
logger("[NETWORK]", qqNumber, message)//因为在一页 所以可以不打QQ
if (e != null) {
logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ
e.printStackTrace()
}
}
}
bot.login()
logger(
"[Bot Login]",
0,
"$qqNumber login successes"
)
frontEnd.pushBot(bot)
}
bot.login()
logger(
"[Bot Login]",
0,
"$qqNumber login successes"
)
frontEnd.pushBot(bot)
} catch (e: Exception) {
logger(
"[Bot Login]",
@ -288,20 +286,19 @@ object MiraiConsole {
}
}
object CommandListener {
val commandChannel: Queue<String> = LinkedBlockingQueue<String>()
fun start() {
thread {
processNextCommandLine()
}
object CommandListener : Job by {
GlobalScope.launch(start = CoroutineStart.LAZY) {
processNextCommandLine()
}
}() {
val commandChannel: Channel<String> = Channel()
tailrec fun processNextCommandLine() {
suspend fun processNextCommandLine() {
if (allDown) {
return
}
var fullCommand = commandChannel.take(1)[0]
if (fullCommand != null) {
for (command in commandChannel) {
var fullCommand = command
if (!fullCommand.startsWith("/")) {
fullCommand = "/$fullCommand"
}
@ -309,7 +306,6 @@ object MiraiConsole {
logger("未知指令 $fullCommand")
}
}
processNextCommandLine();
}
}

View File

@ -1,25 +1,28 @@
package net.mamoe.mirai.console
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.Bot
import net.mamoe.mirai.utils.DefaultLoginSolver
import net.mamoe.mirai.utils.LoginSolver
import net.mamoe.mirai.utils.LoginSolverInputReader
import kotlin.concurrent.thread
class MiraiConsoleUIPure() : MiraiConsoleUI {
class MiraiConsoleUIPure : MiraiConsoleUI {
var requesting = false
var requestStr = ""
init {
thread {
while (true) {
val input = readLine() ?: ""
val input = readLine() ?: return@thread
if (requesting) {
requestStr = input
requesting = false
} else {
MiraiConsole.CommandListener.commandChannel.offer(input)
runBlocking {
MiraiConsole.CommandListener.commandChannel.send(input)
}
}
}
}

View File

@ -118,5 +118,9 @@ kotlin {
}
}
}
//
//tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
// kotlinOptions.jvmTarget = "1.8"
//}
apply(from = rootProject.file("gradle/publish.gradle"))

View File

@ -215,11 +215,14 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
.sendAndExpect<FriendList.GetTroopListSimplify.Response>(retry = 2)
troopListData.groups.forEach { troopNum ->
launch {
try {
// 别用 fun, 别 val, 编译失败警告
lateinit var loadGroup: suspend () -> Unit
loadGroup = suspend {
tryNTimesOrException(3) {
bot.groups.delegate.addLast(
@Suppress("DuplicatedCode")
GroupImpl(
(GroupImpl(
bot = bot,
coroutineContext = bot.coroutineContext,
id = troopNum.groupCode,
@ -241,12 +244,20 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
this.delegate.groupCode = troopNum.groupCode
},
members = bot.queryGroupMemberList(troopNum.groupUin, troopNum.groupCode, troopNum.dwGroupOwnerUin)
)
))
)
} catch (e: Exception) {
}?.let {
logger.error("${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试")
logger.error(e)
logger.error(it)
this@QQAndroidBotNetworkHandler.launch {
delay(10_000)
loadGroup()
}
}
Unit // 别删, 编译失败警告
}
launch {
loadGroup()
}
}
logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}")

View File

@ -150,5 +150,9 @@ kotlin {
}
}
}
//
//tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
// kotlinOptions.jvmTarget = "1.8"
//}
apply(from = rootProject.file("gradle/publish.gradle"))

View File

@ -0,0 +1,16 @@
package net.mamoe.mirai.utils
private var isAddSuppressedSupported: Boolean = true
@MiraiInternalAPI
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
actual fun Throwable.addSuppressed(e: Throwable) {
if (!isAddSuppressedSupported) {
return
}
try {
this.addSuppressed(e)
} catch (e: Exception) {
isAddSuppressedSupported = false
}
}

View File

@ -7,6 +7,9 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:JvmMultifileClass
@file:JvmName("MessageUtils")
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.message.data
@ -14,6 +17,8 @@ package net.mamoe.mirai.message.data
import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.contact.groupCardOrNick
import net.mamoe.mirai.utils.MiraiInternalAPI
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
/**

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
/**
* "@全体成员"
*

View File

@ -7,8 +7,13 @@
* 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
import kotlin.jvm.JvmStatic
/**

View File

@ -7,6 +7,9 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:JvmMultifileClass
@file:JvmName("MessageUtils")
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.message.data
@ -14,13 +17,18 @@ package net.mamoe.mirai.message.data
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import net.mamoe.mirai.utils.io.chunkedHexToBytes
import kotlin.js.JsName
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic
/**
* 自定义表情 (收藏的表情), 图片
*/
sealed class Image : Message {
companion object Key : Message.Key<Image> {
@JvmStatic
@JsName("fromId")
@JvmName("fromId")
operator fun invoke(imageId: String): Image = when (imageId.length) {
37 -> NotOnlineImageFromFile(imageId) // /f8f1ab55-bf8e-4236-b55e-955848d7069f

View File

@ -13,6 +13,7 @@ package net.mamoe.mirai.message.data
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.sendMessage
import kotlin.jvm.JvmSynthetic
/**
* 可发送的或从服务器接收的消息.
@ -82,6 +83,7 @@ interface Message {
* println(c)// "Hello world!"
* ```
*/
@JvmSynthetic // in java they should use `plus` instead
fun followedBy(tail: Message): MessageChain {
require(tail !is SingleOnly) { "SingleOnly Message cannot follow another message" }
require(this !is SingleOnly) { "SingleOnly Message cannot be followed" }
@ -92,6 +94,7 @@ interface Message {
override fun toString(): String
operator fun plus(another: Message): MessageChain = this.followedBy(another)
operator fun plus(another: String): MessageChain = this.followedBy(another.toMessage())
// `+ ""` will be resolved to `plus(String)` instead of `plus(CharSeq)`
operator fun plus(another: CharSequence): MessageChain = this.followedBy(another.toString().toMessage())

View File

@ -7,6 +7,9 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:JvmMultifileClass
@file:JvmName("MessageUtils")
package net.mamoe.mirai.message.data
import net.mamoe.mirai.message.data.NullMessageChain.toString
@ -14,6 +17,9 @@ import net.mamoe.mirai.utils.MiraiExperimentalAPI
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
import kotlin.js.JsName
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
import kotlin.jvm.Volatile
import kotlin.reflect.KProperty
@ -35,10 +41,12 @@ interface MessageChain : Message, MutableList<Message> {
override fun followedBy(tail: Message): MessageChain
// endregion
@JvmSynthetic
operator fun plusAssign(message: Message) {
this.followedBy(message)
}
@JvmSynthetic // make java user happier
operator fun plusAssign(plain: String) {
this.plusAssign(plain.toMessage())
}
@ -53,7 +61,7 @@ interface MessageChain : Message, MutableList<Message> {
operator fun <M : Message> get(key: Message.Key<M>): M = first(key)
override fun eq(other: Message): Boolean {
if(other is MessageChain && other.size != this.size)
if (other is MessageChain && other.size != this.size)
return false
return this.toString() == other.toString()
}
@ -67,13 +75,16 @@ inline operator fun <reified T : Message> MessageChain.getValue(thisRef: Any?, p
/**
* 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 8
*/
@JsName("emptyMessageChain")
@JvmName("newChain")
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(): MessageChain = EmptyMessageChain()
/**
* 构造无初始元素的可修改的 [MessageChain]. 初始大小将会被设定为 [initialCapacity]
*/
@JvmName("newChain")
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(initialCapacity: Int): MessageChain =
if (initialCapacity == 0) EmptyMessageChain()
@ -83,6 +94,8 @@ fun MessageChain(initialCapacity: Int): MessageChain =
* 构造 [MessageChain]
* 若仅提供一个参数, 请考虑使用 [Message.toChain] 以优化性能
*/
@JvmName("newChain")
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(vararg messages: Message): MessageChain =
if (messages.isEmpty()) EmptyMessageChain()
@ -91,6 +104,8 @@ fun MessageChain(vararg messages: Message): MessageChain =
/**
* 构造 [MessageChain]
*/
@JvmName("newChain")
@JsName("newChain")
@Suppress("FunctionName")
fun MessageChain(messages: Iterable<Message>): MessageChain =
MessageChainImpl(messages.toMutableList())
@ -106,6 +121,8 @@ fun MessageChain(messages: Iterable<Message>): MessageChain =
*
* @see Message.toChain receiver 模式
*/
@JvmName("newSingleMessageChain")
@JsName("newChain")
@MiraiExperimentalAPI
@UseExperimental(ExperimentalContracts::class)
@Suppress("FunctionName")
@ -301,7 +318,7 @@ internal inline class MessageChainImpl constructor(
constructor(vararg messages: Message) : this(messages.toMutableList())
// region Message override
override fun toString(): String = this.delegate.joinToString("") { it.toString() }
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): MessageChain {
@ -352,6 +369,7 @@ internal inline class SingleMessageChainImpl(
// region Message override
override operator fun contains(sub: String): Boolean = delegate.contains(sub)
override fun followedBy(tail: Message): MessageChain {
require(tail !is SingleOnly) { "SingleOnly Message cannot follow another message" }
return if (tail is MessageChain) tail.apply { followedBy(delegate) }

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
/**
* 消息源, 用于被引用. 它将由协议模块实现.
* 消息源只用于 [QuoteReply]
@ -18,7 +24,7 @@ package net.mamoe.mirai.message.data
* @see MessageSource.quote 引用这条消息, 创建 [MessageChain]
*/
interface MessageSource : Message {
companion object : Message.Key<MessageSource>
companion object Key : Message.Key<MessageSource>
/**
* 实际上是个随机数, 但服务器确实是用它当做 uid

View File

@ -7,9 +7,19 @@
* 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
/**
* 纯文本. 可含 emoji 表情.
*
* 一般不需要主动构造 [PlainText], [Message] 可直接与 [String] 相加. Java 用户请使用 [MessageChain.plus]
*/
inline class PlainText(val stringValue: String) : Message {
override operator fun contains(sub: String): Boolean = sub in stringValue
override fun toString(): String = stringValue
@ -17,7 +27,7 @@ inline class PlainText(val stringValue: String) : Message {
companion object Key : Message.Key<PlainText>
override fun eq(other: Message): Boolean {
if(other is MessageChain){
if (other is MessageChain) {
return other eq this.toString()
}
return other is PlainText && other.stringValue == this.stringValue

View File

@ -7,10 +7,15 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:JvmMultifileClass
@file:JvmName("MessageUtils")
package net.mamoe.mirai.message.data
import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.utils.MiraiInternalAPI
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
/**

View File

@ -7,10 +7,17 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:JvmMultifileClass
@file:JvmName("MessageUtils")
@file:Suppress("MemberVisibilityCanBePrivate")
package net.mamoe.mirai.message.data
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
/**
* XML 消息, 如分享, 卡片等.
*
@ -30,6 +37,7 @@ inline class XMLMessage(val stringValue: String) : Message,
* 构造一条 XML 消息
*/
@XMLDsl
@MiraiExperimentalAPI("还未支持")
inline fun buildXMLMessage(block: @XMLDsl XMLMessageBuilder.() -> Unit): XMLMessage =
XMLMessage(XMLMessageBuilder().apply(block).text)

View File

@ -0,0 +1,72 @@
/*
* 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
*/
package net.mamoe.mirai.utils
@MiraiInternalAPI
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
expect fun Throwable.addSuppressed(e: Throwable)
@MiraiInternalAPI
@Suppress("DuplicatedCode")
inline fun <R> tryNTimes(repeat: Int, block: () -> R): R {
var lastException: Throwable? = null
repeat(repeat) {
try {
return block()
} catch (e: Throwable) {
if (lastException == null) {
lastException = e
}
lastException!!.addSuppressed(e)
}
}
throw lastException!!
}
@MiraiInternalAPI
@Suppress("DuplicatedCode")
inline fun <R> tryNTimesOrNull(repeat: Int, block: () -> R): R? {
var lastException: Throwable? = null
repeat(repeat) {
try {
return block()
} catch (e: Throwable) {
if (lastException == null) {
lastException = e
}
lastException!!.addSuppressed(e)
}
}
return null
}
@MiraiInternalAPI
@Suppress("DuplicatedCode")
inline fun <R> tryNTimesOrException(repeat: Int, block: () -> R): Throwable? {
var lastException: Throwable? = null
repeat(repeat) {
try {
block()
return null
} catch (e: Throwable) {
if (lastException == null) {
lastException = e
}
lastException!!.addSuppressed(e)
}
}
return lastException!!
}

View File

@ -0,0 +1,16 @@
package net.mamoe.mirai.utils
private var isAddSuppressedSupported: Boolean = true
@MiraiInternalAPI
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
actual fun Throwable.addSuppressed(e: Throwable) {
if (!isAddSuppressedSupported) {
return
}
try {
this.addSuppressed(e)
} catch (e: Exception) {
isAddSuppressedSupported = false
}
}

View File

@ -2,9 +2,9 @@ apply plugin: "kotlin"
apply plugin: "java"
dependencies {
implementation files("../../mirai-core/build/classes/kotlin/jvm/main") // IDE bug
runtimeOnly files("../../mirai-core/build/classes/kotlin/jvm/main") // IDE bug
implementation files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug
runtimeOnly files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug
implementation project(":mirai-core-qqandroid")
api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlinVersion

View File

@ -2,9 +2,9 @@ apply plugin: "java"
apply plugin: "kotlin"
dependencies {
implementation files("../../mirai-core/build/classes/kotlin/jvm/main") // IDE bug
runtimeOnly files("../../mirai-core/build/classes/kotlin/jvm/main") // IDE bug
implementation files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug
runtimeOnly files("../../mirai-core-qqandroid/build/classes/kotlin/jvm/main") // IDE bug
implementation project(":mirai-core-qqandroid")
implementation project(":mirai-japt")
}

View File

@ -5,6 +5,9 @@ import net.mamoe.mirai.japt.BlockingContacts;
import net.mamoe.mirai.japt.BlockingQQ;
import net.mamoe.mirai.japt.Events;
import net.mamoe.mirai.message.GroupMessage;
import net.mamoe.mirai.message.data.At;
import net.mamoe.mirai.message.data.Image;
import net.mamoe.mirai.message.data.MessageUtils;
class BlockingTest {
@ -19,8 +22,14 @@ class BlockingTest {
Events.subscribeAlways(GroupMessage.class, (GroupMessage message) -> {
final BlockingQQ sender = BlockingContacts.createBlocking(message.getSender());
sender.sendMessage("Hello World!");
System.out.println("发送完了");
sender.sendMessage("Hello");
sender.sendMessage(MessageUtils.newChain()
.plus(new At(message.getSender()))
.plus(Image.fromId("{xxxx}.jpg"))
.plus("123465")
);
});
Thread.sleep(999999999);

View File

@ -32,7 +32,7 @@ Mirai Java Apt
<dependencies>
<dependency>
<groupId>net.mamoe</groupId>
<artifactId>mirai-core-qqandroid-jvm</artifactId>
<artifactId>mirai-core-qqandroid</artifactId>
<version>CORE_VERSION</version> <!-- 替换版本为最新版本 -->
</dependency>
@ -51,7 +51,7 @@ repositories {
}
dependencies {
implementation("net.mamoe:mirai-core-qqandroid-jvm:CORE_VERSION")
implementation("net.mamoe:mirai-core-qqandroid:CORE_VERSION")
implementation("net.mamoe:mirai-japt:JAPT_VERSION")
}
```

View File

@ -18,9 +18,9 @@ buildscript {
plugins {
kotlin("jvm")
java
id("com.jfrog.bintray") version "1.8.0"
`maven-publish`
// maven
id("com.jfrog.bintray") version "1.8.0"
}
val kotlinVersion: String by rootProject.ext
@ -77,6 +77,10 @@ tasks.withType<JavaCompile>() {
options.encoding = "UTF-8"
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
bintray {
val keyProps = Properties()
val keyFile = file("../keys.properties")

View File

@ -65,11 +65,11 @@ try{
println("jdk版本为 "+ javaVersionNum)
include(':mirai-console-graphical')
} else {
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 最低需要 JDK 11 才能引入模块 `:mirai-debug`")
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 最低需要 JDK 11 才能引入模块 `:mirai-console-graphical`")
}
}
}catch(Exception ignored){
println("无法确定 JDK 版本, 将不会引入 `:mirai-console-graphical`")
}
enableFeaturePreview('GRADLE_METADATA')