Maa HTTP server DTO实现

This commit is contained in:
iguigui
2022-05-25 20:52:24 +08:00
parent 0c301841b3
commit bc9795fb3c
8 changed files with 300 additions and 59 deletions

View File

@@ -27,6 +27,7 @@ dependencies {
implementation("io.ktor:ktor-server-netty-jvm:$ktor_version")
implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
implementation("io.ktor:ktor-server-cors:$ktor_version")
implementation("io.ktor:ktor-server-websockets:$ktor_version")
implementation("ch.qos.logback:logback-classic:$logback_version")
testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version")

View File

@@ -1,64 +1,42 @@
package com.iguigui.maaj
import com.iguigui.maaj.dto.*
import com.iguigui.maaj.service.MaaService
import com.iguigui.maaj.routing.httpRouting
import com.iguigui.maaj.routing.wsRouting
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.netty.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.request.*
import io.ktor.server.routing.*
import io.ktor.server.plugins.cors.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import java.time.Duration
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.Json
fun main(args: Array<String>): Unit = EngineMain.main(args)
fun Application.module() {
configureRouting()
configure()
httpRouting()
wsRouting()
}
fun Application.configureRouting() {
fun Application.configure(){
install(ContentNegotiation) {
json()
json(Json {
encodeDefaults = true
isLenient = true
allowSpecialFloatingPointValues = true
allowStructuredMapKeys = true
prettyPrint = false
useArrayPolymorphism = false
})
}
install(CORS) {
allowCredentials = true
anyHost()
}
install(WebSockets) {
pingPeriod = Duration.ofSeconds(15)
timeout = Duration.ofSeconds(15)
pingPeriod = java.time.Duration.ofSeconds(15)
timeout = java.time.Duration.ofSeconds(15)
maxFrameSize = Long.MAX_VALUE
masking = false
}
routing {
post("/connect") {
val connect = call.receive<Connect>()
MaaService.connect(connect.adbPath, connect.host, "")
}
post("/appendTask") {
val appendTask = call.receive<AppendTask>()
MaaService.appendTask(appendTask.host, appendTask.type, appendTask.params.toJsonString())
}
post("/start") {
val start = call.receive<Start>()
MaaService.start(start.host)
}
post("/stop") {
val stop = call.receive<Stop>()
MaaService.stop(stop.host)
}
webSocket("/") {
send("You are connected!")
for (frame in incoming) {
frame as? Frame.Text ?: continue
val receivedText = frame.readText()
println("接收到信息 : $receivedText")
send("You said: $receivedText")
}
}
}
}

View File

@@ -8,7 +8,7 @@ import kotlinx.serialization.encodeToString
sealed class WsRequest
@Serializable
data class Connect(
data class ConnectRequest(
@SerialName("adbPath")
val adbPath: String,
@SerialName("host")
@@ -16,7 +16,7 @@ data class Connect(
)
@Serializable
data class AppendTask(
data class AppendTaskRequest(
@SerialName("host")
val host: String,
@SerialName("type")
@@ -30,11 +30,105 @@ sealed class Task
@Serializable
data class Fight(
@SerialName("medicine")
val medicine: Int?,
@SerialName("penguin_id")
val penguinId: String?,
@SerialName("report_to_penguin")
val reportToPenguin: Boolean?,
@SerialName("server")
val server: String?,
@SerialName("stage")
val stage: String
val stage: String?,
@SerialName("stone")
val stone: Int?,
@SerialName("times")
val times: Int?
) : Task()
@Serializable
data class Recruit(
@SerialName("confirm")
val confirm: List<Int>,
@SerialName("expedite")
val expedite: Boolean?,
@SerialName("expedite_times")
val expediteTimes: Int?,
@SerialName("refresh")
val refresh: Boolean?,
@SerialName("select")
val select: List<Int>,
@SerialName("set_time")
val setTime: Boolean?,
@SerialName("times")
val times: Int?
) : Task()
@Serializable
data class Infrast(
@SerialName("drones")
val drones: String?,
@SerialName("facility")
val facility: List<String>,
@SerialName("mode")
val mode: Int?,
@SerialName("replenish")
val replenish: Boolean?,
@SerialName("threshold")
val threshold: Double?
) : Task()
@Serializable
class Visit : Task()
@Serializable
data class Mall(
@SerialName("blacklist")
val blacklist: List<String>?,
@SerialName("buy_first")
val buyFirst: List<String>?,
@SerialName("shopping")
val shopping: Boolean?
) : Task()
@Serializable
class Award : Task()
@Serializable
data class Roguelike(
@SerialName("mode")
val mode: Int?,
@SerialName("opers")
val opers: List<Oper>
) : Task()
@Serializable
data class Oper(
@SerialName("name")
val name: String,
@SerialName("skill")
val skill: Int?,
@SerialName("skill_usage")
val skillUsage: Int?
)
@Serializable
data class Copilot(
@SerialName("filename")
val filename: String,
@SerialName("formation")
val formation: Boolean,
@SerialName("stage_name")
val stageName: String?
)
@Serializable
data class Start(
@SerialName("host")
@@ -51,7 +145,7 @@ data class Stop(
@Serializable
data class ConnectWs(
@SerialName("data")
val `data`: Connect,
val `data`: ConnectRequest,
@SerialName("type")
val type: String
) : WsRequest()

View File

@@ -0,0 +1,74 @@
package com.iguigui.maaj.dto
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.json.jsonObject
@Serializable
data class HttpResponse(
@SerialName("version")
val data: JsonElement = EmptyBaseData.toJsonElement(),
@SerialName("code")
val code: Int = 0,
@SerialName("message")
val message: String = "success"
)
@Serializable
data class WsResponse(
@SerialName("version")
val data: JsonElement,
@SerialName("type")
val type: String,
@SerialName("code")
val code: Int,
@SerialName("message")
val message: String
)
@Serializable
sealed class BaseData
@Serializable
data class GetVersion(
@SerialName("version")
val version: String
) : BaseData()
@Serializable
data class ConnectResponse(
@SerialName("version")
val id: String
) : BaseData()
@Serializable
data class ListInstance(
@SerialName("version")
val list: List<MaaInstanceInfo>
) : BaseData()
@Serializable
data class MaaInstanceInfo(
@SerialName("id")
val id: String,
@SerialName("host")
val host: String,
@SerialName("adbPath")
val adbPath: String,
@SerialName("status")
val status: Int,
) : BaseData()
object EmptyBaseData : BaseData()
fun BaseData.toJsonElement() =
Json.encodeToJsonElement(Json.encodeToJsonElement(this).jsonObject.filterNot { it.key == "type" })

View File

@@ -0,0 +1,45 @@
package com.iguigui.maaj.routing
import com.iguigui.maaj.dto.*
import com.iguigui.maaj.service.MaaService
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
fun Application.httpRouting() {
routing {
route("/v1") {
get("/getVersion") {
val version = MaaService.getVersion()
call.respond(HttpResponse(GetVersion(version).toJsonElement()))
}
get("/listInstance") {
val list = MaaService.listInstance()
call.respond(HttpResponse(ListInstance(list).toJsonElement()))
}
post("/connect") {
val connect = call.receive<ConnectRequest>()
val id = MaaService.connect(connect.adbPath, connect.host, "")
call.respond(HttpResponse(ConnectResponse(id).toJsonElement()))
}
post("/appendTask") {
val appendTask = call.receive<AppendTaskRequest>()
MaaService.appendTask(appendTask.host, appendTask.type, appendTask.params.toJsonString())
call.respond(HttpResponse())
}
post("/start") {
val start = call.receive<Start>()
MaaService.start(start.host)
call.respond(HttpResponse())
}
post("/stop") {
val stop = call.receive<Stop>()
MaaService.stop(stop.host)
call.respond(HttpResponse())
}
}
}
}

View File

@@ -0,0 +1,26 @@
package com.iguigui.maaj.routing
import com.iguigui.maaj.dto.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.request.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
fun Application.wsRouting() {
routing {
webSocket("/v1") {
send("You are connected!")
for (frame in incoming) {
frame as? Frame.Text ?: continue
val receivedText = frame.readText()
println("接收到信息 : $receivedText")
send("You said: $receivedText")
}
}
}
}

View File

@@ -8,9 +8,10 @@ class MaaInstance(private val instance: MeoAssistant, val id: String, val adbPat
constructor(
instance: MeoAssistant,
pointer: Pointer,
id: String, adbPath: String,
host: String
id: String,
adbPath: String,
host: String,
pointer: Pointer
) : this(
instance,
id,
@@ -22,6 +23,8 @@ class MaaInstance(private val instance: MeoAssistant, val id: String, val adbPat
lateinit var pointer: Pointer
var status = 0
override fun callback(msg: Int, detail_json: String?, custom_arg: String?) {
System.out.printf("回调msg : %s , 回调 detail_json : %s ,回调 custom_arg : %s \n", msg, detail_json, custom_arg)
}

View File

@@ -1,11 +1,12 @@
package com.iguigui.maaj.service
import com.iguigui.maaj.dto.MaaInstanceInfo
import com.iguigui.maaj.easySample.MeoAssistant
import com.sun.jna.Native
import java.io.File
import java.util.*
import java.security.MessageDigest
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicBoolean
object MaaService {
@@ -22,18 +23,18 @@ object MaaService {
load
}
fun connect(adbPath: String, host: String, detailJson: String): Boolean {
fun connect(adbPath: String, host: String, detailJson: String): String {
if (instancePool.containsKey(host)) {
return false
return sha1(host)
}
val maaInstance = MaaInstance(meoAssistant, host, adbPath, host)
maaInstance.pointer = meoAssistant.AsstCreateEx(maaInstance, maaInstance.id)
maaInstance.connect()
instancePool.putIfAbsent(host, maaInstance)
return true
return sha1(host)
}
fun appendTask(host: String,type:String, detailJson: String): Int {
fun appendTask(host: String, type: String, detailJson: String): Int {
val appendTask = instancePool[host]?.appendTask(type, detailJson)
return appendTask ?: 0
}
@@ -42,6 +43,25 @@ object MaaService {
fun stop(host: String) = instancePool[host]?.stop()
private fun generatorId() = UUID.randomUUID().toString()
fun getVersion() = "3.9.0"
private fun sha1(password: String): String {
val messageDigest = MessageDigest.getInstance("SHA")
val digests = messageDigest.digest(password.toByteArray())
val stringBuilder = StringBuilder()
for (i in digests.indices) {
var halfbyte = digests[i].toInt() ushr 4 and 0x0F
for (j in 0..1) {
stringBuilder.append(
if (0 <= halfbyte && halfbyte <= 9) ('0'.code + halfbyte).toChar() else ('a'.code + (halfbyte - 10)).toChar()
)
halfbyte = digests[i].toInt() and 0x0F
}
}
return stringBuilder.toString()
}
fun listInstance(): List<MaaInstanceInfo> =
instancePool.values.map { e -> MaaInstanceInfo(e.id, e.host, e.id, e.status) }.toList()
}