Merge remote-tracking branch 'origin/dev' into 1.x

# Conflicts:
#	build.gradle.kts
#	mirai-core-api/src/commonMain/kotlin/event/events/bot.kt
#	mirai-core-api/src/commonMain/kotlin/event/events/friend.kt
This commit is contained in:
Karlatemp 2020-10-03 22:15:52 +08:00
commit 26fdf6b22d
No known key found for this signature in database
GPG Key ID: 21FBDDF664FF06F8
383 changed files with 1437 additions and 4866 deletions

View File

@ -1,45 +0,0 @@
language: android
jdk: oraclejdk8
### need JDK11
env:
global:
- ANDROID_API_LEVEL=28
- ANDROID_BUILD_TOOLS_VERSION=28.0.3
- ANDROID_ABI=armeabi-v7a
android:
components:
- tools
- platform-tools
- tools
- extra-android-m2repository
licenses:
- 'android-sdk-preview-license-52d11cd2'
- 'android-sdk-license-.+'
- 'google-gdk-license-.+'
before_install:
- touch $HOME/.android/repositories.cfg
- yes | sdkmanager "platforms;android-28"
- yes | sdkmanager "build-tools;28.0.3"
### need JDK8( SDK manager thing)
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- $HOME/.android/build-cache
before_script:
- chmod +x gradlew
script:
- ./gradlew clean build
- ./gradlew test

View File

@ -16,6 +16,12 @@ mirai 欢迎一切形式的代码贡献。你可以通过以下几种途径向 m
### 能做什么?
#### 分支
- `master`: 最新稳定版
- `1.x`: 1.x 现有版本的开发
- `dev`: 2.0 重构版本的开发
**请基于 `master` 分支进行文档修改; 基于 `dev` 分支进行其他修改 (否则你的修改可能被关闭或不会立即合并)**
- 代码优化: 优化任何功能设计或实现, 或是引入一个新的设计(请先通过 issue 与维护者达成共识)
@ -25,7 +31,7 @@ mirai 欢迎一切形式的代码贡献。你可以通过以下几种途径向 m
### 注意事项
- 尽量不要引用新的库
- 遵守 Kotlin 官方代码规范(提交前使用 IDE 格式化代码 (commit 时勾选 'Reformat code')
- 不要手动拆解数据包. 请一定使用 `kotlinx.serialization` 拆解 ProtoBuf, 使用 `net.mamoe.mirai.qqandroid.utils.io.serialization.Tars` 拆解 Tars 数据包, 使用 `kotlinx.serialization` 拆解 Json 数据.
- 不要手动拆解数据包. 请一定使用 `kotlinx.serialization` 拆解 ProtoBuf, 使用 `net.mamoe.mirai.internal.utils.io.serialization.Tars` 拆解 Tars 数据包, 使用 `kotlinx.serialization` 拆解 Json 数据.
## 社区

View File

@ -1 +0,0 @@
theme: jekyll-theme-cayman

View File

@ -2,33 +2,35 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.dokka.gradle.DokkaTask
import java.time.Duration
import kotlin.math.pow
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
buildscript {
repositories {
mavenLocal()
// maven(url = "https://mirrors.huaweicloud.com/repository/maven")
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
maven(url = "https://kotlin.bintray.com/kotlinx")
mavenCentral()
jcenter()
google()
mavenCentral()
maven(url = "https://dl.bintray.com/kotlin/kotlin-eap")
maven(url = "https://kotlin.bintray.com/kotlinx")
}
dependencies {
classpath("com.android.tools.build:gradle:${Versions.Android.androidGradlePlugin}")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.Kotlin.compiler}")
classpath("org.jetbrains.kotlin:kotlin-serialization:${Versions.Kotlin.compiler}")
classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${Versions.Kotlin.atomicFU}")
classpath("org.jetbrains.kotlinx:binary-compatibility-validator:${Versions.Kotlin.binaryValidator}")
classpath("com.android.tools.build:gradle:${Versions.androidGradlePlugin}")
classpath("org.jetbrains.kotlinx:atomicfu-gradle-plugin:${Versions.atomicFU}")
classpath("org.jetbrains.kotlinx:binary-compatibility-validator:${Versions.binaryValidator}")
}
}
plugins {
id("org.jetbrains.dokka") version Versions.Kotlin.dokka apply false
kotlin("jvm") version Versions.kotlinCompiler
kotlin("plugin.serialization") version Versions.kotlinCompiler
id("org.jetbrains.dokka") version Versions.dokka apply false
id("net.mamoe.kotlin-jvm-blocking-bridge") version Versions.blockingBridge apply false
id("com.jfrog.bintray") version Versions.Publishing.bintray
id("com.jfrog.bintray") version Versions.bintray
}
// https://github.com/kotlin/binary-compatibility-validator
@ -57,7 +59,7 @@ runCatching {
allprojects {
group = "net.mamoe"
version = Versions.Mirai.version
version = Versions.project
repositories {
mavenLocal()
@ -68,31 +70,84 @@ allprojects {
google()
mavenCentral()
}
}
subprojects {
if (this@subprojects.name == "java-test") {
return@subprojects
}
afterEvaluate {
if (name == "mirai-core-all") {
return@afterEvaluate
configureJvmTarget()
configureMppShadow()
configureEncoding()
configureKotlinTestSettings()
configureKotlinCompilerSettings()
configureKotlinExperimentalUsages()
if (isKotlinJvmProject) {
configureFlattenSourceSets()
}
apply(plugin = "com.github.johnrengelman.shadow")
configureDokka()
}
}
fun Project.configureDokka() {
apply(plugin = "org.jetbrains.dokka")
tasks {
val dokka by getting(DokkaTask::class) {
outputFormat = "html"
outputDirectory = "$buildDir/dokka"
}
val dokkaMarkdown by creating(DokkaTask::class) {
outputFormat = "markdown"
outputDirectory = "$buildDir/dokka-markdown"
}
val dokkaGfm by creating(DokkaTask::class) {
outputFormat = "gfm"
outputDirectory = "$buildDir/dokka-gfm"
}
}
for (task in tasks.filterIsInstance<DokkaTask>()) {
task.configuration {
perPackageOption {
prefix = "net.mamoe.mirai"
skipDeprecated = true
}
for (suppressedPackage in arrayOf(
"net.mamoe.mirai.internal",
"net.mamoe.mirai.event.internal",
"net.mamoe.mirai.utils.internal",
"net.mamoe.mirai.internal"
)) {
perPackageOption {
prefix = suppressedPackage
suppress = true
}
}
}
}
}
@Suppress("NOTHING_TO_INLINE") // or error
fun Project.configureJvmTarget() {
tasks.withType(KotlinJvmCompile::class.java) {
kotlinOptions.jvmTarget = "11"
}
extensions.findByType(JavaPluginExtension::class.java)?.run {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
fun Project.configureMppShadow() {
val kotlin =
runCatching {
(this as ExtensionAware).extensions.getByName("kotlin") as? org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
}.getOrNull() ?: return@afterEvaluate
(this as ExtensionAware).extensions.getByName("kotlin") as? KotlinMultiplatformExtension
}.getOrNull() ?: return
val shadowJvmJar by tasks.creating(ShadowJar::class) sd@{
group = "mirai"
archiveClassifier.set("-all")
val compilations =
kotlin.targets.filter { it.platformType == org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm }
kotlin.targets.filter { it.platformType == KotlinPlatformType.jvm }
.map { it.compilations["main"] }
compilations.forEach {
@ -108,207 +163,112 @@ subprojects {
file.name.endsWith(".sf", ignoreCase = true)
}
/*
this.manifest {
this.attributes(
"Manifest-Version" to 1,
"Implementation-Vendor" to "Mamoe Technologies",
"Implementation-Title" to this@afterEvaluate.name.toString(),
"Implementation-Version" to this@afterEvaluate.version.toString()
"Implementation-Title" to this.name.toString(),
"Implementation-Version" to this.version.toString()
)
}
}
/*
val shadowJarMd5 = tasks.register("shadowJarMd5") {
dependsOn("shadowJvmJar")
val outFiles = shadowJvmJar.outputs.files.associateWith { file ->
File(file.parentFile, file.name.removeSuffix(".jar").removeSuffix("-all") + "-all.jar.md5")
}
outFiles.forEach { (_, output) ->
outputs.files(output)
}
doLast {
for ((origin, output) in outFiles) {
output
.also { it.createNewFile() }
.writeText(origin.inputStream().md5().toUHexString("").trim(Char::isWhitespace))
}
}
tasks.getByName("publish").dependsOn(this)
tasks.getByName("bintrayUpload").dependsOn(this)
}.get()
*/
val githubUpload by tasks.creating {
group = "mirai"
dependsOn(shadowJvmJar)
doFirst {
timeout.set(Duration.ofHours(3))
findLatestFile().let { (_, file) ->
val filename = file.name
println("Uploading file $filename")
runCatching {
upload.GitHub.upload(
file,
project,
"mirai-repo",
"shadow/${project.name}/$filename"
)
}.exceptionOrNull()?.let {
System.err.println("GitHub Upload failed")
it.printStackTrace() // force show stacktrace
throw it
}
runCatching {
upload.GitHub.upload(
file.inputStream().use { upload.GitHub.run { it.md5().hex().toByteArray(Charsets.UTF_8) } },
project,
"mirai-repo",
"shadow/${project.name}/$filename.md5"
)
}.exceptionOrNull()?.let {
System.err.println("GitHub Upload failed")
it.printStackTrace() // force show stacktrace
throw it
}
}
}
}
apply(plugin = "org.jetbrains.dokka")
this.tasks {
val dokka by getting(DokkaTask::class) {
outputFormat = "html"
outputDirectory = "$buildDir/dokka"
}
val dokkaMarkdown by creating(DokkaTask::class) {
outputFormat = "markdown"
outputDirectory = "$buildDir/dokka-markdown"
}
val dokkaGfm by creating(DokkaTask::class) {
outputFormat = "gfm"
outputDirectory = "$buildDir/dokka-gfm"
}
}
val dokkaGitHubUpload by tasks.creating {
group = "mirai"
val dokkaTaskName = "dokka"
dependsOn(tasks.getByName(dokkaTaskName))
doFirst {
val baseDir = file("./build/$dokkaTaskName/${project.name}")
timeout.set(Duration.ofHours(6))
file("build/$dokkaTaskName/").walk()
.filter { it.isFile }
.map { old ->
if (old.name == "index.md") File(old.parentFile, "README.md").also { new -> old.renameTo(new) }
else old
}
// optimize md
.forEach { file ->
if (file.endsWith(".md")) {
file.writeText(
file.readText().replace("index.md", "README.md", ignoreCase = true)
.replace(Regex("""```\n([\s\S]*?)```""")) {
"\n" + """
```kotlin
$it
```
""".trimIndent()
})
} /* else if (file.name == "README.md") {
file.writeText(file.readText().replace(Regex("""(\n\n\|\s)""")) {
"\n\n" + """"
|||
|:----------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
""".trimIndent()
})
}*/
val filename = file.toRelativeString(baseDir)
println("Uploading file $filename")
runCatching {
upload.GitHub.upload(
file,
project,
"mirai-doc",
"${project.name}/${project.version}/$filename"
}
}
fun Project.configureEncoding() {
tasks.withType(JavaCompile::class.java) {
options.encoding = "UTF8"
}
}
fun Project.configureKotlinTestSettings() {
tasks.withType(Test::class) {
useJUnitPlatform()
}
when {
isKotlinJvmProject -> {
dependencies {
testImplementation(kotlin("test-junit5"))
testApi("org.junit.jupiter:junit-jupiter-api:5.2.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.2.0")
}
}
isKotlinMpp -> {
kotlinSourceSets?.forEach { sourceSet ->
if (sourceSet.name == "common") {
sourceSet.dependencies {
implementation(kotlin("test"))
implementation(kotlin("test-annotations-common"))
}
} else {
sourceSet.dependencies {
implementation(kotlin("test-junit5"))
implementation("org.junit.jupiter:junit-jupiter-api:5.2.0")
implementation("org.junit.jupiter:junit-jupiter-engine:5.2.0")
}
}
}
}
}
}
fun Project.configureKotlinCompilerSettings() {
val kotlinCompilations = kotlinCompilations ?: return
for (kotlinCompilation in kotlinCompilations) with(kotlinCompilation) {
if (isKotlinJvmProject) {
@Suppress("UNCHECKED_CAST")
this as KotlinCompilation<KotlinJvmOptions>
}
kotlinOptions.freeCompilerArgs += "-Xjvm-default=all"
}
}
val experimentalAnnotations = arrayOf(
"kotlin.RequiresOptIn",
"kotlin.contracts.ExperimentalContracts",
"kotlin.experimental.ExperimentalTypeInference",
"net.mamoe.mirai.utils.MiraiInternalAPI",
"net.mamoe.mirai.utils.MiraiExperimentalAPI",
"net.mamoe.mirai.LowLevelAPI",
"kotlinx.serialization.ExperimentalSerializationApi"
)
}.exceptionOrNull()?.let {
System.err.println("GitHub Upload failed")
it.printStackTrace() // force show stacktrace
throw it
}
}
fun Project.configureKotlinExperimentalUsages() {
val sourceSets = kotlinSourceSets ?: return
for (target in sourceSets) {
experimentalAnnotations.forEach { a ->
target.languageSettings.useExperimentalAnnotation(a)
target.languageSettings.progressiveMode = true
target.languageSettings.enableLanguageFeature("InlineClasses")
}
}
}
afterEvaluate {
tasks.filterIsInstance<DokkaTask>().forEach { task ->
with(task) {
configuration {
perPackageOption {
prefix = "net.mamoe.mirai"
skipDeprecated = true
}
perPackageOption {
prefix = "net.mamoe.mirai.internal"
suppress = true
}
perPackageOption {
prefix = "net.mamoe.mirai.event.internal"
suppress = true
}
perPackageOption {
prefix = "net.mamoe.mirai.utils.internal"
suppress = true
}
perPackageOption {
prefix = "net.mamoe.mirai.qqandroid.utils"
suppress = true
}
perPackageOption {
prefix = "net.mamoe.mirai.qqandroid.contact"
suppress = true
}
perPackageOption {
prefix = "net.mamoe.mirai.qqandroid.message"
suppress = true
}
perPackageOption {
prefix = "net.mamoe.mirai.qqandroid.network"
suppress = true
}
}
fun Project.configureFlattenSourceSets() {
sourceSets {
findByName("main")?.apply {
resources.setSrcDirs(listOf(projectDir.resolve("resources")))
java.setSrcDirs(listOf(projectDir.resolve("src")))
}
findByName("test")?.apply {
resources.setSrcDirs(listOf(projectDir.resolve("resources")))
java.setSrcDirs(listOf(projectDir.resolve("test")))
}
}
}
val Project.kotlinSourceSets get() = extensions.findByName("kotlin").safeAs<KotlinProjectExtension>()?.sourceSets
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][0-9]*(\.[0-9]*)*.*\.jar""")) }
.onEach { println("matched file: ${it.name}") }
.associateBy { it.nameWithoutExtension.substringAfterLast('-') }
.onEach { println("versions: $it") }
.maxBy { (version, _) ->
version.split('.').let {
if (it.size == 2) it + "0"
else it
}.reversed().foldIndexed(0) { index: Int, acc: Int, s: String ->
acc + 100.0.pow(index).toInt() * (s.toIntOrNull() ?: 0)
}
} ?: error("cannot find any file to upload")
}
val Project.kotlinTargets
get() =
extensions.findByName("kotlin").safeAs<KotlinSingleTargetExtension>()?.target?.let { listOf(it) }
?: extensions.findByName("kotlin").safeAs<KotlinMultiplatformExtension>()?.targets
val Project.isKotlinJvmProject: Boolean get() = extensions.findByName("kotlin") is KotlinJvmProjectExtension
val Project.isKotlinMpp: Boolean get() = extensions.findByName("kotlin") is KotlinMultiplatformExtension
val Project.kotlinCompilations
get() = kotlinTargets?.flatMap { it.compilations }

View File

@ -1,7 +1,6 @@
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "NOTHING_TO_INLINE", "RemoveRedundantBackticks")
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.publish.maven.MavenPublication
@ -9,7 +8,6 @@ import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.bundling.Jar
import org.gradle.kotlin.dsl.*
import upload.Bintray
import java.io.File
import java.util.*
import kotlin.reflect.KProperty
@ -54,7 +52,7 @@ internal fun org.gradle.api.Project.`publishing`(configure: org.gradle.api.publi
(this as org.gradle.api.plugins.ExtensionAware).extensions.configure("publishing", configure)
inline fun Project.setupPublishing(
inline fun Project.configurePublishing(
artifactId: String,
bintrayRepo: String = "mirai",
bintrayPkgName: String = artifactId,

View File

@ -1,3 +1,4 @@
@file:Suppress("ObjectPropertyName", "ObjectPropertyName", "unused")
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
@ -8,42 +9,56 @@
*/
object Versions {
object Mirai {
const val version = "1.3.1"
}
const val project = "2.0-M1"
object Kotlin {
const val compiler = "1.4.10"
const val stdlib = "1.4.10"
const val kotlinCompiler = "1.4.10"
const val kotlinStdlib = "1.4.10"
const val coroutines = "1.3.9"
const val atomicFU = "0.14.4"
const val serialization = "1.0.0-RC"
const val ktor = "1.4.0"
const val ktor = "1.4.1"
const val binaryValidator = "0.2.3"
const val io = "0.1.16"
const val coroutinesIo = "0.1.16"
const val dokka = "0.10.1"
}
val blockingBridge = "1.0.5"
const val blockingBridge = "1.1.0"
object Android {
const val androidGradlePlugin = "3.5.3"
}
object Publishing {
const val bintray = "1.8.5"
}
object Logging {
const val slf4j = "1.7.30"
const val log4j = "2.13.3"
}
}
@Suppress("unused")
fun kotlinx(id: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$id:$version"
@Suppress("unused")
fun ktor(id: String, version: String = Versions.Kotlin.ktor) = "io.ktor:ktor-$id:$version"
fun ktor(id: String, version: String = Versions.ktor) = "io.ktor:ktor-$id:$version"
val `kotlinx-coroutines-core` = kotlinx("coroutines-core", Versions.coroutines)
val `kotlinx-serialization-core` = kotlinx("serialization-core", Versions.serialization)
val `kotlinx-serialization-json` = kotlinx("serialization-json", Versions.serialization)
val `kotlinx-serialization-protobuf` = kotlinx("serialization-protobuf", Versions.serialization)
const val `kotlinx-atomicfu` = "org.jetbrains.kotlinx:atomicfu:${Versions.atomicFU}"
val `kotlinx-io` = kotlinx("io", Versions.io)
val `kotlinx-io-jvm` = kotlinx("io-jvm", Versions.io)
val `kotlinx-coroutines-io` = kotlinx("coroutines-io", Versions.coroutinesIo)
val `kotlinx-coroutines-io-jvm` = kotlinx("coroutines-io-jvm", Versions.coroutinesIo)
val `ktor-serialization` = ktor("serialization", Versions.ktor)
val `ktor-client-core` = ktor("client-core", Versions.ktor)
val `ktor-client-cio` = ktor("client-cio", Versions.ktor)
val `ktor-client-android` = ktor("client-android", Versions.ktor)
val `ktor-network` = ktor("network", Versions.ktor)
val `ktor-client-okhttp` = ktor("client-okhttp", Versions.ktor)
val `ktor-client-serialization-jvm` = ktor("client-serialization-jvm", Versions.ktor)
const val slf4j = "org.slf4j:slf4j-api:" + Versions.slf4j
const val `log4j-api` = "org.apache.logging.log4j:log4j-api:" + Versions.log4j

View File

@ -1,175 +0,0 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package upload
import io.ktor.client.request.*
import io.ktor.client.request.forms.*
import io.ktor.client.statement.*
import io.ktor.http.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
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.*
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
@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)
val bytes = file.readBytes()
runBlocking {
var first = true
retryCatching(1000) {
if (!first) {
println()
println()
println("Upload failed. Waiting 15s")
delay(15_000)
}
first = false
uploadToCuiCloud(
cuiCloudUrl,
key,
"/mirai/${project.name}/${file.nameWithoutExtension}.mp4",
bytes
)
}.getOrThrow()
}
}
@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}")
}
}
}
@OptIn(ExperimentalContracts::class)
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "RESULT_CLASS_IN_RETURN_TYPE")
@kotlin.internal.InlineOnly
internal inline fun <R> retryCatching(n: Int, onFailure: () -> Unit = {}, block: () -> R): Result<R> {
contract {
callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
}
require(n >= 0) { "param n for retryCatching must not be negative" }
var exception: Throwable? = null
repeat(n) {
try {
return Result.success(block())
} catch (e: Throwable) {
try {
exception?.addSuppressed(e)
} catch (e: Throwable) {
}
exception = e
onFailure()
}
}
return Result.failure(exception!!)
}
inline fun <E> buildList(builderAction: MutableList<E>.() -> Unit): List<E> {
return ArrayList<E>().apply(builderAction)
}

View File

@ -1,211 +0,0 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE")
package upload
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.features.*
import io.ktor.client.request.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
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 ByteArray.hex(): String = buildString(size * 2) {
this@hex.forEach { byte ->
val uint = Integer.toHexString(byte.toInt() and 0xFF)
if (uint.length == 1) append('0')
append(uint)
}
}
fun upload(file: File, project: Project, repo: String, targetFilePath: String) = upload(
file.readBytes(), project, repo, targetFilePath
)
fun upload(source: ByteArray, project: Project, repo: String, targetFilePath: String) = runBlocking {
val token = getGithubToken(project)
println("token.length=${token.length}")
val url = "https://api.github.com/repos/project-mirai/$repo/contents/$targetFilePath"
retryCatching(100, onFailure = { delay(30_000) }) { // 403 forbidden?
Http.put<String>("$url?access_token=$token") {
val sha = retryCatching(3, onFailure = { delay(30_000) }) {
getGithubSha(
repo,
targetFilePath,
"master",
project
)
}.getOrNull()
println("sha=$sha")
val content = String(Base64.getEncoder().encode(source))
body = """
{
"message": "Automatically upload on release ${project.name}:${project.version}",
"content": "$content"
${if (sha == null) "" else """, "sha": "$sha" """}
}
""".trimIndent()
}.let {
println("Upload response: $it")
}
delay(1000)
}.getOrThrow()
}
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/project-mirai/$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/project-mirai/$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

@ -3,16 +3,13 @@ import java.io.OutputStream
import java.security.MessageDigest
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* * 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
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@OptIn(ExperimentalUnsignedTypes::class)
fun ByteArray.toUHexString(
separator: String = " ",

View File

@ -1,49 +0,0 @@
@file:Suppress("UNUSED_VARIABLE")
plugins {
kotlin("jvm")
java
}
description = "Binary and source compatibility validator for mirai-core and mirai-core-qqandroid"
repositories {
mavenCentral()
jcenter()
}
kotlin {
sourceSets {
all {
languageSettings.enableLanguageFeature("InlineClasses")
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
}
main {
dependencies {
api(kotlin("stdlib", Versions.Kotlin.stdlib))
runtimeOnly(project(":mirai-core-qqandroid"))
compileOnly("net.mamoe:mirai-core-qqandroid:0.38.0")
}
}
test {
dependencies {
api(kotlin("stdlib", Versions.Kotlin.stdlib))
api(kotlin("test"))
api(kotlin("test-junit"))
runtimeOnly(project(":mirai-core-qqandroid"))
compileOnly("net.mamoe:mirai-core-qqandroid:0.38.0")
}
}
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@ -1,24 +0,0 @@
package compatibility;
import net.mamoe.mirai.Bot;
import net.mamoe.mirai.BotFactoryJvm;
import net.mamoe.mirai.message.data.MessageUtils;
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
public class CompatibilityTest {
public static void main(String[] args) {
Bot bot = BotFactoryJvm.newBot(Long.parseLong(System.getenv("qq")), System.getenv("password"));
bot.getFriend(123).sendMessage(MessageUtils.newChain("")
.plus("")
.plus(MessageUtils.newImage("")));
bot.getFriend(123).sendMessage("");
}
}

View File

@ -1,78 +0,0 @@
package compatibility
import net.mamoe.mirai.message.data.*
import kotlin.test.Test
import kotlin.test.assertEquals
internal class CombinedMessageTest {
@Test
fun testAsSequence() {
var message: Message = "Hello ".toMessage()
message += "World"
assertEquals(
"Hello World",
(message as CombinedMessage).asSequence().joinToString(separator = "")
)
}
@Test
fun testAsSequence2() {
var message: Message = "Hello ".toMessage()
message += listOf(
PlainText("W"),
PlainText("o"),
PlainText("r") + PlainText("ld")
).asMessageChain()
assertEquals(
"Hello World",
(message as CombinedMessage).asSequence().joinToString(separator = "")
)
}
}
fun <T> Iterator<T>.joinToString(
separator: CharSequence = ", ",
prefix: CharSequence = "",
postfix: CharSequence = "",
limit: Int = -1,
truncated: CharSequence = "...",
transform: ((T) -> CharSequence)? = null
): String {
return joinTo(StringBuilder(), separator, prefix, postfix, limit, truncated, transform).toString()
}
fun <T, A : Appendable> Iterator<T>.joinTo(
buffer: A,
separator: CharSequence = ", ",
prefix: CharSequence = "",
postfix: CharSequence = "",
limit: Int = -1,
truncated: CharSequence = "...",
transform: ((T) -> CharSequence)? = null
): A {
buffer.append(prefix)
var count = 0
for (element in this) {
if (++count > 1) buffer.append(separator)
if (limit < 0 || count <= limit) {
buffer.appendElement(element, transform)
} else break
}
if (limit in 0 until count) buffer.append(truncated)
buffer.append(postfix)
return buffer
}
internal fun <T> Appendable.appendElement(element: T, transform: ((T) -> CharSequence)?) {
when {
transform != null -> append(transform(element))
element is CharSequence? -> append(element)
element is Char -> append(element)
else -> append(element.toString())
}
}

View File

@ -1,27 +0,0 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package compatibility
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.PlainText
import org.junit.Test
internal class TestKotlinCompatibility {
@Test
fun testMessageChain() {
val x = PlainText("te") + PlainText("st")
println(Message::class.java.declaredMethods.joinToString("\n"))
println()
println(x::class.java.declaredMethods.joinToString("\n"))
}
}

View File

@ -20,9 +20,9 @@
mirai 项目整体由 核心 (`mirai-core`) 与 控制台(`mirai-console`) 组成.
- [`mirai-core`](../mirai-core) 是机器人服务支持**库**. 提供所有机器人相关 API. **本身只包含抽象类和接口, 使用时还需要同时依赖协议模块**.
- [`mirai-core`](../mirai-core-api) 是机器人服务支持**库**. 提供所有机器人相关 API. **本身只包含抽象类和接口, 使用时还需要同时依赖协议模块**.
可用的协议模块:
- [`mirai-core-qqandroid`](../mirai-core-qqandroid): Android QQ 8.3.0 版本协议实现.
- [`mirai-core-qqandroid`](../mirai-core): Android QQ 8.3.0 版本协议实现.
`mirai-core` 设计为一个 **`支持库`**, 意味着它可以被独立依赖, 在任意项目中使用. 详见下文.

View File

@ -5,9 +5,9 @@ apiValidation {
]
ignoredPackages += [
"net.mamoe.mirai.qqandroid.contact",
"net.mamoe.mirai.qqandroid.message",
"net.mamoe.mirai.qqandroid.network",
"net.mamoe.mirai.qqandroid.utils"
"net.mamoe.mirai.internal.contact",
"net.mamoe.mirai.internal.message",
"net.mamoe.mirai.internal.network",
"net.mamoe.mirai.internal.utils"
]
}

View File

@ -1,47 +0,0 @@
@file:Suppress("UNUSED_VARIABLE")
plugins {
kotlin("jvm")
java
}
description = "Java compatibility validator for mirai-core and mirai-core-qqandroid"
repositories {
mavenCentral()
jcenter()
}
kotlin {
sourceSets {
all {
languageSettings.enableLanguageFeature("InlineClasses")
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
}
main {
dependencies {
api(kotlin("stdlib", Versions.Kotlin.stdlib))
api(project(":mirai-core-qqandroid"))
}
}
test {
dependencies {
api(kotlin("stdlib", Versions.Kotlin.stdlib))
api(kotlin("test"))
api(kotlin("test-junit"))
api(project(":mirai-core-qqandroid"))
}
}
}
}
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

View File

@ -1,20 +0,0 @@
package test;
import net.mamoe.mirai.Bot;
import net.mamoe.mirai.contact.Contact;
import net.mamoe.mirai.contact.QQ;
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
public class MPPCompatibilityTest {
public static void main(String[] args) {
final QQ next = Bot.getInstances().get(0).getFriends().iterator().next();
((Contact) next).sendMessage("");
}
}

View File

@ -9,7 +9,7 @@ plugins {
id("net.mamoe.kotlin-jvm-blocking-bridge")
}
version = Versions.Mirai.version
version = Versions.project
description = "Mirai core shadowed"
java {
@ -22,39 +22,12 @@ tasks.withType(JavaCompile::class.java) {
}
kotlin {
explicitApiWarning()
sourceSets.all {
target.compilations.all {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = freeCompilerArgs + "-Xjvm-default=all"
//useIR = true
}
}
languageSettings.apply {
enableLanguageFeature("InlineClasses")
progressiveMode = true
useExperimentalAnnotation("kotlin.Experimental")
useExperimentalAnnotation("kotlin.RequiresOptIn")
useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiExperimentalAPI")
useExperimentalAnnotation("net.mamoe.mirai.console.ConsoleFrontEndImplementation")
useExperimentalAnnotation("net.mamoe.mirai.console.util.ConsoleExperimentalApi")
useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference")
useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi")
useExperimentalAnnotation("net.mamoe.mirai.console.util.ConsoleInternalApi")
}
}
explicitApi()
}
dependencies {
api(project(":mirai-core"))
api(project(":mirai-core-qqandroid"))
api(project(":mirai-core-api"))
}
setupPublishing("mirai-core-all")
configurePublishing("mirai-core-all")

10
mirai-core-api/README.md Normal file
View File

@ -0,0 +1,10 @@
# mirai-core
mirai 的核心公开 API.
mirai 为多协议设计, `mirai-core` 只提供基础框架和抽象数据类.
具体的各协议实现为 `mirai-core-PROTOCOL`, 这些协议模块都继承自 `mirai-core`.
可用的协议模块:
- [`mirai-core-qqandroid`](../mirai-core): Android QQ 8.3.0 版本协议实现.

View File

@ -4,16 +4,19 @@ plugins {
kotlin("multiplatform")
id("kotlinx-atomicfu")
kotlin("plugin.serialization")
id("signing")
id("net.mamoe.kotlin-jvm-blocking-bridge")
`maven-publish`
id("com.jfrog.bintray")
}
description = "Mirai Protocol implementation for QQ Android"
description = "Mirai API module"
val isAndroidSDKAvailable: Boolean by project
kotlin {
explicitApi()
if (isAndroidSDKAvailable) {
apply(from = rootProject.file("gradle/android.gradle"))
android("android") {
@ -34,84 +37,78 @@ kotlin {
)
}
jvm("jvm") {
}
sourceSets.apply {
all {
languageSettings.enableLanguageFeature("InlineClasses")
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiExperimentalAPI")
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.LowLevelAPI")
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
languageSettings.useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference")
languageSettings.useExperimentalAnnotation("kotlin.time.ExperimentalTime")
languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
languageSettings.useExperimentalAnnotation("kotlinx.serialization.ExperimentalSerializationApi")
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.UnstableExternalImage")
languageSettings.progressiveMode = true
dependencies {
api(project(":mirai-core"))
}
jvm {
withJava()
}
sourceSets {
val commonMain by getting {
dependencies {
api1(kotlinx("serialization-core", Versions.Kotlin.serialization))
api(kotlinx("coroutines-core", Versions.Kotlin.coroutines))
implementation1(kotlinx("serialization-protobuf", Versions.Kotlin.serialization))
api1("org.jetbrains.kotlinx:atomicfu:${Versions.Kotlin.atomicFU}")
api1(kotlinx("io", Versions.Kotlin.io))
implementation1(kotlinx("coroutines-io", Versions.Kotlin.coroutinesIo))
}
}
api(kotlin("serialization"))
api(kotlin("reflect"))
val commonTest by getting {
dependencies {
implementation(kotlin("test-annotations-common"))
implementation(kotlin("test-common"))
implementation(kotlin("script-runtime"))
api1(`kotlinx-serialization-core`)
implementation1(`kotlinx-serialization-protobuf`)
api1(`kotlinx-io`)
api1(`kotlinx-coroutines-io`)
api(`kotlinx-coroutines-core`)
implementation1(`kotlinx-atomicfu`)
api1(`ktor-client-cio`)
api1(`ktor-client-core`)
api1(`ktor-network`)
}
}
if (isAndroidSDKAvailable) {
val androidMain by getting {
androidMain {
dependencies {
}
}
api(kotlin("reflect"))
val androidTest by getting {
dependencies {
implementation(kotlin("test", Versions.Kotlin.compiler))
implementation(kotlin("test-junit", Versions.Kotlin.compiler))
implementation(kotlin("test-annotations-common"))
implementation(kotlin("test-common"))
api1(`kotlinx-io-jvm`)
api1(`kotlinx-coroutines-io-jvm`)
api1(`ktor-client-android`)
}
}
}
val jvmMain by getting {
dependencies {
implementation("org.bouncycastle:bcprov-jdk15on:1.64")
api1(kotlinx("io-jvm", Versions.Kotlin.io))
// api(kotlinx("coroutines-debug", Versions.Kotlin.coroutines))
api(kotlin("reflect"))
compileOnly(`log4j-api`)
compileOnly(slf4j)
api1(`kotlinx-io-jvm`)
api1(`kotlinx-coroutines-io-jvm`)
}
}
val jvmTest by getting {
dependencies {
dependsOn(commonTest)
implementation(kotlin("test", Versions.Kotlin.compiler))
implementation(kotlin("test-junit", Versions.Kotlin.compiler))
implementation("org.pcap4j:pcap4j-distribution:1.8.2")
api("org.pcap4j:pcap4j-distribution:1.8.2")
runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE
}
}
}
}
val NamedDomainObjectContainer<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>.androidMain: NamedDomainObjectProvider<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>
get() = named<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>("androidMain")
val NamedDomainObjectContainer<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>.androidTest: NamedDomainObjectProvider<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>
get() = named<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>("androidTest")
val NamedDomainObjectContainer<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>.jvmMain: NamedDomainObjectProvider<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>
get() = named<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>("jvmMain")
val NamedDomainObjectContainer<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>.jvmTest: NamedDomainObjectProvider<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>
get() = named<org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet>("jvmTest")
fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.implementation1(dependencyNotation: String) =
implementation(dependencyNotation) {
exclude("org.jetbrains.kotlin", "kotlin-stdlib")
@ -132,7 +129,6 @@ fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.api1(dependencyNo
apply(from = rootProject.file("gradle/publish.gradle"))
tasks.withType<com.jfrog.bintray.gradle.tasks.BintrayUploadTask> {
doFirst {
publishing.publications

View File

@ -6,7 +6,6 @@
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress(
"EXPERIMENTAL_API_USAGE", "unused", "FunctionName", "NOTHING_TO_INLINE", "UnusedImport",
"EXPERIMENTAL_OVERRIDE", "CanBeParameter", "MemberVisibilityCanBePrivate"
@ -236,7 +235,7 @@ public abstract class Bot internal constructor(
@PlannedRemoval("1.2.0")
@Deprecated(
"use extension.",
replaceWith = ReplaceWith("image.queryUrl()", imports = ["net.mamoe.mirai.message.data.queryUrl"]),
replaceWith = ReplaceWith("image.queryUrl()", imports = ["queryUrl"]),
level = DeprecationLevel.ERROR
)
@JvmSynthetic

View File

@ -13,6 +13,7 @@ package net.mamoe.mirai.contact
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.utils.asHumanReadable
import kotlin.time.ExperimentalTime
import kotlin.time.seconds
/**
@ -38,6 +39,7 @@ public class MessageTooLargeException(
*
* @see Group.sendMessage
*/
@OptIn(ExperimentalTime::class)
public class BotIsBeingMutedException(
public val target: Group
) : RuntimeException("bot is being muted, remaining ${target.botMuteRemaining.seconds.asHumanReadable} seconds")

View File

@ -1,6 +1,9 @@
package net.mamoe.mirai.data
import kotlinx.serialization.*
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor

View File

@ -37,7 +37,7 @@ import kotlin.jvm.JvmName
//
//
////
//// 此文件存放所有 `net.mamoe.mirai.event.subscribeMessages` 已弃用的函数.
//// 此文件存放所有 `subscribeMessages` 已弃用的函数.
////
//
//

View File

@ -16,8 +16,9 @@ package net.mamoe.mirai.event.events
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.message.action.Nudge
import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.SinceMirai
@ -246,7 +247,7 @@ public data class BotNudgedEvent internal constructor(
* @see MessageEvent.subject
*/
@MiraiExperimentalAPI
@SinceMirai("1.3.2")
@SinceMirai("2.0.0")
public val BotNudgedEvent.subject: Contact
get() = when (val inlineFrom = from) {
is Member -> inlineFrom.group

View File

@ -20,8 +20,8 @@ import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.User
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.internal.MiraiAtomicBoolean
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.message.action.Nudge
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.SinceMirai
import net.mamoe.mirai.utils.internal.runBlocking

View File

@ -22,8 +22,8 @@ import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.BroadcastControllable
import net.mamoe.mirai.event.internal.MiraiAtomicBoolean
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.message.action.Nudge
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.SinceMirai
import net.mamoe.mirai.utils.internal.runBlocking

View File

@ -19,12 +19,12 @@ import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.CancellableEvent
import net.mamoe.mirai.event.events.ImageUploadEvent.Failed
import net.mamoe.mirai.event.events.ImageUploadEvent.Succeed
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageSource
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.SinceMirai
@ -403,7 +403,7 @@ public sealed class ImageUploadEvent : BotEvent, BotActiveEvent, AbstractEvent()
message = """
MessagePreSendEvent MessagePostSendEvent 替换.
""",
replaceWith = ReplaceWith("MessagePreSendEvent", "net.mamoe.mirai.event.events.MessagePreSendEvent"),
replaceWith = ReplaceWith("MessagePreSendEvent", "MessagePreSendEvent"),
level = DeprecationLevel.WARNING
)
public sealed class MessageSendEvent : BotEvent, BotActiveEvent, AbstractEvent() {
@ -415,7 +415,7 @@ public sealed class MessageSendEvent : BotEvent, BotActiveEvent, AbstractEvent()
message = """
GroupMessagePreSendEvent GroupMessagePostSendEvent 替换.
""",
replaceWith = ReplaceWith("GroupMessagePreSendEvent", "net.mamoe.mirai.event.events.GroupMessagePreSendEvent"),
replaceWith = ReplaceWith("GroupMessagePreSendEvent", "GroupMessagePreSendEvent"),
level = DeprecationLevel.WARNING
)
public data class GroupMessageSendEvent internal constructor(
@ -429,7 +429,7 @@ public sealed class MessageSendEvent : BotEvent, BotActiveEvent, AbstractEvent()
""",
replaceWith = ReplaceWith(
"FriendMessagePreSendEvent",
"net.mamoe.mirai.event.events.FriendMessagePreSendEvent"
"FriendMessagePreSendEvent"
),
level = DeprecationLevel.WARNING
)
@ -442,7 +442,7 @@ public sealed class MessageSendEvent : BotEvent, BotActiveEvent, AbstractEvent()
message = """
TempMessagePreSendEvent TempMessagePostSendEvent 替换.
""",
replaceWith = ReplaceWith("TempMessagePreSendEvent", "net.mamoe.mirai.event.events.TempMessagePreSendEvent"),
replaceWith = ReplaceWith("TempMessagePreSendEvent", "TempMessagePreSendEvent"),
level = DeprecationLevel.WARNING
)
public data class TempMessageSendEvent internal constructor(

View File

@ -6,7 +6,6 @@
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai
/**

View File

@ -1,14 +1,11 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* * 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
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.message.action
import net.mamoe.kjbb.JvmBlockingBridge

View File

@ -209,6 +209,7 @@ internal inline fun <T : CustomMessageMetadata> T.customToStringImpl(factory: Cu
return (factory as CustomMessage.Factory<T>).dump(this)
}
@OptIn(ExperimentalUnsignedTypes::class)
@JvmOverloads
@Suppress("DuplicatedCode") // false positive. foreach is not common to UByteArray and ByteArray
internal fun ByteArray.toUHexString(

View File

@ -22,7 +22,6 @@
package net.mamoe.mirai.message.data
import net.mamoe.kjbb.JvmBlockingBridge
import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.message.code.CodableMessage
@ -193,7 +192,7 @@ public fun Image(imageId: String): OfflineImage = when {
* @return 原图 HTTP 下载链接 ( HTTPS)
* @throws IllegalStateException 当无任何 [Bot] 在线时抛出 (因为无法获取相关协议)
*/
@JvmBlockingBridge
//@JvmBlockingBridge
@JvmSynthetic
public suspend fun Image.queryUrl(): String {
@Suppress("DEPRECATION")

View File

@ -52,7 +52,7 @@ public data class PlainText(
*/
@Deprecated(
"为和 mirai code 区分, 请使用 PlainText(this)",
ReplaceWith("PlainText(this)", "net.mamoe.mirai.message.data.PlainText"),
ReplaceWith("PlainText(this)", "PlainText"),
level = DeprecationLevel.WARNING
)
@JvmSynthetic

View File

@ -48,7 +48,7 @@ internal const val ONLINE_OFFLINE_DEPRECATION_MESSAGE = """
@Deprecated(
ONLINE_OFFLINE_DEPRECATION_MESSAGE,
level = DeprecationLevel.ERROR,
replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image")
replaceWith = ReplaceWith("Image", "Image")
)
@Suppress("EXPOSED_SUPER_INTERFACE")
public interface OnlineImage : Image, ConstOriginUrlAware {
@ -69,7 +69,7 @@ public interface OnlineImage : Image, ConstOriginUrlAware {
@Deprecated(
ONLINE_OFFLINE_DEPRECATION_MESSAGE,
level = DeprecationLevel.ERROR,
replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image")
replaceWith = ReplaceWith("Image", "Image")
)
public interface OfflineImage : Image {
public companion object Key : Message.Key<OfflineImage> {
@ -96,7 +96,7 @@ public suspend fun OfflineImage.queryUrl(): String {
@Deprecated(
ONLINE_OFFLINE_DEPRECATION_MESSAGE,
level = DeprecationLevel.ERROR,
replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image")
replaceWith = ReplaceWith("Image", "Image")
)
@Serializable
public data class OfflineGroupImage(
@ -124,7 +124,7 @@ public data class OfflineGroupImage(
@Deprecated(
ONLINE_OFFLINE_DEPRECATION_MESSAGE,
level = DeprecationLevel.ERROR,
replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image")
replaceWith = ReplaceWith("Image", "Image")
)
public abstract class OnlineGroupImage : GroupImage(), OnlineImage
@ -137,7 +137,7 @@ public abstract class OnlineGroupImage : GroupImage(), OnlineImage
@Deprecated(
ONLINE_OFFLINE_DEPRECATION_MESSAGE,
level = DeprecationLevel.ERROR,
replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image")
replaceWith = ReplaceWith("Image", "Image")
)
@Serializable
public data class OfflineFriendImage(
@ -161,7 +161,7 @@ public data class OfflineFriendImage(
@Deprecated(
ONLINE_OFFLINE_DEPRECATION_MESSAGE,
level = DeprecationLevel.ERROR,
replaceWith = ReplaceWith("Image", "net.mamoe.mirai.message.data.Image")
replaceWith = ReplaceWith("Image", "Image")
)
public abstract class OnlineFriendImage : FriendImage(), OnlineImage

View File

@ -23,9 +23,9 @@ import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.events.BotEvent
import net.mamoe.mirai.internal.network.Packet
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.OnlineMessageSource
import net.mamoe.mirai.qqandroid.network.Packet
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
@ -35,7 +35,7 @@ import kotlin.jvm.JvmName
*/
@Deprecated(
message = "use MessageEvent",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
replaceWith = ReplaceWith("MessageEvent", "MessageEvent"),
level = DeprecationLevel.HIDDEN
)
public abstract class MessagePacketBase<out TSender : User, out TSubject : Contact> : Packet, BotEvent,
@ -51,7 +51,7 @@ public abstract class MessagePacketBase<out TSender : User, out TSubject : Conta
@Deprecated(
message = "Ambiguous name. Use MessageEvent instead",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
replaceWith = ReplaceWith("MessageEvent", "MessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
@ -68,7 +68,7 @@ public abstract class MessagePacket : MessagePacketBase<User, Contact>(),
@Deprecated(
message = "Ambiguous name. Use MessageEvent instead",
replaceWith = ReplaceWith("MessageEvent", "net.mamoe.mirai.message.MessageEvent"),
replaceWith = ReplaceWith("MessageEvent", "MessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
@ -85,7 +85,7 @@ public abstract class ContactMessage : MessagePacket(),
@Deprecated(
message = "Ambiguous name. Use FriendMessageEvent instead",
replaceWith = ReplaceWith("FriendMessageEvent", "net.mamoe.mirai.message.FriendMessageEvent"),
replaceWith = ReplaceWith("FriendMessageEvent", "FriendMessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
@ -101,7 +101,7 @@ public abstract class FriendMessage : MessageEvent() {
@Deprecated(
message = "Ambiguous name. Use GroupMessageEvent instead",
replaceWith = ReplaceWith("GroupMessageEvent", "net.mamoe.mirai.message.GroupMessageEvent"),
replaceWith = ReplaceWith("GroupMessageEvent", "GroupMessageEvent"),
level = DeprecationLevel.HIDDEN
)
@Suppress("DEPRECATION_ERROR")
@ -118,7 +118,7 @@ public abstract class GroupMessage : MessageEvent() {
@Deprecated(
message = "Ambiguous name. Use TempMessageEvent instead",
replaceWith = ReplaceWith("TempMessageEvent", "net.mamoe.mirai.message.TempMessageEvent"),
replaceWith = ReplaceWith("TempMessageEvent", "TempMessageEvent"),
level = DeprecationLevel.HIDDEN
)
public abstract class TempMessage : MessageEvent() {

View File

@ -7,7 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.qqandroid.network
package net.mamoe.mirai.internal.network
import net.mamoe.mirai.event.Event
import net.mamoe.mirai.utils.MiraiInternalAPI

Some files were not shown because too many files have changed in this diff Show More