Fix build

This commit is contained in:
Him188 2020-08-01 21:53:24 +08:00
parent 7dfd2fd5c9
commit e53363482d
16 changed files with 201 additions and 476 deletions

View File

@ -8,6 +8,7 @@ import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.CoroutineStart;
import kotlinx.coroutines.future.FutureKt;
import net.mamoe.mirai.console.plugin.jvm.JavaPlugin;
import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI;
import net.mamoe.mirai.message.data.Message;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -152,6 +153,7 @@ public final class JCommandManager {
* @return 执行结果
* @see #executeCommandDetailedAsync(CoroutineScope, CommandSender, Object...)
*/
@ConsoleExperimentalAPI
@NotNull
public static CommandExecuteResult executeCommandDetailed(final @NotNull CommandSender sender, final @NotNull Object... args) throws InterruptedException {
Objects.requireNonNull(sender, "sender");
@ -171,6 +173,7 @@ public final class JCommandManager {
* @return 执行结果
* @see #executeCommandDetailed(CommandSender, Object...)
*/
@ConsoleExperimentalAPI
@NotNull
public static CompletableFuture<@NotNull CommandExecuteResult>
executeCommandDetailedAsync(final @NotNull CoroutineScope scope, final @NotNull CommandSender sender, final @NotNull Object... args) {

View File

@ -20,6 +20,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import net.mamoe.mirai.console.command.internal.*
import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.MessageChain
@ -229,6 +230,7 @@ public suspend fun Command.execute(sender: CommandSender, vararg args: Any, chec
*
* @see JCommandManager.executeCommandDetailed Java 方法
*/
@ConsoleExperimentalAPI
public suspend fun CommandSender.executeCommandDetailed(vararg messages: Any): CommandExecuteResult {
if (messages.isEmpty()) return CommandExecuteResult.CommandNotFound("")
return executeCommandDetailedInternal(messages, messages[0].toString().substringBefore(' '))
@ -243,6 +245,7 @@ public suspend fun CommandSender.executeCommandDetailed(vararg messages: Any): C
*
* @see JCommandManager.executeCommandDetailed Java 方法
*/
@ConsoleExperimentalAPI
public suspend fun CommandSender.executeCommandDetailed(messages: MessageChain): CommandExecuteResult {
if (messages.isEmpty()) return CommandExecuteResult.CommandNotFound("")
return executeCommandDetailedInternal(messages, messages[0].toString())

View File

@ -63,7 +63,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
DefaultSubCommandDescriptor(
"",
permission,
onCommand = block2 { sender: CommandSender, args: Array<out Any> ->
onCommand = { sender: CommandSender, args: Array<out Any> ->
sender.onDefault(args)
}
)
@ -292,7 +292,7 @@ internal fun AbstractReflectionCommand.createSubCommand(
params,
subDescription,
overridePermission?.value?.getInstance() ?: permission,
onCommand = block { sender: CommandSender, args: Array<out Any> ->
onCommand = { sender: CommandSender, args: Array<out Any> ->
val result = if (notStatic) {
if (hasSenderParam) {
function.isSuspend
@ -311,13 +311,4 @@ internal fun AbstractReflectionCommand.createSubCommand(
context = context,
usage = buildUsage.toString()
)
}
private fun block(block: suspend (CommandSender, Array<out Any>) -> Boolean): suspend (CommandSender, Array<out Any>) -> Boolean {
return block
}
private fun block2(block: suspend (CommandSender, Array<out Any>) -> Unit): suspend (CommandSender, Array<out Any>) -> Unit {
return block
}
}

View File

@ -11,22 +11,20 @@
package net.mamoe.mirai.console.plugin.center
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.request.get
import io.ktor.util.KtorExperimentalAPI
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.request.*
import io.ktor.util.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI
import net.mamoe.mirai.console.utils.retryCatching
import java.io.File
@OptIn(UnstableDefault::class)
internal val json = runCatching {
Json(JsonConfiguration(isLenient = true, ignoreUnknownKeys = true))
}.getOrElse { Json(JsonConfiguration.Stable) }
internal val json = Json {
isLenient = true
ignoreUnknownKeys = true
}
@OptIn(KtorExperimentalAPI::class)
internal val Http = HttpClient(CIO)
@ -64,7 +62,7 @@ internal object CuiPluginCenter : PluginCenter {
}.getOrElse { return null }
if (result == "err:not found") return null
return json.parse(PluginCenter.PluginInfo.serializer(), result)
return json.decodeFromString(PluginCenter.PluginInfo.serializer(), result)
}
override suspend fun refresh() {
@ -75,7 +73,7 @@ internal object CuiPluginCenter : PluginCenter {
val result: List<PluginCenter.PluginInsight>
)
val result = json.parse(Result.serializer(), Http.get("https://miraiapi.jasonczc.cn/getPluginList"))
val result = json.decodeFromString(Result.serializer(), Http.get("https://miraiapi.jasonczc.cn/getPluginList"))
check(result.success) { "Failed to fetch plugin list from Cui Cloud" }
plugins = result.result

View File

@ -69,25 +69,25 @@ public interface SerializerAwareValue<T> : Value<T> {
@JvmStatic
@ConsoleExperimentalAPI("will be changed due to reconstruction of kotlinx.serialization")
public fun <T> SerializerAwareValue<T>.serialize(format: StringFormat): String {
return format.stringify(this.serializer, Unit)
return format.encodeToString(this.serializer, Unit)
}
@JvmStatic
@ConsoleExperimentalAPI("will be changed due to reconstruction of kotlinx.serialization")
public fun <T> SerializerAwareValue<T>.serialize(format: BinaryFormat): ByteArray {
return format.dump(this.serializer, Unit)
return format.encodeToByteArray(this.serializer, Unit)
}
@JvmStatic
@ConsoleExperimentalAPI("will be changed due to reconstruction of kotlinx.serialization")
public fun <T> SerializerAwareValue<T>.deserialize(format: StringFormat, value: String) {
format.parse(this.serializer, value)
format.decodeFromString(this.serializer, value)
}
@JvmStatic
@ConsoleExperimentalAPI("will be changed due to reconstruction of kotlinx.serialization")
public fun <T> SerializerAwareValue<T>.deserialize(format: BinaryFormat, value: ByteArray) {
format.load(this.serializer, value)
format.decodeFromByteArray(this.serializer, value)
}
}
}

View File

@ -7,18 +7,15 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("NOTHING_TO_INLINE")
@file:Suppress("NOTHING_TO_INLINE", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
package net.mamoe.mirai.console.setting.internal
import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
import kotlinx.serialization.KSerializer
import net.mamoe.mirai.console.setting.SerializableValue.Companion.serializableValueWith
import net.mamoe.mirai.console.setting.SerializerAwareValue
import net.mamoe.mirai.console.setting.Setting
import net.mamoe.mirai.console.setting.valueFromKType
import net.mamoe.yamlkt.YamlDynamicSerializer
import net.mamoe.yamlkt.YamlNullableDynamicSerializer
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.full.createInstance as createInstanceKotlin
@ -142,63 +139,3 @@ internal fun KClass<*>.isPrimitiveOrBuiltInSerializableValue(): Boolean {
@PublishedApi
@Suppress("UNCHECKED_CAST")
internal inline fun <R> Any.cast(): R = this as R
/**
* Copied from kotlinx.serialization, modifications are marked with "/* mamoe modify */"
* Copyright 2017-2020 JetBrains s.r.o.
*/
@Suppress(
"UNCHECKED_CAST",
"NO_REFLECTION_IN_CLASS_PATH",
"UNSUPPORTED",
"INVISIBLE_MEMBER",
"INVISIBLE_REFERENCE",
"IMPLICIT_CAST_TO_ANY"
)
@OptIn(ImplicitReflectionSerializer::class)
internal fun serializerMirai(type: KType): KSerializer<Any?> {
fun serializerByKTypeImpl(type: KType): KSerializer<Any> {
val rootClass = when (val t = type.classifier) {
is KClass<*> -> t
else -> error("Only KClass supported as classifier, got $t")
} as KClass<Any>
val typeArguments = type.arguments
.map { requireNotNull(it.type) { "Star projections are not allowed, had $it instead" } }
return when {
typeArguments.isEmpty() -> rootClass.serializer()
else -> {
val serializers = typeArguments
.map(::serializer)
// Array is not supported, see KT-32839
when (rootClass) {
List::class, MutableList::class, ArrayList::class -> ListSerializer(serializers[0])
HashSet::class -> SetSerializer(serializers[0])
Set::class, MutableSet::class, LinkedHashSet::class -> SetSerializer(serializers[0])
HashMap::class -> MapSerializer(serializers[0], serializers[1])
Map::class, MutableMap::class, LinkedHashMap::class -> MapSerializer(serializers[0], serializers[1])
Map.Entry::class -> MapEntrySerializer(serializers[0], serializers[1])
Pair::class -> PairSerializer(serializers[0], serializers[1])
Triple::class -> TripleSerializer(serializers[0], serializers[1], serializers[2])
/* mamoe modify */ Any::class -> if (type.isMarkedNullable) YamlNullableDynamicSerializer else YamlDynamicSerializer
else -> {
if (isReferenceArray(type, rootClass)) {
@Suppress("RemoveExplicitTypeArguments")
return ArraySerializer<Any, Any?>(
typeArguments[0].classifier as KClass<Any>,
serializers[0]
).cast()
}
requireNotNull(rootClass.constructSerializerForGivenTypeArgs(*serializers.toTypedArray())) {
"Can't find a method to construct serializer for type ${rootClass.simpleName()}. " +
"Make sure this class is marked as @Serializable or provide serializer explicitly."
}
}
}
}
}.cast()
}
val result = serializerByKTypeImpl(type)
return if (type.isMarkedNullable) result.nullable else result.cast()
}

View File

@ -11,9 +11,14 @@
package net.mamoe.mirai.console.setting.internal
import kotlinx.serialization.*
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.builtins.MapSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.CompositeDecoder
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import net.mamoe.mirai.console.setting.SerializerAwareValue
import net.mamoe.mirai.console.setting.Setting
import net.mamoe.mirai.console.setting.Value
@ -53,7 +58,7 @@ internal abstract class SettingImpl {
@Suppress("UNCHECKED_CAST")
override fun deserialize(decoder: Decoder) {
val descriptor = descriptor
with(decoder.beginStructure(descriptor, *settingUpdaterSerializerTypeArguments)) {
with(decoder.beginStructure(descriptor)) {
if (decodeSequentially()) {
var index = 0
repeat(decodeCollectionSize(descriptor)) {
@ -70,7 +75,7 @@ internal abstract class SettingImpl {
var serialName: String? = null
innerLoop@ while (true) {
val index = decodeElementIndex(descriptor)
if (index == CompositeDecoder.READ_DONE) {
if (index == CompositeDecoder.DECODE_DONE) {
check(serialName == null) { "name must be null at this moment." }
break@outerLoop
}
@ -102,7 +107,7 @@ internal abstract class SettingImpl {
@Suppress("UNCHECKED_CAST")
override fun serialize(encoder: Encoder, value: Unit) {
val descriptor = descriptor
with(encoder.beginCollection(descriptor, valueNodes.size, *settingUpdaterSerializerTypeArguments)) {
with(encoder.beginCollection(descriptor, valueNodes.size)) {
var index = 0
// val vSerializer = settingUpdaterSerializerTypeArguments[1] as KSerializer<Any?>

View File

@ -9,11 +9,11 @@
package net.mamoe.mirai.console.setting.internal
import kotlinx.serialization.Decoder
import kotlinx.serialization.Encoder
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialDescriptor
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import net.mamoe.mirai.console.setting.*
/**
@ -98,6 +98,7 @@ internal abstract class ShortValueImpl : ShortValue, SerializerAwareValue<Short>
else value.hashCode() * 31
}
}
internal abstract class IntValueImpl : IntValue, SerializerAwareValue<Int>, KSerializer<Unit>, AbstractValueImpl<Int> {
constructor()
constructor(default: Int) {

View File

@ -11,7 +11,7 @@
package net.mamoe.mirai.console.setting.internal
import kotlinx.serialization.ImplicitReflectionSerializer
import kotlinx.serialization.UnsafeSerializationApi
import kotlinx.serialization.serializer
import net.mamoe.yamlkt.Yaml
import kotlin.reflect.KClass
@ -452,7 +452,7 @@ internal inline fun <T> MutableSet<T>.observable(crossinline onChanged: () -> Un
}
@OptIn(ImplicitReflectionSerializer::class)
@OptIn(UnsafeSerializationApi::class)
internal fun <R : Any> Any.smartCastPrimitive(clazz: KClass<R>): R {
kotlin.runCatching {
return Yaml.default.parse(clazz.serializer(), this.toString())

View File

@ -0,0 +1,138 @@
/*
* 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.console.setting.internal
import kotlinx.serialization.KSerializer
import kotlinx.serialization.UnsafeSerializationApi
import kotlinx.serialization.builtins.*
import kotlinx.serialization.serializer
import net.mamoe.yamlkt.YamlDynamicSerializer
import net.mamoe.yamlkt.YamlNullableDynamicSerializer
import java.lang.reflect.Modifier
import kotlin.reflect.KClass
import kotlin.reflect.KType
/**
* Copied from kotlinx.serialization, modifications are marked with "/* mamoe modify */"
* Copyright 2017-2020 JetBrains s.r.o.
*/
@OptIn(UnsafeSerializationApi::class)
@Suppress(
"UNCHECKED_CAST",
"NO_REFLECTION_IN_CLASS_PATH",
"UNSUPPORTED",
"INVISIBLE_MEMBER",
"INVISIBLE_REFERENCE",
"IMPLICIT_CAST_TO_ANY"
)
internal fun serializerMirai(type: KType): KSerializer<Any?> {
fun serializerByKTypeImpl(type: KType): KSerializer<Any> {
val rootClass = type.kclass()
val typeArguments = type.arguments
.map { requireNotNull(it.type) { "Star projections in type arguments are not allowed, but had $type" } }
return when {
typeArguments.isEmpty() -> rootClass.serializer()
else -> {
val serializers = typeArguments
.map(::serializer)
// Array is not supported, see KT-32839
when (rootClass) {
List::class, MutableList::class, ArrayList::class -> ListSerializer(serializers[0])
HashSet::class -> SetSerializer(serializers[0])
Set::class, MutableSet::class, LinkedHashSet::class -> SetSerializer(serializers[0])
HashMap::class -> MapSerializer(serializers[0], serializers[1])
Map::class, MutableMap::class, LinkedHashMap::class -> MapSerializer(serializers[0], serializers[1])
Map.Entry::class -> MapEntrySerializer(serializers[0], serializers[1])
Pair::class -> PairSerializer(serializers[0], serializers[1])
Triple::class -> TripleSerializer(serializers[0], serializers[1], serializers[2])
/* mamoe modify */ Any::class -> if (type.isMarkedNullable) YamlNullableDynamicSerializer else YamlDynamicSerializer
else -> {
if (isReferenceArray(rootClass)) {
return ArraySerializer(
typeArguments[0].classifier as KClass<Any>,
serializers[0]
).cast()
}
requireNotNull(rootClass.constructSerializerForGivenTypeArgs(*serializers.toTypedArray())) {
"Can't find a method to construct serializer for type ${rootClass.simpleName}. " +
"Make sure this class is marked as @Serializable or provide serializer explicitly."
}
}
}
}
}.cast()
}
val result = serializerByKTypeImpl(type)
return if (type.isMarkedNullable) result.nullable else result.cast()
}
/**
* Copied from kotlinx.serialization, modifications are marked with "/* mamoe modify */"
* Copyright 2017-2020 JetBrains s.r.o.
*/
@OptIn(UnsafeSerializationApi::class)
@Suppress(
"UNCHECKED_CAST",
"NO_REFLECTION_IN_CLASS_PATH",
"UNSUPPORTED",
"INVISIBLE_MEMBER",
"INVISIBLE_REFERENCE",
"IMPLICIT_CAST_TO_ANY"
)
private fun <T : Any> KClass<T>.constructSerializerForGivenTypeArgs(vararg args: KSerializer<Any?>): KSerializer<T>? {
val jClass = this.java
// Search for serializer defined on companion object.
val companion =
jClass.declaredFields.singleOrNull { it.name == "Companion" }?.apply { isAccessible = true }?.get(null)
if (companion != null) {
val serializer = companion.javaClass.methods
.find { method ->
method.name == "serializer" && method.parameterTypes.size == args.size && method.parameterTypes.all { it == KSerializer::class.java }
}
?.invoke(companion, *args) as? KSerializer<T>
if (serializer != null) return serializer
}
// Check whether it's serializable object
findObjectSerializer(jClass)?.let { return it }
// Search for default serializer if no serializer is defined in companion object.
return try {
jClass.declaredClasses.singleOrNull { it.simpleName == ("\$serializer") }
?.getField("INSTANCE")?.get(null) as? KSerializer<T>
} catch (e: NoSuchFieldException) {
null
}
}
private fun <T : Any> findObjectSerializer(jClass: Class<T>): KSerializer<T>? {
// Check it is an object without using kotlin-reflect
val field =
jClass.declaredFields.singleOrNull { it.name == "INSTANCE" && it.type == jClass && Modifier.isStatic(it.modifiers) }
?: return null
// Retrieve its instance and call serializer()
val instance = field.get(null)
val method =
jClass.methods.singleOrNull { it.name == "serializer" && it.parameters.isEmpty() && it.returnType == KSerializer::class.java }
?: return null
val result = method.invoke(instance)
@Suppress("UNCHECKED_CAST")
return result as? KSerializer<T>
}
private fun isReferenceArray(rootClass: KClass<Any>): Boolean = rootClass.java.isArray
@Suppress("UNCHECKED_CAST")
private fun KType.kclass() = when (val t = classifier) {
is KClass<*> -> t
else -> error("Only KClass supported as classifier, got $t")
} as KClass<Any>

View File

@ -9,7 +9,11 @@
package net.mamoe.mirai.console.setting.internal
import kotlinx.serialization.*
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlin.reflect.KProperty
import kotlin.reflect.full.findAnnotation

View File

@ -9,9 +9,7 @@
package net.mamoe.mirai.console.setting
import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import net.mamoe.mirai.console.utils.ConsoleInternalAPI
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
@ -34,20 +32,19 @@ internal class SettingTest {
}
}
@OptIn(UnstableDefault::class)
private val jsonPrettyPrint = Json(JsonConfiguration(prettyPrint = true))
private val json = Json(JsonConfiguration.Stable)
private val jsonPrettyPrint = Json { prettyPrint = true }
private val json = Json {}
@Test
fun testStringify() {
val setting = MySetting()
var string = json.stringify(setting.updaterSerializer, Unit)
var string = json.encodeToString(setting.updaterSerializer, Unit)
assertEquals("""{"int":1,"map":{},"map2":{}}""", string)
setting.int = 2
string = json.stringify(setting.updaterSerializer, Unit)
string = json.encodeToString(setting.updaterSerializer, Unit)
assertEquals("""{"int":2,"map":{},"map2":{}}""", string)
}
@ -57,10 +54,10 @@ internal class SettingTest {
assertEquals(1, setting.int)
json.parse(
json.decodeFromString(
setting.updaterSerializer, """
{"int":3,"map":{},"map2":{}}
""".trimIndent()
{"int":3,"map":{},"map2":{}}
""".trimIndent()
)
assertEquals(3, setting.int)
@ -77,10 +74,10 @@ internal class SettingTest {
assertEquals(mutableMapOf(), delegation()) // delegation
json.parse(
json.decodeFromString(
setting.updaterSerializer, """
{"int":1,"map":{"t":"test"},"map2":{}}
""".trimIndent()
{"int":1,"map":{"t":"test"},"map2":{}}
""".trimIndent()
)
assertEquals(mapOf("t" to "test").toString(), delegation().toString())
@ -100,10 +97,10 @@ internal class SettingTest {
assertEquals(mutableMapOf(), delegation()) // delegation
json.parse(
json.decodeFromString(
setting.updaterSerializer, """
{"int":1,"map":{},"map2":{"t":{"f":"test"}}}
""".trimIndent()
{"int":1,"map":{},"map2":{"t":{"f":"test"}}}
""".trimIndent()
)
assertEquals(mapOf("t" to mapOf("f" to "test")).toString(), delegation().toString())
@ -125,10 +122,10 @@ internal class SettingTest {
assertEquals(mutableMapOf(), delegation()) // delegation
json.parse(
json.decodeFromString(
setting.updaterSerializer, """
{"int":1,"map":{},"map2":{"t":{"f":"test"}}}
""".trimIndent()
{"int":1,"map":{},"map2":{"t":{"f":"test"}}}
""".trimIndent()
)
assertEquals(mapOf("f" to "test").toString(), delegation().toString())

View File

@ -2,6 +2,7 @@
plugins {
id("com.jfrog.bintray") version Versions.bintray apply false
}
tasks.withType(JavaCompile::class.java) {
options.encoding = "UTF8"
}

View File

@ -1,211 +0,0 @@
/*
* 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.console
import kotlinx.coroutines.CoroutineScope
import kotlinx.io.charsets.Charset
import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.command.CommandManager
import net.mamoe.mirai.console.command.DefaultCommands
import net.mamoe.mirai.console.plugins.PluginManager
import net.mamoe.mirai.console.utils.MiraiConsoleUI
import net.mamoe.mirai.utils.SimpleLogger.LogPriority
import net.mamoe.mirai.utils.WeakRef
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import kotlin.coroutines.EmptyCoroutineContext
object MiraiConsole : CoroutineScope by CoroutineScope(EmptyCoroutineContext) {
/**
* 发布的版本名
*/
const val build = "Pkmon"
lateinit var version: String
internal set
/**
* 获取从Console登陆上的Bot, Bots
* */
@Suppress("DEPRECATION")
@Deprecated(
"use Bot.botInstances from mirai-core",
replaceWith = ReplaceWith("Bot.instances", "net.mamoe.mirai.Bot"),
level = DeprecationLevel.ERROR
)
val bots: List<WeakRef<Bot>>
@Suppress("DEPRECATION_ERROR")
get() = Bot.instances
fun getBotOrNull(uin: Long): Bot? {
return Bot.botInstances.firstOrNull { it.id == uin }
}
class BotNotFoundException(uin: Long) : Exception("Bot $uin Not Found")
fun getBotOrThrow(uin: Long): Bot {
return Bot.botInstances.firstOrNull { it.id == uin } ?: throw BotNotFoundException(uin)
}
/**
* 与前端交互所使用的Logger
*/
internal var logger = MiraiConsoleLogger
/**
* Console运行路径
*/
lateinit var path: String
internal set
/**
* Console前端接口
*/
lateinit var frontEnd: MiraiConsoleUI
internal set
private var started = false
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@Suppress("FunctionName")
@JvmSynthetic
@JvmStatic
fun /* synthetic */`start$default`(
miraiConsole: MiraiConsole,
miraiConsoleUI: MiraiConsoleUI?,
string: String?,
string2: String?,
n: Int,
@Suppress("UNUSED_PARAMETER") `object`: Any?
) {
@Suppress("NAME_SHADOWING")
var string = string
@Suppress("NAME_SHADOWING")
var string2 = string2
if (n and 2 != 0) {
string = "0.0.0"
}
if (n and 4 != 0) {
string2 = "0.0.0"
}
miraiConsole.start(miraiConsoleUI!!, string!!, string2!!)
}
/**
* 启动Console
*/
@JvmOverloads
fun start(
frontEnd: MiraiConsoleUI,
coreVersion: String = "0.0.0",
consoleVersion: String = "0.0.0",
path: String = System.getProperty("user.dir")
) {
if (started) {
return
}
started = true
this.path = path
/* 初始化前端 */
this.version = consoleVersion
this.frontEnd = frontEnd
this.frontEnd.pushVersion(consoleVersion, build, coreVersion)
logger("Mirai-console now running under $path")
logger("Get news in github: https://github.com/mamoe/mirai")
logger("Mirai为开源项目请自觉遵守开源项目协议")
logger("Powered by Mamoe Technologies and contributors")
/* 依次启用功能 */
DefaultCommands()
PluginManager.loadPlugins()
CommandManager.start()
/* 通知启动完成 */
logger("Mirai-console 启动完成")
logger("\"login qqnumber qqpassword \" to login a bot")
logger("\"login qq号 qq密码 \" 来登录一个BOT")
/* 尝试从系统配置自动登录 */
DefaultCommands.tryLoginAuto()
}
/**
* 关闭 Console
*/
fun stop() {
PluginManager.disablePlugins()
CommandManager.cancel()
try {
Bot.botInstances.forEach {
it.close()
}
} catch (ignored: Exception) {
}
}
}
internal object MiraiConsoleLogger {
operator fun invoke(any: Any?) {
invoke(
"[Mirai ${MiraiConsole.version} ${MiraiConsole.build}]",
0L,
any
)
}
operator fun invoke(e: Throwable?) {
invoke(
"[Mirai ${MiraiConsole.version} ${MiraiConsole.build}]",
0L,
e
)
}
operator fun invoke(priority: LogPriority, identityStr: String, identity: Long, any: Any? = null) {
if (any != null) {
MiraiConsole.frontEnd.pushLog(priority, identityStr, identity, "$any")
}
}
operator fun invoke(priority: LogPriority, identityStr: String, identity: Long, e: Throwable? = null) {
if (e != null) {
MiraiConsole.frontEnd.pushLog(priority, identityStr, identity, e.stacktraceString)
}
}
// 设置默认的pushLog输出为 INFO 类型
operator fun invoke(identityStr: String, identity: Long, any: Any? = null) {
if (any != null) {
MiraiConsole.frontEnd.pushLog(LogPriority.INFO, identityStr, identity, "$any")
}
}
operator fun invoke(identityStr: String, identity: Long, e: Throwable? = null) {
if (e != null) {
MiraiConsole.frontEnd.pushLog(LogPriority.INFO, identityStr, identity, e.stacktraceString)
}
}
}
internal val Throwable.stacktraceString: String
get() =
ByteArrayOutputStream().apply {
printStackTrace(PrintStream(this))
}.use { it.toByteArray().encodeToString() }
@Suppress("NOTHING_TO_INLINE")
internal inline fun ByteArray.encodeToString(charset: Charset = Charsets.UTF_8): String =
kotlinx.io.core.String(this, charset = charset)

View File

@ -1,132 +0,0 @@
/*
* 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
*/
@file:Suppress("NOTHING_TO_INLINE", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "unused", "MemberVisibilityCanBePrivate")
package net.mamoe.mirai.console.command
import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.command.AbstractCommandParserContext.Node
import net.mamoe.mirai.contact.Friend
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member
import kotlin.internal.LowPriorityInOverloadResolution
import kotlin.reflect.KClass
/**
* [KClass] [CommandArgParser] 的匹配
*/
interface CommandParserContext {
operator fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>?
/**
* 内建的默认 [CommandArgParser]
*/
object Builtins : CommandParserContext by (CommandParserContext {
Int::class with IntArgParser
Byte::class with ByteArgParser
Short::class with ShortArgParser
Boolean::class with BooleanArgParser
String::class with StringArgParser
Long::class with LongArgParser
Double::class with DoubleArgParser
Float::class with FloatArgParser
Member::class with ExistMemberArgParser
Group::class with ExistGroupArgParser
Friend::class with ExistFriendArgParser
Bot::class with ExistBotArgParser
})
}
fun <T : Any> CommandParserContext.parserFor(param: CommandParam<T>): CommandArgParser<T>? = this[param.type]
/**
* 合并两个 [CommandParserContext], [replacer] 将会替换 [this] 中重复的 parser.
*/
operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandParserContext {
return object : CommandParserContext {
override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? = replacer[klass] ?: this@plus[klass]
}
}
@Suppress("UNCHECKED_CAST")
open class AbstractCommandParserContext(val list: List<Node<*>>) : CommandParserContext {
class Node<T : Any>(
val klass: KClass<T>,
val parser: CommandArgParser<T>
)
override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? =
this.list.firstOrNull { it.klass == klass }?.parser as CommandArgParser<T>?
}
/**
* 构建一个 [CommandParserContext].
*
* ```
* CommandParserContext {
* Int::class with IntArgParser
* Member::class with ExistMemberArgParser
* Group::class with { s: String, sender: CommandSender ->
* Bot.getInstance(s.toLong()).getGroup(s.toLong())
* }
* Bot::class with { s: String ->
* Bot.getInstance(s.toLong())
* }
* }
* ```
*/
@Suppress("FunctionName")
@JvmSynthetic
inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit): CommandParserContext {
return AbstractCommandParserContext(
CommandParserContextBuilder().apply(block).distinctByReversed { it.klass })
}
/**
* @see CommandParserContext
*/
class CommandParserContextBuilder : MutableList<Node<*>> by mutableListOf() {
@JvmName("add")
inline infix fun <T : Any> KClass<T>.with(parser: CommandArgParser<T>): Node<*> =
Node(this, parser)
/**
* 添加一个指令解析器
*/
@JvmSynthetic
@LowPriorityInOverloadResolution
inline infix fun <T : Any> KClass<T>.with(
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
): Node<*> = Node(this, CommandArgParser(parser))
/**
* 添加一个指令解析器
*/
@JvmSynthetic
inline infix fun <T : Any> KClass<T>.with(
crossinline parser: CommandArgParser<T>.(s: String) -> T
): Node<*> = Node(this, CommandArgParser { s: String, _: CommandSender -> parser(s) })
}
@PublishedApi
internal inline fun <T, K> Iterable<T>.distinctByReversed(selector: (T) -> K): List<T> {
val set = HashSet<K>()
val list = ArrayList<T>()
for (i in list.indices.reversed()) {
val element = list[i]
if (set.add(element.let(selector))) {
list.add(element)
}
}
return list
}

View File

@ -1,21 +1,11 @@
pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
jcenter()
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
mavenCentral()
}
resolutionStrategy {
eachPlugin {
val version = requested.version
when (requested.id.id) {
"org.jetbrains.kotlin.jvm" -> useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${version}")
"org.jetbrains.kotlin.plugin.serialization" -> useModule("org.jetbrains.kotlin:kotlin-serialization:${version}")
"com.jfrog.bintray" -> useModule("com.jfrog.bintray.gradle:gradle-bintray-plugin:$version")
}
}
}
}
rootProject.name = "mirai-console"