mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-16 01:40:46 +08:00
Maa WS接口回调实现
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
val ktor_version = "2.0.1"
|
||||
val ktor_version = "2.0.2"
|
||||
val kotlin_version = "1.6.10"
|
||||
val logback_version = "1.2.11"
|
||||
|
||||
|
||||
19
src/Java/Maaj/src/main/java/com/iguigui/maaj/dto/msgEnum.kt
Normal file
19
src/Java/Maaj/src/main/java/com/iguigui/maaj/dto/msgEnum.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package com.iguigui.maaj.dto
|
||||
|
||||
/* Global Info */
|
||||
val INTERNAL_ERROR = 0 // 内部错误
|
||||
val INIT_FAILED = 1 // 初始化失败
|
||||
val CONNECTION_INFO = 2 // 连接相关信息
|
||||
val ALL_TASKS_COMPLETED = 3 // 全部任务完成
|
||||
|
||||
/* TaskChain Info */
|
||||
val TASK_CHAIN_ERROR = 10000 // 任务链执行/识别错误
|
||||
val TASK_CHAIN_START = 10001 // 任务链开始
|
||||
val TASK_CHAIN_COMPLETED = 10002 // 任务链完成
|
||||
val TASK_CHAIN_EXTRA_INFO = 10003 // 任务链额外信息
|
||||
|
||||
/* SubTask Info */
|
||||
val SUB_TASK_ERROR = 20000 // 原子任务执行/识别错误
|
||||
val SUB_TASK_START = 20001 // 原子任务开始
|
||||
val SUB_TASK_COMPLETED = 20002 // 原子任务完成
|
||||
val SUB_TASK_EXTRA_INFO = 20003 // 原子任务额外信息
|
||||
@@ -6,7 +6,6 @@ import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
|
||||
sealed class WsRequest
|
||||
|
||||
@Serializable
|
||||
data class ConnectRequest(
|
||||
@@ -145,25 +144,33 @@ data class Copilot(
|
||||
|
||||
|
||||
@Serializable
|
||||
data class Start(
|
||||
data class StartRequest(
|
||||
@SerialName("id")
|
||||
val id: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Stop(
|
||||
data class StopRequest(
|
||||
@SerialName("id")
|
||||
val id: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class DestroyRequest(
|
||||
@SerialName("id")
|
||||
val id: String,
|
||||
)
|
||||
|
||||
@SerialName("connect")
|
||||
@Serializable
|
||||
data class ConnectWs(
|
||||
data class WsRequest(
|
||||
@SerialName("data")
|
||||
val `data`: ConnectRequest,
|
||||
val `data`: JsonElement,
|
||||
@SerialName("command")
|
||||
val command: String
|
||||
) : WsRequest()
|
||||
val command: String,
|
||||
@SerialName("msgId")
|
||||
val msgId: Int = 0
|
||||
)
|
||||
|
||||
|
||||
fun Task.toJsonString() = Json.encodeToString(this)
|
||||
|
||||
@@ -22,12 +22,14 @@ data class HttpResponse(
|
||||
data class WsResponse(
|
||||
@SerialName("version")
|
||||
val data: JsonElement,
|
||||
@SerialName("type")
|
||||
val type: String,
|
||||
@SerialName("command")
|
||||
val command: String,
|
||||
@SerialName("msgId")
|
||||
val msgId: Int = 0,
|
||||
@SerialName("code")
|
||||
val code: Int,
|
||||
val code: Int = 0,
|
||||
@SerialName("message")
|
||||
val message: String
|
||||
val message: String = "success"
|
||||
)
|
||||
|
||||
@Serializable
|
||||
@@ -102,6 +104,8 @@ data class StopResponse(
|
||||
val result: Boolean
|
||||
) : BaseData()
|
||||
|
||||
|
||||
|
||||
@Serializable
|
||||
data class CallBackLog(
|
||||
@SerialName("id")
|
||||
@@ -122,7 +126,15 @@ fun BaseData.toJsonElement() =
|
||||
Json.encodeToJsonElement(Json.encodeToJsonElement(this).jsonObject.filterNot { it.key == "type" })
|
||||
|
||||
|
||||
fun BaseData.wapperToResponse() =
|
||||
fun BaseData.wapperToHttpResponse() =
|
||||
HttpResponse(Json.encodeToJsonElement(Json.encodeToJsonElement(this).jsonObject.filterNot { it.key == "type" }))
|
||||
|
||||
fun BaseData.wapperToWsResponse(command: String, msgId: Int) =
|
||||
WsResponse(
|
||||
Json.encodeToJsonElement(Json.encodeToJsonElement(this).jsonObject.filterNot { it.key == "type" }),
|
||||
command,
|
||||
msgId
|
||||
)
|
||||
|
||||
fun WsResponse.toJsonString() = Json.encodeToJsonElement(Json.encodeToJsonElement(this).jsonObject.filterNot { it.key == "type" }).toString()
|
||||
|
||||
|
||||
@@ -16,12 +16,12 @@ fun Application.httpRouting() {
|
||||
route("/v1") {
|
||||
get("/getVersion") {
|
||||
val version = MaaService.getVersion()
|
||||
call.respond(GetVersionResponse(version).wapperToResponse())
|
||||
call.respond(GetVersionResponse(version).wapperToHttpResponse())
|
||||
}
|
||||
post("/connect") {
|
||||
with(call.receive<ConnectRequest>()) {
|
||||
val connect = MaaService.connect(adbPath, host, detailJson)
|
||||
call.respond(connect.wapperToResponse())
|
||||
call.respond(connect.wapperToHttpResponse())
|
||||
}
|
||||
}
|
||||
post("/appendTask") {
|
||||
@@ -31,7 +31,7 @@ fun Application.httpRouting() {
|
||||
type,
|
||||
params.jsonObject.toString()
|
||||
)
|
||||
call.respond(AppendTaskResponse(id, result).wapperToResponse())
|
||||
call.respond(AppendTaskResponse(id, result).wapperToHttpResponse())
|
||||
}
|
||||
}
|
||||
post("/setTaskParams") {
|
||||
@@ -42,22 +42,27 @@ fun Application.httpRouting() {
|
||||
taskId,
|
||||
params.jsonObject.toString()
|
||||
)
|
||||
call.respond(SetTaskParamsResponse(id, result).wapperToResponse())
|
||||
call.respond(SetTaskParamsResponse(id, result).wapperToHttpResponse())
|
||||
}
|
||||
}
|
||||
post("/start") {
|
||||
val start = call.receive<Start>()
|
||||
val result = MaaService.start(start.id)
|
||||
call.respond(StartResponse(start.id, result).wapperToResponse())
|
||||
val startRequest = call.receive<StartRequest>()
|
||||
val result = MaaService.start(startRequest.id)
|
||||
call.respond(StartResponse(startRequest.id, result).wapperToHttpResponse())
|
||||
}
|
||||
post("/stop") {
|
||||
val stop = call.receive<Stop>()
|
||||
val result = MaaService.stop(stop.id)
|
||||
call.respond(StartResponse(stop.id, result).wapperToResponse())
|
||||
val stopRequest = call.receive<StopRequest>()
|
||||
val result = MaaService.stop(stopRequest.id)
|
||||
call.respond(StartResponse(stopRequest.id, result).wapperToHttpResponse())
|
||||
}
|
||||
post("/destroy") {
|
||||
val destroy = call.receive<DestroyRequest>()
|
||||
MaaService.destroy(destroy.id)
|
||||
call.respond(EmptyBaseData.wapperToHttpResponse())
|
||||
}
|
||||
get("/listInstance") {
|
||||
val list = MaaService.listInstance()
|
||||
call.respond(ListInstanceResponse(list).wapperToResponse())
|
||||
call.respond(ListInstanceResponse(list).wapperToHttpResponse())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,95 @@
|
||||
package com.iguigui.maaj.routing
|
||||
|
||||
import com.iguigui.maaj.dto.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import com.iguigui.maaj.service.Connection
|
||||
import com.iguigui.maaj.service.MaaService
|
||||
import com.iguigui.maaj.service.MaaService.addConnection
|
||||
import com.iguigui.maaj.service.MaaService.appendTask
|
||||
import com.iguigui.maaj.service.MaaService.removeConnection
|
||||
import com.iguigui.maaj.util.Json
|
||||
import io.ktor.websocket.*
|
||||
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.*
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import java.util.*
|
||||
import kotlin.collections.LinkedHashSet
|
||||
|
||||
|
||||
fun Application.wsRouting() {
|
||||
|
||||
routing {
|
||||
webSocket("/v1") {
|
||||
send("You are connected!")
|
||||
println("Adding user!")
|
||||
val connection = Connection(this)
|
||||
addConnection(connection)
|
||||
for (frame in incoming) {
|
||||
frame as? Frame.Text ?: continue
|
||||
val receivedText = frame.readText()
|
||||
println("接收到信息 : $receivedText")
|
||||
send("You said: $receivedText")
|
||||
try {
|
||||
val receivedText = frame.readText()
|
||||
val wsRequest = Json.decodeFromString(WsRequest.serializer(), receivedText)
|
||||
var response: BaseData? = null
|
||||
when (wsRequest.command) {
|
||||
"connect" -> {
|
||||
with(Json.decodeFromJsonElement(ConnectRequest.serializer(), wsRequest.data)) {
|
||||
response = MaaService.connect(adbPath, host, detailJson)
|
||||
}
|
||||
}
|
||||
"appendTask" -> {
|
||||
with(Json.decodeFromJsonElement(AppendTaskRequest.serializer(), wsRequest.data)) {
|
||||
val result = appendTask(
|
||||
id,
|
||||
type,
|
||||
params.jsonObject.toString()
|
||||
)
|
||||
response = AppendTaskResponse(id, result)
|
||||
}
|
||||
}
|
||||
"setTaskParams" -> {
|
||||
with(Json.decodeFromJsonElement(SetTaskParamsRequest.serializer(), wsRequest.data)) {
|
||||
val result = MaaService.setTaskParams(
|
||||
id,
|
||||
type,
|
||||
taskId,
|
||||
params.jsonObject.toString()
|
||||
)
|
||||
response = SetTaskParamsResponse(id, result)
|
||||
}
|
||||
}
|
||||
"start" -> {
|
||||
val startRequest =
|
||||
Json.decodeFromJsonElement(StartRequest.serializer(), wsRequest.data)
|
||||
val result = MaaService.start(startRequest.id)
|
||||
response = StartResponse(startRequest.id, result)
|
||||
}
|
||||
"stop" -> {
|
||||
val stopRequest =
|
||||
Json.decodeFromJsonElement(StopRequest.serializer(), wsRequest.data)
|
||||
val result = MaaService.stop(stopRequest.id)
|
||||
response = StopResponse(stopRequest.id, result)
|
||||
}
|
||||
"destroy" -> {
|
||||
val destroyRequest =
|
||||
Json.decodeFromJsonElement(DestroyRequest.serializer(), wsRequest.data)
|
||||
MaaService.stop(destroyRequest.id)
|
||||
response = EmptyBaseData
|
||||
}
|
||||
"listInstance" -> {
|
||||
val list = MaaService.listInstance()
|
||||
response = ListInstanceResponse(list)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
response?.let {
|
||||
send(it.wapperToWsResponse(wsRequest.command, wsRequest.msgId).toJsonString())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
println(e.message)
|
||||
} finally {
|
||||
println("Removing $connection!")
|
||||
removeConnection(connection)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.iguigui.maaj.service
|
||||
|
||||
import io.ktor.websocket.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class Connection(val session: DefaultWebSocketSession) {
|
||||
companion object {
|
||||
var lastId = AtomicInteger(0)
|
||||
}
|
||||
val name = "user${lastId.getAndIncrement()}"
|
||||
}
|
||||
@@ -1,56 +1,69 @@
|
||||
package com.iguigui.maaj.service
|
||||
|
||||
import com.iguigui.maaj.dto.CallBackLog
|
||||
import com.iguigui.maaj.dto.*
|
||||
import com.iguigui.maaj.easySample.MeoAssistant
|
||||
import com.iguigui.maaj.util.Json
|
||||
import com.sun.jna.Pointer
|
||||
import java.util.LinkedList
|
||||
import java.util.Queue
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.concurrent.LinkedBlockingQueue
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import kotlin.reflect.KFunction1
|
||||
|
||||
class MaaInstance(
|
||||
private val instance: MeoAssistant,
|
||||
val id: String,
|
||||
val adbPath: String,
|
||||
val host: String,
|
||||
val detailJson: String
|
||||
private val detailJson: String,
|
||||
val callBackAction: KFunction1<CallBackLog, Unit>
|
||||
) :
|
||||
MeoAssistant.AsstApiCallback {
|
||||
|
||||
constructor(
|
||||
instance: MeoAssistant,
|
||||
id: String,
|
||||
adbPath: String,
|
||||
host: String,
|
||||
pointer: Pointer,
|
||||
detailJson: String
|
||||
) : this(
|
||||
instance,
|
||||
id,
|
||||
adbPath,
|
||||
host,
|
||||
detailJson
|
||||
) {
|
||||
this.pointer = pointer
|
||||
}
|
||||
// constructor(
|
||||
// instance: MeoAssistant,
|
||||
// id: String,
|
||||
// adbPath: String,
|
||||
// host: String,
|
||||
// pointer: Pointer,
|
||||
// detailJson: String
|
||||
// ) : this(
|
||||
// instance,
|
||||
// id,
|
||||
// adbPath,
|
||||
// host,
|
||||
// detailJson
|
||||
// ) {
|
||||
// this.pointer = pointer
|
||||
// }
|
||||
|
||||
lateinit var pointer: Pointer
|
||||
|
||||
var uuid = ""
|
||||
|
||||
//状态码,0初始化未运行 1运行中
|
||||
var status = 0
|
||||
|
||||
var logQueue: Queue<CallBackLog> = LinkedBlockingQueue(1000)
|
||||
|
||||
var msgId = AtomicLong(0)
|
||||
// private var logQueue: ArrayBlockingQueue<CallBackLog> = ArrayBlockingQueue(100)
|
||||
//
|
||||
private var msgId = AtomicLong(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)
|
||||
logQueue.offer(CallBackLog(id, msgId.getAndIncrement(), msg, Json.parseToJsonElement(detail_json)))
|
||||
val callBackLog = CallBackLog(id, msgId.getAndIncrement(), msg, Json.parseToJsonElement(detail_json))
|
||||
callBackAction?.call(callBackLog)
|
||||
when (msg) {
|
||||
INTERNAL_ERROR,
|
||||
INIT_FAILED,
|
||||
ALL_TASKS_COMPLETED,
|
||||
TASK_CHAIN_ERROR,
|
||||
TASK_CHAIN_COMPLETED,
|
||||
SUB_TASK_ERROR,
|
||||
SUB_TASK_COMPLETED -> status = 0
|
||||
//也不知道啥算正在运行,姑且认为任务链开始和原子任务开始肯定是在运行中吧
|
||||
TASK_CHAIN_START,
|
||||
SUB_TASK_START -> status = 1
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
fun connect(): Boolean = instance.AsstConnect(pointer, adbPath, host, detailJson)
|
||||
@@ -59,8 +72,17 @@ class MaaInstance(
|
||||
|
||||
fun setTaskParams(type: String, taskId: Int, params: String) = instance.AsstSetTaskParams(pointer, taskId, params)
|
||||
|
||||
fun start() = instance.AsstStart(pointer)
|
||||
fun start(): Boolean {
|
||||
msgId.set(0)
|
||||
return instance.AsstStart(pointer)
|
||||
}
|
||||
|
||||
fun stop() = instance.AsstStop(pointer)
|
||||
fun destroy() = instance.AsstDestroy(pointer)
|
||||
|
||||
//todo
|
||||
private fun addLog(callBackLog: CallBackLog) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +1,29 @@
|
||||
package com.iguigui.maaj.service
|
||||
|
||||
import com.iguigui.maaj.dto.CallBackLog
|
||||
import com.iguigui.maaj.dto.ConnectResponse
|
||||
import com.iguigui.maaj.dto.MaaInstanceInfo
|
||||
import com.iguigui.maaj.dto.toJsonElement
|
||||
import com.iguigui.maaj.easySample.MeoAssistant
|
||||
import com.sun.jna.Native
|
||||
import io.ktor.websocket.*
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.collections.LinkedHashSet
|
||||
|
||||
|
||||
object MaaService {
|
||||
|
||||
private var instancePool: ConcurrentHashMap<String, MaaInstance> = ConcurrentHashMap()
|
||||
|
||||
private val wsConnection = Collections.synchronizedSet<Connection?>(LinkedHashSet())
|
||||
|
||||
val meoAssistant: MeoAssistant by lazy {
|
||||
val f = File(this.javaClass.getResource("")?.path ?: "")
|
||||
var maaPath = f.path
|
||||
@@ -26,31 +37,29 @@ object MaaService {
|
||||
|
||||
fun connect(adbPath: String, host: String, detailJson: String): ConnectResponse {
|
||||
val id = sha1(host)
|
||||
synchronized(id) {
|
||||
if (instancePool.containsKey(id)) {
|
||||
return ConnectResponse(id, true)
|
||||
}
|
||||
val maaInstance = MaaInstance(meoAssistant, host, adbPath, host, detailJson)
|
||||
maaInstance.pointer = meoAssistant.AsstCreateEx(maaInstance, maaInstance.id)
|
||||
val connect = maaInstance.connect()
|
||||
if (!connect) {
|
||||
return ConnectResponse("", false)
|
||||
}
|
||||
instancePool.putIfAbsent(id, maaInstance)
|
||||
if (instancePool.containsKey(id)) {
|
||||
return ConnectResponse(id, true)
|
||||
}
|
||||
val maaInstance = MaaInstance(meoAssistant, host, adbPath, host, detailJson, ::callBackLog)
|
||||
maaInstance.pointer = meoAssistant.AsstCreateEx(maaInstance, maaInstance.id)
|
||||
val connect = maaInstance.connect()
|
||||
if (!connect) {
|
||||
return ConnectResponse("", false)
|
||||
}
|
||||
instancePool.putIfAbsent(id, maaInstance)
|
||||
return ConnectResponse(id, true)
|
||||
}
|
||||
|
||||
fun appendTask(host: String, type: String, detailJson: String) =
|
||||
instancePool[host]?.appendTask(type, detailJson) ?: 0
|
||||
fun appendTask(id: String, type: String, detailJson: String) =
|
||||
instancePool[id]?.appendTask(type, detailJson) ?: 0
|
||||
|
||||
|
||||
fun setTaskParams(host: String, type: String, taskId: Int, detailJson: String) =
|
||||
instancePool[host]?.setTaskParams(type, taskId, detailJson) ?: false
|
||||
fun setTaskParams(id: String, type: String, taskId: Int, detailJson: String) =
|
||||
instancePool[id]?.setTaskParams(type, taskId, detailJson) ?: false
|
||||
|
||||
fun start(host: String) = instancePool[host]?.start() ?: false
|
||||
fun start(id: String) = instancePool[id]?.start() ?: false
|
||||
|
||||
fun stop(host: String) = instancePool[host]?.stop() ?: false
|
||||
fun stop(id: String) = instancePool[id]?.stop() ?: false
|
||||
|
||||
fun getVersion(): String = meoAssistant.AsstGetVersion()
|
||||
|
||||
@@ -73,5 +82,22 @@ object MaaService {
|
||||
fun listInstance(): List<MaaInstanceInfo> =
|
||||
instancePool.values.map { e -> MaaInstanceInfo(e.id, e.host, e.adbPath, e.uuid, e.status) }.toList()
|
||||
|
||||
fun destroy(id: String) = instancePool[id]?.destroy()
|
||||
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun callBackLog(message: CallBackLog) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
wsConnection.forEach { it.session.send(message.toJsonElement().toString()) }
|
||||
}
|
||||
}
|
||||
|
||||
fun addConnection(connection: Connection) {
|
||||
this.wsConnection += connection
|
||||
}
|
||||
|
||||
fun removeConnection(connection: Connection) {
|
||||
this.wsConnection -= connection
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user