石墨消解仪后端服务
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

134 lines
5.2 KiB

3 months ago
  1. package com.iflytop.gd.infrastructure.drivers;
  2. import cn.hutool.core.util.ObjectUtil;
  3. import com.iflytop.gd.system.drivers.CommandBus;
  4. import com.iflytop.gd.system.exceptions.CommandExecTimeoutException;
  5. import com.iflytop.gd.system.exceptions.HardwareErrorException;
  6. import com.iflytop.gd.system.models.DataPacket;
  7. import com.iflytop.gd.system.utils.ByteArray;
  8. import jakarta.annotation.PostConstruct;
  9. import jakarta.websocket.*;
  10. import lombok.extern.slf4j.Slf4j;
  11. import org.springframework.beans.factory.annotation.Value;
  12. import org.springframework.scheduling.annotation.EnableScheduling;
  13. import org.springframework.scheduling.annotation.Scheduled;
  14. import org.springframework.stereotype.Component;
  15. import java.io.IOException;
  16. import java.net.URI;
  17. import java.util.concurrent.CountDownLatch;
  18. import java.util.concurrent.TimeUnit;
  19. /**
  20. * 使用WebSocket实现命令总线功能
  21. */
  22. @Slf4j
  23. @Component
  24. @ClientEndpoint
  25. @EnableScheduling
  26. public class WebSocketCommandBusImpl implements CommandBus {
  27. private Session session;
  28. private CountDownLatch countDownLatch;
  29. private DataPacket lastDataPacket;
  30. private Integer packetIndex = 0;
  31. private final String COMMAND_BUS_WEBSOCKET_URL;
  32. public static final int PACKET_TYPE_CMD = 0xA0;
  33. public static final int PACKET_TYPE_ACK = 0xA1;
  34. public static final int PACKET_TYPE_ERROR_ACK = 0xA2;
  35. public static final int PACKET_TYPE_EVENT = 0xA3;
  36. //TODO 配置硬件服务段ws链接
  37. public WebSocketCommandBusImpl(@Value("${command_bus.websocket_server_url}") String websocketServerUrl) throws DeploymentException, IOException {
  38. this.COMMAND_BUS_WEBSOCKET_URL = websocketServerUrl;
  39. }
  40. @Scheduled(fixedRate = 5000)
  41. @PostConstruct
  42. public void connectToCommandBusWebSocketServer() throws DeploymentException, IOException {
  43. if (this.session == null || !this.session.isOpen()) {
  44. WebSocketContainer container = ContainerProvider.getWebSocketContainer();
  45. URI endpointURI = URI.create(COMMAND_BUS_WEBSOCKET_URL);
  46. try {
  47. this.session = container.connectToServer(this, endpointURI);
  48. } catch (Exception e) {
  49. // log.error(e.getMessage(), e);
  50. }
  51. }
  52. }
  53. @Override
  54. public synchronized DataPacket waitForCommandExec(DataPacket commandPacket, Integer timeout, TimeUnit unit)
  55. throws CommandExecTimeoutException, HardwareErrorException, IOException, InterruptedException {
  56. try {
  57. if (!this.session.isOpen()) {
  58. log.error("Session state={}", this.session.isOpen());
  59. throw new IOException("Session is not open");
  60. }
  61. packetIndex = packetIndex + 1;
  62. if (packetIndex > 30000) {
  63. packetIndex = 1;
  64. }
  65. commandPacket.setPacketIndex(packetIndex);
  66. this.countDownLatch = new CountDownLatch(1);
  67. String byteString = commandPacket.toByteString();
  68. log.info("ModuleId={}, CommandId={}, 数据包二进制字符内容={}", commandPacket.getModuleId(), commandPacket.getCmdId(), byteString);
  69. this.session.getBasicRemote().sendText(byteString);
  70. boolean isTimeout = !this.countDownLatch.await(timeout, unit);
  71. // 命令返回或者超时了
  72. if (isTimeout) {
  73. log.error("Command exec timeout, moduleId={}, commandId={}, timeoutInMilSeconds={}",
  74. commandPacket.getModuleId(), commandPacket.getCmdId(), unit.toMillis(timeout));
  75. throw new CommandExecTimeoutException();
  76. }
  77. log.debug("收到数据包{}", this.lastDataPacket);
  78. // 在指定的时间内得到了响应
  79. if (this.lastDataPacket.getPacketType() == PACKET_TYPE_ERROR_ACK) {
  80. log.error("moduleId={}执行command={}发送硬件错误", this.lastDataPacket.getModuleId(), this.lastDataPacket.getCmdId());
  81. throw new HardwareErrorException();
  82. }
  83. return ObjectUtil.cloneByStream(this.lastDataPacket);
  84. } catch (IOException e) {
  85. log.error("发送指令发生异常", e);
  86. throw e;
  87. } catch (InterruptedException e) {
  88. log.error("Thread: {}被中断", Thread.currentThread().getName());
  89. throw e;
  90. }
  91. }
  92. @OnOpen
  93. public void onOpen(Session session) {
  94. this.session = session;
  95. log.info("WebSocket connection established");
  96. }
  97. @OnMessage
  98. public void onMessage(String message) {
  99. byte[] bytes = ByteArray.hexStringToBytes(message);
  100. log.info("New packet arrived: {}", message);
  101. this.lastDataPacket = new DataPacket(bytes);
  102. if (this.lastDataPacket.getPacketType() == DataPacket.PACKET_TYPE_ACK ||
  103. this.lastDataPacket.getPacketType() == DataPacket.PACKET_TYPE_ERROR_ACK) {
  104. this.countDownLatch.countDown();
  105. }
  106. }
  107. @OnClose
  108. public void onClose() {
  109. if (this.countDownLatch != null) {
  110. this.countDownLatch.countDown();
  111. }
  112. }
  113. @OnError
  114. public void onError(Session session, Throwable throwable) {
  115. if (this.countDownLatch != null) {
  116. this.countDownLatch.countDown();
  117. }
  118. }
  119. }