refactor: DTO 字段去下划线 + SimApiBaseResponse 不再可继承 + 删除 SimApiJson/toJsonString
- 纯 POCO DTO 字段去下划线:AuthDto(id/name/applicationId/profileId/scene 等)、 SimApiLoginItem(id/types/meta/extra)、AesBodyRequest(data)、 SimApiBaseResponse 系列(code/message/data/list/page/count/total) - SimApiBaseResponse 去 open(不再允许继承)+ 删 @SerializerParent(无子类继承) - SimApiResponse<T> / SimApiDataResponse 改为组合(自带 code/message/data) - 删除 toJsonString(无使用点,统一走 simapi_serialization) - 删除 SimApiJson.cj:json() → SimApiUtil.json() 直接序列化; escapeJson() 迁入 SimApiUtil - 同步更新所有字段引用(AuthCenter/AuthIam/HttpClient/ExceptionMiddleware 等) - 保留 sqlsharp 实体 User/Bot 的 _ 前缀(soulsoft 宏依赖)
This commit is contained in:
@@ -2,19 +2,19 @@ version = 0
|
||||
|
||||
[requires]
|
||||
soulsoft_extensions_hosting = {version = "1.0.20260528"}
|
||||
soulsoft_web_http = {version = "1.0.20260528"}
|
||||
soulsoft_web_hosting = {version = "1.0.20260528"}
|
||||
soulsoft_extensions_logging = {version = "1.0.20260528"}
|
||||
soulsoft_web_cors = {version = "1.0.20260528"}
|
||||
soulsoft_extensions_options_configuration = {version = "1.0.20260528"}
|
||||
soulsoft_web_http = {version = "1.0.20260528"}
|
||||
soulsoft_extensions_logging = {version = "1.0.20260528"}
|
||||
soulsoft_extensions_configuration = {version = "1.0.20260528"}
|
||||
soulsoft_web_routing = {version = "1.0.20260528"}
|
||||
soulsoft_extensions_logging_console = {version = "1.0.20260528"}
|
||||
soulsoft_serialization = {version = "1.0.20260528"}
|
||||
soulsoft_net_http = {version = "1.0.20260528"}
|
||||
soulsoft_web_mvc = {version = "1.0.20260528"}
|
||||
soulsoft_extensions_injection = {version = "1.0.20260528"}
|
||||
redis = {version = "1.0.20260627"}
|
||||
soulsoft_web_hosting = {version = "1.0.20260528"}
|
||||
soulsoft_extensions_logging_configuration = {version = "1.0.20260528"}
|
||||
soulsoft_identity_claims = {version = "1.0.20260528"}
|
||||
soulsoft_extensions_configuration = {version = "1.0.20260528"}
|
||||
soulsoft_web_mvc = {version = "1.0.20260528"}
|
||||
soulsoft_serialization = {version = "1.0.20260528"}
|
||||
soulsoft_extensions_options = {version = "1.0.20260528"}
|
||||
soulsoft_web_cors = {version = "1.0.20260528"}
|
||||
redis = {version = "1.0.20260627"}
|
||||
soulsoft_extensions_injection = {version = "1.0.20260528"}
|
||||
soulsoft_net_http = {version = "1.0.20260528"}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class SimApiAuthCenter {
|
||||
response.ensureSuccessStatusCode()
|
||||
let json = response.content.readAsString()
|
||||
let resp = JsonSerializer.Deserialize<SimApiBaseResponse>(json)
|
||||
SimApiError.errorWhen(resp._code != 200, code: 400, message: "签名验证失败")
|
||||
SimApiError.errorWhen(resp.code != 200, code: 400, message: "签名验证失败")
|
||||
} finally {
|
||||
response.close()
|
||||
}
|
||||
@@ -92,7 +92,7 @@ public class SimApiAuthCenter {
|
||||
body["keyword"] = keyword
|
||||
body["skip"] = skip
|
||||
body["take"] = take
|
||||
_client.signQuery<Array<AppAndProfileItem>>("/api/auth/group/search", body: SimApiJson.json(Some(body)))
|
||||
_client.signQuery<Array<AppAndProfileItem>>("/api/auth/group/search", body: SimApiUtil.json(Some(body)))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +102,7 @@ public class SimApiAuthCenter {
|
||||
var body = HashMap<String, Any>()
|
||||
body["profileId"] = profileId
|
||||
body["groupId"] = groupId
|
||||
_client.signQuery<GroupDetailTreeNode>("/api/auth/group/detail", body: SimApiJson.json(Some(body)))
|
||||
_client.signQuery<GroupDetailTreeNode>("/api/auth/group/detail", body: SimApiUtil.json(Some(body)))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,7 +113,7 @@ public class SimApiAuthCenter {
|
||||
body["groupId"] = groupId
|
||||
body["profileId"] = profileId
|
||||
_client.signQuery<Array<String>>("/api/auth/internal/group/related-group-ids",
|
||||
body: SimApiJson.json(Some(body)))
|
||||
body: SimApiUtil.json(Some(body)))
|
||||
}
|
||||
|
||||
// ===== Profile 相关 =====
|
||||
@@ -126,7 +126,7 @@ public class SimApiAuthCenter {
|
||||
body["keyword"] = keyword
|
||||
body["skip"] = skip
|
||||
body["take"] = take
|
||||
_client.signQuery<Array<AppAndProfileItem>>("/api/auth/profile/search", body: SimApiJson.json(Some(body)))
|
||||
_client.signQuery<Array<AppAndProfileItem>>("/api/auth/profile/search", body: SimApiUtil.json(Some(body)))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +139,7 @@ public class SimApiAuthCenter {
|
||||
arr.add(id)
|
||||
}
|
||||
body["ids"] = arr.toArray()
|
||||
_client.signQuery<Array<AppAndProfileItem>>("/api/auth/profile/list", body: SimApiJson.json(Some(body)))
|
||||
_client.signQuery<Array<AppAndProfileItem>>("/api/auth/profile/list", body: SimApiUtil.json(Some(body)))
|
||||
}
|
||||
|
||||
// ===== AuthGate 内部应用专用 =====
|
||||
@@ -151,7 +151,7 @@ public class SimApiAuthCenter {
|
||||
var body = HashMap<String, Any>()
|
||||
body["ProfileId"] = profileId
|
||||
body["AppId"] = applicationId
|
||||
_client.signQuery<Bool>("/api/auth/internal/app/check-owner", body: SimApiJson.json(Some(body)))
|
||||
_client.signQuery<Bool>("/api/auth/internal/app/check-owner", body: SimApiUtil.json(Some(body)))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -166,7 +166,7 @@ public class SimApiAuthCenter {
|
||||
}
|
||||
body["AllowedAppIds"] = arr.toArray()
|
||||
_client.signQuery<Array<AppAndProfileItem>>("/api/auth/internal/app/related",
|
||||
body: SimApiJson.json(Some(body)))
|
||||
body: SimApiUtil.json(Some(body)))
|
||||
}
|
||||
|
||||
// ===== 系统登录 =====
|
||||
@@ -184,7 +184,7 @@ public class SimApiAuthCenter {
|
||||
if (let Some(scene) <- scene) { body["scene"] = scene }
|
||||
if (let Some(data) <- data) { body["data"] = data }
|
||||
if (let Some(backUrl) <- backUrl) { body["backUrl"] = backUrl }
|
||||
let code = _client.signQuery<String>("/api/auth/login/code", body: SimApiJson.json(Some(body)))
|
||||
let code = _client.signQuery<String>("/api/auth/login/code", body: SimApiUtil.json(Some(body)))
|
||||
let server = _client.server
|
||||
GetCodeResponse(code, server, "${server}/auth?code=${code}")
|
||||
}
|
||||
@@ -195,10 +195,10 @@ public class SimApiAuthCenter {
|
||||
public func getLoginInfo(code: String, scene!: ?String = None): LoginInfoResponse {
|
||||
var body = HashMap<String, Any>()
|
||||
body["code"] = code
|
||||
// 说明:C# 的 ErrorWhenNull(resp, 400232, "登录信息获取失败") 对应 signQuery 内部 _data.getOrThrow() 的
|
||||
// 说明:C# 的 ErrorWhenNull(resp, 400232, "登录信息获取失败") 对应 signQuery 内部 data.getOrThrow() 的
|
||||
// None 分支;仓颉版 signQuery 返回非空 T(data 缺失即抛异常),故此处无需重复判空。
|
||||
let resp = _client.signQuery<LoginInfoResponse>("/api/auth/login/get", body: SimApiJson.json(Some(body)))
|
||||
SimApiError.errorWhen(resp._scene != scene, code: 403003, message: "登录场景不匹配")
|
||||
let resp = _client.signQuery<LoginInfoResponse>("/api/auth/login/get", body: SimApiUtil.json(Some(body)))
|
||||
SimApiError.errorWhen(resp.scene != scene, code: 403003, message: "登录场景不匹配")
|
||||
resp
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ public class SimApiAuthCenter {
|
||||
if (let Some(data) <- data) { body["data"] = data }
|
||||
if (let Some(backUrl) <- backUrl) { body["backUrl"] = backUrl }
|
||||
body["profileId"] = userId
|
||||
let code = _client.signQuery<String>("/api/auth/confirm/code", body: SimApiJson.json(Some(body)))
|
||||
let code = _client.signQuery<String>("/api/auth/confirm/code", body: SimApiUtil.json(Some(body)))
|
||||
let server = _client.server
|
||||
GetCodeResponse(code, server, "${server}/confirm?code=${code}")
|
||||
}
|
||||
@@ -225,14 +225,14 @@ public class SimApiAuthCenter {
|
||||
public func confirm(code: String, scene: String, userId!: ?String = None): ConfirmResponse {
|
||||
var body = HashMap<String, Any>()
|
||||
body["code"] = code
|
||||
let resp = _client.signQuery<ConfirmResponse>("/api/auth/confirm/get", body: SimApiJson.json(Some(body)))
|
||||
SimApiError.errorWhen(userId != Some(resp._profileId), code: 403002, message: "安全确认身份不匹配")
|
||||
SimApiError.errorWhen(resp._scene != scene, code: 403003, message: "安全确认场景不匹配")
|
||||
let resp = _client.signQuery<ConfirmResponse>("/api/auth/confirm/get", body: SimApiUtil.json(Some(body)))
|
||||
SimApiError.errorWhen(userId != Some(resp.profileId), code: 403002, message: "安全确认身份不匹配")
|
||||
SimApiError.errorWhen(resp.scene != scene, code: 403003, message: "安全确认场景不匹配")
|
||||
resp
|
||||
}
|
||||
|
||||
/// 简单单字段请求体:{"field":"value"}
|
||||
private static func simpleBody(field: String, value: String): String {
|
||||
"{\"${field}\":\"${SimApiJson.escapeJson(value)}\"}"
|
||||
"{\"${field}\":\"${SimApiUtil.escapeJson(value)}\"}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,49 +18,49 @@ import std.collection.*
|
||||
* 应用/Profile 通用项(对齐 C# AppAndProfileItem)。
|
||||
*/
|
||||
public class AppAndProfileItem {
|
||||
public var _id: String = ""
|
||||
public var _name: String = ""
|
||||
public var _image: ?String = None
|
||||
public var _description: ?String = None
|
||||
public var id: String = ""
|
||||
public var name: String = ""
|
||||
public var image: ?String = None
|
||||
public var description: ?String = None
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全确认响应(对齐 C# ConfirmResponse)。
|
||||
* _data 用 ?HashMap<String, Any> 对齐 C# Dictionary<string,object>?(任意 JSON 对象)。
|
||||
* data 用 ?HashMap<String, Any> 对齐 C# Dictionary<string,object>?(任意 JSON 对象)。
|
||||
*/
|
||||
public class ConfirmResponse {
|
||||
public var _applicationId: String = ""
|
||||
public var _profileId: String = ""
|
||||
public var _scene: ?String = None
|
||||
public var _data: ?HashMap<String, Any> = None
|
||||
public var applicationId: String = ""
|
||||
public var profileId: String = ""
|
||||
public var scene: ?String = None
|
||||
public var data: ?HashMap<String, Any> = None
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录信息响应(对齐 C# LoginInfoResponse)。
|
||||
*/
|
||||
public class LoginInfoResponse {
|
||||
public var _scene: ?String = None
|
||||
public var _data: ?HashMap<String, Any> = None
|
||||
public var _profileId: String = ""
|
||||
public var _name: String = ""
|
||||
public var _image: ?String = None
|
||||
public var _description: ?String = None
|
||||
public var scene: ?String = None
|
||||
public var data: ?HashMap<String, Any> = None
|
||||
public var profileId: String = ""
|
||||
public var name: String = ""
|
||||
public var image: ?String = None
|
||||
public var description: ?String = None
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权码响应(对齐 C# GetCodeResponse)。
|
||||
*/
|
||||
public class GetCodeResponse {
|
||||
public var _code: String = ""
|
||||
public var _server: String = ""
|
||||
public var _fullUrl: String = ""
|
||||
public var code: String = ""
|
||||
public var server: String = ""
|
||||
public var fullUrl: String = ""
|
||||
|
||||
public init() {}
|
||||
|
||||
public init(code: String, server: String, fullUrl: String) {
|
||||
this._code = code
|
||||
this._server = server
|
||||
this._fullUrl = fullUrl
|
||||
this.code = code
|
||||
this.server = server
|
||||
this.fullUrl = fullUrl
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,42 +68,42 @@ public class GetCodeResponse {
|
||||
* 群组关联项(对齐 C# GroupRelatedItem)。
|
||||
*/
|
||||
public class GroupRelatedItem {
|
||||
public var _id: String = ""
|
||||
public var _name: String = ""
|
||||
public var _image: ?String = None
|
||||
public var _description: ?String = None
|
||||
public var _isOwner: Bool = false
|
||||
public var _isAdmin: Bool = false
|
||||
public var _isMember: Bool = false
|
||||
public var id: String = ""
|
||||
public var name: String = ""
|
||||
public var image: ?String = None
|
||||
public var description: ?String = None
|
||||
public var isOwner: Bool = false
|
||||
public var isAdmin: Bool = false
|
||||
public var isMember: Bool = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 群组详情树节点(对齐 C# GroupDetailTreeNode,children 递归)。
|
||||
*/
|
||||
public class GroupDetailTreeNode {
|
||||
public var _id: String = ""
|
||||
public var _name: String = ""
|
||||
public var _image: ?String = None
|
||||
public var _description: ?String = None
|
||||
public var _sort: Int64 = 0
|
||||
public var _children: Array<GroupDetailTreeNode> = []
|
||||
public var id: String = ""
|
||||
public var name: String = ""
|
||||
public var image: ?String = None
|
||||
public var description: ?String = None
|
||||
public var sort: Int64 = 0
|
||||
public var children: Array<GroupDetailTreeNode> = []
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限项(对齐 C# PermissionItem)。
|
||||
*/
|
||||
public class PermissionItem {
|
||||
public var _identifier: String = ""
|
||||
public var _name: String = ""
|
||||
public var _group: String = ""
|
||||
public var _description: String = ""
|
||||
public var identifier: String = ""
|
||||
public var name: String = ""
|
||||
public var group: String = ""
|
||||
public var description: String = ""
|
||||
|
||||
public init() {}
|
||||
|
||||
public init(identifier: String, name: String, group: String, description: String) {
|
||||
this._identifier = identifier
|
||||
this._name = name
|
||||
this._group = group
|
||||
this._description = description
|
||||
this.identifier = identifier
|
||||
this.name = name
|
||||
this.group = group
|
||||
this.description = description
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,15 +29,15 @@ public class SimApiAuthIam {
|
||||
var items = ArrayList<Any>()
|
||||
for (p in permissions) {
|
||||
var item = HashMap<String, Any>()
|
||||
item["identifier"] = p._identifier
|
||||
item["name"] = p._name
|
||||
item["group"] = p._group
|
||||
item["description"] = p._description
|
||||
item["identifier"] = p.identifier
|
||||
item["name"] = p.name
|
||||
item["group"] = p.group
|
||||
item["description"] = p.description
|
||||
items.add(item)
|
||||
}
|
||||
var body = HashMap<String, Any>()
|
||||
body["permissions"] = items.toArray()
|
||||
_client.signQuery<String>("/api/iam/permission/register", body: SimApiJson.json(Some(body)))
|
||||
_client.signQuery<String>("/api/iam/permission/register", body: SimApiUtil.json(Some(body)))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +49,7 @@ public class SimApiAuthIam {
|
||||
if (let Some(groupId) <- groupId) {
|
||||
body["groupId"] = groupId
|
||||
}
|
||||
_client.signQuery<Array<String>>("/api/iam/permission/owned", body: SimApiJson.json(Some(body)))
|
||||
_client.signQuery<Array<String>>("/api/iam/permission/owned", body: SimApiUtil.json(Some(body)))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +62,7 @@ public class SimApiAuthIam {
|
||||
if (let Some(groupId) <- groupId) {
|
||||
body["groupId"] = groupId
|
||||
}
|
||||
let ok = _client.signQuery<Bool>("/api/iam/permission/check", body: SimApiJson.json(Some(body)))
|
||||
let ok = _client.signQuery<Bool>("/api/iam/permission/check", body: SimApiUtil.json(Some(body)))
|
||||
SimApiError.errorWhen(!ok, code: 403, message: "没有该权限")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,33 +6,29 @@
|
||||
package simapi.communications
|
||||
|
||||
import std.collection.*
|
||||
import simapi_serialization.*
|
||||
import simapi_serialization.macros.*
|
||||
|
||||
/**
|
||||
* 基础响应体:所有接口统一返回该结构。
|
||||
* HTTP 状态码始终 200,业务错误通过 code 字段表达。
|
||||
* 序列化/反序列化由 simapi_serialization 反射处理(无需接口/宏);
|
||||
* @SerializerParent 使子类(SimApiResponse<T>/SimApiDataResponse)序列化时包含 _code/_message。
|
||||
* 序列化/反序列化由 simapi_serialization 反射处理(无需接口/宏)。
|
||||
*/
|
||||
@SerializerParent
|
||||
public open class SimApiBaseResponse {
|
||||
public var _code: Int64 = 200
|
||||
public var _message: String = "成功"
|
||||
public class SimApiBaseResponse {
|
||||
public var code: Int64 = 200
|
||||
public var message: String = "成功"
|
||||
|
||||
public init(code: Int64, message: String) {
|
||||
this._code = code
|
||||
this._message = message
|
||||
this.code = code
|
||||
this.message = message
|
||||
}
|
||||
|
||||
public init(code: Int64) {
|
||||
this._code = code
|
||||
this._message = getDefaultMessage(code)
|
||||
this.code = code
|
||||
this.message = getDefaultMessage(code)
|
||||
}
|
||||
|
||||
public init() {
|
||||
this._code = 200
|
||||
this._message = "成功"
|
||||
this.code = 200
|
||||
this.message = "成功"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,20 +46,6 @@ public open class SimApiBaseResponse {
|
||||
case _ => "未知错误代码"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列化为 JSON 字符串(可选 data 字段)。
|
||||
* @param dataJson 已序列化的 data JSON 字符串(可选)。
|
||||
*/
|
||||
public func toJsonString(dataJson!: String = ""): String {
|
||||
var sb = StringBuilder()
|
||||
sb.append("{\"code\":${_code},\"message\":\"${SimApiJson.escapeJson(_message)}\"")
|
||||
if (!dataJson.isEmpty()) {
|
||||
sb.append(",\"data\":${dataJson}")
|
||||
}
|
||||
sb.append("}")
|
||||
sb.toString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,18 +54,18 @@ public open class SimApiBaseResponse {
|
||||
* 说明:泛型类暂不通过反射序列化,可手动转换为 SimApiResponse。
|
||||
*/
|
||||
public class PageResponse<T> {
|
||||
public var _list: Array<T> = Array<T>()
|
||||
public var _page: Int64 = 1
|
||||
public var _count: Int64 = 20
|
||||
public var _total: Int64 = 0
|
||||
public var list: Array<T> = Array<T>()
|
||||
public var page: Int64 = 1
|
||||
public var count: Int64 = 20
|
||||
public var total: Int64 = 0
|
||||
|
||||
public init() {}
|
||||
|
||||
public init(list: Array<T>, page: Int64, count: Int64, total: Int64) {
|
||||
this._list = list
|
||||
this._page = page
|
||||
this._count = count
|
||||
this._total = total
|
||||
this.list = list
|
||||
this.page = page
|
||||
this.count = count
|
||||
this.total = total
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,28 +73,29 @@ public class PageResponse<T> {
|
||||
* 带数据的动态响应。
|
||||
* @param T 数据类型。
|
||||
* 序列化/反序列化由 simapi_serialization 反射处理:
|
||||
* - data 为对象/数组/标量,反射递归
|
||||
* - code/message/data 为普通字段,反射递归
|
||||
* - data 支持任意 T(免约束)
|
||||
* 注:泛型嵌套(SimApiResponse<T>)的反射反序列化已验证可用。
|
||||
*/
|
||||
public class SimApiResponse<T> <: SimApiBaseResponse {
|
||||
public var _data: ?T = None
|
||||
public class SimApiResponse<T> {
|
||||
public var code: Int64 = 200
|
||||
public var message: String = "成功"
|
||||
public var data: ?T = None
|
||||
|
||||
public init() {
|
||||
super()
|
||||
}
|
||||
public init() {}
|
||||
|
||||
public init(data: T) {
|
||||
super()
|
||||
this._data = Some(data)
|
||||
this.data = Some(data)
|
||||
}
|
||||
|
||||
public init(code: Int64, message: String) {
|
||||
super(code, message)
|
||||
this.code = code
|
||||
this.message = message
|
||||
}
|
||||
|
||||
public init(code: Int64, message: String, data: T) {
|
||||
super(code, message)
|
||||
this._data = Some(data)
|
||||
this.code = code
|
||||
this.message = message
|
||||
this.data = Some(data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,27 +12,28 @@ package simapi.communications
|
||||
* SimApiRequestDelegateFactory 派发结果时统一包装 DTO/数组/动态结构。
|
||||
*
|
||||
* 序列化/反序列化由 simapi_serialization 反射处理:
|
||||
* - data 为对象/数组/标量,反射递归
|
||||
* - code/message/data 为普通字段,反射递归
|
||||
* - data 为动态结构(HashMap<String, Any>)同样反射支持
|
||||
*/
|
||||
public class SimApiDataResponse <: SimApiBaseResponse {
|
||||
public var _data: ?Any = None
|
||||
public class SimApiDataResponse {
|
||||
public var code: Int64 = 200
|
||||
public var message: String = "成功"
|
||||
public var data: ?Any = None
|
||||
|
||||
public init() {
|
||||
super()
|
||||
}
|
||||
public init() {}
|
||||
|
||||
public init(data: Any) {
|
||||
super()
|
||||
this._data = Some(data)
|
||||
this.data = Some(data)
|
||||
}
|
||||
|
||||
public init(code: Int64, message: String) {
|
||||
super(code, message)
|
||||
this.code = code
|
||||
this.message = message
|
||||
}
|
||||
|
||||
public init(code: Int64, message: String, data: Any) {
|
||||
super(code, message)
|
||||
this._data = Some(data)
|
||||
this.code = code
|
||||
this.message = message
|
||||
this.data = Some(data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2025 SimcuTeam. All rights reserved.
|
||||
* 移植自 C# 项目 SimApi(E:\simcu\simapi-net),遵循 MIT 许可证。
|
||||
* JSON 序列化统一工具(对应 C# SimApiUtil.Json)。
|
||||
*/
|
||||
|
||||
package simapi.communications
|
||||
|
||||
import std.collection.*
|
||||
import simapi_serialization.*
|
||||
|
||||
/**
|
||||
* JSON 序列化静态工具类。
|
||||
*
|
||||
* 说明:序列化核心委托给 simapi_serialization(JsonSerializer.Serialize),
|
||||
* 全框架 JSON 输出统一走此处,保证与序列化库行为一致。
|
||||
*/
|
||||
public class SimApiJson {
|
||||
private init() {}
|
||||
|
||||
/**
|
||||
* 对象序列化为 JSON 字符串(统一入口)。
|
||||
* @param obj 任意对象(None 输出 null)。
|
||||
*/
|
||||
public static func json(obj: ?Any): String {
|
||||
if (let Some(obj) <- obj) {
|
||||
return JsonSerializer.Serialize(obj)
|
||||
}
|
||||
"null"
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON 字符串转义(统一入口)。
|
||||
* @param s 原始字符串。
|
||||
* @return 转义后可直接放入 JSON 字符串字面量的内容。
|
||||
*/
|
||||
public static func escapeJson(s: String): String {
|
||||
var sb = StringBuilder()
|
||||
for (c in s.runes()) {
|
||||
match (c) {
|
||||
case '"' => sb.append("\\\"")
|
||||
case '\\' => sb.append("\\\\")
|
||||
case '\n' => sb.append("\\n")
|
||||
case '\r' => sb.append("\\r")
|
||||
case '\t' => sb.append("\\t")
|
||||
case _ => sb.append(c)
|
||||
}
|
||||
}
|
||||
sb.toString()
|
||||
}
|
||||
}
|
||||
@@ -13,27 +13,27 @@ import std.collection.*
|
||||
* 对齐 C# SimApiLoginItem(Id / Type / Meta / Extra)。
|
||||
*
|
||||
* 序列化/反序列化由 simapi_serialization 反射处理(免标注、免约束),
|
||||
* 字段 _id/_types/_meta/_extra 全部为受支持类型(String/Array/HashMap)。
|
||||
* 字段 id/types/meta/extra 全部为受支持类型(String/Array/HashMap)。
|
||||
*/
|
||||
public class SimApiLoginItem {
|
||||
public var _id: String = ""
|
||||
public var _types: Array<String> = ["user"]
|
||||
public var _meta: HashMap<String, String> = HashMap<String, String>()
|
||||
public var _extra: HashMap<String, Any> = HashMap<String, Any>()
|
||||
public var id: String = ""
|
||||
public var types: Array<String> = ["user"]
|
||||
public var meta: HashMap<String, String> = HashMap<String, String>()
|
||||
public var extra: HashMap<String, Any> = HashMap<String, Any>()
|
||||
|
||||
public init() {}
|
||||
|
||||
public init(id: String) {
|
||||
this._id = id
|
||||
this._types = ["user"]
|
||||
this._meta = HashMap<String, String>()
|
||||
this._extra = HashMap<String, Any>()
|
||||
this.id = id
|
||||
this.types = ["user"]
|
||||
this.meta = HashMap<String, String>()
|
||||
this.extra = HashMap<String, Any>()
|
||||
}
|
||||
|
||||
public init(id: String, types: Array<String>) {
|
||||
this._id = id
|
||||
this._types = types
|
||||
this._meta = HashMap<String, String>()
|
||||
this._extra = HashMap<String, Any>()
|
||||
this.id = id
|
||||
this.types = types
|
||||
this.meta = HashMap<String, String>()
|
||||
this.extra = HashMap<String, Any>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import simapi.interfaces.*
|
||||
* AES body 请求({"data": "密文"},对齐 C# SimApiOneFieldRequest<string>)。
|
||||
*/
|
||||
public class AesBodyRequest {
|
||||
public var _data: String = ""
|
||||
public var data: String = ""
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +54,7 @@ public class SimApiAesBodyChecker {
|
||||
|
||||
// 2. 反序列化 {"data": "密文"}
|
||||
let req = JsonSerializer.Deserialize<AesBodyRequest>(body)
|
||||
if (req._data.isEmpty()) {
|
||||
if (req.data.isEmpty()) {
|
||||
SimApiError.error(code: 400, message: "请求体缺少密文Data字段")
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public class SimApiAesBodyChecker {
|
||||
}
|
||||
|
||||
// 5. 解密
|
||||
let jsonStr = SimApiAesUtil.decrypt(req._data, key.getOrThrow())
|
||||
let jsonStr = SimApiAesUtil.decrypt(req.data, key.getOrThrow())
|
||||
if (jsonStr.isEmpty()) {
|
||||
SimApiError.error(code: 400, message: "解密失败")
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ public class SimApiAuth {
|
||||
public func login(loginItem: SimApiLoginItem, expireSeconds!: Int64 = 604800, token!: String = ""): String {
|
||||
let newToken = if (token.isEmpty()) { generateToken() } else { token }
|
||||
let tokenKey = "${tokenCachePrefix}${newToken}"
|
||||
let setKey = "${tokenSetCachePrefix}${loginItem._id}"
|
||||
let setKey = "${tokenSetCachePrefix}${loginItem.id}"
|
||||
let json = loginItemJson(loginItem)
|
||||
|
||||
if (let Some(redis) <- _redis) {
|
||||
@@ -93,10 +93,10 @@ public class SimApiAuth {
|
||||
redis.expire(setKey, expireSeconds)
|
||||
} else {
|
||||
_tokenStore[newToken] = TokenEntry(json, nowMillis() + expireSeconds * 1000)
|
||||
var tokens = _userTokens.get(loginItem._id)
|
||||
var tokens = _userTokens.get(loginItem.id)
|
||||
if (tokens == None) {
|
||||
tokens = HashSet<String>()
|
||||
_userTokens[loginItem._id] = tokens.getOrThrow()
|
||||
_userTokens[loginItem.id] = tokens.getOrThrow()
|
||||
}
|
||||
tokens.getOrThrow().add(newToken)
|
||||
}
|
||||
@@ -187,7 +187,7 @@ public class SimApiAuth {
|
||||
public func logout(token: String): Unit {
|
||||
let item = getLogin(token)
|
||||
if (let Some(item) <- item) {
|
||||
removeTokenOfUser(item._id, token)
|
||||
removeTokenOfUser(item.id, token)
|
||||
}
|
||||
let tokenKey = "${tokenCachePrefix}${token}"
|
||||
if (let Some(redis) <- _redis) {
|
||||
|
||||
@@ -131,8 +131,8 @@ public open class SimApiHttpClient {
|
||||
SimApiError.errorWhenFalse(response.isSuccessStatusCode, code: response.statusCode, message: "HTTP ERROR: ${response.statusCode}")
|
||||
let json = response.content.readAsString()
|
||||
let result = JsonSerializer.Deserialize<SimApiResponse<T>>(json)
|
||||
SimApiError.errorWhen(result._code != 200, code: result._code, message: result._message)
|
||||
return result._data.getOrThrow()
|
||||
SimApiError.errorWhen(result.code != 200, code: result.code, message: result.message)
|
||||
return result.data.getOrThrow()
|
||||
} finally {
|
||||
response.close()
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ struct SimApiActionInvoker {
|
||||
let requiredTypes = auth.`type`.split(",")
|
||||
var matched = false
|
||||
for (t in requiredTypes) {
|
||||
if (loginItem._types.contains(t)) {
|
||||
if (loginItem.types.contains(t)) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
|
||||
@@ -172,10 +172,34 @@ public class SimApiUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象序列化为 JSON 字符串(委托给 SimApiJson.json 统一实现,对齐 C# SimApiUtil.Json)。
|
||||
* 将对象序列化为 JSON 字符串(对齐 C# SimApiUtil.Json)。
|
||||
* @param obj 任意对象(None 输出 null)。
|
||||
*/
|
||||
public static func json(obj: ?Any): String {
|
||||
SimApiJson.json(obj)
|
||||
if (let Some(obj) <- obj) {
|
||||
return JsonSerializer.Serialize(obj)
|
||||
}
|
||||
"null"
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON 字符串转义(对齐 C# 内部转义逻辑)。
|
||||
* @param s 原始字符串。
|
||||
* @return 转义后可直接放入 JSON 字符串字面量的内容。
|
||||
*/
|
||||
public static func escapeJson(s: String): String {
|
||||
var sb = StringBuilder()
|
||||
for (c in s.runes()) {
|
||||
match (c) {
|
||||
case '"' => sb.append("\\\"")
|
||||
case '\\' => sb.append("\\\\")
|
||||
case '\n' => sb.append("\\n")
|
||||
case '\r' => sb.append("\\r")
|
||||
case '\t' => sb.append("\\t")
|
||||
case _ => sb.append(c)
|
||||
}
|
||||
}
|
||||
sb.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,7 +218,7 @@ public class SimApiUtil {
|
||||
* @return Base64 字符串。
|
||||
*/
|
||||
public static func base64Encode(obj: Any): String {
|
||||
let json = SimApiJson.json(Some(obj))
|
||||
let json = json(Some(obj))
|
||||
base64Encode(json)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ public class SimApiExceptionMiddleware <: IMiddleware {
|
||||
}
|
||||
var response = SimApiBaseResponse(simEx.code, message)
|
||||
if (context.response.statusCode == 404) {
|
||||
response._message = "接口不存在"
|
||||
response.message = "接口不存在"
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import soulsoft_extensions_logging.*
|
||||
import simapi_serialization.*
|
||||
import simapi.communications.*
|
||||
import simapi.configurations.*
|
||||
import simapi.helpers.*
|
||||
|
||||
/**
|
||||
* 请求日志中间件:记录请求方法、URL、请求头、请求体、响应状态码、耗时与异常。
|
||||
@@ -93,7 +94,7 @@ public class SimApiRequestLogMiddleware <: IMiddleware {
|
||||
var first = true
|
||||
for ((name, values) in context.request.headers) {
|
||||
if (!first) { sb.append(",") }
|
||||
sb.append("\"${SimApiJson.escapeJson(name)}\":\"${SimApiJson.escapeJson(joinValues(values))}\"")
|
||||
sb.append("\"${SimApiUtil.escapeJson(name)}\":\"${SimApiUtil.escapeJson(joinValues(values))}\"")
|
||||
first = false
|
||||
}
|
||||
sb.append("}\n")
|
||||
@@ -147,15 +148,15 @@ public class SimApiRequestLogMiddleware <: IMiddleware {
|
||||
var first = true
|
||||
for ((k, v) in map) {
|
||||
if (!first) { sb.append(",") }
|
||||
sb.append("\"${SimApiJson.escapeJson(k)}\":")
|
||||
sb.append("\"${SimApiUtil.escapeJson(k)}\":")
|
||||
if (let s: String <- v) {
|
||||
if (s.size > maxLen) {
|
||||
sb.append("\"${SimApiJson.escapeJson(s[0..maxLen])}...(${s.size})\"")
|
||||
sb.append("\"${SimApiUtil.escapeJson(s[0..maxLen])}...(${s.size})\"")
|
||||
} else {
|
||||
sb.append("\"${SimApiJson.escapeJson(s)}\"")
|
||||
sb.append("\"${SimApiUtil.escapeJson(s)}\"")
|
||||
}
|
||||
} else {
|
||||
sb.append(SimApiJson.json(Some(v)))
|
||||
sb.append(SimApiUtil.json(Some(v)))
|
||||
}
|
||||
first = false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user