921 lines
43 KiB
Java
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|