Files
yuaihealth/admin/src/main/java/cn/unizk/service/UdpServerService2.java
T

921 lines
43 KiB
Java

package cn.unizk.service;
import cn.hutool.core.date.DateUtil;
import cn.unizk.constant.UniConstant;
import cn.unizk.entity.dto.PrDTO;
import cn.unizk.entity.po.*;
import cn.unizk.mapper.*;
import cn.unizk.task.DeviceTask;
import cn.unizk.utils.XorUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author hao
* @Date 2025/9/10 16:17
* @Version 1.0
**/
@Service
@Slf4j
public class UdpServerService2 {
// 存储设备地址的Map,Key可以是设备ID,Value是设备的IP和端口
private ConcurrentHashMap<String, DeviceInfo> deviceMap = new ConcurrentHashMap<>();
private DatagramSocket serverSocket;
private volatile boolean running = false;
private ExecutorService executorService = Executors.newSingleThreadExecutor();
private static final int LISTEN_PORT = 61100; // 监听的端口
private static final long SESSION_TIMEOUT = 60_000;
@Resource
private UdpClientService udpClientService;
@Resource
private DeviceMapper deviceMapper;
@Resource
private DeviceUsageRecordMapper deviceUsageRecordMapper;
@Resource
private DeviceTask deviceTask;
@Resource
private DeviceUsageDetailMapper usageDetailMapper;
@Resource
private DeviceUpgradeMapper upgradeMapper;
@Resource
private FileService fileService;
@Resource(name = "kryoRedisTemplate")
private RedisTemplate redisTemplate;
@Resource
private GeneratePrService generatePrService;
@Resource
private UserTreatmentParametersMapper userTreatmentParametersMapper;
private static final String UPGRADE_PACKAGE_ROOT_PATH = "/opt/jkadmin/upgrade/";
@Getter
@Setter
public static class DeviceInfo {
private String muid;
private String status;
private String ip;
private int port;
private Boolean startCount = false;
private final long lastActiveTime;
// DeviceInfo(){}
/*public boolean getStartCount(){
return this.startCount;
}*/
DeviceInfo(String muid, String status, String ip, int port) {
this.muid = muid;
this.status = status;
this.ip = ip;
this.port = port;
this.startCount = false;
this.lastActiveTime = System.currentTimeMillis();
}
DeviceInfo(String muid, String status, String ip, int port, boolean startCount) {
this.muid = muid;
this.status = status;
this.ip = ip;
this.port = port;
this.startCount = startCount;
this.lastActiveTime = System.currentTimeMillis();
}
}
@PostConstruct
public void startServer() {
try {
serverSocket = new DatagramSocket(LISTEN_PORT);
running = true;
log.info("UDP Server started on port: {}", LISTEN_PORT);
// 启动一个线程来持续接收消息
executorService.execute(this::receivePackets);
} catch (SocketException e) {
log.error("Failed to start UDP server on port: {}", LISTEN_PORT, e);
}
}
@PreDestroy
public void stopServer() {
running = false;
if (serverSocket != null && !serverSocket.isClosed()) {
serverSocket.close();
}
executorService.shutdown();
log.info("UDP Server stopped.");
}
/**
* 持续接收UDP数据包的方法
*/
private void receivePackets() {
byte[] receiveBuffer = new byte[1024]; // 缓冲区
log.info("持续接收UDP数据包,{}", serverSocket.isClosed());
while (running && !serverSocket.isClosed()) {
try {
DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
serverSocket.receive(receivePacket); // 阻塞等待接收数据
log.info("处理接收到的数据包");
// 处理接收到的数据包(可以在新线程中处理,避免阻塞接收)
handlePacket(receivePacket);
} catch (Exception e) {
if (running) { // 只有在运行状态下的异常才打印
log.error("Error receiving packet: ", e);
}
}
}
}
/**
* 处理接收到的UDP数据包
*
* @param packet 接收到的数据包
*/
private void handlePacket(DatagramPacket packet) {
// 获取发送方的IP和端口
String deviceIp = packet.getAddress().getHostAddress();
int devicePort = packet.getPort();
// 获取数据内容并转换为字符串
String receivedMessage = new String(packet.getData(), 0, packet.getLength());
log.info("Received from {}:{} - Message: {}",
deviceIp, devicePort, receivedMessage);
if (StringUtils.isBlank(receivedMessage)) {
log.info("接收到的数据包为空");
return;
}
// 关键步骤:解析数据包,获取设备ID并注册设备地址
// 假设数据包格式为: "muid:XXXXX;Status:Online;"
// 您需要根据硬件同事提供的实际协议格式进行解析
String muid = parsemuid(receivedMessage); // 需要实现此方法
String status = receivedMessage.substring(2, 3);
String status2 = receivedMessage.substring(1, 3);
if ("30".equals(status2)) {
status = "9";
}
log.info("解析得到的muid={}", muid);
log.info("解析得到的状态码是:{}", status);
if (muid != null && !muid.isEmpty()) {
Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
// 将设备信息存入Map
System.out.println("Device registered: " + muid + " at " + deviceIp + ":" + devicePort);
if (Objects.isNull(device)) {
log.info("数据库不存在该设备,muid={}", muid);
} else {
DeviceInfo deviceInfo = deviceMap.get(muid);
if ("1".equals(status)) {
if (Objects.isNull(deviceInfo)) {
log.info("deviceMap缓存中没有{}这个设备", muid);
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
} else {
/*if (deviceInfo.getStartCount() && device.getSurplus() > 0 && device.getPaymentMethod() != null && device.getPaymentMethod() == 2){
log.info("设备状态为01开机,开始计数startCount为true");
int count = device.getSurplus() - 1;
device.setSurplus(count);
device.setExpireTime(String.valueOf(count));
deviceMapper.updateById(device);
}*/
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
}
String lo = null, la = null;
String[] items = receivedMessage.split("\\|");
for (String item : items) {
if (item.startsWith("LO")) {
lo = item.substring(2);
}
if (item.startsWith("LA")) {
la = item.substring(2);
}
}
if (lo != null && la != null) {
device.setLo(lo);
device.setLa(la);
deviceMapper.updateById(device);
}
parseDeviceInfo(device, receivedMessage);
/**
* 拿device的硬件版本和软件版本去查device_upgrade表,如果跟当前版本不一致则升级
*/
DeviceUpgrade upgrade = upgradeMapper.selectOne(new LambdaQueryWrapper<DeviceUpgrade>().eq(DeviceUpgrade::getBeCurrentVersion, 1));
Device nDevice = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
if (Objects.nonNull(upgrade) && upgrade.getHVersion().equals(nDevice.getHw()) && !upgrade.getSVersion().equals(nDevice.getSw()) && nDevice.getUpgradeSwitch() == 1) {
log.info("回复升级心跳,回复升级心跳回复升级心跳,回复升级心跳,回复升级心跳");
replyUpgradeHeartbeat(deviceMap.get(muid), packet);
} else {
/*String o = (String) redisTemplate.opsForValue().get(UniConstant.REDIS_CURRENT_DEVICE_USER + device.getDeviceId());
PrDTO prDTO = generatePrService.generatePr(o);
PrDTO cachePrdto = (PrDTO) redisTemplate.opsForValue().get(o + device.getDeviceId());*/
replyHeartbeat(deviceMap.get(muid), packet, null, null);
}
DeviceUsageDetail detail = new DeviceUsageDetail();
detail.setStatus(status);
recordUse(device, detail);
if (device.getOperatingStatus() == 0) {
changeDeviceOperatingStatus(device.getDeviceId(), 2);
}
}
if ((("1".equals(status) && device.getSurplus() < 1) || device.getForcePay() == 1) && device.getFreeCount() < 1) {
log.info("设备状态为1,无剩余使用次数,马上停,强制付费");
String c1 = "$01|MU{uid}|DT{date}|ON{1}|CF1|WM1|TC000|*{CRC}\r\n";
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
String replace = c1.replace("{uid}", muid).replace("{date}", now).replace("{1}", "0");
String crc = replace.substring(1, replace.lastIndexOf("*"));
String asciiHex = XorUtil.xorAsciiHex(crc);
String s = replace.replace("{CRC}", asciiHex);
byte[] sendData = s.getBytes(StandardCharsets.UTF_8);
DatagramPacket sendPacket = new DatagramPacket(
sendData,
sendData.length,
packet.getSocketAddress()
);
try {
serverSocket.send(sendPacket);
} catch (IOException e) {
e.printStackTrace();
}
deviceMapper.updateStatus(device.getDeviceId(), "0");
}
if ("2".equals(status)) {
updateLastRunTime(device);
String mo = parseMo(device, receivedMessage);
if ((device.getSurplus() < 1 || device.getForcePay() == 1) && device.getFreeCount() < 1) {
log.info("设备状态为2,五剩余使用次数,马上听");
//马上停
String c2 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
String replace = c2.replace("{uid}", muid)
.replace("{date}", now).replace("{1}", "0").replace("{2}", "000");
String crc = replace.substring(1, replace.lastIndexOf("*"));
String asciiHex = XorUtil.xorAsciiHex(crc);
String s = replace.replace("{CRC}", asciiHex);
byte[] sendData = s.getBytes(StandardCharsets.UTF_8);
DatagramPacket sendPacket = new DatagramPacket(
sendData,
sendData.length,
packet.getSocketAddress()
);
try {
serverSocket.send(sendPacket);
} catch (IOException e) {
e.printStackTrace();
}
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
deviceMapper.updateStatus(device.getDeviceId(), "0");
} else {
try {
Device dvie = toLiliao(device.getDeviceId());
DeviceUsageDetail detail = parseMsgToDetail(receivedMessage);
detail.setStatus(status);
recordUse(dvie, detail);
} catch (Exception e) {
log.error("记录设备使用发生异常", e);
}
if (device.getPaymentMethod() == 1) {
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
} else {
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort, true));
}
replyHeartbeat(deviceMap.get(muid), packet, null, null);
}
}
if ("3".equals(status)) {
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
// String o = (String) redisTemplate.opsForValue().get(UniConstant.REDIS_CURRENT_DEVICE_USER + device.getDeviceId());
// PrDTO o1 = (PrDTO) redisTemplate.opsForValue().get(o + device.getDeviceId());
//openid是扫码开机的时候放到redis的
// String openid = (String) redisTemplate.opsForValue().get(UniConstant.DEVICE_ID + device.getDeviceId());
// String openid = "oATNGvnMbu6tbNgbnFZPWtJBGvFM";
Integer appUserId = 9;
PrDTO prDTO = generatePrService.generatePr(appUserId);
if (Objects.nonNull(prDTO)){
List<PrDTO.PrItem> prItems = prDTO.getPrItems();
if (CollectionUtils.isNotEmpty(prItems)){
List<UserTreatmentParameters> list = new ArrayList<>();
for (PrDTO.PrItem prItem : prItems) {
UserTreatmentParameters userTreatmentParameters = new UserTreatmentParameters();
userTreatmentParameters.setAppUserId(appUserId);
userTreatmentParameters.setDeviceId(device.getDeviceId());
userTreatmentParameters.setFr(prItem.getFr());
userTreatmentParameters.setPl(prItem.getPl());
userTreatmentParameters.setPw(prItem.getPw());
userTreatmentParameters.setUl(prItem.getUl());
userTreatmentParameters.setTl(prItem.getTl());
userTreatmentParameters.setCreateTime(LocalDateTime.now());
userTreatmentParameters.setStatus(1);
list.add(userTreatmentParameters);
}
List<UserTreatmentParameters> userTreatmentParametersList = userTreatmentParametersMapper.selectList(new LambdaQueryWrapper<UserTreatmentParameters>().eq(UserTreatmentParameters::getAppUserId, appUserId));
if (CollectionUtils.isEmpty(userTreatmentParametersList)){
userTreatmentParametersMapper.insert(list);
}
}
}
replyHeartbeat(deviceMap.get(muid), packet, prDTO, null);
}
if (Objects.isNull(deviceInfo)) {
deviceMap.put(muid, new DeviceInfo(muid, status, deviceIp, devicePort));
deviceInfo = deviceMap.get(muid);
}
if ("9".equals(status)) {
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort));
/*String o = (String) redisTemplate.opsForValue().get(UniConstant.REDIS_CURRENT_DEVICE_USER + device.getDeviceId());
PrDTO prDTO = (PrDTO) redisTemplate.opsForValue().get(o + device.getDeviceId());*/
String prId = null,tn = null;
String[] items = receivedMessage.split("\\|");
for (String item : items) {
if (item.startsWith("CI")){
prId = item.substring(2);
}
if (item.startsWith("TN")){
tn = item.substring(2);
}
}
PrDTO prDTO = prId == null ? null : (PrDTO) redisTemplate.opsForValue().get(prId);
if (Objects.isNull(prDTO)) {
log.info("status=9,proDTO is null;status=9,proDTO is null;");
log.info("status=9,proDTO is null;status=9,proDTO is null;");
log.info("status=9,proDTO is null;status=9,proDTO is null;");
log.info("status=9,proDTO is null;status=9,proDTO is null;");
log.info("status=9,proDTO is null;status=9,proDTO is null;");
}
deviceInfo = deviceMap.get(muid);
replyHeartbeat(deviceInfo, packet, prDTO, tn);
}
/*if ("4".equals(status) && deviceInfo.getStartCount() && device.getPaymentMethod() != null && device.getPaymentMethod() == 2){
log.info("设备状态为4,关机,并且startCount为true");
int count = device.getSurplus() - 1;
device.setSurplus(count);
device.setExpireTime(String.valueOf(count));
deviceMapper.updateById(device);
deviceMap.put(muid, new DeviceInfo(muid,status, deviceIp, devicePort));
}*/
if ("4".equals(status)) {
try {
Device selectById = deviceMapper.selectById(device.getDeviceId());
if (selectById.getForcePay() == 2) {
Device dce = new Device();
dce.setDeviceId(device.getDeviceId());
dce.setForcePay(1);
dce.setStatus("0");
deviceMapper.updateById(dce);
}
if (selectById.getFreeCount() > 0) {
Device device5 = new Device();
device5.setDeviceId(device.getDeviceId());
device5.setFreeCount(selectById.getFreeCount() - 1);
deviceMapper.updateById(device5);
}
changeDeviceOperatingStatus(device.getDeviceId(), 1);
updateRecord(device.getDeviceId());
deleteUserTreatParam(device.getDeviceId());
} catch (Exception e) {
log.error("更新设备使用记录发生异常", e);
}
}
}
}
//马上回
/*log.info("马上回------");
// udpClientService.sendCommand(deviceIp,devicePort,"$01|MU000B57020457D4B100001F97|DT20251011163826|ON0|CF1|WM1|TC000|*7E\r\n");
InetAddress address = null;
try {
address = InetAddress.getByName(deviceIp);
} catch (UnknownHostException e) {
e.printStackTrace();
}
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF1|WM1|TC000|*{CRC}\r\n";
String c02 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
String command = "$01|MU000B57020457D4B100001F97|DT20251011163826|ON0|CF1|WM1|TC000|*7E\r\n";
if ("1".equals(status)){
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
String replace = c01.replace("{uid}", muid).replace("{date}", now).replace("{1}", "0");
String crc = replace.substring(1, replace.lastIndexOf("*"));
String asciiHex = XorUtil.xorAsciiHex(crc);
command = replace.replace("{CRC}", asciiHex);
}
if ("2".equals(status)){
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
String replace = c02.replace("{uid}", muid)
.replace("{date}", now).replace("{1}", "0").replace("{2}", "000");
String crc = replace.substring(1, replace.lastIndexOf("*"));
String asciiHex = XorUtil.xorAsciiHex(crc);
command = replace.replace("{CRC}", asciiHex);
}
byte[] sendData = command.getBytes(StandardCharsets.UTF_8);
DatagramPacket sendPacket = new DatagramPacket(
sendData,
sendData.length,
packet.getSocketAddress()
);
try {
serverSocket.send(sendPacket);
} catch (IOException e) {
e.printStackTrace();
}*/
}
private void getPR(DeviceInfo info, DatagramPacket packet) {
if (Objects.isNull(info)) {
log.info("method->replyHeartbeat,DeviceInfo is null");
return;
}
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|WM1|TC000|PR1|*{CRC}\r\n";
}
private void replyHeartbeat(DeviceInfo info, DatagramPacket packet, PrDTO prDTO, String tn) {
if (Objects.isNull(info)) {
log.info("method->replyHeartbeat,DeviceInfo is null");
return;
}
String status = info.getStatus();
String muid = info.getMuid();
switch (status) {
case "1":
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|WM1|TC000|*{CRC}\r\n";
Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
String replace = c01.replace("{uid}", muid).replace("{date}", now)
.replace("{1}", device.getStatus()).replace("{2}", device.getCf());
String crc = replace.substring(1, replace.lastIndexOf("*"));
String asciiHex = XorUtil.xorAsciiHex(crc);
String message = replace.replace("{CRC}", asciiHex);
byte[] sendData = message.getBytes(StandardCharsets.UTF_8);
DatagramPacket sendPacket = new DatagramPacket(
sendData,
sendData.length,
packet.getSocketAddress()
);
try {
serverSocket.send(sendPacket);
} catch (IOException e) {
e.printStackTrace();
}
break;
case "2":
String c02 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
Device device2 = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
String now2 = DateUtil.format(new Date(), "yyyyMMddHHmmss");
String replace2 = c02.replace("{uid}", muid)
.replace("{date}", now2).replace("{1}", device2.getStatus()).replace("{2}", "000");
String crc2 = replace2.substring(1, replace2.lastIndexOf("*"));
String asciiHex2 = XorUtil.xorAsciiHex(crc2);
String msg = replace2.replace("{CRC}", asciiHex2);
byte[] sendData2 = msg.getBytes(StandardCharsets.UTF_8);
DatagramPacket sendPacket2 = new DatagramPacket(
sendData2,
sendData2.length,
packet.getSocketAddress()
);
try {
serverSocket.send(sendPacket2);
} catch (IOException e) {
e.printStackTrace();
}
break;
case "3":
String defaultDm = "$03|MU{uid}|CI00|CN00|*{CRC}\r\n";
String dm = "$03|MU{uid}|CI{1}|CN{2}|*{CRC}\r\n";
if (prDTO == null) {
log.info("status==3;prDTO=====null;===null");
defaultDm = defaultDm.replace("{uid}", muid);
String substring = defaultDm.substring(1, defaultDm.lastIndexOf("*"));
String xorAsciiHex = XorUtil.xorAsciiHex(substring);
String s = defaultDm.replace("{CRC}", xorAsciiHex);
byte[] sendData3 = s.getBytes(StandardCharsets.UTF_8);
DatagramPacket datagramPacket = new DatagramPacket(sendData3, sendData3.length, packet.getSocketAddress());
try {
serverSocket.send(datagramPacket);
} catch (IOException e) {
e.printStackTrace();
}
} else {
log.info("prDTO========={}", prDTO.toString());
redisTemplate.opsForValue().set(prDTO.getId(),prDTO,2,TimeUnit.HOURS);
List<PrDTO.PrItem> prItems = prDTO.getPrItems();
String cn = prItems.size() > 9 ? String.valueOf(prItems.size()) : "0"+prItems.size();
dm = dm.replace("{uid}", muid).replace("{1}", prDTO.getId()).replace("{2}", cn);
String substring = dm.substring(1, dm.lastIndexOf("*"));
String xorAsciiHex = XorUtil.xorAsciiHex(substring);
String s = dm.replace("{CRC}", xorAsciiHex);
log.info("回传给硬件的数据:{}",s);
byte[] sendData3 = s.getBytes(StandardCharsets.UTF_8);
DatagramPacket datagramPacket = new DatagramPacket(sendData3, sendData3.length, packet.getSocketAddress());
try {
serverSocket.send(datagramPacket);
} catch (IOException e) {
e.printStackTrace();
}
}
break;
case "9":
if (prDTO == null) {
log.info("case=9,prDTO=null;case=9,prDTO=null;case=9,prDTO=null;case=9,prDTO=null;case=9,prDTO=null;case=9,prDTO=null");
String defaultDm9 = "$03|MU{uid}|CI123456790123456|TN01|FR03|PW50|PL08|UL01|TL017|*{CRC}\r\n";
String substring = defaultDm9.substring(1, defaultDm9.lastIndexOf("*"));
String xorAsciiHex = XorUtil.xorAsciiHex(substring);
String s = defaultDm9.replace("{CRC}", xorAsciiHex);
byte[] sendData3 = s.getBytes(StandardCharsets.UTF_8);
DatagramPacket datagramPacket = new DatagramPacket(sendData3, sendData3.length, packet.getSocketAddress());
try {
serverSocket.send(datagramPacket);
} catch (IOException e) {
e.printStackTrace();
}
} else {
List<PrDTO.PrItem> prItems = prDTO.getPrItems();
// String tn1 = tn.substring(1);
PrDTO.PrItem prItem = prItems.get(Integer.parseInt(tn)-1);
String cm9 = "$30|MU{uid}|CI{1}|TN{2}|FR{3}|PW{4}|PL{5}|UL{6}|TL{7}|*{CRC}\r\n";
cm9 = cm9.replace("{uid}", muid).replace("{1}", prDTO.getId()).replace("{2}", tn)
.replace("{3}", prItem.getFr()).replace("{4}", prItem.getPw()).replace("{5}", prItem.getPl())
.replace("{6}", prItem.getUl()).replace("{7}", prItem.getTl());
String substring = cm9.substring(1, cm9.lastIndexOf("*"));
String xorAsciiHex = XorUtil.xorAsciiHex(substring);
String s = cm9.replace("{CRC}", xorAsciiHex);
log.info("status=9,远程下参数数据是:{}",s);
byte[] sendData3 = s.getBytes(StandardCharsets.UTF_8);
DatagramPacket datagramPacket = new DatagramPacket(sendData3, sendData3.length, packet.getSocketAddress());
try {
serverSocket.send(datagramPacket);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void parseDeviceInfo(Device device, String msg) {
String[] items = msg.split("\\|");
String hw = null, sw = null, ic = null, cf = null, wm = null, cr = null;
for (String item : items) {
if (item.startsWith("HW")) {
hw = item.substring(2);
}
if (item.startsWith("SW")) {
sw = item.substring(2);
}
if (item.startsWith("IC")) {
ic = item.substring(2);
}
if (item.startsWith("CF")) {
cf = item.substring(2);
}
if (item.startsWith("WM")) {
wm = item.substring(2);
}
if (item.startsWith("CR")) {
cr = item.substring(2);
}
}
device.setHw(hw);
device.setSw(sw);
device.setIccid(ic);
if (StringUtils.isBlank(device.getCf())) {
device.setCf(cf);
}
device.setWm(wm);
device.setCr(cr);
device.setOperatingStatus(3);
device.setLastRunTime(LocalDateTime.now());
log.info("解析设备回复的数据得到的硬件版本为:{},软件版本为:{}",hw,sw);
log.info("服务器上的LocalDateTime.now()========={}", LocalDateTime.now());
deviceMapper.updateDeviceInfo(device);
}
private String parseMo(Device device, String msg) {
String[] items = msg.split("\\|");
String mo = null;
for (String item : items) {
if (item.startsWith("MO")) {
mo = item.substring(2);
break;
}
}
device.setMo(mo);
Device dv = new Device();
dv.setDeviceId(device.getDeviceId());
dv.setMo(mo);
deviceMapper.updateById(dv);
return mo;
}
private void deleteUserTreatParam(String deviceId){
LambdaUpdateWrapper<UserTreatmentParameters> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(UserTreatmentParameters::getStatus,0).eq(UserTreatmentParameters::getDeviceId,deviceId);
userTreatmentParametersMapper.update(updateWrapper);
}
private DeviceUsageDetail parseMsgToDetail(String msg) {
String[] items = msg.split("\\|");
String fr = null, pw = null, pl = null, ul = null, wt = null;
for (String item : items) {
if (item.startsWith("FR")) {
fr = item.substring(2);
}
if (item.startsWith("PW")) {
pw = item.substring(2);
}
if (item.startsWith("PL")) {
pl = item.substring(2);
}
if (item.startsWith("UL")) {
ul = item.substring(2);
}
if (item.startsWith("WT")) {
wt = item.substring(2);
}
}
DeviceUsageDetail detail = new DeviceUsageDetail();
detail.setFr(fr);
detail.setPw(pw);
detail.setPl(pl);
detail.setUl(ul);
detail.setWt(wt);
return detail;
}
private void updateLastRunTime(Device device) {
Device d = new Device();
d.setDeviceId(device.getDeviceId());
d.setLastRunTime(LocalDateTime.now());
deviceMapper.updateById(d);
}
private Device toLiliao(String deviceId) {
Device device = deviceMapper.selectById(deviceId);
if (Objects.nonNull(device) && device.getOperatingStatus() != 0) {
device.setOperatingStatus(0);
deviceMapper.updateById(device);
deviceTask.addAbnormalDeviceTask(deviceId);
}
return device;
}
private void recordUse(Device device, DeviceUsageDetail detail) {
if (Objects.isNull(device)) {
log.info("设备使用记录recordUse->device is null");
return;
}
device.setLastRunTime(LocalDateTime.now());
deviceMapper.updateById(device);
DeviceUsageRecord record = deviceUsageRecordMapper.selectOne(new LambdaQueryWrapper<DeviceUsageRecord>()
.eq(DeviceUsageRecord::getDeviceId, device.getDeviceId())
.eq(DeviceUsageRecord::getStartUseFlag, "true"));
if (Objects.nonNull(record)) {
DeviceUsageDetail selectOne = usageDetailMapper.selectOne(new LambdaQueryWrapper<DeviceUsageDetail>().
eq(DeviceUsageDetail::getUsageRecordId, record.getId()).orderByDesc(DeviceUsageDetail::getCreateTime).last("limit 1"));
long seconds = Duration.between(selectOne.getCreateTime(), LocalDateTime.now()).getSeconds();
if ("2".equals(detail.getStatus()) && seconds > 30) {
detail.setUsageRecordId(record.getId());
detail.setCreateTime(LocalDateTime.now());
usageDetailMapper.insert(detail);
}
log.info("设备正在运行");
return;
}
DeviceUsageRecord deviceUsageRecord = new DeviceUsageRecord();
deviceUsageRecord.setStartTime(LocalDateTime.now(Clock.systemDefaultZone()));
deviceUsageRecord.setDeviceId(device.getDeviceId());
deviceUsageRecord.setStartUseFlag(UniConstant.CONST_TRUE);
deviceUsageRecord.setWm(device.getWm());
deviceUsageRecord.setBelong(device.getAffiliatedWith());
deviceUsageRecord.setMuid(device.getMuid());
deviceUsageRecordMapper.insert(deviceUsageRecord);
if (device.getPaymentMethod() != null && device.getPaymentMethod() == 2 && device.getSurplus() > 0) {
int count = device.getSurplus() - 1;
device.setSurplus(count);
device.setExpireTime(String.valueOf(count));
deviceMapper.updateById(device);
}
detail.setCreateTime(LocalDateTime.now());
detail.setUsageRecordId(deviceUsageRecord.getId());
/*
如果真要记录待机状态,那么把status=1的recordUse()放开,在这里加上根据deviceUsageRecord.getId()和status=1去查DeviceUsageDetail表,
如果不为空则不插入数据,即只记录一条状态为待机的数据
*/
List<DeviceUsageDetail> usageDetails = usageDetailMapper.selectList(new LambdaQueryWrapper<DeviceUsageDetail>().eq(DeviceUsageDetail::getUsageRecordId, deviceUsageRecord.getId())
.eq(DeviceUsageDetail::getStatus, "1"));
if (CollectionUtils.isEmpty(usageDetails)) {
usageDetailMapper.insert(detail);
}
}
private void updateRecord(String deviceId) {
DeviceUsageRecord deviceUsageRecord = deviceUsageRecordMapper.selectOne(new LambdaQueryWrapper<DeviceUsageRecord>()
.eq(DeviceUsageRecord::getDeviceId, deviceId)
.eq(DeviceUsageRecord::getStartUseFlag, UniConstant.CONST_TRUE));
if (Objects.isNull(deviceUsageRecord)) {
return;
}
deviceUsageRecord.setEndTime(LocalDateTime.now(Clock.systemDefaultZone()));
deviceUsageRecord.setStartUseFlag(UniConstant.CONST_FALSE);
deviceUsageRecordMapper.updateById(deviceUsageRecord);
DeviceUsageDetail detail = new DeviceUsageDetail();
detail.setStatus("4");
detail.setCreateTime(LocalDateTime.now());
detail.setUsageRecordId(deviceUsageRecord.getId());
usageDetailMapper.insert(detail);
}
private void changeDeviceOperatingStatus(String deviceId, Integer status) {
Device device = deviceMapper.selectById(deviceId);
if (Objects.isNull(device)) {
return;
}
device.setOperatingStatus(status);
deviceMapper.updateById(device);
}
public boolean reply(Device device, String status) {
String muid = device.getMuid();
DeviceInfo deviceInfo = getDeviceInfo(muid);
if (deviceInfo == null) {
log.info("设备会话已过期,请设备先上报一次数据");
return false;
}
String message = "";
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|WM1|TC000|*{CRC}\r\n";
String c02 = "$02|MU{uid}|DT{date}|ON{1}|SN{2}|*{CRC}\r\n";
if ("1".equals(deviceInfo.getStatus())) {
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
String replace = c01.replace("{uid}", muid).replace("{date}", now).replace("{1}", status).replace("{2}", device.getCf());
String crc = replace.substring(1, replace.lastIndexOf("*"));
String asciiHex = XorUtil.xorAsciiHex(crc);
message = replace.replace("{CRC}", asciiHex);
} else if ("2".equals(deviceInfo.getStatus())) {
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
String replace = c02.replace("{uid}", muid)
.replace("{date}", now).replace("{1}", status).replace("{2}", "000");
String crc = replace.substring(1, replace.lastIndexOf("*"));
String asciiHex = XorUtil.xorAsciiHex(crc);
message = replace.replace("{CRC}", asciiHex);
} else if ("4".equals(deviceInfo.getStatus())) {
log.info("设备为关机状态");
return true;
}
try {
log.info("最终发送的数据为:{}", message);
byte[] data = message.getBytes(StandardCharsets.UTF_8);
InetAddress address = InetAddress.getByName(deviceInfo.getIp());
DatagramPacket packet = new DatagramPacket(data, data.length, address, deviceInfo.getPort());
serverSocket.send(packet);
System.out.printf("UDP Reply sent to %s:%d -> %s%n", deviceInfo.getIp(), deviceInfo.getPort(), message);
device.setStatus(status);
deviceMapper.updateById(device);
return true;
} catch (IOException e) {
log.info("回复设备UDP消息发送异常");
e.printStackTrace();
return true;
}
}
/**
* 根据实际协议解析设备ID
* 这是一个示例,您需要根据硬件数据包的实际格式重写此方法
*
* @param message 收到的原始消息
* @return 解析出的设备ID
*/
private String parsemuid(String message) {
Pattern p = Pattern.compile("^[^|]*\\|([^|]+)\\|");
Matcher matcher = p.matcher(message);
if (matcher.find()) {
return matcher.group(1).substring(2);
}
// 如果协议里没有ID,也可以用IP:端口作为唯一标识
return null;
}
/**
* 获取设备信息
*
* @param muid 设备ID
* @return 设备信息,如果不存在则返回null
*/
public DeviceInfo getDeviceInfo(String muid) {
DeviceInfo deviceInfo = deviceMap.get(muid);
if (Objects.nonNull(deviceInfo) && System.currentTimeMillis() - deviceInfo.getLastActiveTime() < SESSION_TIMEOUT) {
return deviceInfo;
} else {
if (Objects.isNull(deviceInfo)) {
deviceMap.remove(muid);
return null;
}
if (!deviceInfo.getStartCount()) {
deviceMap.remove(muid);
}
return null;
}
}
/**
* 获取所有在线设备
*/
public ConcurrentHashMap<String, DeviceInfo> getOnlineDevices() {
return new ConcurrentHashMap<>(deviceMap);
}
private void replyUpgradeHeartbeat(DeviceInfo info, DatagramPacket packet) {
if (Objects.isNull(info)) {
log.info("method->replyHeartbeat,DeviceInfo is null");
return;
}
String c01 = "$01|MU{uid}|DT{date}|ON{1}|CF{2}|UP{3}|WM1|TC000|*{CRC}\r\n";
/*
查device_upgrade表拿到当前版本升级包名称,然后去/opt/jkadmin/upgrade下面拿到升级包
调fileService拆包,得到包数量,替换{3},然后回复
*/
DeviceUpgrade deviceUpgrade = upgradeMapper.selectOne(new LambdaQueryWrapper<DeviceUpgrade>().eq(DeviceUpgrade::getBeCurrentVersion, 1));
if (Objects.isNull(deviceUpgrade)) {
replyHeartbeat(info, packet, null, null);
} else {
String fileUrl = UPGRADE_PACKAGE_ROOT_PATH + deviceUpgrade.getFileName();
List<byte[]> packages = null;
try {
packages = fileService.splitFileWithNIO(fileUrl);
} catch (IOException e) {
log.error("拆包发生异常-.-.-.-.-.-.-.-.-.", e);
}
if (CollectionUtils.isNotEmpty(packages) && packages.size() <= 32) {
String muid = info.getMuid();
Device device = deviceMapper.selectOne(new LambdaQueryWrapper<Device>().eq(Device::getMuid, muid));
if (Objects.isNull(device)) {
return;
}
String now = DateUtil.format(new Date(), "yyyyMMddHHmmss");
String r = c01.replace("{uid}", muid).replace("{date}", now).replace("{1}", device.getStatus())
.replace("{2}", device.getCf()).replace("{3}", String.valueOf(packages.size()));
String crc = r.substring(1, r.lastIndexOf("*"));
String xorAsciiHex = XorUtil.xorAsciiHex(crc);
String msg = r.replace("{CRC}", xorAsciiHex);
log.info("回复升级心跳数据:{}", msg);
byte[] bytes = msg.getBytes(StandardCharsets.UTF_8);
DatagramPacket sendPacket = new DatagramPacket(bytes, bytes.length, packet.getSocketAddress());
try {
serverSocket.send(sendPacket);
} catch (IOException e) {
log.error("回复升级心跳包发生异常", e);
}
} else {
log.info("升级包为空或升级包大小超过1024*32");
replyHeartbeat(info, packet, null, null);
}
}
}
}