From a2f215fe63bd313bfac2a894c170673ccbc252c4 Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Thu, 19 Oct 2017 10:03:02 +0500 Subject: Implement buffered commands --- src/org/traccar/api/resource/CommandResource.java | 8 ++- src/org/traccar/database/CommandsManager.java | 60 ++++++++++++++--------- src/org/traccar/database/ConnectionManager.java | 5 +- swagger.json | 14 ++++-- 4 files changed, 56 insertions(+), 31 deletions(-) diff --git a/src/org/traccar/api/resource/CommandResource.java b/src/org/traccar/api/resource/CommandResource.java index 8da9f8447..996c15daf 100644 --- a/src/org/traccar/api/resource/CommandResource.java +++ b/src/org/traccar/api/resource/CommandResource.java @@ -62,15 +62,19 @@ public class CommandResource extends ExtendedObjectResource { Context.getPermissionsManager().checkReadonly(getUserId()); long deviceId = entity.getDeviceId(); long id = entity.getId(); + boolean sent; if (deviceId != 0 && id != 0) { Context.getPermissionsManager().checkPermission(Command.class, getUserId(), id); Context.getPermissionsManager().checkDevice(getUserId(), deviceId); Context.getPermissionsManager().checkUserDeviceCommand(getUserId(), deviceId, id); - Context.getCommandsManager().sendCommand(id, deviceId); + sent = Context.getCommandsManager().sendCommand(id, deviceId); } else { Context.getPermissionsManager().checkLimitCommands(getUserId()); Context.getPermissionsManager().checkDevice(getUserId(), deviceId); - Context.getCommandsManager().sendCommand(entity); + sent = Context.getCommandsManager().sendCommand(entity, deviceId); + } + if (!sent) { + return Response.accepted(entity).build(); } return Response.ok(entity).build(); } diff --git a/src/org/traccar/database/CommandsManager.java b/src/org/traccar/database/CommandsManager.java index 521a2e1d1..624fe56cd 100644 --- a/src/org/traccar/database/CommandsManager.java +++ b/src/org/traccar/database/CommandsManager.java @@ -21,6 +21,10 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; import org.traccar.BaseProtocol; import org.traccar.Context; @@ -31,26 +35,22 @@ import org.traccar.model.Position; public class CommandsManager extends ExtendedObjectManager { - private boolean fallbackToText; + private final Map> deviceQueues = new ConcurrentHashMap<>(); public CommandsManager(DataManager dataManager) { super(dataManager, Command.class); - fallbackToText = Context.getConfig().getBoolean("command.fallbackToSms"); } public boolean checkDeviceCommand(long deviceId, long commandId) { return !getAllDeviceItems(deviceId).contains(commandId); } - public void sendCommand(Command command) throws Exception { - sendCommand(command, command.getDeviceId(), fallbackToText); + public boolean sendCommand(long commandId, long deviceId) throws Exception { + return sendCommand(getById(commandId), deviceId); } - public void sendCommand(long commandId, long deviceId) throws Exception { - sendCommand(getById(commandId), deviceId, false); - } - - public void sendCommand(Command command, long deviceId, boolean fallbackToText) throws Exception { + public boolean sendCommand(Command command, long deviceId) throws Exception { + boolean sent = true; if (command.getTextChannel()) { Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); String phone = Context.getIdentityManager().getById(deviceId).getPhone(); @@ -71,32 +71,26 @@ public class CommandsManager extends ExtendedObjectManager { if (activeDevice != null) { activeDevice.sendCommand(command); } else { - if (fallbackToText) { - command.setTextChannel(true); - sendCommand(command, deviceId, false); - } else { - throw new RuntimeException("Device is not online"); - } + sent = !getDeviceQueue(deviceId).add(command); } } + return sent; } public Collection getSupportedCommands(long deviceId) { List result = new ArrayList<>(); Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId); - boolean online = Context.getConnectionManager().getActiveDevice(deviceId) != null; for (long commandId : getAllDeviceItems(deviceId)) { Command command = getById(commandId); - if (command.getTextChannel() || online) { - if (lastPosition != null) { - BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); - if (protocol.getSupportedTextCommands().contains(command.getType()) - || online && protocol.getSupportedDataCommands().contains(command.getType())) { - result.add(commandId); - } - } else if (command.getType().equals(Command.TYPE_CUSTOM)) { + if (lastPosition != null) { + BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); + if ((command.getTextChannel() + ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands()) + .contains(command.getType())) { result.add(commandId); } + } else if (command.getType().equals(Command.TYPE_CUSTOM)) { + result.add(commandId); } } return result; @@ -133,4 +127,22 @@ public class CommandsManager extends ExtendedObjectManager { return result; } + private Queue getDeviceQueue(long deviceId) { + if (!deviceQueues.containsKey(deviceId)) { + deviceQueues.put(deviceId, new ConcurrentLinkedQueue()); + } + return deviceQueues.get(deviceId); + } + + public void sendQueuedCommands(ActiveDevice activeDevice) { + Queue deviceQueue = deviceQueues.get(activeDevice.getDeviceId()); + if (deviceQueue != null) { + Command command = deviceQueue.poll(); + while (command != null) { + activeDevice.sendCommand(command); + command = deviceQueue.poll(); + } + } + } + } diff --git a/src/org/traccar/database/ConnectionManager.java b/src/org/traccar/database/ConnectionManager.java index de11db21b..e5a7a272f 100644 --- a/src/org/traccar/database/ConnectionManager.java +++ b/src/org/traccar/database/ConnectionManager.java @@ -57,7 +57,9 @@ public class ConnectionManager { } public void addActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) { - activeDevices.put(deviceId, new ActiveDevice(deviceId, protocol, channel, remoteAddress)); + ActiveDevice activeDevice = new ActiveDevice(deviceId, protocol, channel, remoteAddress); + activeDevices.put(deviceId, activeDevice); + Context.getCommandsManager().sendQueuedCommands(activeDevice); } public void removeActiveDevice(Channel channel) { @@ -122,6 +124,7 @@ public class ConnectionManager { public void run(Timeout timeout) throws Exception { if (!timeout.isCancelled()) { updateDevice(deviceId, Device.STATUS_UNKNOWN, null); + activeDevices.remove(deviceId); } } }, deviceTimeout, TimeUnit.MILLISECONDS)); diff --git a/swagger.json b/swagger.json index 120544798..82f34ac1d 100644 --- a/swagger.json +++ b/swagger.json @@ -108,11 +108,11 @@ "/commands/send": { "get": { "summary": "Fetch a list of Saved Commands supported by Device at the moment", - "description": "Return a list of saved commands linked to Device and its groups, filtered by current Device state and protocol support", + "description": "Return a list of saved commands linked to Device and its groups, filtered by current Device protocol support", "parameters": [ { "$ref": "#/parameters/deviceId" - }, + } ], "responses": { "200": { @@ -144,13 +144,19 @@ ], "responses": { "200": { - "description": "OK", + "description": "Command sent", + "schema": { + "$ref": "#/definitions/Command" + } + }, + "202": { + "description": "Command queued", "schema": { "$ref": "#/definitions/Command" } }, "400": { - "description": "Could happen when dispatching to a device that is offline, the user doesn't have permission or an incorrect command _type_ for the device" + "description": "Could happen when the user doesn't have permission or an incorrect command _type_ for the device" } } } -- cgit v1.2.3 From c4191e726f3f0a8ca83ea47f3316a266e5a22b5d Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Fri, 20 Oct 2017 12:56:54 +0500 Subject: Use List instead of Queue --- src/org/traccar/database/CommandsManager.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/org/traccar/database/CommandsManager.java b/src/org/traccar/database/CommandsManager.java index 624fe56cd..af35965b9 100644 --- a/src/org/traccar/database/CommandsManager.java +++ b/src/org/traccar/database/CommandsManager.java @@ -22,9 +22,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; import org.traccar.BaseProtocol; import org.traccar.Context; @@ -35,7 +33,7 @@ import org.traccar.model.Position; public class CommandsManager extends ExtendedObjectManager { - private final Map> deviceQueues = new ConcurrentHashMap<>(); + private final Map> deviceQueues = new ConcurrentHashMap<>(); public CommandsManager(DataManager dataManager) { super(dataManager, Command.class); @@ -127,20 +125,18 @@ public class CommandsManager extends ExtendedObjectManager { return result; } - private Queue getDeviceQueue(long deviceId) { + private List getDeviceQueue(long deviceId) { if (!deviceQueues.containsKey(deviceId)) { - deviceQueues.put(deviceId, new ConcurrentLinkedQueue()); + deviceQueues.put(deviceId, new ArrayList()); } return deviceQueues.get(deviceId); } public void sendQueuedCommands(ActiveDevice activeDevice) { - Queue deviceQueue = deviceQueues.get(activeDevice.getDeviceId()); + List deviceQueue = deviceQueues.get(activeDevice.getDeviceId()); if (deviceQueue != null) { - Command command = deviceQueue.poll(); - while (command != null) { + for (Command command : deviceQueue) { activeDevice.sendCommand(command); - command = deviceQueue.poll(); } } } -- cgit v1.2.3 From 39be24a58767c05cb7001e77db1bae56cdbe4445 Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Fri, 20 Oct 2017 14:42:03 +0500 Subject: Unwrap ternary operator --- src/org/traccar/database/CommandsManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/traccar/database/CommandsManager.java b/src/org/traccar/database/CommandsManager.java index af35965b9..f9feb927d 100644 --- a/src/org/traccar/database/CommandsManager.java +++ b/src/org/traccar/database/CommandsManager.java @@ -82,9 +82,9 @@ public class CommandsManager extends ExtendedObjectManager { Command command = getById(commandId); if (lastPosition != null) { BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol()); - if ((command.getTextChannel() - ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands()) - .contains(command.getType())) { + if (command.getTextChannel() && protocol.getSupportedTextCommands().contains(command.getType()) + || !command.getTextChannel() + && protocol.getSupportedDataCommands().contains(command.getType())) { result.add(commandId); } } else if (command.getType().equals(Command.TYPE_CUSTOM)) { -- cgit v1.2.3 From 91da9fa8e53836e71c36609132c38797317ae9e1 Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Fri, 20 Oct 2017 15:12:11 +0500 Subject: Reverted using Queue --- src/org/traccar/database/CommandsManager.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/org/traccar/database/CommandsManager.java b/src/org/traccar/database/CommandsManager.java index f9feb927d..cae4ac6f7 100644 --- a/src/org/traccar/database/CommandsManager.java +++ b/src/org/traccar/database/CommandsManager.java @@ -22,7 +22,9 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; import org.traccar.BaseProtocol; import org.traccar.Context; @@ -33,7 +35,7 @@ import org.traccar.model.Position; public class CommandsManager extends ExtendedObjectManager { - private final Map> deviceQueues = new ConcurrentHashMap<>(); + private final Map> deviceQueues = new ConcurrentHashMap<>(); public CommandsManager(DataManager dataManager) { super(dataManager, Command.class); @@ -125,18 +127,20 @@ public class CommandsManager extends ExtendedObjectManager { return result; } - private List getDeviceQueue(long deviceId) { + private Queue getDeviceQueue(long deviceId) { if (!deviceQueues.containsKey(deviceId)) { - deviceQueues.put(deviceId, new ArrayList()); + deviceQueues.put(deviceId, new ConcurrentLinkedQueue()); } return deviceQueues.get(deviceId); } public void sendQueuedCommands(ActiveDevice activeDevice) { - List deviceQueue = deviceQueues.get(activeDevice.getDeviceId()); + Queue deviceQueue = deviceQueues.get(activeDevice.getDeviceId()); if (deviceQueue != null) { - for (Command command : deviceQueue) { + Command command = deviceQueue.poll(); + while (command != null) { activeDevice.sendCommand(command); + command = deviceQueue.poll(); } } } -- cgit v1.2.3