11 changed files with 600 additions and 479 deletions
@ -1,10 +0,0 @@ |
|||
package com.galaxis.rcs.common.enums; |
|||
|
|||
public enum AgvEventType { |
|||
OFFLINE, ONLINE, FREE, |
|||
PLAN_COMPLETE, PLAN_ACCEPT, PLAN_CANCEL, |
|||
PLAN_PAUSE, PLAN_RESUME, |
|||
DEVICE_TASK_COMPLETE, DEVICE_TASK_EXCEPTION, |
|||
POS_CHANGED, DIRECTION_CHANGED, |
|||
LOW_BATTERY, STUCK |
|||
} |
|||
@ -1,66 +0,0 @@ |
|||
package com.galaxis.rcs.ptr; |
|||
|
|||
import com.galaxis.rcs.common.enums.AgvEventType; |
|||
import com.yvan.logisticsModel.LogisticsRuntime; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.concurrent.*; |
|||
|
|||
@Slf4j |
|||
public class AgvEventManager { |
|||
private final Map<AgvEventType, List<AgvEventListener>> listeners = new ConcurrentHashMap<>(); |
|||
private final Map<String, ScheduledFuture<?>> stuckMonitors = new ConcurrentHashMap<>(); |
|||
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4); |
|||
private final LogisticsRuntime runtime; |
|||
|
|||
public AgvEventManager(LogisticsRuntime runtime) { |
|||
this.runtime = runtime; |
|||
} |
|||
|
|||
public void registerListener(AgvEventType type, AgvEventListener listener) { |
|||
listeners.computeIfAbsent(type, k -> new CopyOnWriteArrayList<>()).add(listener); |
|||
} |
|||
|
|||
public void unregisterListener(AgvEventType type, AgvEventListener listener) { |
|||
List<AgvEventListener> list = listeners.get(type); |
|||
if (list != null) { |
|||
list.remove(listener); |
|||
} |
|||
} |
|||
|
|||
public void fireEvent(AgvEventType type, Object... args) { |
|||
List<AgvEventListener> list = listeners.get(type); |
|||
if (list != null) { |
|||
for (AgvEventListener listener : list) { |
|||
try { |
|||
listener.onEvent(type, args); |
|||
} catch (Exception e) { |
|||
log.error("Error handling event {}", type, e); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
public void monitorMovement(String agvId, PosDirection startPos, int delayOfSeconds) { |
|||
// 取消现有的监控
|
|||
cancelStuckMonitor(agvId); |
|||
|
|||
ScheduledFuture<?> future = scheduler.schedule(() -> { |
|||
PtrAgvItem agv = (PtrAgvItem) this.runtime.executorItemMap.get(agvId); |
|||
if (agv != null && agv.isSamePosition(startPos)) { |
|||
fireEvent(AgvEventType.STUCK, agv, delayOfSeconds); |
|||
} |
|||
}, delayOfSeconds, TimeUnit.SECONDS); |
|||
|
|||
stuckMonitors.put(agvId, future); |
|||
} |
|||
|
|||
public void cancelStuckMonitor(String agvId) { |
|||
ScheduledFuture<?> future = stuckMonitors.remove(agvId); |
|||
if (future != null) { |
|||
future.cancel(false); |
|||
} |
|||
} |
|||
} |
|||
@ -1,6 +1,4 @@ |
|||
package com.galaxis.rcs.ptr; |
|||
|
|||
import com.galaxis.rcs.common.enums.AgvEventType; |
|||
package com.yvan.event; |
|||
|
|||
public interface AgvEventListener { |
|||
void onEvent(AgvEventType type, Object... args); |
|||
@ -0,0 +1,82 @@ |
|||
package com.yvan.event; |
|||
|
|||
public enum AgvEventType { |
|||
/** |
|||
* 设备离线 |
|||
*/ |
|||
OFFLINE, |
|||
/** |
|||
* 设备上线 |
|||
*/ |
|||
ONLINE, |
|||
/** |
|||
* 设备阻挡 |
|||
*/ |
|||
BLOCKED, |
|||
/** |
|||
* 设备阻挡恢复 |
|||
*/ |
|||
BLOCKED_RECOVER, |
|||
/** |
|||
* 设备空闲 |
|||
*/ |
|||
FREE, |
|||
/** |
|||
* 规划任务序列全部完成 |
|||
* (ExecutorItem sender) |
|||
*/ |
|||
PLAN_TASK_SEQUENCE_COMPLETE, |
|||
/** |
|||
* 某一个规划任务被完成 |
|||
* (ExecutorItem sender, PlanTaskSequence taskSequence, RcsTaskPlan taskPlan) |
|||
*/ |
|||
PLAN_TASK_COMPLETE, |
|||
/** |
|||
* 规划任务异常 |
|||
*/ |
|||
PLAN_TASK_EXCEPTION, |
|||
/** |
|||
* 规划任务已接受 |
|||
* (ExecutorItem sender, PlanTaskSequence taskSequence) |
|||
*/ |
|||
PLAN_TASK_SEQUENCE_ACCEPT, |
|||
/** |
|||
* 规划任务已取消 |
|||
* (ExecutorItem sender) |
|||
*/ |
|||
PLAN_TASK_SEQUENCE_CANCEL, |
|||
/** |
|||
* 规划任务已暂停 |
|||
* (ExecutorItem sender) |
|||
*/ |
|||
PLAN_TASK_SEQUENCE_PAUSE, |
|||
/** |
|||
* 规划任务已恢复 |
|||
* (ExecutorItem sender) |
|||
*/ |
|||
PLAN_TASK_SEQUENCE_RESUME, |
|||
/** |
|||
* 设备任务已完成 |
|||
* (ExecutorItem sender, PtrAgvDeviceTask deviceTask) |
|||
*/ |
|||
DEVICE_TASK_COMPLETE, |
|||
/** |
|||
* 设备任务异常 |
|||
*/ |
|||
DEVICE_TASK_EXCEPTION, |
|||
/** |
|||
* 设备位置改变 |
|||
* (ExecutorItem sender, PosDirection newPosDirection, PosDirection originPosDirection) |
|||
*/ |
|||
POS_CHANGED, |
|||
/** |
|||
* 设备姿态改变 |
|||
* (ExecutorItem sender, PosDirection newPosDirection, PosDirection originPosDirection) |
|||
*/ |
|||
DIRECTION_CHANGED, |
|||
/** |
|||
* 设备低电量 |
|||
* (ExecutorItem sender) |
|||
*/ |
|||
LOW_BATTERY, |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
package com.yvan.event; |
|||
|
|||
import java.util.Set; |
|||
import java.util.concurrent.CopyOnWriteArraySet; |
|||
|
|||
public class EventManager { |
|||
|
|||
private final Set<AgvEventListener> eventListeners = new CopyOnWriteArraySet<>(); |
|||
|
|||
public void fireEvent(AgvEventType type, Object... args) { |
|||
for (AgvEventListener listener : eventListeners) { |
|||
listener.onEvent(type, args); |
|||
} |
|||
} |
|||
|
|||
// 事件监听管理
|
|||
public void subscribe(AgvEventListener listener) { |
|||
eventListeners.add(listener); |
|||
} |
|||
|
|||
public void unsubscribe(AgvEventListener listener) { |
|||
eventListeners.remove(listener); |
|||
} |
|||
} |
|||
@ -0,0 +1,114 @@ |
|||
package com.yvan.state; |
|||
|
|||
import org.clever.core.mapper.JacksonMapper; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Objects; |
|||
import java.util.concurrent.Executors; |
|||
import java.util.concurrent.ScheduledExecutorService; |
|||
import java.util.concurrent.ScheduledFuture; |
|||
import java.util.concurrent.TimeUnit; |
|||
import java.util.function.Consumer; |
|||
import java.util.function.Supplier; |
|||
|
|||
/** |
|||
* VariableMonitor<T> 类用于周期性检查某个变量的值是否发生变化。 |
|||
* 如果发生变化,就触发回调通知所有监听器。 |
|||
* <p> |
|||
* 本实现使用 Jackson 序列化对象为 JSON 字符串进行比较,适用于: |
|||
* - Map |
|||
* - List |
|||
* - Set |
|||
* - 自定义实体类 |
|||
* - 嵌套结构 |
|||
* <p> |
|||
* 并自动防止循环引用问题。 |
|||
* |
|||
* @param <T> 被监控变量的类型 |
|||
*/ |
|||
public class VariableMonitor<T> { |
|||
|
|||
// 提供当前变量值的方法
|
|||
private final Supplier<T> provider; |
|||
|
|||
// 轮询间隔时间(毫秒)
|
|||
private final long intervalMillis; |
|||
|
|||
// 定时任务执行器
|
|||
private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); |
|||
|
|||
// 当前调度的任务对象
|
|||
private ScheduledFuture<?> future; |
|||
|
|||
// 上一次变量的 JSON 表示
|
|||
private String lastJson; |
|||
|
|||
// 存储所有的监听器
|
|||
private final List<Consumer<T>> listeners = new ArrayList<>(); |
|||
|
|||
public VariableMonitor(Supplier<T> provider, long intervalMillis) { |
|||
this.provider = provider; |
|||
this.intervalMillis = intervalMillis; |
|||
this.lastJson = JacksonMapper.getInstance().toJson(provider.get()); |
|||
} |
|||
|
|||
/** |
|||
* 启动定时轮询任务 |
|||
*/ |
|||
public void start() { |
|||
future = scheduler.scheduleAtFixedRate(() -> { |
|||
T currentValue = provider.get(); |
|||
String currentJson; |
|||
currentJson = JacksonMapper.getInstance().toJson(currentValue); |
|||
|
|||
if (!Objects.equals(lastJson, currentJson)) { |
|||
notifyListeners(currentValue); |
|||
lastJson = currentJson; |
|||
} |
|||
}, 0, intervalMillis, TimeUnit.MILLISECONDS); |
|||
} |
|||
|
|||
/** |
|||
* 停止定时任务 |
|||
*/ |
|||
public void stop() { |
|||
if (future != null) { |
|||
future.cancel(false); |
|||
} |
|||
scheduler.shutdownNow(); |
|||
} |
|||
|
|||
/** |
|||
* 添加一个监听器 |
|||
* |
|||
* @param listener 回调函数,接收新值作为参数 |
|||
*/ |
|||
public void addListener(Consumer<T> listener) { |
|||
listeners.add(listener); |
|||
} |
|||
|
|||
/** |
|||
* 移除一个监听器 |
|||
* |
|||
* @param listener 要移除的监听器 |
|||
*/ |
|||
public void removeListener(Consumer<T> listener) { |
|||
listeners.remove(listener); |
|||
} |
|||
|
|||
/** |
|||
* 通知所有监听器变量发生了变化 |
|||
* |
|||
* @param newValue 新的变量值 |
|||
*/ |
|||
private void notifyListeners(T newValue) { |
|||
for (Consumer<T> listener : listeners) { |
|||
try { |
|||
listener.accept(newValue); |
|||
} catch (Exception e) { |
|||
System.err.println("监听器执行出错: " + e.getMessage()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue