Explorar o código

Add http api basics

Him188 %!s(int64=6) %!d(string=hai) anos
pai
achega
d261cd7b7e

+ 3 - 0
mirai-api-http/README.md

@@ -0,0 +1,3 @@
+# mirai-api-http
+
+Coroutine-based Http API adapter for Mirai.  

+ 75 - 0
mirai-api-http/build.gradle.kts

@@ -0,0 +1,75 @@
+@file:Suppress("UNUSED_VARIABLE")
+
+plugins {
+    id("kotlinx-atomicfu")
+    kotlin("jvm")
+    id("kotlinx-serialization")
+}
+
+group = "net.mamoe.mirai"
+version = "0.1.0"
+
+description = "Mirai Http Api"
+
+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 org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.kotlinx(id: String, version: String) {
+    implementation("org.jetbrains.kotlinx:$id:$version")
+}
+
+fun org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler.ktor(id: String, version: String = ktorVersion) {
+    implementation("io.ktor:$id:$version")
+}
+
+kotlin {
+
+
+    sourceSets["main"].apply {
+        dependencies {
+            implementation(project(":mirai-core"))
+
+            kotlin("kotlin-stdlib-jdk8", kotlinVersion)
+            kotlin("kotlin-stdlib-jdk7", kotlinVersion)
+            kotlin("kotlin-reflect", kotlinVersion)
+
+            ktor("ktor-server-cio")
+            kotlinx("kotlinx-io-jvm", kotlinXIoVersion)
+            ktor("ktor-http-jvm")
+        }
+    }
+
+    sourceSets["test"].apply {
+        dependencies {
+        }
+        kotlin.outputDir = file("build/classes/kotlin/jvm/test")
+        kotlin.setSrcDirs(listOf("src/$name/kotlin"))
+
+    }
+
+    sourceSets.all {
+        languageSettings.enableLanguageFeature("InlineClasses")
+        languageSettings.useExperimentalAnnotation("kotlin.Experimental")
+
+        dependencies {
+            kotlin("kotlin-stdlib", kotlinVersion)
+            kotlin("kotlin-serialization", kotlinVersion)
+
+            kotlinx("atomicfu", atomicFuVersion)
+            kotlinx("kotlinx-io", kotlinXIoVersion)
+            kotlinx("kotlinx-coroutines-io", coroutinesIoVersion)
+            kotlinx("kotlinx-coroutines-core", coroutinesVersion)
+            kotlinx("kotlinx-serialization-runtime", serializationVersion)
+            ktor("ktor-server-core")
+            ktor("ktor-http")
+        }
+    }
+}

+ 136 - 0
mirai-api-http/src/main/kotlin/net.mamoe.mirai.api.http/MiraiHttpApplication.kt

@@ -0,0 +1,136 @@
+package net.mamoe.mirai.api.http
+
+import io.ktor.application.Application
+import io.ktor.application.ApplicationCall
+import io.ktor.application.call
+import io.ktor.application.install
+import io.ktor.features.CallLogging
+import io.ktor.features.DefaultHeaders
+import io.ktor.http.HttpMethod
+import io.ktor.http.HttpStatusCode
+import io.ktor.response.respond
+import io.ktor.routing.Route
+import io.ktor.routing.route
+import io.ktor.routing.routing
+import io.ktor.server.engine.applicationEngineEnvironment
+import io.ktor.util.pipeline.ContextDsl
+import io.ktor.util.pipeline.PipelineContext
+import io.ktor.util.pipeline.PipelineInterceptor
+import net.mamoe.mirai.Bot
+import net.mamoe.mirai.addFriend
+import net.mamoe.mirai.getGroup
+import net.mamoe.mirai.getQQ
+import net.mamoe.mirai.utils.io.hexToBytes
+import net.mamoe.mirai.utils.io.hexToUBytes
+
+fun main() {
+    Application(applicationEngineEnvironment {}).apply { mirai() }
+}
+
+@UseExperimental(ExperimentalUnsignedTypes::class)
+fun Application.mirai() {
+    install(DefaultHeaders)
+    install(CallLogging)
+
+    routing {
+        mirai("/sendFriendMessage") {
+            // TODO: 2019/11/21 解析图片消息等为 Message
+            Bot.instanceWhose(qq = param("bot")).getQQ(param("qq")).sendMessage(param<String>("message"))
+            call.ok()
+        }
+
+        mirai("/sendGroupMessage") {
+            Bot.instanceWhose(qq = param("bot")).getGroup(param<UInt>("group")).sendMessage(param<String>("message"))
+            call.ok()
+        }
+
+        mirai("/event/message") {
+            // TODO: 2019/11/21
+            Bot.instanceWhose(qq = param("bot"))
+        }
+
+        mirai("/addFriend") {
+            Bot.instanceWhose(qq = param("bot")).addFriend(
+                id = param("qq"),
+                lazyMessage = paramOrNull<String?>("message")?.let { { it } } ?: { "" },
+                lazyRemark = paramOrNull<String?>("remark")?.let { { it } } ?: { "" }
+            )
+
+            call.ok()
+        }
+    }
+}
+
+
+@ContextDsl
+private fun Route.mirai(path: String, body: PipelineInterceptor<Unit, ApplicationCall>): Route {
+    return route(path, HttpMethod.Get) {
+        handle {
+            try {
+                this.body(this.subject)
+            } catch (e: IllegalAccessException) {
+                call.respond(HttpStatusCode.BadRequest, e.message)
+            }
+        }
+    }
+}
+
+
+@Suppress("NOTHING_TO_INLINE")
+suspend inline fun ApplicationCall.ok() = this.respond(HttpStatusCode.OK, "OK")
+
+/**
+ * 错误请求. 抛出这个异常后将会返回错误给一个请求
+ */
+open class IllegalAccessException : Exception {
+    override val message: String get() = super.message!!
+
+    constructor(message: String) : super(message, null)
+    constructor(cause: Throwable) : super(cause.toString(), cause)
+    constructor(message: String, cause: Throwable?) : super(message, cause)
+}
+
+/**
+ * 错误参数
+ */
+class IllegalParamException(message: String) : IllegalAccessException(message)
+
+fun PipelineContext<Unit, ApplicationCall>.illegalParam(
+    expectingType: String?,
+    paramName: String,
+    actualValue: String? = call.parameters[paramName]
+): Nothing = throw IllegalParamException("Illegal param. A $expectingType is required for `$paramName` while `$actualValue` is given")
+
+@Suppress("IMPLICIT_CAST_TO_ANY")
+@UseExperimental(ExperimentalUnsignedTypes::class)
+private inline fun <reified R> PipelineContext<Unit, ApplicationCall>.param(name: String): R = this.paramOrNull(name) ?: illegalParam(R::class.simpleName, name)
+
+@Suppress("IMPLICIT_CAST_TO_ANY")
+@UseExperimental(ExperimentalUnsignedTypes::class)
+private inline fun <reified R> PipelineContext<Unit, ApplicationCall>.paramOrNull(name: String): R? =
+    when {
+        R::class == Byte::class -> call.parameters[name]?.toByte()
+        R::class == Int::class -> call.parameters[name]?.toInt()
+        R::class == Short::class -> call.parameters[name]?.toShort()
+        R::class == Float::class -> call.parameters[name]?.toFloat()
+        R::class == Long::class -> call.parameters[name]?.toLong()
+        R::class == Double::class -> call.parameters[name]?.toDouble()
+        R::class == Boolean::class -> when (call.parameters[name]) {
+            "true" -> true
+            "false" -> false
+            "0" -> false
+            "1" -> true
+            null -> null
+            else -> illegalParam("boolean", name)
+        }
+
+        R::class == String::class -> call.parameters[name]
+
+        R::class == UByte::class -> call.parameters[name]?.toUByte()
+        R::class == UInt::class -> call.parameters[name]?.toUInt()
+        R::class == UShort::class -> call.parameters[name]?.toUShort()
+
+        R::class == UByteArray::class -> call.parameters[name]?.hexToUBytes()
+        R::class == ByteArray::class -> call.parameters[name]?.hexToBytes()
+        else -> error(name::class.simpleName + " is not supported")
+    } as R?

+ 0 - 122
mirai-core/build.gradle.backup

@@ -1,122 +0,0 @@
-kotlin {
-    targets {
-        fromPreset(presets.jvm, "jvm")
-        //fromPreset(presets.jvm, "android")
-        //fromPreset(presets.mingwX64, "mingwX64")
-    }
-    jvm{
-        withJava()
-    }
-
-    /*
-    mingwX64("mingwX64") {
-        binaries {
-            executable {
-                // Change to specify fully qualified name of your application's entry point:
-                entryPoint = 'hex.main'
-                // Specify command-line arguments, if necessary:
-                runTask?.args('')
-            }
-        }
-    }*/
-
-    sourceSets {
-        commonMain {
-            dependencies {
-                api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-common', version: kotlinVersion
-                api group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlinVersion
-                api group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core-common', version: coroutinesVersion
-                api group: 'org.jetbrains.kotlinx', name: 'atomicfu-common', version: atomicFuVersion
-                api group: 'org.jetbrains.kotlinx', name: 'kotlinx-io', version: kotlinXIoVersion
-                api group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-io', version: coroutinesIoVersion
-
-                implementation "com.soywiz.korlibs.klock:klock:$klockVersion"
-
-                api group: 'io.ktor', name: 'ktor-client-core', version: ktorVersion
-                api group: 'io.ktor', name: 'ktor-network', version: ktorVersion
-                //api group: 'io.ktor', name: 'ktor-client-cio', version: ktorVersion
-                //api group: 'io.ktor', name: 'ktor-client', version: ktorVersion
-                api group: 'io.ktor', name: 'ktor-http', version: ktorVersion
-                //api group: 'io.ktor', name: 'ktor-utils', version: ktorVersion
-                //api group: 'io.ktor', name: 'ktor-io', version: ktorio_version
-            }
-        }
-
-        jvmMain {
-            apply plugin: 'java'
-
-            dependencies {
-                api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: kotlinVersion
-                api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlinVersion
-                api group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlinVersion
-                api group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: coroutinesVersion
-                api group: 'org.jetbrains.kotlinx', name: 'atomicfu', version: atomicFuVersion
-                api group: 'org.jetbrains.kotlinx', name: 'kotlinx-io', version: kotlinXIoVersion
-                // api group: 'org.jetbrains.kotlinx', name: 'kotlinx-io-jvm', version: kotlinXIoVersion
-                api group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-io', version: coroutinesIoVersion
-
-                api group: 'io.ktor', name: 'ktor-http-cio', version: ktorVersion
-                api group: 'io.ktor', name: 'ktor-http', version: ktorVersion
-                api group: 'io.ktor', name: 'ktor-client-core-jvm', version: ktorVersion
-                api group: 'io.ktor', name: 'ktor-client-cio', version: ktorVersion
-
-                implementation 'org.yaml:snakeyaml:1.18'
-                implementation 'org.jsoup:jsoup:1.12.1'
-                implementation 'org.ini4j:ini4j:0.5.2'
-            }
-        }
-
-        /*
-        mingwX64Main {
-
-            dependencies {
-                // https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-reflect
-                implementation rootProject.ext.kotlinCommon
-                implementation rootProject.ext.coroutine
-                implementation rootProject.ext.coroutineNative
-                implementation rootProject.ext.kotlinNative
-                implementation rootProject.ext.reflect
-
-                //implementation rootProject.ext.coroutine
-                implementation rootProject.ext.kotlinxIONative
-            }
-        }*/
-
-        jvmTest {
-            apply plugin: 'java'
-        }
-
-
-        androidMain{
-            dependencies{
-                api 'com.google.android:android:4.1.1.4'
-                api 'com.android.support:support-annotations:26.1.0'
-
-                api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: kotlinVersion
-                api group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: kotlinVersion
-                api group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: kotlinVersion
-                api group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: coroutinesVersion
-                api group: 'org.jetbrains.kotlinx', name: 'atomicfu', version: atomicFuVersion
-                api group: 'org.jetbrains.kotlinx', name: 'kotlinx-io', version: kotlinXIoVersion
-                // api group: 'org.jetbrains.kotlinx', name: 'kotlinx-io-jvm', version: kotlinXIoVersion
-                api group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-io', version: coroutinesIoVersion
-
-                api group: 'io.ktor', name: 'ktor-http-cio', version: ktorVersion
-                api group: 'io.ktor', name: 'ktor-http', version: ktorVersion
-                api group: 'io.ktor', name: 'ktor-client-core-jvm', version: ktorVersion
-                api group: 'io.ktor', name: 'ktor-client-cio', version: ktorVersion
-            }
-        }
-
-        all {
-            languageSettings.enableLanguageFeature("InlineClasses")
-        }
-    }
-}
-
-compileKotlinJvm {
-}
-
-compileTestJava{
-
-}

+ 1 - 0
settings.gradle

@@ -4,6 +4,7 @@ include(':mirai-core')
 
 include(':mirai-console')
 include(':mirai-api')
+include(':mirai-api-http')
 include(':mirai-demos:mirai-demo-1')
 include(':mirai-demos:mirai-demo-gentleman')
 include(':mirai-demos')