diff --git a/src/main/java/com/tuoheng/machine/MachineCommandManager.java b/src/main/java/com/tuoheng/machine/MachineCommandManager.java index d2e6e70..07b93ab 100644 --- a/src/main/java/com/tuoheng/machine/MachineCommandManager.java +++ b/src/main/java/com/tuoheng/machine/MachineCommandManager.java @@ -64,8 +64,8 @@ public class MachineCommandManager { * @param sn 设备SN号 * @param newStates 新状态 */ - public void updateMachineStates(String sn, MachineStates newStates) { - stateManager.updateStates(sn, newStates); + public void updateMachineStates(String sn, MachineStates newStates,Boolean force) { + stateManager.updateStates(sn, newStates,force); } /** diff --git a/src/main/java/com/tuoheng/machine/readme.txt b/src/main/java/com/tuoheng/machine/readme.txt index 3a8e057..7e5d293 100644 --- a/src/main/java/com/tuoheng/machine/readme.txt +++ b/src/main/java/com/tuoheng/machine/readme.txt @@ -1,3 +1,4 @@ + 单节点部署(默认) # 使用内存存储(默认配置) @@ -8,7 +9,8 @@ machine.state.store.type=redis # 配置节点ID(可选,不配置会自动生成) machine.node.id=node-1 - + #本地启动redis + #docker run --name some-redis -d -p 6379:6379 redi # Redis 配置 spring.redis.host=localhost spring.redis.port=6379 diff --git a/src/main/java/com/tuoheng/machine/statemachine/store/RedisMachineStateStore.java b/src/main/java/com/tuoheng/machine/statemachine/store/RedisMachineStateStore.java index 9fb6507..e244629 100644 --- a/src/main/java/com/tuoheng/machine/statemachine/store/RedisMachineStateStore.java +++ b/src/main/java/com/tuoheng/machine/statemachine/store/RedisMachineStateStore.java @@ -1,81 +1,92 @@ package com.tuoheng.machine.statemachine.store; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.tuoheng.machine.state.MachineStates; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; +import java.util.concurrent.TimeUnit; + /** * 基于 Redis 的设备状态存储实现 * 适用于多节点部署的生产环境 * + * Redis 数据结构: + * - Key: machine:state:{sn} + * - Value: MachineStates (JSON) + * - TTL: 86400 秒(24小时) + * * 使用方式: * 1. 在 application.properties 中配置:machine.state.store.type=redis - * 2. 实现 Redis 相关的序列化和反序列化逻辑 - * 3. 配置 Redis 连接信息 - * - * 注意:当前为空实现,需要在生产环境部署时完善 + * 2. 配置 Redis 连接信息 */ @Slf4j @Component @ConditionalOnProperty(name = "machine.state.store.type", havingValue = "redis") public class RedisMachineStateStore implements MachineStateStore { - // TODO: 注入 RedisTemplate 或 StringRedisTemplate - // private final RedisTemplate redisTemplate; + private final StringRedisTemplate redisTemplate; + private final ObjectMapper objectMapper; - // TODO: 配置 Redis key 的前缀 - // private static final String KEY_PREFIX = "machine:state:"; + // Redis key 前缀 + private static final String KEY_PREFIX = "machine:state:"; - // TODO: 配置状态的过期时间(可选) - // private static final long EXPIRE_SECONDS = 86400; // 24小时 + // 配置状态的过期时间 + private static final long EXPIRE_SECONDS = 86400; // 24小时 - public RedisMachineStateStore() { - log.warn("使用 Redis 状态存储实现,但当前为空实现,请在生产环境部署前完善"); + public RedisMachineStateStore(StringRedisTemplate redisTemplate, ObjectMapper objectMapper) { + this.redisTemplate = redisTemplate; + this.objectMapper = objectMapper; + log.info("使用 Redis 设备状态存储实现"); } @Override public MachineStates getStates(String sn) { - // TODO: 实现从 Redis 获取状态 - // String key = KEY_PREFIX + sn; - // MachineStates states = redisTemplate.opsForValue().get(key); - // if (states == null) { - // states = new MachineStates(); - // saveStates(sn, states); - // } - // return states; + String key = KEY_PREFIX + sn; + String json = redisTemplate.opsForValue().get(key); - log.warn("Redis 状态存储未实现,返回默认状态: sn={}", sn); - return new MachineStates(); + if (json == null) { + log.debug("Redis 中不存在设备状态,返回默认状态: sn={}", sn); + MachineStates states = new MachineStates(); + saveStates(sn, states); + return states; + } + + try { + MachineStates states = objectMapper.readValue(json, MachineStates.class); + log.debug("从 Redis 获取设备状态: sn={}", sn); + return states; + } catch (JsonProcessingException e) { + log.error("反序列化设备状态失败: sn={}", sn, e); + return new MachineStates(); + } } @Override public void saveStates(String sn, MachineStates states) { - // TODO: 实现保存状态到 Redis - // String key = KEY_PREFIX + sn; - // redisTemplate.opsForValue().set(key, states, EXPIRE_SECONDS, TimeUnit.SECONDS); - // log.debug("保存设备状态到 Redis: sn={}", sn); - - log.warn("Redis 状态存储未实现,跳过保存: sn={}", sn); + try { + String key = KEY_PREFIX + sn; + String json = objectMapper.writeValueAsString(states); + redisTemplate.opsForValue().set(key, json, EXPIRE_SECONDS, TimeUnit.SECONDS); + log.debug("保存设备状态到 Redis: sn={}", sn); + } catch (JsonProcessingException e) { + log.error("序列化设备状态失败: sn={}", sn, e); + } } @Override public void removeStates(String sn) { - // TODO: 实现从 Redis 删除状态 - // String key = KEY_PREFIX + sn; - // redisTemplate.delete(key); - // log.debug("从 Redis 中移除设备状态: sn={}", sn); - - log.warn("Redis 状态存储未实现,跳过删除: sn={}", sn); + String key = KEY_PREFIX + sn; + redisTemplate.delete(key); + log.debug("从 Redis 中移除设备状态: sn={}", sn); } @Override public boolean exists(String sn) { - // TODO: 实现检查 Redis 中是否存在状态 - // String key = KEY_PREFIX + sn; - // return Boolean.TRUE.equals(redisTemplate.hasKey(key)); - - log.warn("Redis 状态存储未实现,返回 false: sn={}", sn); - return false; + String key = KEY_PREFIX + sn; + return Boolean.TRUE.equals(redisTemplate.hasKey(key)); } } \ No newline at end of file diff --git a/src/test/java/com/tuoheng/old/DrcStateMachineTest.java b/src/test/java/com/tuoheng/old/DrcStateMachineTest.java index 31a744a..ab5f3bc 100644 --- a/src/test/java/com/tuoheng/old/DrcStateMachineTest.java +++ b/src/test/java/com/tuoheng/old/DrcStateMachineTest.java @@ -29,6 +29,7 @@ import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @Slf4j @TestMethodOrder(MethodOrderer.OrderAnnotation.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class DrcStateMachineTest { @@ -57,6 +58,7 @@ public class DrcStateMachineTest { initState = true; // 使用 VendorRegistry 绑定 SN 到厂家 vendorRegistry.bindSnToVendor(SN, "DJI"); + machineCommandManager.updateMachineStates(SN,new MachineStates(),true); } @Test @@ -81,7 +83,8 @@ public class DrcStateMachineTest { public void checkTakeOffCommand() throws ExecutionException, InterruptedException { CompletableFuture future = machineCommandManager.executeCommand(SN, CommandType.TAKE_OFF,new HashMap<>()); - assertFalse(future.get().isSuccess()); + CommandResult result = future.get(); + assertFalse(result.isSuccess()); } @Test @@ -91,7 +94,7 @@ public class DrcStateMachineTest { MachineStates machineStates = new MachineStates(); machineStates.setAirportState(AirportState.ONLINE); machineStates.setDroneState(DroneState.ONLINE); - machineCommandManager.updateMachineStates(SN, machineStates); + machineCommandManager.updateMachineStates(SN, machineStates,false); machineStates = machineCommandManager.getMachineStates(SN); assertNotNull(machineStates); @@ -181,7 +184,7 @@ public class DrcStateMachineTest { // 添加延迟,等待状态回调监听器注册 try { - Thread.sleep(50); // 等待50ms + Thread.sleep(200); // 等待200ms } catch (InterruptedException e) { e.printStackTrace(); }