新版仿真ws消息推送实现

This commit is contained in:
joylink_zhangsai 2021-04-22 16:04:28 +08:00
parent 303760220a
commit e15ed2db11
16 changed files with 163 additions and 29 deletions

View File

@ -4,10 +4,12 @@ import club.joylink.rtss.constants.MapPrdTypeEnum;
import club.joylink.rtss.simulation.cbtc.data.vo.SimulationVO;
import club.joylink.rtss.simulation.rt.RtSimulationService;
import club.joylink.rtss.vo.LoginUserInfoVO;
import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.map.MapVO;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
@RestController
@RequestMapping("/rtSimulation")
@ -33,4 +35,16 @@ public class RtSimulationController {
return rtSimulationService.getMapData(id);
}
@ApiOperation(value = "退出计划")
@PostMapping("/{id}/planOver")
public void planOver(@PathVariable String id) {
this.rtSimulationService.init(id);
}
@ApiOperation(value = "清除仿真")
@DeleteMapping("/{group}/clear")
public void clearSimulation(@PathVariable String group, @ApiIgnore @RequestAttribute UserVO user) {
this.rtSimulationService.clearSimulation(group, user);
}
}

View File

@ -370,6 +370,10 @@ public abstract class Simulation<U extends SimulationUser, M extends Simulation
return member;
}
public List<M> getSimulationMembers() {
return new ArrayList<>(this.simulationMemberMap.values());
}
public List<M> querySimulationMembersOfRole(Object role) {
return this.simulationMemberMap.values().stream()
.filter(m -> Objects.equals(m.getRole(), role))

View File

@ -43,6 +43,11 @@ public class SimulationCommonController {
this.simulationManager.updateSpeed(id, speed);
}
@GetMapping("/{id}/members")
public List<SimulationMember> getSimulationMembers(@PathVariable String id) {
return this.simulationManager.getSimulationMembers(id);
}
@PostMapping("/{id}/member/{memberId}/operate/{type}")
public Object operate(@PathVariable String id, @PathVariable String memberId,
@PathVariable String type, @RequestBody Map<String, Object> params) {
@ -54,6 +59,11 @@ public class SimulationCommonController {
this.simulationManager.memberPlayedByUser(id, memberId, userId);
}
@GetMapping("/{id}/users")
public List<SimulationUser> getSimulationUsers(@PathVariable String id) {
return this.simulationManager.getSimulationUsers(id);
}
@DeleteMapping("/{id}/destroy")
public void destroy(@PathVariable String id) {
this.simulationManager.destroy(id);

View File

@ -3,6 +3,7 @@ package club.joylink.rtss.simulation;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.event.SimulationMemberPlayChangeEvent;
import club.joylink.rtss.simulation.messaging.websocket.DefaultMessageSender;
import club.joylink.rtss.simulation.rt.RtSimulation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
@ -144,4 +145,14 @@ public class SimulationManager {
public List<Simulation> getSimulationList() {
return new ArrayList<>(simulationCache.values());
}
public List<SimulationMember> getSimulationMembers(String id) {
Simulation simulation = getById(id);
return simulation.getSimulationMembers();
}
public List<SimulationUser> getSimulationUsers(String id) {
Simulation simulation = getById(id);
return simulation.getSimulationUsers();
}
}

View File

@ -44,14 +44,14 @@ public abstract class SimulationUser {
BusinessExceptionAssertEnum.OPERATION_NOT_SUPPORTED
.assertNotTrue(set.contains(destination));
set.add(destination);
log.debug(String.format("用户[%s]订阅[%s-%s]", wsSessionId, destination));
log.debug(String.format("用户[%s]订阅[%s-%s]", this.id, wsSessionId, destination));
}
public void unsubscribe(String wsSessionId, String destination) {
Set<String> set = wsSubscribeMap.get(wsSessionId);
if (set != null) {
set.remove(destination);
log.debug(String.format("用户[%s]取消了订阅[%s-%s]", wsSessionId, destination));
log.debug(String.format("用户[%s]取消了订阅[%s-%s]", this.id, wsSessionId, destination));
}
}
@ -66,7 +66,7 @@ public abstract class SimulationUser {
public void disconnect(String wsSessionId) {
this.wsSubscribeMap.remove(wsSessionId);
log.debug(String.format("用户[%s]断开了连接[%s]", wsSessionId));
log.debug(String.format("用户[%s]断开了连接[%s]", this.id, wsSessionId));
}
public void play(SimulationMember member) {

View File

@ -16,7 +16,7 @@ public class AtsApiService {
AtsSwitch atsSwitch = atsRepository.getSwitchById(cilSwitch.getId());
if (atsSwitch.getPosition() != cilSwitch.getPosition()) {
atsSwitch.setPosition(cilSwitch.getPosition());
atsRepository.ready2Send(atsSwitch.getId());
atsRepository.ready2Send(atsSwitch.getId(), 1, atsSwitch.getPosition());
}
}

View File

@ -1,13 +1,16 @@
package club.joylink.rtss.simulation.rt.ATS;
import club.joylink.rtss.simulation.SimulationUser;
import club.joylink.rtss.simulation.rt.ATS.bo.AtsRepository;
import club.joylink.rtss.simulation.rt.ATS.bo.AtsRepositoryBuilder;
import club.joylink.rtss.simulation.rt.CIL.bo.CilDevice;
import club.joylink.rtss.simulation.rt.RtSimulation;
import club.joylink.rtss.simulation.rt.RtSimulationSubscribeTopic;
import club.joylink.rtss.vo.client.map.MapVO;
import club.joylink.rtss.vo.client.map.newmap.MapGraphDataNewVO;
import club.joylink.rtss.vo.client.map.newmap.MapLogicDataNewVO;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
/**
* ATS逻辑
@ -18,4 +21,29 @@ public class AtsLogicService {
AtsRepository atsRepository = AtsRepositoryBuilder.buildFrom(mapVO);
rtSimulation.addRepository(atsRepository);
}
public void addJobs(RtSimulation rtSimulation) {
for (RtSimulationSubscribeTopic topic : RtSimulationSubscribeTopic.values()) {
rtSimulation.addJob("MESSAGE-" + topic.name(), () -> sendMessages(rtSimulation, topic), topic.getRate());
}
}
public void sendMessages(RtSimulation rtSimulation, RtSimulationSubscribeTopic topic) {
AtsRepository repository = rtSimulation.getRepository(AtsRepository.NAME, AtsRepository.class);
List<List<Object>> messages = repository.removeReady2SendMessages();
if (!CollectionUtils.isEmpty(messages)) {
List<SimulationUser> simulationUsers = rtSimulation.getSimulationUsers();
String dest = topic.buildDestination(rtSimulation.getId());
for (SimulationUser simulationUser : simulationUsers) {
if (simulationUser.isSubscribe(dest)) {
rtSimulation.pushMessageToUser(simulationUser.getId(), dest, messages);
}
}
}
}
public List<List<Object>> getAllMessages(RtSimulation rtSimulation) {
AtsRepository repository = rtSimulation.getRepository(AtsRepository.NAME, AtsRepository.class);
return repository.getAllMessages();
}
}

View File

@ -4,6 +4,7 @@ import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.SimulationRepository;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -15,7 +16,7 @@ public class AtsRepository extends SimulationRepository {
// TODO: 2021/4/22 如果设备id有重复那不同类的设备的消息需要分开存
Map<String, List<Object>> messageMap = new HashMap<>();
Map<String, List<Object>> sendMessageMap = new HashMap<>();
Map<String, List<Object>> ready2SendMessageMap = new HashMap<>();
Map<String, AtsRoute> routeMap = new HashMap<>();
Map<String, AtsRunPlan> runPlanMap = new HashMap<>();
@ -48,7 +49,22 @@ public class AtsRepository extends SimulationRepository {
return atsSwitch;
}
public void ready2Send(String id) {
sendMessageMap.putIfAbsent(id, messageMap.get(id));
public void ready2Send(String id, int i, Object value) {
List<Object> message = messageMap.get(id);
if (message != null) {
message.set(i, value);
ready2SendMessageMap.putIfAbsent(id, message);
}
}
public List<List<Object>> removeReady2SendMessages() {
ArrayList<List<Object>> messages = new ArrayList<>(this.ready2SendMessageMap.values());
ready2SendMessageMap.clear();
return messages;
}
public List<List<Object>> getAllMessages() {
return new ArrayList<>(this.messageMap.values());
}
}

View File

@ -26,7 +26,7 @@ public class AtsRepositoryBuilder {
for (MapSwitchVO switchVO : switchList) {
AtsSwitch atsSwitch = new AtsSwitch(switchVO.getCode(), switchVO.getName());
switchMap.put(atsSwitch.getId(), atsSwitch);
messageMap.put(atsSwitch.getId(), atsSwitch.buildMessage());
}
}

View File

@ -1,8 +1,11 @@
package club.joylink.rtss.simulation.rt.ATS.bo;
import club.joylink.rtss.simulation.rt.RtSimulationSubscribeTopic;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import java.util.Arrays;
import java.util.List;
@Getter
@ -13,4 +16,8 @@ public class AtsSwitch extends AtsDevice {
super(id, name);
}
public List<Object> buildMessage() {
return Arrays.asList(id, position);
}
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.rt.CIL;
import club.joylink.rtss.simulation.rt.ATS.AtsApiService;
import club.joylink.rtss.simulation.rt.CIL.bo.*;
import club.joylink.rtss.simulation.rt.RtSimulation;
import club.joylink.rtss.simulation.rt.SRD.SrdApiService;
@ -27,6 +28,9 @@ public class CilLogicService {
@Autowired
private CilRouteLogicService cilRouteLogicService;
@Autowired
private AtsApiService atsApiService;
public void buildRepository(RtSimulation rtSimulation, MapVO mapVO) {
CilRepository cilRepository = CilRepositoryBuilder.buildFrom(mapVO);
rtSimulation.addRepository(cilRepository);
@ -40,6 +44,9 @@ public class CilLogicService {
rtSimulation.addJob("cilMainLogic",
() -> this.mainLogic(rtSimulation, cilRepository),
CilMainLogicRate);
rtSimulation.addJob("cilStateSend2Ats",
() -> sendState2Ats(rtSimulation, cilRepository),
DeviceStateCollectRate);
}
private void collectDeviceState(RtSimulation rtSimulation, CilRepository repository) {
@ -72,4 +79,10 @@ public class CilLogicService {
private void mainLogic(RtSimulation rtSimulation, CilRepository cilRepository) {
this.cilRouteLogicService.routeLogic(rtSimulation, cilRepository);
}
private void sendState2Ats(RtSimulation rtSimulation, CilRepository cilRepository) {
for (CilSwitch cilSwitch : cilRepository.getSwitches()) {
atsApiService.handle(rtSimulation, cilSwitch);
}
}
}

View File

@ -67,6 +67,10 @@ public class CilRepository extends SimulationRepository {
return cilSwitch;
}
public List<CilSwitch> getSwitches() {
return new ArrayList<>(switchMap.values());
}
public CilSignal getSignalById(String id) {
CilSignal cilSignal = this.signalMap.get(id);
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(cilSignal);

View File

@ -32,6 +32,8 @@ public class RtSimulationService {
private SrdLogicService srdLogicService;
@Autowired
private AtsLogicService atsLogicService;
@Autowired
private RtSimulationSubscribeMessageService rtSimulationSubscribeMessageService;
public RtSimulation create(UserVO userVO, Long mapId, MapPrdTypeEnum prdTypeEnum) {
Objects.requireNonNull(mapId);
@ -43,16 +45,17 @@ public class RtSimulationService {
this.simulationManager.save(rtSimulation);
this.srdLogicService.addJobs(rtSimulation);
this.cilLogicService.addJobs(rtSimulation);
this.atsLogicService.addJobs(rtSimulation);
this.initSimulationMember(rtSimulation);
this.initCreatorPlayMember(rtSimulation);
rtSimulation.addSubscribeMessageService(rtSimulationSubscribeMessageService);
simulationManager.start(rtSimulation.getId());
return rtSimulation;
}
private void initCreatorPlayMember(RtSimulation rtSimulation) {
if (MapPrdTypeEnum.LOCAL.equals(rtSimulation.getPrdType())) {
List<RtSimulationMember> memberList = rtSimulation.querySimulationMembersOfRole(RtSimulationMember.Role.LOWS);
this.simulationManager.memberPlayedByUser(rtSimulation.getId(), memberList.get(0).getId(), rtSimulation.getCreator().getId());
}
List<RtSimulationMember> memberList = rtSimulation.querySimulationMembersOfRole(RtSimulationMember.Role.LOWS);
this.simulationManager.memberPlayedByUser(rtSimulation.getId(), memberList.get(0).getId(), rtSimulation.getCreator().getId());
}
private void initSimulationMember(RtSimulation rtSimulation) {
@ -86,4 +89,13 @@ public class RtSimulationService {
RtSimulation rtSimulation = simulationManager.getById(id, RtSimulation.class);
return rtSimulation.getMapVO();
}
public void init(String id) {
RtSimulation rtSimulation = simulationManager.getById(id, RtSimulation.class);
rtSimulation.init();
}
public void clearSimulation(String group, UserVO user) {
}
}

View File

@ -1,11 +1,26 @@
package club.joylink.rtss.simulation.rt;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.Simulation;
import club.joylink.rtss.simulation.SimulationManager;
import club.joylink.rtss.simulation.SimulationSubscribeMessageService;
import club.joylink.rtss.simulation.SimulationUser;
import club.joylink.rtss.simulation.rt.ATS.AtsLogicService;
import club.joylink.rtss.simulation.rt.ATS.bo.AtsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class RtSimulationSubscribeMessageService implements SimulationSubscribeMessageService {
@Autowired
private AtsLogicService atsLogicService;
@Autowired
private SimulationManager simulationManager;
@Override
public boolean acceptedSubscribePath(String destination) {
return RtSimulationSubscribeTopic.hasMatched(destination);
@ -14,16 +29,12 @@ public class RtSimulationSubscribeMessageService implements SimulationSubscribeM
@Override
public Object buildMessageOfSubscribe(String destination) {
RtSimulationSubscribeTopic topic = RtSimulationSubscribeTopic.match(destination);
return null;
}
public void addJobs(RtSimulation rtSimulation) {
for (RtSimulationSubscribeTopic topic : RtSimulationSubscribeTopic.values()) {
rtSimulation.addJob("MESSAGE-" + topic.name(), () -> buildMessages(rtSimulation, topic), topic.getRate());
String id = topic.getId(destination);
RtSimulation simulation = simulationManager.getById(id, RtSimulation.class);
switch (topic) {
case ATS:
return atsLogicService.getAllMessages(simulation);
}
}
public Object buildMessages(RtSimulation rtSimulation, RtSimulationSubscribeTopic topic) {
return null;
}

View File

@ -1,5 +1,6 @@
package club.joylink.rtss.simulation.rt;
import club.joylink.rtss.simulation.Simulation;
import club.joylink.rtss.simulation.rt.SRD.SrdLogicService;
import lombok.Getter;
import org.springframework.util.PropertyPlaceholderHelper;
@ -46,7 +47,8 @@ public enum RtSimulationSubscribeTopic {
}
public boolean isMatch(String destination) {
String[] patterns = StringUtils.tokenizeToStringArray(this.destPattern, PATH_SEPARATOR);
String destPattern = Simulation.MESSAGE_SUB_PREFIX + this.destPattern;
String[] patterns = StringUtils.tokenizeToStringArray(destPattern, PATH_SEPARATOR);
String[] dests = StringUtils.tokenizeToStringArray(destination, PATH_SEPARATOR);
if (patterns.length == dests.length) {
for (int i = 0; i < patterns.length; i++) {
@ -64,7 +66,8 @@ public enum RtSimulationSubscribeTopic {
}
public String getId(String destination) {
String[] patterns = StringUtils.tokenizeToStringArray(this.destPattern, PATH_SEPARATOR);
String destPattern = Simulation.MESSAGE_SUB_PREFIX + this.destPattern;
String[] patterns = StringUtils.tokenizeToStringArray(destPattern, PATH_SEPARATOR);
String[] dests = StringUtils.tokenizeToStringArray(destination, PATH_SEPARATOR);
if (patterns.length == dests.length) {
for (int i = 0; i < patterns.length; i++) {
@ -82,7 +85,8 @@ public enum RtSimulationSubscribeTopic {
public String buildDestination(String simulationId) {
Properties properties = new Properties();
properties.put("id", simulationId);
String dest = placeholderHelper.replacePlaceholders(this.destPattern, properties);
String dest = Simulation.MESSAGE_SUB_PREFIX + this.destPattern;
dest = placeholderHelper.replacePlaceholders(dest, properties);
return dest;
}
}

View File

@ -18,10 +18,10 @@ public class StompClientManager {
WebSocketStompClient stompClient = new WebSocketStompClient(socketClient);
SimulationSessionHandler handler = new SimulationSessionHandler();
ListenableFuture<StompSession> future = stompClient
.connect("ws://192.168.8.129:9000/joylink-websocket?token=aaa",
.connect("ws://192.168.3.120:9000/joylink-websocket?token=cc789dc2b2f003b2593f5eafbf4763bd",
handler, "null");
StompSession stompSession = future.get();
stompSession.subscribe("/user/queue/simulation/1/", handler);
stompSession.subscribe("/user/queue/simulation/11/ats", handler);
}
}