Review: misc improvements

This commit is contained in:
Him188 2020-03-21 16:07:48 +08:00
parent 02173d96df
commit 20e699fb31
9 changed files with 104 additions and 126 deletions

View File

@ -11,7 +11,7 @@ const val CONSOLE_TERMINAL = "Terminal"
const val CONSOLE_GRAPHICAL = "Graphical" const val CONSOLE_GRAPHICAL = "Graphical"
object ConsoleUpdater { internal object ConsoleUpdater {
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
private object Links : HashMap<String, Map<String, String>>() { private object Links : HashMap<String, Map<String, String>>() {

View File

@ -20,7 +20,7 @@ import java.net.URLClassLoader
import kotlin.math.pow import kotlin.math.pow
import kotlin.system.exitProcess import kotlin.system.exitProcess
object CoreUpdator { internal object CoreUpdater {
fun getProtocolLib(): File? { fun getProtocolLib(): File? {
contentPath.listFiles()?.forEach { file -> contentPath.listFiles()?.forEach { file ->

View File

@ -1,9 +1,9 @@
@file:Suppress("EXPERIMENTAL_API_USAGE") @file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.console.wrapper package net.mamoe.mirai.console.wrapper
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO import io.ktor.client.engine.cio.CIO
import io.ktor.client.features.ClientRequestException
import io.ktor.client.request.get import io.ktor.client.request.get
import io.ktor.client.statement.HttpResponse import io.ktor.client.statement.HttpResponse
import io.ktor.utils.io.ByteReadChannel import io.ktor.utils.io.ByteReadChannel
@ -11,14 +11,11 @@ import io.ktor.utils.io.jvm.javaio.copyTo
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
import kotlin.system.exitProcess import kotlin.system.exitProcess
val Http: HttpClient internal val Http: HttpClient = HttpClient(CIO)
get() = HttpClient(CIO)
internal inline fun <R> tryNTimesOrQuit(repeat: Int, errorHint: String, block: (Int) -> R) {
inline fun <R> tryNTimesOrQuit(repeat: Int, errorHint: String, block: (Int) -> R){
var lastException: Throwable? = null var lastException: Throwable? = null
repeat(repeat) { repeat(repeat) {
@ -38,82 +35,84 @@ inline fun <R> tryNTimesOrQuit(repeat: Int, errorHint: String, block: (Int) -> R
} }
suspend inline fun HttpClient.downloadRequest(url: String): ByteReadChannel { internal suspend inline fun HttpClient.downloadRequest(url: String): ByteReadChannel {
return with(this.get<HttpResponse>(url)){ return with(this.get<HttpResponse>(url)) {
if(this.status.value == 404 || this.status.value == 403){ if (this.status.value == 404 || this.status.value == 403) {
error("File not found") error("File not found")
} }
if(this.headers["status"] !=null && this.headers["status"] == "404"){ if (this.headers["status"] != null && this.headers["status"] == "404") {
error("File not found") error("File not found")
} }
this.content this.content
} }
} }
private val jcenterPath = "https://jcenter.bintray.com/{group}/{project}/{version}/:{project}-{version}.{extension}" private val jcenterPath = "https://jcenter.bintray.com/{group}/{project}/{version}/:{project}-{version}.{extension}"
private val aliyunPath = "https://maven.aliyun.com/nexus/content/repositories/jcenter/{group}/{project}/{version}/{project}-{version}.{extension}" private val aliyunPath =
"https://maven.aliyun.com/nexus/content/repositories/jcenter/{group}/{project}/{version}/{project}-{version}.{extension}"
private fun String.buildPath( private fun String.buildPath(
groupName: String, groupName: String,
projectName: String, projectName: String,
version: String, version: String,
extension: String extension: String
):String{ ): String {
return this return this
.replace( .replace(
"{group}",groupName "{group}", groupName
) )
.replace( .replace(
"{project}",projectName "{project}", projectName
) )
.replace( .replace(
"{extension}",extension "{extension}", extension
) )
.replace( .replace(
"{version}",version "{version}", version
) )
} }
suspend fun HttpClient.downloadMaven( internal suspend fun HttpClient.downloadMaven(
groupName: String, groupName: String,
projectName: String, projectName: String,
version: String, version: String,
extension: String extension: String
):ByteReadChannel{ ): ByteReadChannel {
return kotlin.runCatching { return kotlin.runCatching {
downloadRequest( downloadRequest(
aliyunPath.buildPath(groupName,projectName,version,extension) aliyunPath.buildPath(groupName, projectName, version, extension)
) )
}.getOrElse { }.getOrElse {
downloadRequest( downloadRequest(
jcenterPath.buildPath(groupName,projectName,version,extension) jcenterPath.buildPath(groupName, projectName, version, extension)
) )
} }
} }
suspend inline fun HttpClient.downloadMavenArchive( internal suspend inline fun HttpClient.downloadMavenArchive(
groupName: String, groupName: String,
projectName: String, projectName: String,
version: String version: String
):ByteReadChannel{ ): ByteReadChannel {
return downloadMaven(groupName,projectName,version,"jar") return downloadMaven(groupName, projectName, version, "jar")
} }
suspend inline fun HttpClient.downloadMavenPom( internal suspend inline fun HttpClient.downloadMavenPom(
groupName: String, groupName: String,
projectName: String, projectName: String,
version: String version: String
):ByteReadChannel{ ): ByteReadChannel {
return downloadMaven(groupName,projectName,version,"pom") return downloadMaven(groupName, projectName, version, "pom")
} }
suspend fun HttpClient.downloadMavenPomAsString( internal suspend fun HttpClient.downloadMavenPomAsString(
groupName: String, groupName: String,
projectName: String, projectName: String,
version: String version: String
):String{ ): String {
return kotlin.runCatching { return kotlin.runCatching {
this.get<String>( this.get<String>(
aliyunPath.buildPath(groupName,projectName,version,"pom") aliyunPath.buildPath(groupName, projectName, version, "pom")
) )
}.getOrElse { }.getOrElse {
this.get( this.get(
@ -123,12 +122,11 @@ suspend fun HttpClient.downloadMavenPomAsString(
} }
/** /**
* 只要填content path后面的就可以 * 只要填 content path 后面的就可以
*/ */
suspend fun ByteReadChannel.saveToContent(filepath:String){ internal suspend fun ByteReadChannel.saveToContent(filepath: String) {
val fileStream = File(contentPath.absolutePath + "/" + filepath).also { val fileStream = File(contentPath.absolutePath + "/" + filepath).also {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
it.createNewFile() it.createNewFile()
} }

View File

@ -9,7 +9,10 @@
@file:Suppress("EXPERIMENTAL_API_USAGE") @file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.console.wrapper package net.mamoe.mirai.console.wrapper
import kotlinx.coroutines.* import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.io.File import java.io.File
import java.net.URLClassLoader import java.net.URLClassLoader
import java.util.* import java.util.*
@ -56,31 +59,31 @@ object WrapperMain {
println("Starting version check...") println("Starting version check...")
runBlocking { runBlocking {
launch { launch {
CoreUpdator.versionCheck() CoreUpdater.versionCheck()
} }
launch { launch {
ConsoleUpdater.versionCheck(type) ConsoleUpdater.versionCheck(type)
} }
} }
println("Version check complete, starting Mirai") println("Version check complete, starting Mirai")
println("Core :" + CoreUpdator.getCore()!!) println("Core :" + CoreUpdater.getCore()!!)
println("Protocol:" + CoreUpdator.getProtocolLib()!!) println("Protocol:" + CoreUpdater.getProtocolLib()!!)
println("Console :" + ConsoleUpdater.getFile()!! ) println("Console :" + ConsoleUpdater.getFile()!!)
println("Root :" + System.getProperty("user.dir") + "/") println("Root :" + System.getProperty("user.dir") + "/")
val loader = MiraiClassLoader( val loader = MiraiClassLoader(
CoreUpdator.getCore()!!, CoreUpdater.getCore()!!,
CoreUpdator.getProtocolLib()!!, CoreUpdater.getProtocolLib()!!,
ConsoleUpdater.getFile()!!, ConsoleUpdater.getFile()!!,
this.javaClass.classLoader this.javaClass.classLoader
) )
when(type) { when (type) {
CONSOLE_PURE -> { CONSOLE_PURE -> {
loader.loadClass("net.mamoe.mirai.BotFactoryJvm") loader.loadClass("net.mamoe.mirai.BotFactoryJvm")
loader.loadClass( loader.loadClass(
"net.mamoe.mirai.console.pure.MiraiConsolePureLoader" "net.mamoe.mirai.console.pure.MiraiConsolePureLoader"
).getMethod("load", String::class.java,String::class.java) ).getMethod("load", String::class.java, String::class.java)
.invoke(null,CoreUpdator.getCurrentVersion(),ConsoleUpdater.getCurrentVersion()) .invoke(null, CoreUpdater.getCurrentVersion(), ConsoleUpdater.getCurrentVersion())
} }
} }
} }

View File

@ -17,6 +17,8 @@ import net.mamoe.mirai.message.data.Message
/** /**
* 指令发送者 * 指令发送者
*
* @see AbstractCommandSender 请继承于该抽象类
*/ */
interface CommandSender { interface CommandSender {
/** /**
@ -35,7 +37,7 @@ interface CommandSender {
fun sendMessageBlocking(message: String) = runBlocking { sendMessage(message) } fun sendMessageBlocking(message: String) = runBlocking { sendMessage(message) }
} }
abstract class CommandSenderImpl : CommandSender { abstract class AbstractCommandSender : CommandSender {
internal val builder = StringBuilder() internal val builder = StringBuilder()
override fun appendMessage(message: String) { override fun appendMessage(message: String) {
@ -52,7 +54,7 @@ abstract class CommandSenderImpl : CommandSender {
/** /**
* 控制台指令执行者. 代表由控制台执行指令 * 控制台指令执行者. 代表由控制台执行指令
*/ */
object ConsoleCommandSender : CommandSenderImpl() { object ConsoleCommandSender : AbstractCommandSender() {
override suspend fun sendMessage(messageChain: Message) { override suspend fun sendMessage(messageChain: Message) {
MiraiConsole.logger("[Command]", 0, messageChain.toString()) MiraiConsole.logger("[Command]", 0, messageChain.toString())
} }
@ -71,7 +73,7 @@ object ConsoleCommandSender : CommandSenderImpl() {
* 联系人指令执行者. 代表由一个 QQ 用户执行指令 * 联系人指令执行者. 代表由一个 QQ 用户执行指令
*/ */
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
open class ContactCommandSender(val contact: Contact) : CommandSenderImpl() { open class ContactCommandSender(val contact: Contact) : AbstractCommandSender() {
override suspend fun sendMessage(messageChain: Message) { override suspend fun sendMessage(messageChain: Message) {
contact.sendMessage(messageChain) contact.sendMessage(messageChain)
} }

View File

@ -23,7 +23,9 @@ import java.net.URLClassLoader
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext
/**
* 所有插件的基类
*/
abstract class PluginBase abstract class PluginBase
@JvmOverloads constructor(coroutineContext: CoroutineContext = EmptyCoroutineContext) : CoroutineScope { @JvmOverloads constructor(coroutineContext: CoroutineContext = EmptyCoroutineContext) : CoroutineScope {
@ -34,7 +36,7 @@ abstract class PluginBase
* 插件被分配的数据目录数据目录会与插件名称同名 * 插件被分配的数据目录数据目录会与插件名称同名
*/ */
val dataFolder: File by lazy { val dataFolder: File by lazy {
File(PluginManager.pluginsPath + "/" + PluginManager.lastPluginName).also { File(PluginManager.pluginsPath + "/" + pluginName).also {
it.mkdir() it.mkdir()
} }
} }
@ -69,31 +71,13 @@ abstract class PluginBase
} }
internal fun enable() {
this.onEnable()
}
/** /**
* 加载一个data folder中的Config * 加载一个 [dataFolder] 中的 [Config]
* 这个config是read-write的
*/ */
fun loadConfig(fileName: String): Config { fun loadConfig(fileName: String): Config {
return Config.load(dataFolder.absolutePath + "/" + fileName) return Config.load(dataFolder.absolutePath + "/" + fileName)
} }
@JvmOverloads
internal fun disable(throwable: CancellationException? = null) {
this.coroutineContext[Job]!!.cancelChildren(throwable)
try {
this.onDisable()
} catch (e: Exception) {
logger.info(e)
}
}
internal var pluginName: String = ""
val logger: MiraiLogger by lazy { val logger: MiraiLogger by lazy {
SimpleLogger("Plugin $pluginName") { priority, message, e -> SimpleLogger("Plugin $pluginName") { priority, message, e ->
val identityString = "[${pluginName}]" val identityString = "[${pluginName}]"
@ -120,16 +104,34 @@ abstract class PluginBase
/** /**
* 加载 resource 中的 [Config] * 加载 resource 中的 [Config]
* 这个 [Config] read-only * 这个 [Config] 只读
*/ */
fun getResourcesConfig(fileName: String): Config { fun getResourcesConfig(fileName: String): Config {
if (!fileName.contains(".")) { require(fileName.contains(".")) { "Unknown Config Type" }
error("Unknown Config Type")
}
return Config.load(getResources(fileName) ?: error("No such file: $fileName"), fileName.substringAfter('.')) return Config.load(getResources(fileName) ?: error("No such file: $fileName"), fileName.substringAfter('.'))
} }
// internal
internal fun enable() {
this.onEnable()
}
internal fun disable(throwable: CancellationException? = null) {
this.coroutineContext[Job]!!.cancelChildren(throwable)
try {
this.onDisable()
} catch (e: Exception) {
logger.info(e)
}
}
internal var pluginName: String = ""
} }
/**
* 插件描述
*/
class PluginDescription( class PluginDescription(
val name: String, val name: String,
val author: String, val author: String,

View File

@ -66,8 +66,7 @@ class MiraiConsoleUIPure : MiraiConsoleUI {
override fun pushLog(priority: LogPriority, identityStr: String, identity: Long, message: String) { override fun pushLog(priority: LogPriority, identityStr: String, identity: Long, message: String) {
var priorityStr = "[${priority.name}]" var priorityStr = "[${priority.name}]"
val _message = message + COLOR_RESET /*
/**
* 通过ANSI控制码添加颜色 * 通过ANSI控制码添加颜色
* 更多的颜色定义在 [MiraiConsoleUIPure] companion * 更多的颜色定义在 [MiraiConsoleUIPure] companion
*/ */
@ -86,7 +85,7 @@ class MiraiConsoleUIPure : MiraiConsoleUI {
else -> priorityStr else -> priorityStr
} }
println("\u001b[0m " + sdf.format(Date()) + " $priorityStr $identityStr $_message") println("\u001b[0m " + sdf.format(Date()) + " $priorityStr $identityStr ${message + COLOR_RESET}")
} }
override fun prePushBot(identity: Long) { override fun prePushBot(identity: Long) {

View File

@ -2,25 +2,25 @@ package net.mamoe.mirai.console.scheduler
import net.mamoe.mirai.console.plugins.PluginBase import net.mamoe.mirai.console.plugins.PluginBase
interface SchedulerTask<T:PluginBase>{ interface SchedulerTask<T : PluginBase> {
abstract fun onTick(i:Long) abstract fun onTick(i: Long)
abstract fun onRun() abstract fun onRun()
} }
abstract class RepeatTask<T:PluginBase>( abstract class RepeatTask<T : PluginBase>(
val intervalInMs: Int val intervalInMs: Int
):SchedulerTask<T>{ ) : SchedulerTask<T> {
override fun onTick(i: Long) { override fun onTick(i: Long) {
if(i%intervalInMs == 0L){ if (i % intervalInMs == 0L) {
onRun() onRun()
} }
} }
companion object{ companion object {
fun <T:PluginBase> of( fun <T : PluginBase> of(
intervalInMs: Int, runnable: () -> Unit intervalInMs: Int, runnable: () -> Unit
):RepeatTask<T>{ ): RepeatTask<T> {
return AnonymousRepeatTask<T>( return AnonymousRepeatTask<T>(
intervalInMs, runnable intervalInMs, runnable
) )
@ -28,42 +28,18 @@ abstract class RepeatTask<T:PluginBase>(
} }
} }
internal class AnonymousRepeatTask<T: PluginBase>( internal class AnonymousRepeatTask<T : PluginBase>(
intervalInMs: Int, private val runnable: () -> Unit intervalInMs: Int, private val runnable: () -> Unit
): RepeatTask<T>(intervalInMs){ ) : RepeatTask<T>(intervalInMs) {
override fun onRun() { override fun onRun() {
runnable.invoke() runnable.invoke()
} }
} }
fun <T:PluginBase> T.repeatTask( fun <T : PluginBase> T.repeatTask(
intervalInMs: Int, runnable: () -> Unit intervalInMs: Int, runnable: () -> Unit
):RepeatTask<T>{ ): RepeatTask<T> {
return AnonymousRepeatTask<T>( return AnonymousRepeatTask<T>(
intervalInMs, runnable intervalInMs, runnable
) )
} }
fun <T> repeatTask(){
}
class X: PluginBase() {
override fun onLoad() {
//kotlin
this.repeatTask(5){
}
//java1
RepeatTask.of<X>(5){
}
//java2
class Xtask:RepeatTask<X>(5){
override fun onRun() {
}
}
}
}

View File

@ -14,15 +14,14 @@ import net.mamoe.mirai.utils.LoginSolver
import net.mamoe.mirai.utils.SimpleLogger.LogPriority import net.mamoe.mirai.utils.SimpleLogger.LogPriority
/** /**
* 只需要实现一个这个 传入MiraiConsole 就可以绑定UI层与Console层 * 只需要实现一个这个传入 MiraiConsole 就可以绑定 UI 层与 Console
* 注意线程 * 需要保证线程安全
*/ */
interface MiraiConsoleUI { interface MiraiConsoleUI {
/** /**
* UI层展示一条log * UI 层展示一条 log
* *
* identitylog所属的screen, Main=0; Bot=Bot.uin * identitylog 所属的 screen, Main=0; Bot=Bot.uin
*/ */
fun pushLog( fun pushLog(
identity: Long, identity: Long,
@ -37,14 +36,14 @@ interface MiraiConsoleUI {
) )
/** /**
* UI层准备接受新增的一个BOT * UI 层准备接受新增的一个BOT
*/ */
fun prePushBot( fun prePushBot(
identity: Long identity: Long
) )
/** /**
* UI层接受一个新的bot * UI 层接受一个新的bot
* */ * */
fun pushBot( fun pushBot(
bot: Bot bot: Bot
@ -58,14 +57,13 @@ interface MiraiConsoleUI {
) )
/** /**
* 让UI层提供一个Input * UI 层提供一个输入, 相当于 [readLine]
* 这个Input 等于 Command
*/ */
suspend fun requestInput(hint:String): String suspend fun requestInput(hint: String): String
/** /**
* UI层更新BOT管理员的数据 * UI 层更新 bot 管理员的数据
*/ */
fun pushBotAdminStatus( fun pushBotAdminStatus(
identity: Long, identity: Long,
@ -73,7 +71,7 @@ interface MiraiConsoleUI {
) )
/** /**
* UI层创建一个LoginSolver * UI 层创建一个 [LoginSolver]
*/ */
fun createLoginSolver(): LoginSolver fun createLoginSolver(): LoginSolver