This commit is contained in:
2025-11-03 10:33:30 +08:00
parent 148583cdaa
commit e924e8c0e6
46 changed files with 1151 additions and 428 deletions

View File

@@ -1,6 +1,15 @@
package quant.rich.emoney.controller.api;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.NonNull;
@@ -9,27 +18,110 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.nano.MessageNano;
import org.apache.commons.lang3.StringUtils;
import jakarta.annotation.PostConstruct;
import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import nano.BaseResponse.Base_Response;
import quant.rich.emoney.annotation.ResponseDecodeExtension;
import quant.rich.emoney.entity.sqlite.ProtocolMatch;
import quant.rich.emoney.exception.RException;
import quant.rich.emoney.pojo.dto.EmoneyConvertResult;
import quant.rich.emoney.pojo.dto.EmoneyProtobufBody;
import quant.rich.emoney.service.sqlite.ProtocolMatchService;
import quant.rich.emoney.service.sqlite.StrategyAndPoolService;
import quant.rich.emoney.util.SpringBeanDetector;
import quant.rich.emoney.util.SpringContextHolder;
/**
* 益盟 ProtocolBuf 报文解析 API 控制器
*/
@RestController
@RequestMapping("/api/v1/proto")
@Slf4j
public class ProtoDecodeControllerV1 {
@Autowired
private ProtocolMatchService protocolMatchService;
ProtocolMatchService protocolMatchService;
@Autowired
StrategyAndPoolService strategyAndPoolService;
@Autowired
Reflections reflections;
Map<String, List<MethodInfo>> responseDecodeExtensions = new HashMap<String, List<MethodInfo>>();
@Data
@AllArgsConstructor
private static class MethodInfo {
Method method;
Class<?> declaringClass;
Integer order;
}
@PostConstruct
void postConstruct() {
// Reflections 扫描所有注解并根据 protocolId 和 order 排序
Set<Method> methods = reflections.getMethodsAnnotatedWith(ResponseDecodeExtension.class);
for (Method m : methods) {
MethodInfo info;
ResponseDecodeExtension ex = m.getAnnotation(ResponseDecodeExtension.class);
String protocolId = ex.protocolId();
Integer order = ex.order();
// 判断 method 是否为单参数接受 JsonNode 的方法
Class<?>[] parameterTypes = m.getParameterTypes();
Class<?> declaringClass = m.getDeclaringClass();
if (parameterTypes.length != 1 || parameterTypes[0] != JsonNode.class) {
log.warn("方法 {}#{} 不为类型为 JsonNode 的单参数方法,暂不支持作为解码额外选项",
declaringClass.getSimpleName(), m.getName(), declaringClass.getSimpleName());
continue;
}
// 判断 method 是否是静态
if (Modifier.isStatic(m.getModifiers())) {
info = new MethodInfo(m, null, order);
}
else {
if (!SpringBeanDetector.isSpringManagedClass(declaringClass)) {
log.warn("方法 {} 所属类 {} 不归属于 Spring 管理,目前暂不支持作为解码额外选项",
m.getName(), declaringClass.getSimpleName());
continue;
}
info = new MethodInfo(m, declaringClass, order);
}
List<MethodInfo> list = responseDecodeExtensions.get(protocolId);
if (list == null) {
list = new ArrayList<>();
list.add(info);
responseDecodeExtensions.put(protocolId, list);
}
else {
list.add(info);
}
}
for (List<MethodInfo> list : responseDecodeExtensions.values()) {
list.sort(Comparator.comparingInt(info -> info.getOrder()));
}
log.debug("共载入 {} 个 ProtocolID 的 {} 个方法",
responseDecodeExtensions.keySet().size(), responseDecodeExtensions.values().size());
}
/**
* 解析 emoney protobuf 的请求
* @param <U>
* @param body
* @return
*/
@SuppressWarnings("unchecked")
@PostMapping("/request/decode")
public <U extends MessageNano> EmoneyConvertResult requestDecode(
@@ -39,13 +131,14 @@ public class ProtoDecodeControllerV1 {
Integer protocolId = body.getProtocolId();
if (Objects.isNull(protocolId)) {
throw RException.badRequest("protocolId cannot be null");
throw RException.badRequest("protocolId 不能为 null");
}
ProtocolMatch match = protocolMatchService.getById(protocolId);
if (Objects.isNull(match) || StringUtils.isBlank(match.getClassName())) {
throw RException.badRequest("暂无对应 protocolId = " + protocolId + " 的记录,可等 response decoder 搜集到后重试");
throw RException
.badRequest("暂无对应 protocolId = ", protocolId, " 的记录,可等待 response decoder 收集到后再重试");
}
String className = new StringBuilder()
@@ -111,7 +204,7 @@ public class ProtoDecodeControllerV1 {
Integer protocolId = body.getProtocolId();
ProtocolMatch match = null;
if (Objects.isNull(protocolId)) {
log.warn("protocolId is null, cannot update protocolMatch");
log.warn("protocolId 为空 null, 无法更新 protocolMatch");
}
else {
match = protocolMatchService.getById(protocolId);
@@ -178,8 +271,30 @@ public class ProtoDecodeControllerV1 {
U nano = (U)MessageNano.mergeFrom(
(MessageNano)clazz.getDeclaredConstructor().newInstance(),
baseResponse.detail.getValue());
JsonNode jo = new ObjectMapper().valueToTree(nano);
// 协议 9400 则更新到 StrategyAndPool 里面去
if (protocolId == 9400) {
strategyAndPoolService.updateByQueryResponse(jo);
}
// 查找 ResponseDecodeExtension
List<MethodInfo> methodInfos = responseDecodeExtensions.get(protocolId.toString());
if (methodInfos != null) {
for (MethodInfo methodInfo : methodInfos) {
Object instance = null;
if (methodInfo.getDeclaringClass() != null) {
// 获取 spring 管理的实例类
instance = SpringContextHolder.getBean(methodInfo.getDeclaringClass());
}
// invoke
methodInfo.getMethod().invoke(instance, jo);
}
}
return EmoneyConvertResult
.ok(new ObjectMapper().valueToTree(nano))
.ok((Serializable)jo)
.setProtocolId(protocolId)
.setSupposedClassName(className);
}