mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-04 12:57:00 +08:00
222 lines
7.9 KiB
Kotlin
222 lines
7.9 KiB
Kotlin
/*
|
|
* Copyright 2019-2021 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("WRONG_MODIFIER_CONTAINING_DECLARATION", "unused")
|
|
@file:OptIn(ConsoleInternalApi::class)
|
|
|
|
package net.mamoe.mirai.console
|
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Job
|
|
import net.mamoe.mirai.Bot
|
|
import net.mamoe.mirai.BotFactory
|
|
import net.mamoe.mirai.console.MiraiConsole.INSTANCE
|
|
import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
|
|
import net.mamoe.mirai.console.extensions.BotConfigurationAlterer
|
|
import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
|
|
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
|
|
import net.mamoe.mirai.console.plugin.PluginManager
|
|
import net.mamoe.mirai.console.plugin.center.PluginCenter
|
|
import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader
|
|
import net.mamoe.mirai.console.plugin.loader.PluginLoader
|
|
import net.mamoe.mirai.console.util.AnsiMessageBuilder
|
|
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
|
|
import net.mamoe.mirai.console.util.ConsoleInternalApi
|
|
import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScopeContext
|
|
import net.mamoe.mirai.console.util.SemVersion
|
|
import net.mamoe.mirai.utils.BotConfiguration
|
|
import net.mamoe.mirai.utils.MiraiLogger
|
|
import net.mamoe.mirai.utils.verbose
|
|
import java.io.File
|
|
import java.nio.file.Path
|
|
import java.time.Instant
|
|
|
|
|
|
/**
|
|
* mirai-console 实例
|
|
*
|
|
* @see INSTANCE
|
|
* @see MiraiConsoleImplementation
|
|
*/
|
|
public interface MiraiConsole : CoroutineScope {
|
|
/**
|
|
* Console 运行根目录, 由前端决定确切路径.
|
|
*
|
|
* 所有子模块都会在这个目录之下创建子目录.
|
|
*
|
|
* @see PluginManager.pluginsPath
|
|
* @see PluginManager.pluginsDataPath
|
|
* @see PluginManager.pluginsConfigPath
|
|
*/
|
|
public val rootPath: Path
|
|
|
|
/**
|
|
* Console 主日志.
|
|
*
|
|
* **实现细节**: 这个 [MiraiLogger] 的 [MiraiLogger.identity] 通常为 `main`
|
|
*
|
|
* **注意**: 插件不应该在任何时刻使用它.
|
|
*/
|
|
@ConsoleInternalApi
|
|
public val mainLogger: MiraiLogger
|
|
|
|
/**
|
|
* 内建加载器列表, 一般需要包含 [JvmPluginLoader].
|
|
*
|
|
* @return 不可变 [List] ([java.util.Collections.unmodifiableList])
|
|
*/
|
|
public val builtInPluginLoaders: List<Lazy<PluginLoader<*, *>>>
|
|
|
|
/**
|
|
* 此 Console 后端构建时间
|
|
*/
|
|
public val buildDate: Instant
|
|
|
|
/**
|
|
* 此 Console 后端版本号
|
|
*/
|
|
public val version: SemVersion
|
|
|
|
|
|
@ConsoleExperimentalApi
|
|
public val pluginCenter: PluginCenter
|
|
|
|
/**
|
|
* 创建一个 logger
|
|
*/
|
|
@ConsoleExperimentalApi
|
|
public fun createLogger(identity: String?): MiraiLogger
|
|
|
|
/**
|
|
* 是否支持使用 Ansi 输出彩色信息
|
|
*
|
|
* 注: 不是每个前端都可能提供 `org.fusesource.jansi:jansi` 库支持,
|
|
* 请不要直接使用 `org.fusesource.jansi:jansi`
|
|
*
|
|
* @see [AnsiMessageBuilder]
|
|
*/
|
|
@ConsoleExperimentalApi
|
|
public val isAnsiSupported: Boolean
|
|
|
|
public companion object INSTANCE : MiraiConsole by MiraiConsoleImplementationBridge {
|
|
/**
|
|
* 获取 [MiraiConsole] 的 [Job]
|
|
*/ // MiraiConsole.INSTANCE.getJob()
|
|
public val job: Job
|
|
get() = MiraiConsole.coroutineContext[Job]
|
|
?: throw MalformedMiraiConsoleImplementationError("Internal error: Job not found in MiraiConsole.coroutineContext")
|
|
|
|
/**
|
|
* 添加一个 [Bot] 实例到全局 Bot 列表, 但不登录.
|
|
*
|
|
* 调用 [Bot.login] 可登录.
|
|
*
|
|
* @see Bot.botInstances 获取现有 [Bot] 实例列表
|
|
* @see BotConfigurationAlterer ExtensionPoint
|
|
*/
|
|
// don't static
|
|
@ConsoleExperimentalApi("This is a low-level API and might be removed in the future.")
|
|
public fun addBot(id: Long, password: String, configuration: BotConfiguration.() -> Unit = {}): Bot =
|
|
addBotImpl(id, password, configuration)
|
|
|
|
/**
|
|
* 添加一个 [Bot] 实例到全局 Bot 列表, 但不登录.
|
|
*
|
|
* 调用 [Bot.login] 可登录.
|
|
*
|
|
* @see Bot.instances 获取现有 [Bot] 实例列表
|
|
* @see BotConfigurationAlterer ExtensionPoint
|
|
*/
|
|
@ConsoleExperimentalApi("This is a low-level API and might be removed in the future.")
|
|
public fun addBot(id: Long, password: ByteArray, configuration: BotConfiguration.() -> Unit = {}): Bot =
|
|
addBotImpl(id, password, configuration)
|
|
|
|
@Suppress("UNREACHABLE_CODE")
|
|
private fun addBotImpl(id: Long, password: Any, configuration: BotConfiguration.() -> Unit = {}): Bot {
|
|
var config = BotConfiguration().apply {
|
|
|
|
workingDir = MiraiConsole.rootDir
|
|
.resolve("bots")
|
|
.resolve(id.toString())
|
|
.also { it.mkdirs() }
|
|
|
|
mainLogger.verbose { "Bot $id working in $workingDir" }
|
|
|
|
val deviceInRoot = MiraiConsole.rootDir.resolve("device.json")
|
|
val deviceInWorkingDir = workingDir.resolve("device.json")
|
|
|
|
val deviceInfoInWorkingDir = workingDir.resolve("deviceInfo.json")
|
|
if (!deviceInWorkingDir.exists()) {
|
|
when {
|
|
deviceInfoInWorkingDir.exists() -> {
|
|
// rename bots/id/deviceInfo.json to bots/id/device.json
|
|
mainLogger.verbose { "Renaming $deviceInfoInWorkingDir to $deviceInWorkingDir" }
|
|
deviceInfoInWorkingDir.renameTo(deviceInWorkingDir)
|
|
}
|
|
deviceInRoot.exists() -> {
|
|
// copy root/device.json to bots/id/device.json
|
|
mainLogger.verbose { "Coping $deviceInRoot to $deviceInWorkingDir" }
|
|
deviceInRoot.copyTo(deviceInWorkingDir)
|
|
}
|
|
}
|
|
}
|
|
|
|
fileBasedDeviceInfo("device.json")
|
|
|
|
redirectNetworkLogToDirectory()
|
|
this.botLoggerSupplier = {
|
|
MiraiLogger.create("Bot.${it.id}")
|
|
}
|
|
parentCoroutineContext = MiraiConsole.childScopeContext("Bot $id")
|
|
autoReconnectOnForceOffline()
|
|
|
|
this.loginSolver = MiraiConsoleImplementationBridge.createLoginSolver(id, this)
|
|
configuration()
|
|
}
|
|
|
|
config = GlobalComponentStorage.run {
|
|
BotConfigurationAlterer.foldExtensions(config) { acc, extension ->
|
|
extension.alterConfiguration(id, acc)
|
|
|
|
}
|
|
}
|
|
|
|
return when (password) {
|
|
is ByteArray -> BotFactory.newBot(id, password, config)
|
|
is String -> BotFactory.newBot(id, password, config)
|
|
else -> throw IllegalArgumentException("Bad password type: `${password.javaClass.name}`. Require ByteArray or String")
|
|
}
|
|
}
|
|
|
|
@ConsoleExperimentalApi("This is a low-level API and might be removed in the future.")
|
|
public val isActive: Boolean
|
|
get() = job.isActive
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* @see MiraiConsole.rootPath
|
|
*/
|
|
public val MiraiConsole.rootDir: File get() = rootPath.toFile()
|
|
|
|
/**
|
|
* [MiraiConsoleImplementation] 实现有误时抛出.
|
|
*
|
|
* @see MiraiConsoleImplementation.start
|
|
*/
|
|
public class MalformedMiraiConsoleImplementationError : Error {
|
|
public constructor() : super()
|
|
public constructor(message: String?) : super(message)
|
|
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
|
public constructor(cause: Throwable?) : super(cause)
|
|
}
|
|
|