From 27004f3b9c32ebf3a9f99fa2388ebcbd3fcfb5de Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 27 Aug 2020 23:45:17 -0700 Subject: Add device inactivity event --- src/main/java/org/traccar/Context.java | 8 +++ src/main/java/org/traccar/Main.java | 2 + src/main/java/org/traccar/model/Event.java | 3 +- .../java/org/traccar/schedule/ScheduleManager.java | 27 ++++++++ .../schedule/TaskDeviceInactivityCheck.java | 79 ++++++++++++++++++++++ templates/full/deviceInactive.vm | 12 ++++ templates/short/deviceInactive.vm | 3 + 7 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/traccar/schedule/ScheduleManager.java create mode 100644 src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java create mode 100644 templates/full/deviceInactive.vm create mode 100644 templates/short/deviceInactive.vm diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java index 9c20db9e4..a7848d356 100644 --- a/src/main/java/org/traccar/Context.java +++ b/src/main/java/org/traccar/Context.java @@ -40,6 +40,7 @@ import org.traccar.database.MaintenancesManager; import org.traccar.database.MediaManager; import org.traccar.database.NotificationManager; import org.traccar.database.PermissionsManager; +import org.traccar.schedule.ScheduleManager; import org.traccar.database.UsersManager; import org.traccar.geocoder.Geocoder; import org.traccar.helper.Log; @@ -165,6 +166,12 @@ public final class Context { return serverManager; } + public static ScheduleManager scheduleManager; + + public static ScheduleManager getScheduleManager() { + return scheduleManager; + } + private static GeofenceManager geofenceManager; public static GeofenceManager getGeofenceManager() { @@ -332,6 +339,7 @@ public final class Context { } serverManager = new ServerManager(); + scheduleManager = new ScheduleManager(); if (config.getBoolean("event.forward.enable")) { eventForwarder = new JsonTypeEventForwarder(); diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java index a0d93dbc8..59afab3a5 100644 --- a/src/main/java/org/traccar/Main.java +++ b/src/main/java/org/traccar/Main.java @@ -144,6 +144,7 @@ public final class Main { if (Context.getWebServer() != null) { Context.getWebServer().start(); } + Context.getScheduleManager().start(); scheduleHealthCheck(); scheduleDatabaseCleanup(); @@ -153,6 +154,7 @@ public final class Main { Runtime.getRuntime().addShutdownHook(new Thread(() -> { LOGGER.info("Shutting down server..."); + Context.getScheduleManager().stop(); if (Context.getWebServer() != null) { Context.getWebServer().stop(); } diff --git a/src/main/java/org/traccar/model/Event.java b/src/main/java/org/traccar/model/Event.java index ee7fcc679..5eee2a0a0 100644 --- a/src/main/java/org/traccar/model/Event.java +++ b/src/main/java/org/traccar/model/Event.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ public class Event extends Message { public static final String TYPE_DEVICE_ONLINE = "deviceOnline"; public static final String TYPE_DEVICE_UNKNOWN = "deviceUnknown"; public static final String TYPE_DEVICE_OFFLINE = "deviceOffline"; + public static final String TYPE_DEVICE_INACTIVE = "deviceInactive"; public static final String TYPE_DEVICE_MOVING = "deviceMoving"; public static final String TYPE_DEVICE_STOPPED = "deviceStopped"; diff --git a/src/main/java/org/traccar/schedule/ScheduleManager.java b/src/main/java/org/traccar/schedule/ScheduleManager.java new file mode 100644 index 000000000..3f19d6152 --- /dev/null +++ b/src/main/java/org/traccar/schedule/ScheduleManager.java @@ -0,0 +1,27 @@ +package org.traccar.schedule; + +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +public class ScheduleManager { + + private ScheduledExecutorService executor; + + public void start() { + + executor = Executors.newSingleThreadScheduledExecutor(); + + new TaskDeviceInactivityCheck().schedule(executor); + + } + + public void stop() { + + if (executor != null) { + executor.shutdown(); + executor = null; + } + + } + +} diff --git a/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java b/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java new file mode 100644 index 000000000..80641d7d4 --- /dev/null +++ b/src/main/java/org/traccar/schedule/TaskDeviceInactivityCheck.java @@ -0,0 +1,79 @@ +/* + * Copyright 2020 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.schedule; + +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Position; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class TaskDeviceInactivityCheck implements Runnable { + + public static final String ATTRIBUTE_DEVICE_INACTIVITY_START = "deviceInactivityStart"; + public static final String ATTRIBUTE_DEVICE_INACTIVITY_PERIOD = "deviceInactivityPeriod"; + public static final String ATTRIBUTE_LAST_UPDATE = "lastUpdate"; + + private static final long CHECK_PERIOD_MINUTES = 15; + + public void schedule(ScheduledExecutorService executor) { + executor.scheduleAtFixedRate(this, CHECK_PERIOD_MINUTES, CHECK_PERIOD_MINUTES, TimeUnit.MINUTES); + } + + @Override + public void run() { + long currentTime = System.currentTimeMillis(); + long checkPeriod = TimeUnit.MINUTES.toMillis(CHECK_PERIOD_MINUTES); + + Map events = new HashMap<>(); + for (Device device : Context.getDeviceManager().getAllDevices()) { + if (device.getLastUpdate() != null && checkDevice(device, currentTime, checkPeriod)) { + Event event = new Event(Event.TYPE_DEVICE_INACTIVE, device.getId()); + event.set(ATTRIBUTE_LAST_UPDATE, device.getLastUpdate().getTime()); + events.put(event, null); + } + } + + Context.getNotificationManager().updateEvents(events); + } + + private boolean checkDevice(Device device, long currentTime, long checkPeriod) { + long deviceInactivityStart = device.getLong(ATTRIBUTE_DEVICE_INACTIVITY_START); + if (deviceInactivityStart > 0) { + long timeThreshold = device.getLastUpdate().getTime() + deviceInactivityStart; + if (currentTime >= timeThreshold) { + + if (currentTime - checkPeriod < timeThreshold) { + return true; + } + + long deviceInactivityPeriod = device.getLong(ATTRIBUTE_DEVICE_INACTIVITY_PERIOD); + if (deviceInactivityPeriod > 0) { + long count = (currentTime - timeThreshold - 1) / deviceInactivityPeriod; + timeThreshold += count * deviceInactivityPeriod; + return currentTime - checkPeriod < timeThreshold; + } + + } + } + return false; + } + +} diff --git a/templates/full/deviceInactive.vm b/templates/full/deviceInactive.vm new file mode 100644 index 000000000..51aead653 --- /dev/null +++ b/templates/full/deviceInactive.vm @@ -0,0 +1,12 @@ +#set($subject = "$device.name: inactive") +#set($lastUpdate = $dateTool.getDate()) +#set($ignore = $lastUpdate.setTime($event.getLong("lastUpdate"))) + + + +Device: $device.name
+Inactive
+Last Update: $dateTool.format("YYYY-MM-dd HH:mm:ss", $lastUpdate, $locale, $timezone)
+Link: $webUrl?eventId=$event.id + + diff --git a/templates/short/deviceInactive.vm b/templates/short/deviceInactive.vm new file mode 100644 index 000000000..d7431124c --- /dev/null +++ b/templates/short/deviceInactive.vm @@ -0,0 +1,3 @@ +#set($lastUpdate = $dateTool.getDate()) +#set($ignore = $lastUpdate.setTime($event.getLong("lastUpdate"))) +$device.name inactive from $dateTool.format("YYYY-MM-dd HH:mm:ss", $lastUpdate, $locale, $timezone) -- cgit v1.2.3