Vehicle/src/main/java/com/muyu/service/impl/VehicleInstanceServiceImpl....

428 lines
16 KiB
Java

package com.muyu.service.impl;
import com.alibaba.fastjson2.JSONArray;
import com.muyu.common.PageList;
import com.muyu.common.Result;
import com.muyu.domain.PositionRouteInfo;
import com.muyu.domain.Vehicle;
import com.muyu.domain.model.PositionModel;
import com.muyu.domain.model.TaskModel;
import com.muyu.domain.req.CheckPositionReq;
import com.muyu.domain.req.GearReq;
import com.muyu.domain.req.MsgReq;
import com.muyu.domain.req.VehicleInstanceListReq;
import com.muyu.domain.resp.UnifiedTaskResp;
import com.muyu.domain.resp.VehicleInstanceResp;
import com.muyu.service.PositionRouteService;
import com.muyu.service.VehicleInstanceService;
import com.muyu.utils.MD5Util;
import com.muyu.utils.ReflectUtils;
import com.muyu.vehicle.VehicleInstance;
import com.muyu.vehicle.api.ClientAdmin;
import com.muyu.vehicle.api.req.VehicleConnectionReq;
import com.muyu.vehicle.core.LocalContainer;
import com.muyu.vehicle.model.VehicleData;
import com.muyu.vehicle.model.properties.MqttProperties;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;
/**
* @author DongZeLiang
* @version 1.0
* @description 车辆实例业务实现层
* @date 2023/11/22
*/
@Log4j2
@Service
public class VehicleInstanceServiceImpl implements VehicleInstanceService {
@Autowired
private PositionRouteService positionRouteService;
@Autowired
private ClientAdmin clientAdmin;
@Value("${mqtt.server.host}")
private String broker;
/**
* 根据车辆生成车辆实例
*
* @param vehicle 车辆信息
*/
@Override
public void init(Vehicle vehicle) {
VehicleInstance vehicleInstance = new VehicleInstance();
vehicleInstance.setVehicle(vehicle);
vehicleInstance.setVehicleData(VehicleData.vehicleBuild(vehicle));
LocalContainer.setVehicleInstance(vehicleInstance);
log.debug("构建车辆对象: [{}]", vehicle.getVin());
}
/**
* 车辆结果对象
*
* @param vehicleInstanceListReq 车辆查询
*
* @return 车辆对象
*/
@Override
public PageList<VehicleInstanceResp> queryList (VehicleInstanceListReq vehicleInstanceListReq) {
Stream<VehicleInstance> stream = LocalContainer.vehicleDataMap.values()
.stream();
if (StringUtils.isNotBlank(vehicleInstanceListReq.getVin())){
stream = stream.filter(vehicleInstance ->
vehicleInstance.getVin().contains(vehicleInstanceListReq.getVin()));
}
if (vehicleInstanceListReq.isOnline()){
stream = stream.sorted(Comparator.comparingInt(o -> (o.isOnline() ? 0 : 1)));
}
return PageList.<VehicleInstanceResp>builder()
.total(LocalContainer.total())
.rows(
stream
.map(VehicleInstanceResp::instanceBuild)
.skip((vehicleInstanceListReq.getPage() - 1) * vehicleInstanceListReq.getPageSize())
.limit(vehicleInstanceListReq.getPageSize())
.toList()
)
.build();
}
/**
* 车辆客户端初始化
*
* @param vin vin
*/
@Override
public void vehicleClientInit (String vin) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(vin);
if (vehicleInstance == null){
throw new RuntimeException("没有【"+vin+"】车辆");
}
String timestamp = String.valueOf(System.currentTimeMillis());
VehicleConnectionReq connectionReq = VehicleConnectionReq.builder()
.vin(vin)
.timestamp(timestamp)
.userName(MD5Util.encrypted(vin+timestamp))
.nonce(MD5Util.encrypted(UUID.randomUUID().toString().replace("-", "")))
.build();
Result<String> result = clientAdmin.vehicleConnection(connectionReq);
if (result.getCode() != 200){
log.error("车辆:[{}],申请上线异常:[{}]", vin, result.getMsg());
throw new RuntimeException("远程服务器没有【"+vin+"】车辆");
}
MqttProperties mqttProperties = MqttProperties.builder()
.broker(broker)
.topic(result.getData())
.clientId(vin)
.username(connectionReq.getUserName())
.password(vin+connectionReq.getTimestamp()+connectionReq.getNonce())
.build();
vehicleInstance.setMqttProperties(mqttProperties);
vehicleInstance.initClient();
}
/**
* 车辆客户端关闭
*
* @param vin vin
*/
@Override
public void vehicleClientClose (String vin) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(vin);
vehicleInstance.closeClient();
}
/**
* 选择车辆轨迹
*
* @param checkPositionReq 切换轨迹
*/
@Override
public void checkPosition (CheckPositionReq checkPositionReq) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(checkPositionReq.getVin());
List<PositionModel> positionModelList =
this.positionRouteService.getPositionModelByRouteName(checkPositionReq.getPositionCode());
vehicleInstance.settingPosition(positionModelList);
vehicleInstance.setPositionCode(checkPositionReq.getPositionCode());
}
/**
* 车辆消息操作
*
* @param msgReq
*/
@Override
public void msg (MsgReq msgReq) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(msgReq.getVin());
switch (msgReq.getMsgCode()){
case "上报" -> {
if(vehicleInstance.getVehicleThread() == null){
vehicleInstance.initVehicleThread();
}
vehicleInstance.startSend();
}
case "暂停" -> vehicleInstance.pauseSend();
case "停止" -> vehicleInstance.stopSend();
default -> throw new RuntimeException("车辆消息事件错误");
}
}
/**
* 设置档位
*
* @param gearReq
*/
@Override
public void gear (GearReq gearReq) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(gearReq.getVin());
vehicleInstance.setGear(gearReq.getGear());
}
/**
* 修改车辆报文
*
* @param vin vin
* @param statusKey 状态键
* @param statusValue 状态值
*/
@Override
public void editStatus (String vin, String statusKey, Integer statusValue) {
VehicleInstance vehicleInstance = LocalContainer.getVehicleInstance(vin);
VehicleData vehicleData = vehicleInstance.getVehicleData();
ReflectUtils.invokeSetter(vehicleData, statusKey, statusValue);
}
// private final AtomicBoolean unifiedStatus = new AtomicBoolean(Boolean.TRUE);
/**
* 任务执行模型
*/
private final TaskModel taskModel = new TaskModel();
/**
* 一键上线
*/
@Override
public void unifiedOnline () {
// 获取离线车辆
List<VehicleInstance> offlineVehicleInstanceList
= LocalContainer.getOfflineVehicleInstance();
Thread taskThread = new Thread(() -> {
try {
// 筛选出离线车辆并使用并行流进行上线操作
offlineVehicleInstanceList
.stream()
.parallel()
.map(VehicleInstance::getVin)
.forEach(vin -> {
try {
this.vehicleClientInit(vin);
taskModel.incrementSuccess();
}catch (Exception exception){
log.error("车辆上线异常:{}", exception.getMessage());
taskModel.incrementError();
}
});
} catch (Exception exception) {
log.error("车辆一件上线报错:{}", exception.getMessage(), exception);
}
taskModel.down();
});
taskModel.submit("一键上线", offlineVehicleInstanceList.size(), taskThread);
}
/**
* 一键离线
*/
@Override
public void unifiedOffline () {
List<VehicleInstance> onlineVehicleInstanceList = LocalContainer.getOnlineVehicleInstance();
Thread taskThread = new Thread(() -> {
try {
// 筛选出在线车辆使用并行流操作先停止车辆上报动作再进行车辆离线操作
onlineVehicleInstanceList
.stream()
.parallel()
.forEach(vehicleInstance -> {
try {
vehicleInstance.stopSend();
vehicleInstance.closeClient();
taskModel.incrementSuccess();
}catch (Exception exception){
log.error("车辆离线异常:{}", exception.getMessage());
taskModel.incrementError();
}
});
} catch (Exception exception) {
log.error("车辆一键离线报错:{}", exception.getMessage(), exception);
}
taskModel.down();
});
taskModel.submit("一键离线", onlineVehicleInstanceList.size(), taskThread);
}
/**
* 一键上报
*/
@Override
public void unifiedSend () {
List<VehicleInstance> vehicleInstanceList = LocalContainer.getOnlineVehicleInstance();
if (vehicleInstanceList.isEmpty()){
throw new RuntimeException("还没有车辆连接到服务器,请先让车辆上线");
}
// 获取到所有路径
List<PositionRouteInfo> positionRouteInfoList = positionRouteService.list();
// 路径长度
int positionSize = positionRouteInfoList.size();
// 随机数
Random random = new Random();
Thread taskThread = new Thread(() -> {
try {
vehicleInstanceList
.stream()
.parallel()
.forEach(vehicleInstance -> {
try {
// 随机一个路径结果
int positionIndex = random.nextInt(0, positionSize);
PositionRouteInfo positionRouteInfo = positionRouteInfoList.get(positionIndex);
String positionCode = positionRouteInfo.getName();
List<PositionModel> positionModelList = JSONArray.parseArray(positionRouteInfo.getRouteData(), String.class)
.stream()
.map(PositionModel::strBuild)
.toList();
// 设置车辆路径
vehicleInstance.settingPosition(positionModelList);
vehicleInstance.setPositionCode(positionCode);
// 设置车辆档位
vehicleInstance.setGear("D");
// 开启线程进行上报
if (vehicleInstance.getVehicleThread() == null) {
vehicleInstance.initVehicleThread();
}
vehicleInstance.startSend();
taskModel.incrementSuccess();
}catch (Exception exception){
log.info("车辆设置一键上报失败:{}", exception.getMessage());
taskModel.incrementError();
}
});
} catch (Exception exception) {
log.error("车辆一键上报报错:{}", exception.getMessage(), exception);
}
taskModel.down();
});
taskModel.submit("一键上报", vehicleInstanceList.size(),taskThread);
}
/**
* 一键重置路径
*/
@Override
public void unifiedPosition () {
List<VehicleInstance> vehicleInstanceList = LocalContainer.getOnlineVehicleInstance();
Thread taskThread = new Thread(() -> {
try {
// 获取到所有路径
List<PositionRouteInfo> positionRouteInfoList = positionRouteService.list();
// 路径长度
int positionSize = positionRouteInfoList.size();
// 随机数
Random random = new Random();
vehicleInstanceList
.stream()
.parallel()
.forEach(vehicleInstance -> {
try {
// 随机一个路径结果
int positionIndex = random.nextInt(0, positionSize);
PositionRouteInfo positionRouteInfo = positionRouteInfoList.get(positionIndex);
String positionCode = positionRouteInfo.getName();
List<PositionModel> positionModelList = JSONArray.parseArray(positionRouteInfo.getRouteData(), String.class)
.stream()
.map(PositionModel::strBuild)
.toList();
// 设置车辆路径
vehicleInstance.settingPosition(positionModelList);
vehicleInstance.setPositionCode(positionCode);
taskModel.incrementSuccess();
} catch (Exception exception) {
log.error("车辆设置路线异常:[{}]", exception.getMessage());
taskModel.incrementError();
}
});
} catch (Exception exception) {
log.error("车辆一键重置路径报错:{}", exception.getMessage(), exception);
}
taskModel.down();
});
taskModel.submit("一键重置路径",vehicleInstanceList.size(), taskThread);
}
/**
* 一键取消上报
*/
@Override
public void unifiedStop () {
List<VehicleInstance> onlineVehicleInstanceList = LocalContainer.getOnlineVehicleInstance();
Thread taskThread = new Thread(() -> {
try {
LocalContainer.getOnlineVehicleInstance()
.stream()
.parallel()
.forEach(vehicleInstance -> {
try {
vehicleInstance.stopSend();
taskModel.incrementSuccess();
}catch (Exception exception){
log.info("车辆一键取消上报发生错误:{}", exception.getMessage());
taskModel.incrementError();
}
});
taskModel.down();
} catch (Exception exception) {
log.error("车辆一键取消上报报错:{}", exception.getMessage(), exception);
}
});
taskModel.submit("一键取消上报", onlineVehicleInstanceList.size(), taskThread);
}
/**
* 一键执行状态
*
* @return 一键执行状态
*/
@Override
public UnifiedTaskResp unifiedStatus() {
boolean unifiedStatus = this.taskModel.getUnifiedStatus().get();
return UnifiedTaskResp.builder()
.unifiedStatus(unifiedStatus)
.taskErrorSum(this.taskModel.getErrorSum())
.taskExecutionSum(this.taskModel.getTaskExecutionSum())
.taskSuccessSum(this.taskModel.getSuccessSum())
.taskName(this.taskModel.getTaskName())
.taskStartTime(System.currentTimeMillis() - this.taskModel.getTaskStartTime())
.build();
}
}