Merge remote-tracking branch 'origin/master'

# Conflicts:
#	mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/PluginCenter.kt
This commit is contained in:
jiahua.liu 2020-04-02 23:20:04 +08:00
commit c1c114ef07
24 changed files with 612 additions and 208 deletions

48
.github/workflows/cui.yml vendored Normal file
View File

@ -0,0 +1,48 @@
# This is a basic workflow to help you get started with Actions
name: CuiCloud Publish
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
release:
types:
- created
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Gradle clean
run: ./gradlew clean
- name: Gradle build
run: ./gradlew build # if test's failed, don't publish
- name: Gradle :mirai-console:cuiCloudUpload
run: ./gradlew :mirai-console:cuiCloudUpload -Dcui_cloud_key=${{ secrets.CUI_CLOUD_KEY }} -Pcui_cloud_key=${{ secrets.CUI_CLOUD_KEY }} -Dcui_cloud_url=${{ secrets.CUI_CLOUD_URL }} -Pcui_cloud_url=${{ secrets.CUI_CLOUD_URL }}
- name: Gradle :mirai-console-qqandroid:cuiCloudUpload
run: ./gradlew :mirai-console-graphical:cuiCloudUpload -Dcui_cloud_key=${{ secrets.CUI_CLOUD_KEY }} -Pcui_cloud_key=${{ secrets.CUI_CLOUD_KEY }} -Dcui_cloud_url=${{ secrets.CUI_CLOUD_URL }} -Pcui_cloud_url=${{ secrets.CUI_CLOUD_URL }}
# - name: Upload artifact
# uses: actions/upload-artifact@v1.0.0
# with:
# # Artifact name
# name: mirai-core
# # Directory containing files to upload
# path: "mirai-core/build/libs/mirai-core-*-all.jar"
# - name: Upload artifact
# uses: actions/upload-artifact@v1.0.0
# with:
# # Artifact name
# name: mirai-core-qqandroid-all
# # Directory containing files to upload
# path: "mirai-core-qqandroid/build/libs/mirai-core-qqandroid-*-all.jar"

48
.github/workflows/shadow.yml vendored Normal file
View File

@ -0,0 +1,48 @@
# This is a basic workflow to help you get started with Actions
name: mirai-repo Publish
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
on:
release:
types:
- created
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Gradle clean
run: ./gradlew clean
- name: Gradle build
run: ./gradlew build # if test's failed, don't publish
- name: Gradle :mirai-console:githubUpload
run: ./gradlew :mirai-console:githubUpload -Dgithub_token=${{ secrets.MAMOE_TOKEN }} -Pgithub_token=${{ secrets.MAMOE_TOKEN }}
- name: Gradle :mirai-console-qqandroid:githubUpload
run: ./gradlew :mirai-console-graphical:githubUpload -Dgithub_token=${{ secrets.MAMOE_TOKEN }} -Pgithub_token=${{ secrets.MAMOE_TOKEN }}
# - name: Upload artifact
# uses: actions/upload-artifact@v1.0.0
# with:
# # Artifact name
# name: mirai-core
# # Directory containing files to upload
# path: "mirai-core/build/libs/mirai-core-*-all.jar"
# - name: Upload artifact
# uses: actions/upload-artifact@v1.0.0
# with:
# # Artifact name
# name: mirai-core-qqandroid-all
# # Directory containing files to upload
# path: "mirai-core-qqandroid/build/libs/mirai-core-qqandroid-*-all.jar"

View File

@ -1,44 +0,0 @@
buildscript {
repositories {
mavenLocal()
maven { url 'https://mirrors.huaweicloud.com/repository/maven' }
jcenter()
mavenCentral()
google()
maven { url 'https://dl.bintray.com/kotlin/kotlin-eap' }
maven { url 'https://dl.bintray.com/kotlin/kotlin-dev' }
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0'
classpath "org.jetbrains.kotlin:kotlin-serialization:1.4-M1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4-M1"
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' // don't use any other.
}
}
try {
def keyProps = new Properties()
def keyFile = file("local.properties")
if (keyFile.exists()) keyFile.withInputStream { keyProps.load(it) }
if (!keyProps.getProperty("sdk.dir", "").isEmpty()) {
project.ext.set("isAndroidSDKAvailable", true)
} else {
project.ext.set("isAndroidSDKAvailable", false)
}
} catch (Exception ignored) {
}
allprojects {
group = "net.mamoe"
repositories {
mavenLocal()
maven { url "https://mirrors.huaweicloud.com/repository/maven" }
jcenter()
mavenCentral()
google()
maven { url "https://dl.bintray.com/kotlin/kotlin-eap" }
maven { url "https://dl.bintray.com/kotlin/kotlin-dev" }
}
}

103
build.gradle.kts Normal file
View File

@ -0,0 +1,103 @@
@file:Suppress("UnstableApiUsage")
import kotlin.math.pow
buildscript {
repositories {
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
maven(url = "https://mirrors.huaweicloud.com/repository/maven")
jcenter()
mavenCentral()
}
dependencies {
classpath("com.github.jengelman.gradle.plugins:shadow:5.2.0")
classpath("org.jetbrains.kotlin:kotlin-serialization:${Versions.Kotlin.stdlib}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Kotlin.stdlib}")
classpath("com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4") // don"t use any other.
}
}
allprojects {
group = "net.mamoe"
repositories {
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
maven(url = "https://mirrors.huaweicloud.com/repository/maven")
jcenter()
mavenCentral()
}
}
subprojects {
afterEvaluate {
apply(plugin = "com.github.johnrengelman.shadow")
val kotlin =
(this as ExtensionAware).extensions.getByName("kotlin") as? org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
?: return@afterEvaluate
val githubUpload by tasks.creating {
group = "mirai"
dependsOn(tasks.getByName("shadowJar"))
doFirst {
timeout.set(java.time.Duration.ofHours(3))
findLatestFile()?.let { (_, file) ->
val filename = file.name
println("Uploading file $filename")
runCatching {
upload.GitHub.upload(
file,
"https://api.github.com/repos/mamoe/mirai-repo/contents/shadow/${project.name}/$filename",
project
)
}.exceptionOrNull()?.let {
System.err.println("GitHub Upload failed")
it.printStackTrace() // force show stacktrace
throw it
}
}
}
}
val cuiCloudUpload by tasks.creating {
group = "mirai"
dependsOn(tasks.getByName("shadowJar"))
doFirst {
timeout.set(java.time.Duration.ofHours(3))
findLatestFile()?.let { (_, file) ->
val filename = file.name
println("Uploading file $filename")
runCatching {
upload.CuiCloud.upload(
file,
project
)
}.exceptionOrNull()?.let {
System.err.println("CuiCloud Upload failed")
it.printStackTrace() // force show stacktrace
throw it
}
}
}
}
}
}
fun Project.findLatestFile(): Map.Entry<String, File>? {
return File(projectDir, "build/libs").walk()
.filter { it.isFile }
.onEach { println("all files=$it") }
.filter { it.name.matches(Regex("""${project.name}-([0-9]|\.)*-all\.jar""")) }
.onEach { println("matched file: ${it.name}") }
.associateBy { it.nameWithoutExtension.substringAfterLast('-').replace("-all", "") }
.onEach { println("versions: $it") }
.maxBy {
it.key.split('.').foldRightIndexed(0) { index: Int, s: String, acc: Int ->
acc + 100.0.pow(2 - index).toInt() * (s.toIntOrNull() ?: 0)
}
}
}

View File

@ -4,4 +4,24 @@ plugins {
repositories {
jcenter()
}
kotlin {
sourceSets.all {
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
languageSettings.useExperimentalAnnotation("kotlin.RequiresOptIn")
}
}
dependencies {
fun kotlinx(id: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$id:$version"
fun ktor(id: String, version: String) = "io.ktor:ktor-$id:$version"
api("org.jsoup:jsoup:1.12.1")
api("com.google.code.gson:gson:2.8.6")
api(kotlinx("coroutines-core", "1.3.3"))
api(ktor("client-core", "1.3.2"))
api(ktor("client-cio", "1.3.2"))
api(ktor("client-json", "1.3.2"))
}

View File

@ -0,0 +1,134 @@
/*
* 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 upload
import io.ktor.client.request.forms.MultiPartFormDataContent
import io.ktor.client.request.forms.formData
import io.ktor.client.request.post
import io.ktor.client.statement.HttpResponse
import io.ktor.http.isSuccess
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.gradle.api.Project
import org.gradle.kotlin.dsl.provideDelegate
import java.io.File
import java.util.*
@Suppress("DEPRECATION")
object CuiCloud {
private fun getUrl(project: Project): String {
kotlin.runCatching {
@Suppress("UNUSED_VARIABLE", "LocalVariableName")
val cui_cloud_url: String by project
return cui_cloud_url
}
System.getProperty("cui_cloud_url", null)?.let {
return it.trim()
}
File(File(System.getProperty("user.dir")).parent, "/cuiUrl.txt").let { local ->
if (local.exists()) {
return local.readText().trim()
}
}
File(File(System.getProperty("user.dir")), "/cuiUrl.txt").let { local ->
if (local.exists()) {
return local.readText().trim()
}
}
error("cannot find url for CuiCloud")
}
private fun getKey(project: Project): String {
kotlin.runCatching {
@Suppress("UNUSED_VARIABLE", "LocalVariableName")
val cui_cloud_key: String by project
return cui_cloud_key
}
System.getProperty("cui_cloud_key", null)?.let {
return it.trim()
}
File(File(System.getProperty("user.dir")).parent, "/cuiToken.txt").let { local ->
if (local.exists()) {
return local.readText().trim()
}
}
File(File(System.getProperty("user.dir")), "/cuiToken.txt").let { local ->
if (local.exists()) {
return local.readText().trim()
}
}
error("cannot find key for CuiCloud")
}
fun upload(file: File, project: Project) {
val cuiCloudUrl = getUrl(project)
val key = getKey(project)
runBlocking {
uploadToCuiCloud(
cuiCloudUrl,
key,
"/mirai/${project.name}/${file.nameWithoutExtension}.mp4",
file.readBytes()
)
}
}
@UseExperimental(ExperimentalStdlibApi::class)
private suspend fun uploadToCuiCloud(
cuiCloudUrl: String,
cuiToken: String,
filePath: String,
content: ByteArray
) {
println("filePath=$filePath")
println("content=${content.size / 1024 / 1024} MB")
val response = withContext(Dispatchers.IO) {
Http.post<HttpResponse>(cuiCloudUrl) {
body = MultiPartFormDataContent(
formData {
append("base64", Base64.getEncoder().encodeToString(content))
append("filePath", filePath)
append("large", "true")
append("key", cuiToken)
}
)
}
}
println(response.status)
val buffer = ByteArray(4096)
val resp = buildList<Byte> {
while (true) {
val read = response.content.readAvailable(buffer, 0, buffer.size)
if (read == -1) {
break
}
addAll(buffer.toList().take(read))
}
}
println(String(resp.toByteArray()))
if (!response.status.isSuccess()) {
error("Cui cloud response: ${response.status}")
}
}
}
inline fun <E> buildList(builderAction: MutableList<E>.() -> Unit): List<E> {
return ArrayList<E>().apply(builderAction)
}

View File

@ -0,0 +1,178 @@
@file:Suppress("EXPERIMENTAL_API_USAGE")
package upload
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.features.HttpTimeout
import io.ktor.client.request.put
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.gradle.api.Project
import org.gradle.kotlin.dsl.provideDelegate
import org.jsoup.Connection
import org.jsoup.Jsoup
import java.io.File
import java.util.*
internal val Http = HttpClient(CIO) {
engine {
requestTimeout = 600_000
}
install(HttpTimeout) {
socketTimeoutMillis = 600_000
requestTimeoutMillis = 600_000
connectTimeoutMillis = 600_000
}
}
object GitHub {
private fun getGithubToken(project: Project): String {
kotlin.runCatching {
@Suppress("UNUSED_VARIABLE", "LocalVariableName")
val github_token: String by project
return github_token
}
System.getProperty("github_token", null)?.let {
return it.trim()
}
File(File(System.getProperty("user.dir")).parent, "/token.txt").let { local ->
if (local.exists()) {
return local.readText().trim()
}
}
File(File(System.getProperty("user.dir")), "/token.txt").let { local ->
if (local.exists()) {
return local.readText().trim()
}
}
error(
"Cannot find github token, " +
"please specify by creating a file token.txt in project dir, " +
"or by providing JVM parameter 'github_token'"
)
}
fun upload(file: File, url: String, project: Project) = runBlocking {
val token = getGithubToken(project)
println("token.length=${token.length}")
Http.put<String>("$url?access_token=$token") {
val sha = getGithubSha("mirai-repo", "shadow/${project.name}/${file.name}", "master", project)
println("sha=$sha")
val content = String(Base64.getEncoder().encode(file.readBytes()))
body = """
{
"message": "automatically upload on release",
"content": "$content"
${if (sha == null) "" else """, "sha": "$sha" """}
}
""".trimIndent()
}.let {
println("Upload response: $it")
}
}
private suspend fun getGithubSha(
repo: String,
filePath: String,
branch: String,
project: Project
): String? {
fun String.asJson(): JsonObject {
return JsonParser.parseString(this).asJsonObject
}
/*
* 只能获取1M以内/branch为master的sha
* */
class TargetTooLargeException() : Exception("Target TOO Large")
suspend fun getShaSmart(repo: String, filePath: String, project: Project): String? {
return withContext(Dispatchers.IO) {
val response = Jsoup
.connect(
"https://api.github.com/repos/mamoe/$repo/contents/$filePath?access_token=" + getGithubToken(
project
)
)
.ignoreContentType(true)
.ignoreHttpErrors(true)
.method(Connection.Method.GET)
.execute()
if (response.statusCode() == 404) {
null
} else {
val p = response.body().asJson()
if (p.has("message") && p["message"].asString == "This API returns blobs up to 1 MB in size. The requested blob is too large to fetch via the API, but you can use the Git Data API to request blobs up to 100 MB in size.") {
throw TargetTooLargeException()
}
p.get("sha").asString
}
}
}
suspend fun getShaStupid(
repo: String,
filePath: String,
branch: String,
project: Project
): String? {
val resp = withContext(Dispatchers.IO) {
Jsoup
.connect(
"https://api.github.com/repos/mamoe/$repo/git/ref/heads/$branch?access_token=" + getGithubToken(
project
)
)
.ignoreContentType(true)
.ignoreHttpErrors(true)
.method(Connection.Method.GET)
.execute()
}
if (resp.statusCode() == 404) {
println("Branch Not Found")
return null
}
val info = resp.body().asJson().get("object").asJsonObject.get("url").asString
var parentNode = withContext(Dispatchers.IO) {
Jsoup.connect(info + "?access_token=" + getGithubToken(project)).ignoreContentType(true)
.method(Connection.Method.GET)
.execute().body().asJson().get("tree").asJsonObject.get("url").asString
}
filePath.split("/").forEach { subPath ->
withContext(Dispatchers.IO) {
Jsoup.connect(parentNode + "?access_token=" + getGithubToken(project)).ignoreContentType(true)
.method(Connection.Method.GET).execute().body().asJson().get("tree").asJsonArray
}.forEach list@{
with(it.asJsonObject) {
if (this.get("path").asString == subPath) {
parentNode = this.get("url").asString
return@list
}
}
}
}
check(parentNode.contains("/blobs/"))
return parentNode.substringAfterLast("/")
}
return if (branch == "master") {
try {
getShaSmart(repo, filePath, project)
} catch (e: TargetTooLargeException) {
getShaStupid(repo, filePath, branch, project)
}
} else {
getShaStupid(repo, filePath, branch, project)
}
}
}

View File

@ -11,33 +11,18 @@ import org.gradle.kotlin.dsl.DependencyHandlerScope
object Versions {
object Mirai {
const val core = "0.31.0"
const val console = "0.4.1"
const val core = "0.32.0"
const val console = "0.4.2"
const val consoleGraphical = "0.0.5"
const val consoleWrapper = "0.2.0"
}
object Kotlin {
const val stdlib = "1.4-M1"
const val coroutines = "1.3.5-1.4-M1"
const val atomicFU = "0.14.2-1.4-M1"
const val serialization = "0.20.0-1.4-M1"
const val ktor = "1.3.2-1.4-M1"
const val io = "0.1.16"
const val coroutinesIo = "0.1.16"
const val dokka = "0.10.1"
const val stdlib = "1.3.71"
const val coroutines = "1.3.5"
const val serialization = "0.20.0"
const val ktor = "1.3.2"
}
object Android {
const val androidGradlePlugin = "3.5.3"
}
object Publishing {
const val bintray = "1.8.4-jetbrains-3"
}
}
@Suppress("unused")

View File

@ -49,21 +49,6 @@ bintray {
}
}
val kotlinVersion: String by rootProject.ext
val atomicFuVersion: String by rootProject.ext
val coroutinesVersion: String by rootProject.ext
val kotlinXIoVersion: String by rootProject.ext
val coroutinesIoVersion: String by rootProject.ext
val klockVersion: String by rootProject.ext
val ktorVersion: String by rootProject.ext
val serializationVersion: String by rootProject.ext
fun kotlinx(id: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$id:$version"
fun ktor(id: String, version: String) = "io.ktor:ktor-$id:$version"
dependencies {
compileOnly("net.mamoe:mirai-core-jvm:${Versions.Mirai.core}")
implementation(project(":mirai-console"))

View File

@ -85,7 +85,7 @@ class MiraiGraphicalUIController : Controller(), MiraiConsoleUI {
}
override fun pushBot(bot: Bot) = Platform.runLater {
cache[bot.uin]?.bot = bot
cache[bot.id]?.bot = bot
}
override fun pushVersion(consoleVersion: String, consoleBuild: String, coreVersion: String) {

View File

@ -15,7 +15,7 @@ tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>() {
}
}
dependencies {
api("net.mamoe:mirai-core-qqandroid-jvm:${Versions.Mirai.core}")
compileOnly("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
api(project(":mirai-console"))
api(group = "com.googlecode.lanterna", name = "lanterna", version = "3.0.2")
}

View File

@ -97,8 +97,8 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI {
}
override fun pushBot(bot: Bot) {
botAdminCount[bot.uin] = 0
screens.add(bot.uin)
botAdminCount[bot.id] = 0
screens.add(bot.id)
drawFrame(this.getScreenName(currentScreenId))
if (terminal is SwingTerminalFrame) {
terminal.flush()

View File

@ -119,13 +119,4 @@ internal object ConsoleUpdater {
}
}
private suspend fun downloadConsole(version: String) {
/*
tryNTimesOrQuit(3, "Failed to download Console, please seek for help") {
Http.downloadMavenArchive("net/mamoe", getProjectName(), version)
.saveToContent("${getProjectName()}-$version.jar")
}
*/
}
}

View File

@ -79,7 +79,7 @@ private class MiraiDownloaderImpl(
val input= con.inputStream
totalSize.addAndGet(con.contentLength)
val outputStream = FileOutputStream(file)
var len = -1
var len: Int
val buff = ByteArray(1024)
while (input.read(buff).also { len = it } != -1) {
totalDownload.addAndGet(buff.size)

View File

@ -32,7 +32,6 @@ dependencies {
testApi("net.mamoe:mirai-core-qqandroid-jvm:${Versions.Mirai.core}")
testApi(kotlin("stdlib"))
testApi("org.jsoup:jsoup:1.12.1")
}
version = Versions.Mirai.console
@ -103,4 +102,8 @@ compileKotlin.kotlinOptions {
val compileTestKotlin: KotlinCompile by tasks
compileTestKotlin.kotlinOptions {
jvmTarget = "1.8"
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@ -13,7 +13,6 @@ import kotlinx.coroutines.GlobalScope;
import net.mamoe.mirai.event.Event;
import net.mamoe.mirai.event.Listener;
import net.mamoe.mirai.event.ListeningStatus;
import net.mamoe.mirai.event.internal.EventInternalJvmKt;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
@ -35,7 +34,7 @@ public final class Events {
*/
@NotNull
public static <E extends Event> Listener<E> subscribe(@NotNull Class<E> eventClass, @NotNull Function<E, ListeningStatus> onEvent) {
return EventInternalJvmKt._subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent);
return EventsImplKt.subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent);
}
/**
@ -49,7 +48,7 @@ public final class Events {
*/
@NotNull
public static <E extends Event> Listener<E> subscribeAlways(@NotNull Class<E> eventClass, @NotNull Consumer<E> onEvent) {
return EventInternalJvmKt._subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent);
return EventsImplKt.subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent);
}

View File

@ -9,16 +9,13 @@
package net.mamoe.mirai.console
import kotlinx.coroutines.runBlocking
import kotlinx.io.charsets.Charset
import net.mamoe.mirai.Bot
import net.mamoe.mirai.console.command.CommandManager
import net.mamoe.mirai.console.command.CommandSender
import net.mamoe.mirai.console.command.ConsoleCommandSender
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.io.encodeToString
import java.io.ByteArrayOutputStream
import java.io.PrintStream
@ -29,6 +26,7 @@ object MiraiConsole {
*/
const val build = "Pkmon"
lateinit var version: String
internal set
/**
* 获取从Console登陆上的Bot, Bots
@ -36,7 +34,7 @@ object MiraiConsole {
val bots get() = Bot.instances
fun getBotOrNull(uin: Long): Bot? {
return bots.asSequence().mapNotNull { it.get() }.firstOrNull { it.uin == uin }
return bots.asSequence().mapNotNull { it.get() }.firstOrNull { it.id == uin }
}
/**
@ -98,64 +96,12 @@ object MiraiConsole {
*/
fun stop() {
PluginManager.disablePlugins()
CommandManager.cancel()
CommandManager.cancel()
try {
bots.forEach {
it.get()?.close()
}
} catch (ignored: Exception) { }
}
@Suppress("RedundantSuspendModifier") // binary compatibility
@Deprecated(
"Please use CommandManager directly, this will be removed in later release",
ReplaceWith(
"CommandManager",
"net.mamoe.mirai.console.command.CommandManager"
),
level = DeprecationLevel.ERROR
)
object CommandProcessor {
@Deprecated(
"Please use CommandManager directly, this will be removed in later release", ReplaceWith(
"CommandManager.runConsoleCommand(command)",
"net.mamoe.mirai.console.command.CommandManager"
), level = DeprecationLevel.ERROR
)
suspend fun runConsoleCommand(command: String) {
CommandManager.runCommand(ConsoleCommandSender, command)
}
@Deprecated(
"Please use CommandManager directly, this will be removed in later release", ReplaceWith(
"CommandManager.runCommand(sender, command)",
"net.mamoe.mirai.console.command.CommandManager"
), level = DeprecationLevel.ERROR
)
suspend fun runCommand(sender: CommandSender, command: String) {
CommandManager.runCommand(sender, command)
}
@Deprecated(
"Please use CommandManager directly, this will be removed in later release", ReplaceWith(
"CommandManager.runCommand(command)",
"net.mamoe.mirai.console.command.CommandManager",
"net.mamoe.mirai.console.command.ConsoleCommandSender"
), level = DeprecationLevel.ERROR
)
fun runConsoleCommandBlocking(command: String) =
runBlocking { CommandManager.runCommand(ConsoleCommandSender, command) }
@Suppress("unused")
@Deprecated(
"Please use CommandManager directly, this will be removed in later release", ReplaceWith(
"CommandManager.runCommand(sender, command)",
"net.mamoe.mirai.console.command.CommandManager"
), level = DeprecationLevel.ERROR
)
fun runCommandBlocking(sender: CommandSender, command: String) = runBlocking {
CommandManager.runCommand(sender, command)
} catch (ignored: Exception) {
}
}
}
@ -208,4 +154,9 @@ internal val Throwable.stacktraceString: String
get() =
ByteArrayOutputStream().apply {
printStackTrace(PrintStream(this))
}.use { it.toByteArray().encodeToString() }
}.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

@ -2,34 +2,34 @@ package net.mamoe.mirai.console.center
interface PluginCenter {
companion object{
val Default:PluginCenter = CuiPluginCenter
companion object {
val Default: PluginCenter = CuiPluginCenter
}
data class PluginInsight(
val name:String,
val version:String,
val coreVersion:String,
val consoleVersion:String,
val author:String,
val name: String,
val version: String,
val coreVersion: String,
val consoleVersion: String,
val author: String,
val description: String,
val tags:List<String>,
val commands:List<String>,
val tags: List<String>,
val commands: List<String>
)
data class PluginInfo(
val name:String,
val version:String,
val coreVersion:String,
val consoleVersion:String,
val tags:List<String>,
val author:String,
val contact:String,
val name: String,
val version: String,
val coreVersion: String,
val consoleVersion: String,
val tags: List<String>,
val author: String,
val contact: String,
val description: String,
val usage:String,
val vcs:String,
val commands:String,
val changeLog:List<String>
val usage: String,
val vcs: String,
val commands: String,
val changeLog: List<String>
)
/**
@ -37,7 +37,7 @@ interface PluginCenter {
* 能获取到多少由实际的PluginCenter决定
* 返回 插件名->Insight
*/
suspend fun fetchPlugin(page: Int) :Map<String,PluginInsight>
suspend fun fetchPlugin(page: Int): Map<String, PluginInsight>
/**
* 尝试获取到某个插件by全名, case sensitive

View File

@ -50,22 +50,10 @@ interface Command {
*/
inline fun Command.register(commandOwner: CommandOwner) = CommandManager.register(commandOwner,this)
/**
* 构造并注册一个指令
*/
@Deprecated("this will be removed in next few release")
object AnonymousCommandOwner:CommandOwner
@Deprecated("this will become internal in next few release, please use PluginBase.registerCommand() for plugin")
inline fun registerCommand(builder: CommandBuilder.() -> Unit): Command {
return CommandBuilder().apply(builder).register(AnonymousCommandOwner)
}
internal inline fun registerConsoleCommands(builder: CommandBuilder.() -> Unit):Command{
return CommandBuilder().apply(builder).register(ConsoleCommandOwner)
}
inline fun PluginBase.registerCommand(builder: CommandBuilder.() -> Unit):Command{
return CommandBuilder().apply(builder).register(this.asCommandOwner())
}

View File

@ -19,7 +19,6 @@ import net.mamoe.mirai.console.utils.removeManager
import net.mamoe.mirai.contact.sendMessage
import net.mamoe.mirai.event.subscribeMessages
import net.mamoe.mirai.getFriendOrNull
import net.mamoe.mirai.utils.FileBasedDeviceInfo
import net.mamoe.mirai.utils.SimpleLogger
import java.util.*
@ -117,7 +116,7 @@ object DefaultCommands {
try {
MiraiConsole.frontEnd.prePushBot(qqNumber)
val bot = Bot(qqNumber, qqPassword) {
+FileBasedDeviceInfo
fileBasedDeviceInfo()
this.loginSolver = MiraiConsole.frontEnd.createLoginSolver()
this.botLoggerSupplier = {
SimpleLogger("BOT $qqNumber]") { _, message, e ->
@ -168,10 +167,10 @@ object DefaultCommands {
val bot = args[0]
var find = false
MiraiConsole.bots.forEach {
if (it.get()?.uin.toString().contains(bot)) {
if (it.get()?.id.toString().contains(bot)) {
find = true
appendMessage(
"" + it.get()?.uin + ": 在线中; 好友数量:" + it.get()?.friends?.size + "; 群组数量:" + it.get()
"" + it.get()?.id + ": 在线中; 好友数量:" + it.get()?.friends?.size + "; 群组数量:" + it.get()
?.groups?.size
)
}

View File

@ -7,10 +7,26 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package net.mamoe.mirai.console.events;
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.event.Event
import net.mamoe.mirai.event.Listener
import net.mamoe.mirai.event.ListeningStatus
import net.mamoe.mirai.event.broadcast
import net.mamoe.mirai.event.internal._subscribeEventForJaptOnly
import java.util.function.Consumer
import java.util.function.Function
internal fun <E : Event> broadcast(e: E): E = runBlocking { e.broadcast() }
internal fun <E : Event> Class<E>.subscribeEventForJaptOnly(
scope: CoroutineScope,
onEvent: Function<E, ListeningStatus>
): Listener<E> = _subscribeEventForJaptOnly(scope, onEvent)
internal fun <E : Event> Class<E>.subscribeEventForJaptOnly(scope: CoroutineScope, onEvent: Consumer<E>): Listener<E> =
_subscribeEventForJaptOnly(scope, onEvent)

View File

@ -17,8 +17,8 @@ import com.moandjiezana.toml.Toml
import com.moandjiezana.toml.TomlWriter
import kotlinx.serialization.Serializable
import kotlinx.serialization.UnstableDefault
import net.mamoe.mirai.console.encodeToString
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.encodeToString
import org.yaml.snakeyaml.Yaml
import java.io.File
import java.io.InputStream
@ -486,7 +486,7 @@ abstract class FileConfigImpl internal constructor(
}
@UseExperimental(MiraiInternalAPI::class)
@OptIn(MiraiInternalAPI::class)
class JsonConfig internal constructor(
content: String
) : FileConfigImpl(content) {
@ -513,7 +513,7 @@ class JsonConfig internal constructor(
}
}
@UseExperimental(MiraiInternalAPI::class)
@OptIn(MiraiInternalAPI::class)
class YamlConfig internal constructor(content: String) : FileConfigImpl(content) {
constructor(file: File) : this(file.readText()) {
this.file = file
@ -536,7 +536,7 @@ class YamlConfig internal constructor(content: String) : FileConfigImpl(content)
}
@UseExperimental(MiraiInternalAPI::class)
@OptIn(MiraiInternalAPI::class)
class TomlConfig internal constructor(content: String) : FileConfigImpl(content) {
constructor(file: File) : this(file.readText()) {
this.file = file

View File

@ -16,8 +16,8 @@ import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.command.Command
import net.mamoe.mirai.console.command.CommandManager
import net.mamoe.mirai.console.command.CommandSender
import net.mamoe.mirai.console.encodeToString
import net.mamoe.mirai.utils.SimpleLogger
import net.mamoe.mirai.utils.io.encodeToString
import java.io.File
import java.io.InputStream
import java.lang.reflect.Constructor

View File

@ -24,23 +24,23 @@ internal object BotManagers {
}
fun Bot.addManager(long: Long) {
BOT_MANAGERS.putIfAbsent(this.uin.toString(), mutableListOf<Long>())
BOT_MANAGERS[this.uin.toString()] =
(BOT_MANAGERS.getLongList(this.uin.toString()) as MutableList<Long>).apply { add(long) }
BOT_MANAGERS.putIfAbsent(this.id.toString(), mutableListOf<Long>())
BOT_MANAGERS[this.id.toString()] =
(BOT_MANAGERS.getLongList(this.id.toString()) as MutableList<Long>).apply { add(long) }
BotManagers.config.save()
}
fun Bot.removeManager(long: Long) {
BOT_MANAGERS.putIfAbsent(this.uin.toString(), mutableListOf<Long>())
BOT_MANAGERS[this.uin.toString()] =
(BOT_MANAGERS.getLongList(this.uin.toString()) as MutableList<Long>).apply { add(long) }
BOT_MANAGERS.putIfAbsent(this.id.toString(), mutableListOf<Long>())
BOT_MANAGERS[this.id.toString()] =
(BOT_MANAGERS.getLongList(this.id.toString()) as MutableList<Long>).apply { add(long) }
BotManagers.config.save()
}
val Bot.managers: List<Long>
get() {
BOT_MANAGERS.putIfAbsent(this.uin.toString(), mutableListOf<Long>())
return BOT_MANAGERS.getLongList(this.uin.toString())
BOT_MANAGERS.putIfAbsent(this.id.toString(), mutableListOf<Long>())
return BOT_MANAGERS.getLongList(this.id.toString())
}
fun Bot.checkManager(long: Long): Boolean {