-
Notifications
You must be signed in to change notification settings - Fork 1
feat(api): 封装JsonEditorTool为可调用的WebSocket API - 新增JsonApi类,管理多个JsonEditorTool实例 - 添加Tool和ToolData内部类,支持类和字段信息查询 - 实现WebSocket服务器,支持客户端连接和消息广播 - 设计WebSocketData、WebSocketDataType及DataType枚举,定义消息格式 - 实现消息内容自动解析与结构化处理 - 增加日志、错误、警告及调试信息的回调支持 - 兼容不同数据类型的输入输出处理逻辑 - 删除.gitignore中部分冗余文件忽略配置 #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e3584e6
133f74f
f295c93
5e1fadf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
This file was deleted.
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| � | ||
| ɝ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,2 @@ | ||
| 8 | ||
| 7 | ||
| 0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,240 @@ | ||
| package com.mindustry.ide.tool.json | ||
|
|
||
| import kotlinx.serialization.Serializable | ||
| import kotlinx.serialization.json.Json | ||
| import kotlinx.serialization.json.jsonArray | ||
| import kotlinx.serialization.json.jsonObject | ||
| import kotlinx.serialization.json.jsonPrimitive | ||
| import org.java_websocket.WebSocket | ||
| import org.java_websocket.handshake.ClientHandshake | ||
| import org.java_websocket.server.WebSocketServer | ||
| import java.net.InetSocketAddress | ||
|
|
||
|
|
||
| /** | ||
| * 将JsonEditorTool封装成可调用的api | ||
| * @author ZenXSin | ||
| **/ | ||
| class JsonApi { | ||
|
|
||
| val toolManagers = mutableMapOf<String, Pair<JsonEditorTool, Tool>>() | ||
|
|
||
| class Tool(val jet: JsonEditorTool) { | ||
| fun getAllClass(): List<String> { | ||
| return jet.parser.classMap?.keys()?.map { it.toString() } ?: listOf("JsonEditorTool列表为空,请先初始化") | ||
| } | ||
|
|
||
| fun getAllField(className: String): List<String> { | ||
| return jet.parser.classMap?.get(className)?.fields?.map { it.name } ?: listOf("类 $className 不存在,请检查") | ||
| } | ||
|
|
||
| fun getFieldDoc(className: String, fieldName: String): String { | ||
| return jet.parser.getFieldDoc(className, fieldName) | ||
| } | ||
|
|
||
| fun getFieldDefaultValue(className: String, fieldName: String): String { | ||
| return jet.parser.getFieldDefaultValue(className, fieldName) | ||
| } | ||
|
|
||
|
|
||
| } | ||
|
|
||
| class ToolData { | ||
| val classDatas: MutableMap<Int, Tool> = mutableMapOf() | ||
| val parser: JsonParser = JsonParser() | ||
| private var nextId: Int = 0 | ||
|
|
||
| var error: (String) -> Unit = {} | ||
| var info: (String) -> Unit = {} | ||
| var warning: (String) -> Unit = {} | ||
| var debug: (String) -> Unit = {} | ||
|
|
||
| fun newClass(className: String): Int { | ||
| val id = nextId++ | ||
| val tool = Tool(ApiJsonEditorTool(parser)) | ||
| classDatas[id] = tool | ||
| debug("----------") | ||
| debug("创建类: $className, ID: $id") | ||
| debug("----------") | ||
| return id | ||
| } | ||
|
|
||
| fun removeClass(classId: Int): Boolean { | ||
| debug("----------") | ||
| if (classDatas.containsKey(classId)) { | ||
| debug("类 $classId 存在") | ||
| } else { | ||
| debug("类 $classId 不存在") | ||
| } | ||
| debug("删除类: $classId") | ||
| debug("----------") | ||
| return classDatas.remove(classId) != null | ||
| } | ||
|
|
||
| inner class ApiJsonEditorTool(parser: JsonParser) : JsonEditorTool(parser) { | ||
| override fun error(message: String) { | ||
| this@ToolData.error(message) | ||
| } | ||
|
|
||
| override fun info(message: String) { | ||
| this@ToolData.info(message) | ||
| } | ||
|
|
||
| override fun warning(message: String) { | ||
| this@ToolData.warning(message) | ||
| } | ||
|
|
||
| override fun debug(message: String) { | ||
| this@ToolData.debug(message) | ||
| } | ||
| } | ||
|
|
||
| class JsonApiWebSocketHandler(val toolData: ToolData, val port: Int) { | ||
| private var server: Server? = null | ||
|
|
||
| fun start() { | ||
| if (server != null) { | ||
| println("WebSocket 服务器已在运行") | ||
| return | ||
| } | ||
| server = Server(InetSocketAddress(port)) | ||
| server?.start() | ||
| println("WebSocket 服务器启动在端口: $port") | ||
| } | ||
|
|
||
| fun stop() { | ||
| server?.let { | ||
| try { | ||
| it.stop(1000) | ||
| println("WebSocket 服务器已停止") | ||
| } catch (e: Exception) { | ||
| println("停止服务器失败: ${e.message}") | ||
| } finally { | ||
| server = null | ||
| } | ||
| } | ||
| } | ||
|
|
||
| init { | ||
| toolData.info = { | ||
| broadcast("") | ||
| } | ||
| } | ||
|
|
||
| fun broadcast(message: String) { | ||
| server?.broadcast(message) | ||
| println("广播消息: $message") | ||
| } | ||
|
|
||
| class Server(address: InetSocketAddress) : WebSocketServer(address) { | ||
| override fun onOpen(conn: WebSocket, handshake: ClientHandshake) { | ||
| println("客户端连接: ${conn.remoteSocketAddress}") | ||
| } | ||
|
|
||
| override fun onMessage(conn: WebSocket, message: String) { | ||
| println("收到消息: $message") | ||
| conn.send("Echo: $message") | ||
|
Comment on lines
+134
to
+136
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For any client that connects to the new WebSocket server and sends one of the defined request types such as Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| override fun onClose(conn: WebSocket, code: Int, reason: String, remote: Boolean) { | ||
| println("客户端断开: ${conn.remoteSocketAddress}, 原因: $reason") | ||
| } | ||
|
|
||
| override fun onError(conn: WebSocket?, ex: Exception) { | ||
| println("WebSocket 错误: ${ex.message}") | ||
| } | ||
|
|
||
| override fun onStart() { | ||
| println("WebSocket 服务器已启动") | ||
| } | ||
| } | ||
|
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 规范化的Api接口 | ||
| * @author ZenXSin | ||
| * @param content 内容 | ||
| * @param wsType 内容类型 | ||
| * @param out 推送还是接收,默认为接收 | ||
| * @param strList 接收消息时解析的内容,按照wsType中input的顺序排列 | ||
| **/ | ||
|
|
||
| @Serializable | ||
| data class WebSocketData( | ||
| var wsType: WebSocketDataType, | ||
| var content: String, | ||
| var out: Boolean = false, | ||
| var strList: MutableList<String> = mutableListOf() | ||
| ) { | ||
| init { | ||
| if (!out) { | ||
| val json = Json.parseToJsonElement(content) | ||
|
|
||
| for (i in wsType.input) { | ||
| when (i.second) { | ||
| DataType.String -> { | ||
| strList.add(json.jsonObject[i.first]!!.jsonPrimitive.content) | ||
| } | ||
|
|
||
| DataType.Int -> { | ||
| strList.add(json.jsonObject[i.first]!!.jsonPrimitive.content) | ||
| } | ||
|
|
||
| DataType.Float -> { | ||
| strList.add(json.jsonObject[i.first]!!.jsonPrimitive.content) | ||
| } | ||
|
|
||
| DataType.List -> { | ||
| val jsonArray = json.jsonObject[i.first]!!.jsonArray | ||
| strList.add(jsonArray.toString()) //[x1,x2] | ||
| } | ||
|
|
||
| DataType.Boolean -> { | ||
| strList.add(json.jsonObject[i.first]!!.jsonPrimitive.content) | ||
| } | ||
|
|
||
| DataType.Object -> TODO() | ||
| } | ||
| } | ||
| } else { | ||
| //TODO 暂时不知道些什么 | ||
| } | ||
| } | ||
|
|
||
| } | ||
|
|
||
| /** | ||
| * WebSocket推送消息的类型 | ||
| * @author ZenXSin | ||
| * @param input 外部推送接收的内容 | ||
| * @param output 内部推送发送的内容 | ||
| **/ | ||
| enum class WebSocketDataType( | ||
| val input: List<Pair<String, DataType>> = listOf(), | ||
| val output: List<Pair<String, DataType>> = listOf() | ||
| ) { | ||
| Log(listOf("text" to DataType.String)), | ||
| AllClass(output = listOf("Class_List" to DataType.List)), | ||
| AllField(listOf("Class_Name" to DataType.String), listOf("Field_List" to DataType.List)) | ||
| } | ||
|
|
||
| enum class DataType { | ||
| String, Int, Float, List, Boolean, Object | ||
| } | ||
|
|
||
| class InputData { | ||
| var str: String = "" | ||
| var int: Int = 0 | ||
| var float: Float = 0f | ||
| var list: MutableList<InputData> = mutableListOf() | ||
| var boolean: Boolean = false | ||
| var obj: () -> Unit = {} | ||
| } | ||
|
|
||
| //Test | ||
| fun main() { | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the release workflow, a failed
bash ./gradlew assemblenow continues to the artifact upload and release steps instead of failing the job immediately; when the APK build fails late or produces only partial outputs, the workflow can still publish a release without the expected APK, masking the broken build. The same pattern is also applied to the tool jar step below.Useful? React with 👍 / 👎.