package com.dronecontrol.socketcontrol.input; import com.dronecontrol.socketcontrol.input.data.MovementData; import com.dronecontrol.socketcontrol.input.data.PilotAction; import com.dronecontrol.socketcontrol.input.data.PilotData; import com.dronecontrol.socketcontrol.input.events.MovementDataListener; import com.dronecontrol.socketcontrol.input.events.PilotActionListener; import com.dronecontrol.socketcontrol.input.socket.SocketClientDataListener; import com.google.common.collect.Sets; import org.codehaus.jackson.map.ObjectMapper; import javax.inject.Inject; import java.io.IOException; import java.util.Collection; import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class SocketDataReceiver implements SocketClientDataListener { private final int FAILSAFE_DELAY = 200; private final ScheduledExecutorService worker; private final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(SocketDataReceiver.class); private final Runnable movementValidityChecker = new Runnable() { @Override public void run() { checkDelayForLastCommand(); } }; private final ObjectMapper objectMapper; private Set<MovementDataListener> movementDataListeners; private Set<PilotActionListener> pilotActionListeners; private long lastCommandTimeStamp; @Inject public SocketDataReceiver(ObjectMapper objectMapper) { this.objectMapper = objectMapper; movementDataListeners = Sets.newCopyOnWriteArraySet(); pilotActionListeners = Sets.newCopyOnWriteArraySet(); worker = Executors.newSingleThreadScheduledExecutor(); lastCommandTimeStamp = getCurrentTimeStamp(); startCheckingMovementValidity(); } public void startCheckingMovementValidity() { worker.scheduleAtFixedRate(movementValidityChecker, FAILSAFE_DELAY, FAILSAFE_DELAY, TimeUnit.MILLISECONDS); } public void dispose() { worker.shutdown(); } private void checkDelayForLastCommand() { if (timeSinceLastCommand() > FAILSAFE_DELAY) { emitMovementData(MovementData.NO_MOVEMENT); } } private long timeSinceLastCommand() { return getCurrentTimeStamp() - lastCommandTimeStamp; } private long getCurrentTimeStamp() { return new java.util.Date().getTime(); } @Override public void OnData(String message) { PilotData pilotData = getPilotData(message); if (pilotData != null) { emitMovementData(pilotData.getMovementData()); emitPilotActions(pilotData.getPilotActions()); } } private PilotData getPilotData(String message) { try { return objectMapper.readValue(message, PilotData.class); } catch (IOException e) { logger.warn(String.format("Error while deserializing movement data '%s': %s", message, e.getMessage())); return null; } } private void emitMovementData(MovementData movementData) { lastCommandTimeStamp = getCurrentTimeStamp(); invokeMovementDataListeners(movementData); } private void invokeMovementDataListeners(MovementData movementData) { for (MovementDataListener listener : movementDataListeners) { listener.onMovementData(movementData); } } private void emitPilotActions(Collection<PilotAction> pilotActions) { for (PilotAction pilotAction : pilotActions) { invokePilotActionListeners(pilotAction); } } private void invokePilotActionListeners(PilotAction pilotAction) { for (PilotActionListener listener : pilotActionListeners) { listener.onPilotAction(pilotAction); } } public synchronized void addMovementDataListener(MovementDataListener listener) { movementDataListeners.add(listener); } public synchronized void addPilotActionListener(PilotActionListener listener) { pilotActionListeners.add(listener); } }