From 0bf22eb231e3eb9ecf912f41dcc8f5e7f7fa8865 Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 01:10:06 +0000 Subject: Fix INF message on GV310LAU --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 28 +++++++++++++++++----- .../protocol/Gl200TextProtocolDecoderTest.java | 11 +++++++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 7a8d67cf9..b998f718e 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -122,12 +122,12 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_INF = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GTINF,") - .expression("(?:.{6}|.{10})?,") // protocol version + .expression("(.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("(?:[0-9A-Z]{17},)?") // vin .expression("(?:[^,]+)?,") // device name .number("(xx),") // state - .expression("(?:[0-9Ff]{20})?,") // iccid + .expression("([0-9Ff]{20})?,") // iccid .number("(d{1,2}),") // rssi .number("d{1,2},") .expression("[01]{1,2},") // external power @@ -148,6 +148,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { .expression("(?:[01])?,").optional() // pin15 mode .number("(d+)?,") // adc1 .number("(d+)?,").optional() // adc2 + .number("(d+)?,").optional() // adc3 .number("(xx)?,") // digital input .number("(xx)?,") // digital output .number("[-+]dddd,") // timezone @@ -163,10 +164,17 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private Object decodeInf(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_INF, sentence); - Position position = initPosition(parser, channel, remoteAddress); - if (position == null) { + if (!parser.matches()) { return null; } + String protocolVersion = parser.next(); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + Position position = new Position(); + position.setProtocol(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); switch (parser.nextHexInt()) { case 0x16: @@ -197,9 +205,14 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { break; } + position.set(Position.KEY_ICCID, parser.next()); position.set(Position.KEY_RSSI, parser.nextInt()); - - parser.next(); // odometer or external power + + if (protocolVersion.startsWith("6E")) { // GV310LAU + position.set(Position.KEY_POWER, parser.nextDouble() / 1000); // odometer or external power + } else { + parser.next(); // odometer or external power + } position.set(Position.KEY_BATTERY, parser.nextDouble()); position.set(Position.KEY_CHARGE, parser.nextInt() == 1); @@ -210,6 +223,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + 1, parser.next()); position.set(Position.PREFIX_ADC + 2, parser.next()); + if (protocolVersion.startsWith("6E")) { + position.set(Position.PREFIX_ADC + 3, parser.next()); + } position.set(Position.KEY_INPUT, parser.next()); position.set(Position.KEY_OUTPUT, parser.next()); diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index b6e50e07d..768704b68 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -487,6 +487,17 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { verifyAttributes(decoder, buffer( "+ACK:GTGEO,1A0102,135790246811220,,0,0008,20100310172830,11F0")); + verifyAttributes(decoder, buffer( + "+RESP:GTINF,6E0202,868589060187625,RA82,11,89883030000091225018,41,0,1,12349,,4.15,0,1,0,0,20240328231013,0,0,0,0,00,00,+0000,0,20240328231015,7D4F")); + + verifyAttribute(decoder, buffer( + "+RESP:GTINF,6E0202,868589060187625,RA82,11,89883030000091225018,41,0,1,12349,,4.15,0,1,0,0,20240328231013,0,0,0,0,00,00,+0000,0,20240328231015,7D4F"), + Position.KEY_POWER, 12.349); + + verifyAttribute(decoder, buffer( + "+RESP:GTINF,6E0202,868589060187625,RA82,11,89883030000091225018,41,0,1,12349,,4.15,0,1,0,0,20240328231013,0,0,0,0,00,00,+0000,0,20240328231015,7D4F"), + Position.PREFIX_ADC + 3, "0"); + decoder.setModelOverride("GV355CEU"); verifyAttributes(decoder, buffer( -- cgit v1.2.3 From 2a57c25829fc11c2fcf4d55aa6b866f8fc6305f7 Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 01:17:59 +0000 Subject: fix trailing spaces --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index b998f718e..c0a2a2ea0 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -207,7 +207,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ICCID, parser.next()); position.set(Position.KEY_RSSI, parser.nextInt()); - + if (protocolVersion.startsWith("6E")) { // GV310LAU position.set(Position.KEY_POWER, parser.nextDouble() / 1000); // odometer or external power } else { -- cgit v1.2.3 From 97b61ee431d8384ad2c233adcd9e478b074bc41d Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 19:15:38 +0000 Subject: start refactoring --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 52 +++++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index c0a2a2ea0..0e08066ab 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -42,6 +42,7 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.TimeZone; +import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -51,6 +52,37 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private final DateFormat dateFormat; + private static final HashMap devices = new HashMap() {{ + put("52", "GL50"); + put("55", "GL50B"); + put("02", "GL200"); + put("04", "GV200"); + put("06", "GV300"); + put("08", "GMT100"); + put("09", "GV50P"); // GV50 Plus + put("0F", "GV55"); + put("50", "GV55W"); + put("10", "GV55 LITE"); + put("11", "GL500"); + put("1A", "GL300"); + put("1F", "GV500"); + put("5E", "GV500MAP"); + put("25", "GV300"); // New Version + put("35", "GV200"); // New Version + put("27", "GV300W"); + put("2F", "GV55"); // New Version + put("30", "GL300"); // New Version + put("36", "GV500"); // New Version + put("2C", "GL300W"); // New version + put("3F", "GMT100"); // New version + put("F8", "GV800W"); + put("41", "GV75W"); + put("FC", "GV600W"); + put("6E", "GV310LAU"); + put("802004", "GV58LAU"); + put("802005", "GV355CEU"); + }}; + public Gl200TextProtocolDecoder(Protocol protocol) { super(protocol); dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); @@ -62,9 +94,14 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { ignoreFixTime = getConfig().getBoolean(Keys.PROTOCOL_IGNORE_FIX_TIME.withPrefix(getProtocolName())); } - private String getDeviceModel(DeviceSession deviceSession, String value) { - String model = value.isEmpty() ? getDeviceModel(deviceSession) : value; - return model != null ? model.toUpperCase() : ""; + private String getDeviceModel(String protocolVersion) { + if (devices.containsKey(protocolVersion.substring(0, 2))) { + return devices.get(protocolVersion.substring(0, 2)); + } + if (devices.containsKey(protocolVersion.substring(0, 6))) { + return devices.get(protocolVersion.substring(0, 6)); + } + return ""; } private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { @@ -471,7 +508,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private Object decodeCan(Channel channel, SocketAddress remoteAddress, String[] v) throws ParseException { int index = 0; index += 1; // header - index += 1; // protocol version + String protocolVersion = v[index++]; // protocol version DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, v[index++]); if (deviceSession == null) { return null; @@ -480,7 +517,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - String model = getDeviceModel(deviceSession, v[index++]); + String model = getDeviceModel(protocolVersion); + index += 1; // device name index += 1; // report type index += 1; // can bus state long reportMask = Long.parseLong(v[index++], 16); @@ -888,13 +926,13 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private Object decodeEri(Channel channel, SocketAddress remoteAddress, String[] v) throws ParseException { int index = 0; index += 1; // header - index += 1; // protocol version + String protocolVersion = v[index++]; // protocol version DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, v[index++]); if (deviceSession == null) { return null; } - String model = getDeviceModel(deviceSession, v[index++]); + String model = getDeviceModel(protocolVersion); long mask = Long.parseLong(v[index++], 16); Double power = v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001; index += 1; // report type -- cgit v1.2.3 From b95fa6a433fe9fc464aa59256d0b33da46809d0b Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 19:43:06 +0000 Subject: C2 and F1 fallback to device name and attribute --- .../java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 0e08066ab..817e03f67 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -79,6 +79,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { put("41", "GV75W"); put("FC", "GV600W"); put("6E", "GV310LAU"); + put("C2", "GV600M"); + put("F1", "GV350M"); put("802004", "GV58LAU"); put("802005", "GV355CEU"); }}; @@ -94,14 +96,15 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { ignoreFixTime = getConfig().getBoolean(Keys.PROTOCOL_IGNORE_FIX_TIME.withPrefix(getProtocolName())); } - private String getDeviceModel(String protocolVersion) { + private String getDeviceModel(DeviceSession deviceSession, String value, String protocolVersion) { if (devices.containsKey(protocolVersion.substring(0, 2))) { return devices.get(protocolVersion.substring(0, 2)); } if (devices.containsKey(protocolVersion.substring(0, 6))) { return devices.get(protocolVersion.substring(0, 6)); } - return ""; + String model = value.isEmpty() ? getDeviceModel(deviceSession) : value; + return model != null ? model.toUpperCase() : ""; } private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { @@ -517,8 +520,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - String model = getDeviceModel(protocolVersion); - index += 1; // device name + String model = getDeviceModel(deviceSession, v[index++], protocolVersion); index += 1; // report type index += 1; // can bus state long reportMask = Long.parseLong(v[index++], 16); @@ -932,7 +934,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return null; } - String model = getDeviceModel(protocolVersion); + String model = getDeviceModel(deviceSession, v[index++], protocolVersion); long mask = Long.parseLong(v[index++], 16); Double power = v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001; index += 1; // report type -- cgit v1.2.3 From 7ed2a8b54d9e269b0b5d180dc976d38926cd5bac Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 19:58:44 +0000 Subject: order device models by id use getDeviceModel --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 23 +++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 817e03f67..16098bc05 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -52,35 +52,35 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private final DateFormat dateFormat; - private static final HashMap devices = new HashMap() {{ - put("52", "GL50"); - put("55", "GL50B"); + private static final HashMap devices = new HashMap() {{ put("02", "GL200"); put("04", "GV200"); put("06", "GV300"); put("08", "GMT100"); put("09", "GV50P"); // GV50 Plus put("0F", "GV55"); - put("50", "GV55W"); put("10", "GV55 LITE"); put("11", "GL500"); put("1A", "GL300"); put("1F", "GV500"); - put("5E", "GV500MAP"); put("25", "GV300"); // New Version - put("35", "GV200"); // New Version put("27", "GV300W"); + put("2C", "GL300W"); // New version put("2F", "GV55"); // New Version put("30", "GL300"); // New Version + put("35", "GV200"); // New Version put("36", "GV500"); // New Version - put("2C", "GL300W"); // New version put("3F", "GMT100"); // New version - put("F8", "GV800W"); put("41", "GV75W"); - put("FC", "GV600W"); + put("50", "GV55W"); + put("52", "GL50"); + put("55", "GL50B"); + put("5E", "GV500MAP"); put("6E", "GV310LAU"); put("C2", "GV600M"); put("F1", "GV350M"); + put("F8", "GV800W"); + put("FC", "GV600W"); put("802004", "GV58LAU"); put("802005", "GV355CEU"); }}; @@ -248,7 +248,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ICCID, parser.next()); position.set(Position.KEY_RSSI, parser.nextInt()); - if (protocolVersion.startsWith("6E")) { // GV310LAU + String model = getDeviceModel(deviceSession, "", protocolVersion); + if (model.equals("GV310LAU")) { position.set(Position.KEY_POWER, parser.nextDouble() / 1000); // odometer or external power } else { parser.next(); // odometer or external power @@ -263,7 +264,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.PREFIX_ADC + 1, parser.next()); position.set(Position.PREFIX_ADC + 2, parser.next()); - if (protocolVersion.startsWith("6E")) { + if (model.equals("GV310LAU")) { position.set(Position.PREFIX_ADC + 3, parser.next()); } -- cgit v1.2.3 From 1450fc6a6cb3d56eefff7d0f222a868b3568c592 Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 20:04:18 +0000 Subject: fix trailing spaces fix naming convention --- .../java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 16098bc05..9b7737b36 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -52,7 +52,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private final DateFormat dateFormat; - private static final HashMap devices = new HashMap() {{ + private static final HashMap DEVICE_MODELS = new HashMap() {{ put("02", "GL200"); put("04", "GV200"); put("06", "GV300"); @@ -97,11 +97,11 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } private String getDeviceModel(DeviceSession deviceSession, String value, String protocolVersion) { - if (devices.containsKey(protocolVersion.substring(0, 2))) { - return devices.get(protocolVersion.substring(0, 2)); + if (DEVICE_MODELS.containsKey(protocolVersion.substring(0, 2))) { + return DEVICE_MODELS.get(protocolVersion.substring(0, 2)); } - if (devices.containsKey(protocolVersion.substring(0, 6))) { - return devices.get(protocolVersion.substring(0, 6)); + if (DEVICE_MODELS.containsKey(protocolVersion.substring(0, 6))) { + return DEVICE_MODELS.get(protocolVersion.substring(0, 6)); } String model = value.isEmpty() ? getDeviceModel(deviceSession) : value; return model != null ? model.toUpperCase() : ""; -- cgit v1.2.3 From 078ddb342c7af83d22767224a7d5b7c7e8ab4fe7 Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 21:57:07 +0000 Subject: Statics should be above instance variables. remove comments --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 9b7737b36..e30fafcaf 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -47,30 +47,26 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { - - private boolean ignoreFixTime; - - private final DateFormat dateFormat; - + private static final HashMap DEVICE_MODELS = new HashMap() {{ put("02", "GL200"); put("04", "GV200"); put("06", "GV300"); put("08", "GMT100"); - put("09", "GV50P"); // GV50 Plus + put("09", "GV50P"); put("0F", "GV55"); put("10", "GV55 LITE"); put("11", "GL500"); put("1A", "GL300"); put("1F", "GV500"); - put("25", "GV300"); // New Version + put("25", "GV300"); put("27", "GV300W"); - put("2C", "GL300W"); // New version - put("2F", "GV55"); // New Version - put("30", "GL300"); // New Version - put("35", "GV200"); // New Version - put("36", "GV500"); // New Version - put("3F", "GMT100"); // New version + put("2C", "GL300W"); + put("2F", "GV55"); + put("30", "GL300"); + put("35", "GV200"); + put("36", "GV500"); + put("3F", "GMT100"); put("41", "GV75W"); put("50", "GV55W"); put("52", "GL50"); @@ -85,6 +81,10 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { put("802005", "GV355CEU"); }}; + private boolean ignoreFixTime; + + private final DateFormat dateFormat; + public Gl200TextProtocolDecoder(Protocol protocol) { super(protocol); dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); @@ -108,13 +108,13 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { - if (parser.matches()) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession != null) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - return position; - } +if (parser.matches()) { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession != null) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + return position; +} } return null; } @@ -294,7 +294,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private Object decodeVer(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_VER, sentence); - Position position = initPosition(parser, channel, remoteAddress); + Position position = initPosition(parser, channel, remoteAddress); if (position == null) { return null; } -- cgit v1.2.3 From b0b1257473b8895ba4e8b867442c13f5b7c048f7 Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 21:59:13 +0000 Subject: fix identation --- .../org/traccar/protocol/Gl200TextProtocolDecoder.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index e30fafcaf..bf8644033 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -108,13 +108,13 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { -if (parser.matches()) { - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); - if (deviceSession != null) { - Position position = new Position(getProtocolName()); - position.setDeviceId(deviceSession.getDeviceId()); - return position; -} + if (parser.matches()) { + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession != null) { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + return position; + } } return null; } -- cgit v1.2.3 From 51dd3b44a6e81f523f37aacb23ad5b39de1d9eca Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 22:00:32 +0000 Subject: remove trailing spaces --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index bf8644033..b953aa8ca 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -83,7 +83,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private boolean ignoreFixTime; - private final DateFormat dateFormat; + private final DateFormat dateFormat; public Gl200TextProtocolDecoder(Protocol protocol) { super(protocol); -- cgit v1.2.3 From 432a59c8e15e0ce5ed0cb472864f627e3eadea6e Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 22:26:21 +0000 Subject: 50: Line has trailing spaces --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index b953aa8ca..1d4688e69 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -47,7 +47,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { - + private static final HashMap DEVICE_MODELS = new HashMap() {{ put("02", "GL200"); put("04", "GV200"); -- cgit v1.2.3 From 829387a48e278ea7428ee719cf6973ecf36271b9 Mon Sep 17 00:00:00 2001 From: jcardus Date: Fri, 29 Mar 2024 22:32:00 +0000 Subject: weird --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 1d4688e69..623352106 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -294,7 +294,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private Object decodeVer(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_VER, sentence); - Position position = initPosition(parser, channel, remoteAddress); + Position position = initPosition(parser, channel, remoteAddress); if (position == null) { return null; } -- cgit v1.2.3 From 9e750264dd9a1cbfbd7e1aadfdeedbcdbb5d0a0d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 30 Mar 2024 07:19:43 -0700 Subject: Refactor and add more models --- .../traccar/protocol/Gl200TextProtocolDecoder.java | 104 ++++++++++++--------- .../protocol/Gl200TextProtocolDecoderTest.java | 16 ++-- 2 files changed, 65 insertions(+), 55 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 623352106..5ac7b2417 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -41,45 +41,52 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.TimeZone; -import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { - private static final HashMap DEVICE_MODELS = new HashMap() {{ - put("02", "GL200"); - put("04", "GV200"); - put("06", "GV300"); - put("08", "GMT100"); - put("09", "GV50P"); - put("0F", "GV55"); - put("10", "GV55 LITE"); - put("11", "GL500"); - put("1A", "GL300"); - put("1F", "GV500"); - put("25", "GV300"); - put("27", "GV300W"); - put("2C", "GL300W"); - put("2F", "GV55"); - put("30", "GL300"); - put("35", "GV200"); - put("36", "GV500"); - put("3F", "GMT100"); - put("41", "GV75W"); - put("50", "GV55W"); - put("52", "GL50"); - put("55", "GL50B"); - put("5E", "GV500MAP"); - put("6E", "GV310LAU"); - put("C2", "GV600M"); - put("F1", "GV350M"); - put("F8", "GV800W"); - put("FC", "GV600W"); - put("802004", "GV58LAU"); - put("802005", "GV355CEU"); - }}; + private static final Map PROTOCOL_MODELS = Map.ofEntries( + Map.entry("02", "GL200"), + Map.entry("04", "GV200"), + Map.entry("06", "GV300"), + Map.entry("08", "GMT100"), + Map.entry("09", "GV50P"), + Map.entry("0F", "GV55"), + Map.entry("10", "GV55 LITE"), + Map.entry("11", "GL500"), + Map.entry("1A", "GL300"), + Map.entry("1F", "GV500"), + Map.entry("25", "GV300"), + Map.entry("27", "GV300W"), + Map.entry("28", "GL300VC"), + Map.entry("2C", "GL300W"), + Map.entry("2F", "GV55"), + Map.entry("30", "GL300"), + Map.entry("31", "GV65"), + Map.entry("35", "GV200"), + Map.entry("36", "GV500"), + Map.entry("3F", "GMT100"), + Map.entry("40", "GL500"), + Map.entry("41", "GV75W"), + Map.entry("42", "GT501"), + Map.entry("44", "GL530"), + Map.entry("45", "GB100"), + Map.entry("50", "GV55W"), + Map.entry("52", "GL50"), + Map.entry("55", "GL50B"), + Map.entry("5E", "GV500MAP"), + Map.entry("6E", "GV310LAU"), + Map.entry("C2", "GV600M"), + Map.entry("DC", "GV600MG"), + Map.entry("DE", "GL500M"), + Map.entry("F1", "GV350M"), + Map.entry("F8", "GV800W"), + Map.entry("FC", "GV600W"), + Map.entry("802004", "GV58LAU"), + Map.entry("802005", "GV355CEU")); private boolean ignoreFixTime; @@ -96,15 +103,18 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { ignoreFixTime = getConfig().getBoolean(Keys.PROTOCOL_IGNORE_FIX_TIME.withPrefix(getProtocolName())); } - private String getDeviceModel(DeviceSession deviceSession, String value, String protocolVersion) { - if (DEVICE_MODELS.containsKey(protocolVersion.substring(0, 2))) { - return DEVICE_MODELS.get(protocolVersion.substring(0, 2)); + private String getDeviceModel(DeviceSession deviceSession, String protocolVersion) { + String declaredModel = getDeviceModel(deviceSession); + if (declaredModel != null) { + return declaredModel.toUpperCase(); } - if (DEVICE_MODELS.containsKey(protocolVersion.substring(0, 6))) { - return DEVICE_MODELS.get(protocolVersion.substring(0, 6)); + if (PROTOCOL_MODELS.containsKey(protocolVersion.substring(0, 2))) { + return PROTOCOL_MODELS.get(protocolVersion.substring(0, 2)); } - String model = value.isEmpty() ? getDeviceModel(deviceSession) : value; - return model != null ? model.toUpperCase() : ""; + if (PROTOCOL_MODELS.containsKey(protocolVersion.substring(0, 6))) { + return PROTOCOL_MODELS.get(protocolVersion.substring(0, 6)); + } + return ""; } private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { @@ -162,12 +172,12 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { private static final Pattern PATTERN_INF = new PatternBuilder() .text("+").expression("(?:RESP|BUFF):GTINF,") - .expression("(.{6}|.{10})?,") // protocol version + .expression("(.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("(?:[0-9A-Z]{17},)?") // vin .expression("(?:[^,]+)?,") // device name .number("(xx),") // state - .expression("([0-9Ff]{20})?,") // iccid + .expression("([0-9Ff]{20})?,") // iccid .number("(d{1,2}),") // rssi .number("d{1,2},") .expression("[01]{1,2},") // external power @@ -248,9 +258,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ICCID, parser.next()); position.set(Position.KEY_RSSI, parser.nextInt()); - String model = getDeviceModel(deviceSession, "", protocolVersion); + String model = getDeviceModel(deviceSession, protocolVersion); if (model.equals("GV310LAU")) { - position.set(Position.KEY_POWER, parser.nextDouble() / 1000); // odometer or external power + position.set(Position.KEY_POWER, parser.nextDouble() / 1000); } else { parser.next(); // odometer or external power } @@ -521,7 +531,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - String model = getDeviceModel(deviceSession, v[index++], protocolVersion); + String model = getDeviceModel(deviceSession, protocolVersion); + index += 1; // device name index += 1; // report type index += 1; // can bus state long reportMask = Long.parseLong(v[index++], 16); @@ -935,7 +946,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { return null; } - String model = getDeviceModel(deviceSession, v[index++], protocolVersion); + String model = getDeviceModel(deviceSession, protocolVersion); + index += 1; // device name long mask = Long.parseLong(v[index++], 16); Double power = v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001; index += 1; // report type diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 768704b68..bc1bee229 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -52,14 +52,14 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTFRI,5E0100,862061048023666,,,12940,10,1,1,0.0,97,179.8,-90.366478,38.735379,20230616183231,0310,0410,6709,03ADF710,00,6223.7,,,,,110000,,,,202306161834$")); verifyAttribute(decoder, buffer( - "+BUFF:GTERI,410502,864802030794634,GV75W,00000001,,10,1,1,0.0,0,3027.8,-78.706612,-0.955699,20230418170736,0740,0002,A08C,2AB72D,00,0.0,,,,100,110000,1,0099,20230418171004,8B98$"), + "+BUFF:GTERI,410502,864802030794634,,00000001,,10,1,1,0.0,0,3027.8,-78.706612,-0.955699,20230418170736,0740,0002,A08C,2AB72D,00,0.0,,,,100,110000,1,0099,20230418171004,8B98$"), Position.KEY_FUEL_LEVEL, 153); verifyPositions(decoder, false, buffer( "+BUFF:GTFRI,2E0503,861106050005423,,,0,1,,,,,,,,,,,,0,0,,98,1,0,,,20200101000001,0083$")); verifyAttribute(decoder, buffer( - "+RESP:GTERI,271002,863457051562823,GV300,00000002,,10,1,1,0.0,15,28.2,-58.695253,-34.625413,20230119193305,0722,0007,1168,16B3BB,00,0.0,,,,99,210100,2,1,28F8A149F69A3C25,1,0190,20230119193314,07C7$"), + "+RESP:GTERI,271002,863457051562823,,00000002,,10,1,1,0.0,15,28.2,-58.695253,-34.625413,20230119193305,0722,0007,1168,16B3BB,00,0.0,,,,99,210100,2,1,28F8A149F69A3C25,1,0190,20230119193314,07C7$"), Position.PREFIX_TEMP + 1, 25.0); verifyAttribute(decoder, buffer( @@ -176,7 +176,7 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTERI,310603,863286023345490,,00000002,,10,1,2,0.3,0,155.7,8.000000,52.000000,20171215213040,0262,0002,1450,9F13,00,1130.3,00539:27:19,,,110000,2,1,28FFD5239115034E,1,,20171215213041,27C7$")); verifyPositions(decoder, buffer( - "+RESP:GTERI,250C02,868789023691057,GV300,00000019,,10,1,1,0.0,196,2258.0,-99.201807,19.559242,20180214002957,0334,0003,235B,7F8D,00,6786.7,,,,100,110000,1,0394,1,4,100.0,100.0,20180214003006,C72B$")); + "+RESP:GTERI,250C02,868789023691057,,00000019,,10,1,1,0.0,196,2258.0,-99.201807,19.559242,20180214002957,0334,0003,235B,7F8D,00,6786.7,,,,100,110000,1,0394,1,4,100.0,100.0,20180214003006,C72B$")); verifyAttributes(decoder, buffer( "+RESP:GTCAN,310603,863286023335723,gv65,00,1,C03FFFFF,,0,,719601.00,,,,,,,,274.99,179.02,95.98,84761.00,,,0,,0,,,0,0.0,216,29.8,-2.155296,51.899400,20180209172714,0234,0010,53F3,8D38,00,20180211002128,E94E$")); @@ -203,7 +203,7 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTOBD,360701,864251020253807,LSGTC58UX7Y067312,GV500,0,70FFFF,LSGTC58UX7Y067312,1,12309,983A8140,0,0,33,nan,,0,0,0,,10,0,,0,4.4,0,83.7,36.235142,49.967324,20170829112348,0255,0001,2760,9017,00,690.1,20170829112400,3456$")); verifyPositions(decoder, buffer( - "+RESP:GTERI,060502,861074023620928,GV300,00000002,27822,10,1,1,0.0,84,2870.9,-78.531796,-0.277329,20170825045344,,,,,,0.0,01138:30:24,,,83,220104,2,1,28FF2776A2150308,1,FFAD,0,20170825045348,A88C$")); + "+RESP:GTERI,060502,861074023620928,,00000002,27822,10,1,1,0.0,84,2870.9,-78.531796,-0.277329,20170825045344,,,,,,0.0,01138:30:24,,,83,220104,2,1,28FF2776A2150308,1,FFAD,0,20170825045348,A88C$")); verifyAttributes(decoder, buffer( "+RESP:GTINF,280500,A1000043D20139,GL300VC,41,,31,0,0,,,3.87,0,1,1,,,20170802150751,70,,48.0,,,20170802112145,03AC$")); @@ -218,7 +218,7 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTTRI,862370030005908,1,0,99,1,0.0,354,18.5,18.821100,-34.084002,20170607152024,0655,0001,00DD,1CAE,00,0103010100,20170607172115,3E7D$")); verifyPositions(decoder, buffer( - "+RESP:GTERI,060800,861074023677175,GV300,00000002,12351,10,1,1,0.0,0,2862.4,-78.467273,-0.164998,20170529181717,,,,,,0.0,00259:11:50,,,0,210104,2,1,28E17436060000E2,1,015F,0,20170529181723,2824$")); + "+RESP:GTERI,060800,861074023677175,,00000002,12351,10,1,1,0.0,0,2862.4,-78.467273,-0.164998,20170529181717,,,,,,0.0,00259:11:50,,,0,210104,2,1,28E17436060000E2,1,015F,0,20170529181723,2824$")); verifyPosition(decoder, buffer( "+RESP:GTSWG,110100,358688000000158,,1,0,2.1,0,27.1,121.390717,31.164424,20110901073917,0460,0000,1878,0873,,20110901154653,0015$")); @@ -239,7 +239,7 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTFRI,060228,862894020180553,,14827,10,1,1,3.4,199,409.6,-63.174466,-17.739317,20170407121823,0000,0000,0000,0000,00,15989.5,01070:43:13,13,180,0,220101,,,,20170407081824,9607$")); verifyPositions(decoder, buffer( - "+RESP:GTERI,060502,861074023376992,GV300,00000002,27239,10,1,1,0.2,312,183.3,-79.320820,-2.499110,20170401212005,0740,0000,EE4E,C98F,00,0.0,02114:36:35,,,90,220504,2,0,0,20170401212007,9E3D$")); + "+RESP:GTERI,060502,861074023376992,,00000002,27239,10,1,1,0.2,312,183.3,-79.320820,-2.499110,20170401212005,0740,0000,EE4E,C98F,00,0.0,02114:36:35,,,90,220504,2,0,0,20170401212007,9E3D$")); verifyPositions(decoder, buffer( "+RESP:GTFRI,060502,861074023689626,,25202,10,1,1,0.0,0,2744.1,-78.261047,0.023452,20170401211940,,,,,,0.0,00079:19:15,,,51,110000,,,,20170401212003,4DA7$")); @@ -251,7 +251,7 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTERI,06020B,862170010196747,,00000000,,10,1,2,1.8,0,-2.5,117.198440,31.845219,20120802061037,0460,0000,5663,0358,00,0.0,,,,0,410000,20120802061040,0012$")); verifyPositions(decoder, buffer( - "+RESP:GTERI,060502,861074023692562,GV300,00000002,14197,10,1,1,0.2,220,491.8,-79.064212,-2.159754,20170401212007,0740,0000,EE49,CE25,00,0.0,01509:10:58,,,87,220104,2,0,0,20170401212010,D14D$")); + "+RESP:GTERI,060502,861074023692562,,00000002,14197,10,1,1,0.2,220,491.8,-79.064212,-2.159754,20170401212007,0740,0000,EE49,CE25,00,0.0,01509:10:58,,,87,220104,2,0,0,20170401212010,D14D$")); verifyPositions(decoder, buffer( "+RESP:GTFRI,210102,354524044925825,,1,1,1,29,2.8,0,133.7,-90.203063,32.265473,20170318005208,,,,,10800,4,20170318005208,0002$")); @@ -498,8 +498,6 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { "+RESP:GTINF,6E0202,868589060187625,RA82,11,89883030000091225018,41,0,1,12349,,4.15,0,1,0,0,20240328231013,0,0,0,0,00,00,+0000,0,20240328231015,7D4F"), Position.PREFIX_ADC + 3, "0"); - decoder.setModelOverride("GV355CEU"); - verifyAttributes(decoder, buffer( "+RESP:GTCAN,8020050605,867488060270575,,00,1,FFFFFFFF,8LBETF3W4N0001613,,,22.54,0,,,,,,,7.84,4.61,3.24,3.33,,8080,,,00,0.00,0.00,1,14,14,2371,0,001FFFFF,,,,,,,,,7158,9998,0,7.84,0.00,0.00,558,,,,,,,C0,,,,,0,0.0,346,2848.5,-78.592371,-0.968132,20240202083437,0740,0002,526C,00AE7907,00,20240202083440,3F6D$")); -- cgit v1.2.3 From 3066f3ccfa2a674fae27922f9f94b5e16eb68f9b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 30 Mar 2024 07:29:04 -0700 Subject: Model detection optimization --- .../org/traccar/protocol/Gl200TextProtocolDecoder.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 5ac7b2417..b14f64f4a 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -79,6 +79,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { Map.entry("55", "GL50B"), Map.entry("5E", "GV500MAP"), Map.entry("6E", "GV310LAU"), + Map.entry("BD", "CV200"), Map.entry("C2", "GV600M"), Map.entry("DC", "GV600MG"), Map.entry("DE", "GL500M"), @@ -108,13 +109,14 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (declaredModel != null) { return declaredModel.toUpperCase(); } - if (PROTOCOL_MODELS.containsKey(protocolVersion.substring(0, 2))) { - return PROTOCOL_MODELS.get(protocolVersion.substring(0, 2)); - } - if (PROTOCOL_MODELS.containsKey(protocolVersion.substring(0, 6))) { - return PROTOCOL_MODELS.get(protocolVersion.substring(0, 6)); + String versionPrefix; + if (protocolVersion.length() > 6) { + versionPrefix = protocolVersion.substring(0, 6); + } else { + versionPrefix = protocolVersion.substring(0, 2); } - return ""; + String model = PROTOCOL_MODELS.get(versionPrefix); + return model != null ? model : ""; } private Position initPosition(Parser parser, Channel channel, SocketAddress remoteAddress) { -- cgit v1.2.3 From 8fe2d697064c88f5dadf5ca3aeca51ba7e925fd9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 30 Mar 2024 07:38:13 -0700 Subject: Support virtual ignition messages --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 6 ++++-- .../java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index b14f64f4a..775e98401 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -1031,7 +1031,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { } private static final Pattern PATTERN_IGN = new PatternBuilder() - .text("+").expression("(?:RESP|BUFF):GTIG[NF],") + .text("+").expression("(?:RESP|BUFF):GT[IV]G[NF],") .expression("(?:.{6}|.{10})?,") // protocol version .number("(d{15}|x{14}),") // imei .expression("[^,]*,") // device name @@ -1055,7 +1055,7 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { decodeLocation(position, parser); - position.set(Position.KEY_IGNITION, sentence.contains("IGN")); + position.set(Position.KEY_IGNITION, sentence.contains("GN")); position.set(Position.KEY_HOURS, parseHours(parser.next())); position.set(Position.KEY_ODOMETER, parser.nextDouble() * 1000); @@ -1677,6 +1677,8 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { break; case "IGN": case "IGF": + case "VGN": + case "VGF": result = decodeIgn(channel, remoteAddress, sentence); break; case "LSW": diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index bc1bee229..4cccf8fa2 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,14 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "+RESP:GTVGN,C2010D,869653060009939,GV600M,453966,0,0.0,0,163.9,10.239379,45.931389,20231210233723,0222,0010,2F31,006D7621,,,0.0,20240107182623,143F$"), + Position.KEY_IGNITION, true); + + verifyAttribute(decoder, buffer( + "+RESP:GTIGF,8020050502,867488060278727,,509,1,0.0,184,32.6,14.003446,42.654554,20240219124629,0222,0001,0FAD,0497F715,00,,0.0,20240219124630,FD2F$"), + Position.KEY_IGNITION, false); + verifyPositions(decoder, buffer( "+RESP:GTERI,C2010D,869653060009939,GV600M,00000100,,10,1,0,0.0,0,163.9,10.239379,45.931389,20231210233723,0222,0010,2F31,006D7621,,0.0,,,,3,410000,,1,0,6,4,0,,01BF,Sondaporte,EA7D0A3882F6,1,3484,21.81,43,00,00,0,0,0,20240114221802,1875$")); -- cgit v1.2.3 From ee996425221ca64fdf00777d9035cedc6dccfa43 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 30 Mar 2024 15:23:00 -0700 Subject: Improve time handler --- src/main/java/org/traccar/handler/TimeHandler.java | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/traccar/handler/TimeHandler.java b/src/main/java/org/traccar/handler/TimeHandler.java index 3c3e17450..ef0c3445d 100644 --- a/src/main/java/org/traccar/handler/TimeHandler.java +++ b/src/main/java/org/traccar/handler/TimeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2024 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. @@ -18,13 +18,12 @@ package org.traccar.handler; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; -import org.traccar.BaseProtocolDecoder; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -56,17 +55,16 @@ public class TimeHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { - if (enabled && msg instanceof Position && (protocols == null - || protocols.contains(ctx.pipeline().get(BaseProtocolDecoder.class).getProtocolName()))) { - + if (enabled && msg instanceof Position) { Position position = (Position) msg; - if (useServerTime) { - position.setDeviceTime(position.getServerTime()); - position.setFixTime(position.getServerTime()); - } else { - position.setFixTime(position.getDeviceTime()); + if (protocols == null || protocols.contains(position.getProtocol())) { + if (useServerTime) { + position.setDeviceTime(position.getServerTime()); + position.setFixTime(position.getServerTime()); + } else { + position.setFixTime(position.getDeviceTime()); + } } - } ctx.fireChannelRead(msg); } -- cgit v1.2.3 From f84e2710e05660822633ec9e61cde44c03a42d7e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 30 Mar 2024 18:46:37 -0700 Subject: Refactor position and event handlers --- debug.xml | 1 + src/main/java/org/traccar/BaseDataHandler.java | 38 ---- src/main/java/org/traccar/BasePipelineFactory.java | 97 +++------- .../java/org/traccar/ExtendedObjectDecoder.java | 2 +- src/main/java/org/traccar/MainEventHandler.java | 194 -------------------- .../org/traccar/PositionForwardingHandler.java | 141 --------------- src/main/java/org/traccar/ProcessingHandler.java | 145 +++++++++++++++ .../traccar/handler/AcknowledgementHandler.java | 121 ------------- .../org/traccar/handler/BasePositionHandler.java | 27 +++ .../traccar/handler/ComputedAttributesHandler.java | 40 ++--- .../org/traccar/handler/CopyAttributesHandler.java | 16 +- .../java/org/traccar/handler/DatabaseHandler.java | 49 ++++++ .../org/traccar/handler/DefaultDataHandler.java | 55 ------ .../java/org/traccar/handler/DistanceHandler.java | 13 +- .../org/traccar/handler/EngineHoursHandler.java | 16 +- .../java/org/traccar/handler/FilterHandler.java | 25 +-- .../java/org/traccar/handler/GeocoderHandler.java | 65 ++++--- .../java/org/traccar/handler/GeofenceHandler.java | 15 +- .../org/traccar/handler/GeolocationHandler.java | 73 ++++---- .../org/traccar/handler/HemisphereHandler.java | 16 +- .../java/org/traccar/handler/MotionHandler.java | 16 +- .../traccar/handler/NetworkForwarderHandler.java | 72 -------- .../org/traccar/handler/NetworkMessageHandler.java | 57 ------ .../org/traccar/handler/OpenChannelHandler.java | 42 ----- .../traccar/handler/PositionForwardingHandler.java | 137 +++++++++++++++ .../org/traccar/handler/RemoteAddressHandler.java | 56 ------ .../org/traccar/handler/SpeedLimitHandler.java | 49 ++---- .../traccar/handler/StandardLoggingHandler.java | 89 ---------- src/main/java/org/traccar/handler/TimeHandler.java | 15 +- .../traccar/handler/events/AlertEventHandler.java | 17 +- .../traccar/handler/events/BaseEventHandler.java | 32 +--- .../handler/events/BehaviorEventHandler.java | 18 +- .../handler/events/CommandResultEventHandler.java | 17 +- .../traccar/handler/events/DriverEventHandler.java | 18 +- .../traccar/handler/events/FuelEventHandler.java | 22 +-- .../handler/events/GeofenceEventHandler.java | 21 +-- .../handler/events/IgnitionEventHandler.java | 25 +-- .../handler/events/MaintenanceEventHandler.java | 19 +- .../traccar/handler/events/MediaEventHandler.java | 16 +- .../traccar/handler/events/MotionEventHandler.java | 22 +-- .../handler/events/OverspeedEventHandler.java | 27 ++- .../handler/network/AcknowledgementHandler.java | 121 +++++++++++++ .../traccar/handler/network/MainEventHandler.java | 195 +++++++++++++++++++++ .../handler/network/NetworkForwarderHandler.java | 72 ++++++++ .../handler/network/NetworkMessageHandler.java | 57 ++++++ .../handler/network/OpenChannelHandler.java | 42 +++++ .../handler/network/RemoteAddressHandler.java | 54 ++++++ .../handler/network/StandardLoggingHandler.java | 89 ++++++++++ .../org/traccar/handler/DistanceHandlerTest.java | 5 +- .../org/traccar/handler/MotionHandlerTest.java | 3 +- .../handler/events/AlertEventHandlerTest.java | 12 +- .../events/CommandResultEventHandlerTest.java | 10 +- .../handler/events/IgnitionEventHandlerTest.java | 8 +- .../events/MaintenanceEventHandlerTest.java | 25 ++- 54 files changed, 1258 insertions(+), 1371 deletions(-) delete mode 100644 src/main/java/org/traccar/BaseDataHandler.java delete mode 100644 src/main/java/org/traccar/MainEventHandler.java delete mode 100644 src/main/java/org/traccar/PositionForwardingHandler.java create mode 100644 src/main/java/org/traccar/ProcessingHandler.java delete mode 100644 src/main/java/org/traccar/handler/AcknowledgementHandler.java create mode 100644 src/main/java/org/traccar/handler/BasePositionHandler.java create mode 100644 src/main/java/org/traccar/handler/DatabaseHandler.java delete mode 100644 src/main/java/org/traccar/handler/DefaultDataHandler.java delete mode 100644 src/main/java/org/traccar/handler/NetworkForwarderHandler.java delete mode 100644 src/main/java/org/traccar/handler/NetworkMessageHandler.java delete mode 100644 src/main/java/org/traccar/handler/OpenChannelHandler.java create mode 100644 src/main/java/org/traccar/handler/PositionForwardingHandler.java delete mode 100644 src/main/java/org/traccar/handler/RemoteAddressHandler.java delete mode 100644 src/main/java/org/traccar/handler/StandardLoggingHandler.java create mode 100644 src/main/java/org/traccar/handler/network/AcknowledgementHandler.java create mode 100644 src/main/java/org/traccar/handler/network/MainEventHandler.java create mode 100644 src/main/java/org/traccar/handler/network/NetworkForwarderHandler.java create mode 100644 src/main/java/org/traccar/handler/network/NetworkMessageHandler.java create mode 100644 src/main/java/org/traccar/handler/network/OpenChannelHandler.java create mode 100644 src/main/java/org/traccar/handler/network/RemoteAddressHandler.java create mode 100644 src/main/java/org/traccar/handler/network/StandardLoggingHandler.java diff --git a/debug.xml b/debug.xml index 2569bb8cd..028e9210b 100644 --- a/debug.xml +++ b/debug.xml @@ -16,6 +16,7 @@ true false + true true diff --git a/src/main/java/org/traccar/BaseDataHandler.java b/src/main/java/org/traccar/BaseDataHandler.java deleted file mode 100644 index 48794b0d7..000000000 --- a/src/main/java/org/traccar/BaseDataHandler.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2015 - 2018 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; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import org.traccar.model.Position; - -public abstract class BaseDataHandler extends ChannelInboundHandlerAdapter { - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof Position) { - Position position = handlePosition((Position) msg); - if (position != null) { - ctx.fireChannelRead(position); - } - } else { - super.channelRead(ctx, msg); - } - } - - protected abstract Position handlePosition(Position position); - -} diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java index ca4a4ae63..6d9431ad6 100644 --- a/src/main/java/org/traccar/BasePipelineFactory.java +++ b/src/main/java/org/traccar/BasePipelineFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2024 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. @@ -25,36 +25,13 @@ import io.netty.channel.ChannelPipeline; import io.netty.handler.timeout.IdleStateHandler; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.handler.AcknowledgementHandler; -import org.traccar.handler.ComputedAttributesHandler; -import org.traccar.handler.CopyAttributesHandler; -import org.traccar.handler.DefaultDataHandler; -import org.traccar.handler.DistanceHandler; -import org.traccar.handler.EngineHoursHandler; -import org.traccar.handler.FilterHandler; -import org.traccar.handler.GeocoderHandler; -import org.traccar.handler.GeofenceHandler; -import org.traccar.handler.GeolocationHandler; -import org.traccar.handler.HemisphereHandler; -import org.traccar.handler.MotionHandler; -import org.traccar.handler.NetworkForwarderHandler; -import org.traccar.handler.NetworkMessageHandler; -import org.traccar.handler.OpenChannelHandler; -import org.traccar.handler.RemoteAddressHandler; -import org.traccar.handler.SpeedLimitHandler; -import org.traccar.handler.StandardLoggingHandler; -import org.traccar.handler.TimeHandler; -import org.traccar.handler.events.AlertEventHandler; -import org.traccar.handler.events.BehaviorEventHandler; -import org.traccar.handler.events.CommandResultEventHandler; -import org.traccar.handler.events.DriverEventHandler; -import org.traccar.handler.events.FuelEventHandler; -import org.traccar.handler.events.GeofenceEventHandler; -import org.traccar.handler.events.IgnitionEventHandler; -import org.traccar.handler.events.MaintenanceEventHandler; -import org.traccar.handler.events.MediaEventHandler; -import org.traccar.handler.events.MotionEventHandler; -import org.traccar.handler.events.OverspeedEventHandler; +import org.traccar.handler.network.AcknowledgementHandler; +import org.traccar.handler.network.MainEventHandler; +import org.traccar.handler.network.NetworkForwarderHandler; +import org.traccar.handler.network.NetworkMessageHandler; +import org.traccar.handler.network.OpenChannelHandler; +import org.traccar.handler.network.RemoteAddressHandler; +import org.traccar.handler.network.StandardLoggingHandler; import java.util.Map; @@ -83,15 +60,7 @@ public abstract class BasePipelineFactory extends ChannelInitializer { protected abstract void addProtocolHandlers(PipelineBuilder pipeline); - @SafeVarargs - private void addHandlers(ChannelPipeline pipeline, Class... handlerClasses) { - for (Class handlerClass : handlerClasses) { - if (handlerClass != null) { - pipeline.addLast(injector.getInstance(handlerClass)); - } - } - } - + @SuppressWarnings("unchecked") public static T getHandler(ChannelPipeline pipeline, Class clazz) { for (Map.Entry handlerEntry : pipeline) { ChannelHandler handler = handlerEntry.getValue(); @@ -107,6 +76,11 @@ public abstract class BasePipelineFactory extends ChannelInitializer { return null; } + private T injectMembers(T object) { + injector.injectMembers(object); + return object; + } + @Override protected void initChannel(Channel channel) { final ChannelPipeline pipeline = channel.pipeline(); @@ -119,15 +93,11 @@ public abstract class BasePipelineFactory extends ChannelInitializer { pipeline.addLast(new OpenChannelHandler(connector)); if (config.hasKey(Keys.SERVER_FORWARD)) { int port = config.getInteger(Keys.PROTOCOL_PORT.withPrefix(protocol)); - var handler = new NetworkForwarderHandler(port); - injector.injectMembers(handler); - pipeline.addLast(handler); + pipeline.addLast(injectMembers(new NetworkForwarderHandler(port))); } pipeline.addLast(new NetworkMessageHandler()); - - var loggingHandler = new StandardLoggingHandler(protocol); - injector.injectMembers(loggingHandler); - pipeline.addLast(loggingHandler); + pipeline.addLast(new RemoteAddressHandler(config)); + pipeline.addLast(injectMembers(new StandardLoggingHandler(protocol))); if (!connector.isDatagram() && !config.getBoolean(Keys.SERVER_INSTANT_ACKNOWLEDGEMENT)) { pipeline.addLast(new AcknowledgementHandler()); @@ -135,7 +105,7 @@ public abstract class BasePipelineFactory extends ChannelInitializer { addProtocolHandlers(handler -> { if (handler instanceof BaseProtocolDecoder || handler instanceof BaseProtocolEncoder) { - injector.injectMembers(handler); + injectMembers(handler); } else { if (handler instanceof ChannelInboundHandler) { handler = new WrapperInboundHandler((ChannelInboundHandler) handler); @@ -146,35 +116,8 @@ public abstract class BasePipelineFactory extends ChannelInitializer { pipeline.addLast(handler); }); - addHandlers( - pipeline, - TimeHandler.class, - GeolocationHandler.class, - HemisphereHandler.class, - DistanceHandler.class, - RemoteAddressHandler.class, - FilterHandler.class, - GeofenceHandler.class, - GeocoderHandler.class, - SpeedLimitHandler.class, - MotionHandler.class, - CopyAttributesHandler.class, - EngineHoursHandler.class, - ComputedAttributesHandler.class, - PositionForwardingHandler.class, - DefaultDataHandler.class, - MediaEventHandler.class, - CommandResultEventHandler.class, - OverspeedEventHandler.class, - BehaviorEventHandler.class, - FuelEventHandler.class, - MotionEventHandler.class, - GeofenceEventHandler.class, - AlertEventHandler.class, - IgnitionEventHandler.class, - MaintenanceEventHandler.class, - DriverEventHandler.class, - MainEventHandler.class); + pipeline.addLast(injector.getInstance(ProcessingHandler.class)); + pipeline.addLast(injector.getInstance(MainEventHandler.class)); } } diff --git a/src/main/java/org/traccar/ExtendedObjectDecoder.java b/src/main/java/org/traccar/ExtendedObjectDecoder.java index cddddcd80..9468e2fff 100644 --- a/src/main/java/org/traccar/ExtendedObjectDecoder.java +++ b/src/main/java/org/traccar/ExtendedObjectDecoder.java @@ -23,7 +23,7 @@ import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.util.ReferenceCountUtil; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.handler.AcknowledgementHandler; +import org.traccar.handler.network.AcknowledgementHandler; import org.traccar.helper.DataConverter; import org.traccar.model.Position; diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java deleted file mode 100644 index fb0171d63..000000000 --- a/src/main/java/org/traccar/MainEventHandler.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2012 - 2022 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; - -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.socket.DatagramChannel; -import io.netty.handler.codec.http.HttpRequestDecoder; -import io.netty.handler.timeout.IdleStateEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.database.StatisticsManager; -import org.traccar.handler.AcknowledgementHandler; -import org.traccar.helper.DateUtil; -import org.traccar.helper.NetworkUtil; -import org.traccar.helper.model.PositionUtil; -import org.traccar.model.Device; -import org.traccar.model.Position; -import org.traccar.session.ConnectionManager; -import org.traccar.session.cache.CacheManager; -import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; - -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.util.Arrays; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; - -@Singleton -@ChannelHandler.Sharable -public class MainEventHandler extends ChannelInboundHandlerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(MainEventHandler.class); - - private final Set connectionlessProtocols = new HashSet<>(); - private final Set logAttributes = new LinkedHashSet<>(); - - private final CacheManager cacheManager; - private final Storage storage; - private final ConnectionManager connectionManager; - private final StatisticsManager statisticsManager; - - @Inject - public MainEventHandler( - Config config, CacheManager cacheManager, Storage storage, ConnectionManager connectionManager, - StatisticsManager statisticsManager) { - this.cacheManager = cacheManager; - this.storage = storage; - this.connectionManager = connectionManager; - this.statisticsManager = statisticsManager; - String connectionlessProtocolList = config.getString(Keys.STATUS_IGNORE_OFFLINE); - if (connectionlessProtocolList != null) { - connectionlessProtocols.addAll(Arrays.asList(connectionlessProtocolList.split("[, ]"))); - } - logAttributes.addAll(Arrays.asList(config.getString(Keys.LOGGER_ATTRIBUTES).split("[, ]"))); - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) { - if (msg instanceof Position) { - - Position position = (Position) msg; - Device device = cacheManager.getObject(Device.class, position.getDeviceId()); - - try { - if (PositionUtil.isLatest(cacheManager, position)) { - Device updatedDevice = new Device(); - updatedDevice.setId(position.getDeviceId()); - updatedDevice.setPositionId(position.getId()); - storage.updateObject(updatedDevice, new Request( - new Columns.Include("positionId"), - new Condition.Equals("id", updatedDevice.getId()))); - - cacheManager.updatePosition(position); - connectionManager.updatePosition(true, position); - } - } catch (StorageException error) { - LOGGER.warn("Failed to update device", error); - } - - StringBuilder builder = new StringBuilder(); - builder.append("[").append(NetworkUtil.session(ctx.channel())).append("] "); - builder.append("id: ").append(device.getUniqueId()); - for (String attribute : logAttributes) { - switch (attribute) { - case "time": - builder.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false)); - break; - case "position": - builder.append(", lat: ").append(String.format("%.5f", position.getLatitude())); - builder.append(", lon: ").append(String.format("%.5f", position.getLongitude())); - break; - case "speed": - if (position.getSpeed() > 0) { - builder.append(", speed: ").append(String.format("%.1f", position.getSpeed())); - } - break; - case "course": - builder.append(", course: ").append(String.format("%.1f", position.getCourse())); - break; - case "accuracy": - if (position.getAccuracy() > 0) { - builder.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy())); - } - break; - case "outdated": - if (position.getOutdated()) { - builder.append(", outdated"); - } - break; - case "invalid": - if (!position.getValid()) { - builder.append(", invalid"); - } - break; - default: - Object value = position.getAttributes().get(attribute); - if (value != null) { - builder.append(", ").append(attribute).append(": ").append(value); - } - break; - } - } - LOGGER.info(builder.toString()); - - statisticsManager.registerMessageStored(position.getDeviceId(), position.getProtocol()); - - ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position)); - } - } - - @Override - public void channelActive(ChannelHandlerContext ctx) { - if (!(ctx.channel() instanceof DatagramChannel)) { - LOGGER.info("[{}] connected", NetworkUtil.session(ctx.channel())); - } - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) { - LOGGER.info("[{}] disconnected", NetworkUtil.session(ctx.channel())); - closeChannel(ctx.channel()); - - boolean supportsOffline = BasePipelineFactory.getHandler(ctx.pipeline(), HttpRequestDecoder.class) == null - && !connectionlessProtocols.contains(ctx.pipeline().get(BaseProtocolDecoder.class).getProtocolName()); - connectionManager.deviceDisconnected(ctx.channel(), supportsOffline); - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { - while (cause.getCause() != null && cause.getCause() != cause) { - cause = cause.getCause(); - } - LOGGER.info("[{}] error", NetworkUtil.session(ctx.channel()), cause); - closeChannel(ctx.channel()); - } - - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { - if (evt instanceof IdleStateEvent) { - LOGGER.info("[{}] timed out", NetworkUtil.session(ctx.channel())); - closeChannel(ctx.channel()); - } - } - - private void closeChannel(Channel channel) { - if (!(channel instanceof DatagramChannel)) { - channel.close(); - } - } - -} diff --git a/src/main/java/org/traccar/PositionForwardingHandler.java b/src/main/java/org/traccar/PositionForwardingHandler.java deleted file mode 100644 index a79b01367..000000000 --- a/src/main/java/org/traccar/PositionForwardingHandler.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2015 - 2022 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; - -import io.netty.channel.ChannelHandler; -import io.netty.util.Timeout; -import io.netty.util.Timer; -import io.netty.util.TimerTask; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.forward.PositionData; -import org.traccar.forward.PositionForwarder; -import org.traccar.forward.ResultHandler; -import org.traccar.model.Device; -import org.traccar.model.Position; -import org.traccar.session.cache.CacheManager; - -import jakarta.annotation.Nullable; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -@Singleton -@ChannelHandler.Sharable -public class PositionForwardingHandler extends BaseDataHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(PositionForwardingHandler.class); - - private final CacheManager cacheManager; - private final Timer timer; - - private final PositionForwarder positionForwarder; - - private final boolean retryEnabled; - private final int retryDelay; - private final int retryCount; - private final int retryLimit; - - private final AtomicInteger deliveryPending; - - @Inject - public PositionForwardingHandler( - Config config, CacheManager cacheManager, Timer timer, @Nullable PositionForwarder positionForwarder) { - - this.cacheManager = cacheManager; - this.timer = timer; - this.positionForwarder = positionForwarder; - - this.retryEnabled = config.getBoolean(Keys.FORWARD_RETRY_ENABLE); - this.retryDelay = config.getInteger(Keys.FORWARD_RETRY_DELAY); - this.retryCount = config.getInteger(Keys.FORWARD_RETRY_COUNT); - this.retryLimit = config.getInteger(Keys.FORWARD_RETRY_LIMIT); - - this.deliveryPending = new AtomicInteger(); - } - - class AsyncRequestAndCallback implements ResultHandler, TimerTask { - - private final PositionData positionData; - - private int retries = 0; - - AsyncRequestAndCallback(PositionData positionData) { - this.positionData = positionData; - deliveryPending.incrementAndGet(); - } - - private void send() { - positionForwarder.forward(positionData, this); - } - - private void retry(Throwable throwable) { - boolean scheduled = false; - try { - if (retryEnabled && deliveryPending.get() <= retryLimit && retries < retryCount) { - schedule(); - scheduled = true; - } - } finally { - int pending = scheduled ? deliveryPending.get() : deliveryPending.decrementAndGet(); - LOGGER.warn("Position forwarding failed: " + pending + " pending", throwable); - } - } - - private void schedule() { - timer.newTimeout(this, retryDelay * (long) Math.pow(2, retries++), TimeUnit.MILLISECONDS); - } - - @Override - public void onResult(boolean success, Throwable throwable) { - if (success) { - deliveryPending.decrementAndGet(); - } else { - retry(throwable); - } - } - - @Override - public void run(Timeout timeout) { - boolean sent = false; - try { - if (!timeout.isCancelled()) { - send(); - sent = true; - } - } finally { - if (!sent) { - deliveryPending.decrementAndGet(); - } - } - } - } - - @Override - protected Position handlePosition(Position position) { - if (positionForwarder != null) { - PositionData positionData = new PositionData(); - positionData.setPosition(position); - positionData.setDevice(cacheManager.getObject(Device.class, position.getDeviceId())); - new AsyncRequestAndCallback(positionData).send(); - } - return position; - } - -} diff --git a/src/main/java/org/traccar/ProcessingHandler.java b/src/main/java/org/traccar/ProcessingHandler.java new file mode 100644 index 000000000..7627c719b --- /dev/null +++ b/src/main/java/org/traccar/ProcessingHandler.java @@ -0,0 +1,145 @@ +/* + * Copyright 2024 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; + +import com.google.inject.Injector; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import org.traccar.database.NotificationManager; +import org.traccar.handler.BasePositionHandler; +import org.traccar.handler.ComputedAttributesHandler; +import org.traccar.handler.CopyAttributesHandler; +import org.traccar.handler.DatabaseHandler; +import org.traccar.handler.DistanceHandler; +import org.traccar.handler.EngineHoursHandler; +import org.traccar.handler.FilterHandler; +import org.traccar.handler.GeocoderHandler; +import org.traccar.handler.GeofenceHandler; +import org.traccar.handler.GeolocationHandler; +import org.traccar.handler.HemisphereHandler; +import org.traccar.handler.MotionHandler; +import org.traccar.handler.PositionForwardingHandler; +import org.traccar.handler.SpeedLimitHandler; +import org.traccar.handler.TimeHandler; +import org.traccar.handler.events.AlertEventHandler; +import org.traccar.handler.events.BaseEventHandler; +import org.traccar.handler.events.BehaviorEventHandler; +import org.traccar.handler.events.CommandResultEventHandler; +import org.traccar.handler.events.DriverEventHandler; +import org.traccar.handler.events.FuelEventHandler; +import org.traccar.handler.events.GeofenceEventHandler; +import org.traccar.handler.events.IgnitionEventHandler; +import org.traccar.handler.events.MaintenanceEventHandler; +import org.traccar.handler.events.MediaEventHandler; +import org.traccar.handler.events.MotionEventHandler; +import org.traccar.handler.events.OverspeedEventHandler; +import org.traccar.handler.network.AcknowledgementHandler; +import org.traccar.model.Position; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Singleton +@ChannelHandler.Sharable +public class ProcessingHandler extends ChannelInboundHandlerAdapter { + + private final NotificationManager notificationManager; + private final List positionHandlers; + private final List eventHandlers; + + @Inject + public ProcessingHandler(Injector injector, NotificationManager notificationManager) { + this.notificationManager = notificationManager; + + positionHandlers = Stream.of( + TimeHandler.class, + GeolocationHandler.class, + HemisphereHandler.class, + DistanceHandler.class, + FilterHandler.class, + GeofenceHandler.class, + GeocoderHandler.class, + SpeedLimitHandler.class, + MotionHandler.class, + EngineHoursHandler.class, + ComputedAttributesHandler.class, + CopyAttributesHandler.class, + PositionForwardingHandler.class, + DatabaseHandler.class) + .map((clazz) -> (BasePositionHandler) injector.getInstance(clazz)) + .filter(Objects::nonNull) + .collect(Collectors.toUnmodifiableList()); + + eventHandlers = Stream.of( + MediaEventHandler.class, + CommandResultEventHandler.class, + OverspeedEventHandler.class, + BehaviorEventHandler.class, + FuelEventHandler.class, + MotionEventHandler.class, + GeofenceEventHandler.class, + AlertEventHandler.class, + IgnitionEventHandler.class, + MaintenanceEventHandler.class, + DriverEventHandler.class) + .map((clazz) -> (BaseEventHandler) injector.getInstance(clazz)) + .filter(Objects::nonNull) + .collect(Collectors.toUnmodifiableList()); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof Position) { + processPositionHandlers(ctx, (Position) msg); + } + super.channelRead(ctx, msg); + } + + private void processPositionHandlers(ChannelHandlerContext ctx, Position position) { + var iterator = positionHandlers.iterator(); + iterator.next().handlePosition(position, new BasePositionHandler.Callback() { + @Override + public void processed(Position position) { + if (position != null) { + if (iterator.hasNext()) { + iterator.next().handlePosition(position, this); + } else { + processEventHandlers(ctx, position); + } + } else { + finishedProcessing(ctx, null); + } + } + }); + } + + private void processEventHandlers(ChannelHandlerContext ctx, Position position) { + eventHandlers.forEach(handler -> handler.analyzePosition( + position, (event) -> notificationManager.updateEvents(Map.of(event, position)))); + finishedProcessing(ctx, position); + } + + private void finishedProcessing(ChannelHandlerContext ctx, Position position) { + ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position)); + } + +} diff --git a/src/main/java/org/traccar/handler/AcknowledgementHandler.java b/src/main/java/org/traccar/handler/AcknowledgementHandler.java deleted file mode 100644 index 4c1085998..000000000 --- a/src/main/java/org/traccar/handler/AcknowledgementHandler.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2023 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.handler; - -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelOutboundHandlerAdapter; -import io.netty.channel.ChannelPromise; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -public class AcknowledgementHandler extends ChannelOutboundHandlerAdapter { - - private static final Logger LOGGER = LoggerFactory.getLogger(AcknowledgementHandler.class); - - public interface Event { - } - - public static class EventReceived implements Event { - } - - public static class EventDecoded implements Event { - private final Collection objects; - - public EventDecoded(Collection objects) { - this.objects = objects; - } - - public Collection getObjects() { - return objects; - } - } - - public static class EventHandled implements Event { - private final Object object; - - public EventHandled(Object object) { - this.object = object; - } - - public Object getObject() { - return object; - } - } - - private static final class Entry { - private final Object message; - private final ChannelPromise promise; - - private Entry(Object message, ChannelPromise promise) { - this.message = message; - this.promise = promise; - } - - public Object getMessage() { - return message; - } - - public ChannelPromise getPromise() { - return promise; - } - } - - private List queue; - private final Set waiting = new HashSet<>(); - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - List output = new LinkedList<>(); - synchronized (this) { - if (msg instanceof Event) { - if (msg instanceof EventReceived) { - LOGGER.debug("Event received"); - if (queue == null) { - queue = new LinkedList<>(); - } - } else if (msg instanceof EventDecoded) { - EventDecoded event = (EventDecoded) msg; - LOGGER.debug("Event decoded {}", event.getObjects().size()); - waiting.addAll(event.getObjects()); - } else if (msg instanceof EventHandled) { - EventHandled event = (EventHandled) msg; - LOGGER.debug("Event handled"); - waiting.remove(event.getObject()); - } - if (!(msg instanceof EventReceived) && waiting.isEmpty()) { - output.addAll(queue); - queue = null; - } - } else if (queue != null) { - LOGGER.debug("Message queued"); - queue.add(new Entry(msg, promise)); - } else { - LOGGER.debug("Message sent"); - output.add(new Entry(msg, promise)); - } - } - for (Entry entry : output) { - ctx.write(entry.getMessage(), entry.getPromise()); - } - } - -} diff --git a/src/main/java/org/traccar/handler/BasePositionHandler.java b/src/main/java/org/traccar/handler/BasePositionHandler.java new file mode 100644 index 000000000..2fee5c652 --- /dev/null +++ b/src/main/java/org/traccar/handler/BasePositionHandler.java @@ -0,0 +1,27 @@ +/* + * Copyright 2015 - 2024 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.handler; + +import org.traccar.model.Position; + +public abstract class BasePositionHandler { + + public interface Callback { + void processed(Position position); + } + + public abstract void handlePosition(Position position, Callback callback); +} diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 8b010ceae..8d6fb39c3 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,26 +16,15 @@ */ package org.traccar.handler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.List; - -import io.netty.channel.ChannelHandler; -import org.apache.commons.jexl3.JexlFeatures; -import org.apache.commons.jexl3.JexlEngine; +import jakarta.inject.Inject; import org.apache.commons.jexl3.JexlBuilder; -import org.apache.commons.jexl3.introspection.JexlSandbox; +import org.apache.commons.jexl3.JexlEngine; import org.apache.commons.jexl3.JexlException; +import org.apache.commons.jexl3.JexlFeatures; import org.apache.commons.jexl3.MapContext; +import org.apache.commons.jexl3.introspection.JexlSandbox; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.traccar.BaseDataHandler; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Attribute; @@ -43,12 +32,17 @@ import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; -@Singleton -@ChannelHandler.Sharable -public class ComputedAttributesHandler extends BaseDataHandler { +public class ComputedAttributesHandler extends BasePositionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(ComputedAttributesHandler.class); @@ -144,7 +138,7 @@ public class ComputedAttributesHandler extends BaseDataHandler { } @Override - protected Position handlePosition(Position position) { + public void handlePosition(Position position, Callback callback) { Collection attributes = cacheManager.getDeviceObjects(position.getDeviceId(), Attribute.class); for (Attribute attribute : attributes) { if (attribute.getAttribute() != null) { @@ -202,7 +196,7 @@ public class ComputedAttributesHandler extends BaseDataHandler { } } } - return position; + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/CopyAttributesHandler.java b/src/main/java/org/traccar/handler/CopyAttributesHandler.java index 42b438e41..9c31bf56e 100644 --- a/src/main/java/org/traccar/handler/CopyAttributesHandler.java +++ b/src/main/java/org/traccar/handler/CopyAttributesHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,20 +16,14 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; -import org.traccar.BaseDataHandler; +import jakarta.inject.Inject; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@ChannelHandler.Sharable -public class CopyAttributesHandler extends BaseDataHandler { +public class CopyAttributesHandler extends BasePositionHandler { private final boolean enabled; private final CacheManager cacheManager; @@ -41,7 +35,7 @@ public class CopyAttributesHandler extends BaseDataHandler { } @Override - protected Position handlePosition(Position position) { + public void handlePosition(Position position, Callback callback) { if (enabled) { String attributesString = AttributeUtil.lookup( cacheManager, Keys.PROCESSING_COPY_ATTRIBUTES, position.getDeviceId()); @@ -54,7 +48,7 @@ public class CopyAttributesHandler extends BaseDataHandler { } } } - return position; + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/DatabaseHandler.java b/src/main/java/org/traccar/handler/DatabaseHandler.java new file mode 100644 index 000000000..b1f218a1e --- /dev/null +++ b/src/main/java/org/traccar/handler/DatabaseHandler.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015 - 2024 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.handler; + +import jakarta.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.model.Position; +import org.traccar.storage.Storage; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Request; + +public class DatabaseHandler extends BasePositionHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHandler.class); + + private final Storage storage; + + @Inject + public DatabaseHandler(Storage storage) { + this.storage = storage; + } + + @Override + public void handlePosition(Position position, Callback callback) { + + try { + position.setId(storage.addObject(position, new Request(new Columns.Exclude("id")))); + } catch (Exception error) { + LOGGER.warn("Failed to store position", error); + } + + callback.processed(position); + } + +} diff --git a/src/main/java/org/traccar/handler/DefaultDataHandler.java b/src/main/java/org/traccar/handler/DefaultDataHandler.java deleted file mode 100644 index cca6dcd0a..000000000 --- a/src/main/java/org/traccar/handler/DefaultDataHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015 - 2022 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.handler; - -import io.netty.channel.ChannelHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.BaseDataHandler; -import org.traccar.model.Position; -import org.traccar.storage.Storage; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Request; - -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@ChannelHandler.Sharable -public class DefaultDataHandler extends BaseDataHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(DefaultDataHandler.class); - - private final Storage storage; - - @Inject - public DefaultDataHandler(Storage storage) { - this.storage = storage; - } - - @Override - protected Position handlePosition(Position position) { - - try { - position.setId(storage.addObject(position, new Request(new Columns.Exclude("id")))); - } catch (Exception error) { - LOGGER.warn("Failed to store position", error); - } - - return position; - } - -} diff --git a/src/main/java/org/traccar/handler/DistanceHandler.java b/src/main/java/org/traccar/handler/DistanceHandler.java index db8c73779..ee5d64894 100644 --- a/src/main/java/org/traccar/handler/DistanceHandler.java +++ b/src/main/java/org/traccar/handler/DistanceHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2015 Amila Silva * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,19 +16,14 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import org.traccar.BaseDataHandler; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.DistanceCalculator; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -@Singleton -@ChannelHandler.Sharable -public class DistanceHandler extends BaseDataHandler { +public class DistanceHandler extends BasePositionHandler { private final CacheManager cacheManager; @@ -45,7 +40,7 @@ public class DistanceHandler extends BaseDataHandler { } @Override - protected Position handlePosition(Position position) { + public void handlePosition(Position position, Callback callback) { double distance = 0.0; if (position.hasAttribute(Position.KEY_DISTANCE)) { @@ -76,7 +71,7 @@ public class DistanceHandler extends BaseDataHandler { position.set(Position.KEY_DISTANCE, distance); position.set(Position.KEY_TOTAL_DISTANCE, totalDistance + distance); - return position; + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/EngineHoursHandler.java b/src/main/java/org/traccar/handler/EngineHoursHandler.java index 621205b34..ed5f9b509 100644 --- a/src/main/java/org/traccar/handler/EngineHoursHandler.java +++ b/src/main/java/org/traccar/handler/EngineHoursHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,17 +16,11 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; -import org.traccar.BaseDataHandler; +import jakarta.inject.Inject; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@ChannelHandler.Sharable -public class EngineHoursHandler extends BaseDataHandler { +public class EngineHoursHandler extends BasePositionHandler { private final CacheManager cacheManager; @@ -36,7 +30,7 @@ public class EngineHoursHandler extends BaseDataHandler { } @Override - protected Position handlePosition(Position position) { + public void handlePosition(Position position, Callback callback) { if (!position.hasAttribute(Position.KEY_HOURS)) { Position last = cacheManager.getPosition(position.getDeviceId()); if (last != null) { @@ -49,7 +43,7 @@ public class EngineHoursHandler extends BaseDataHandler { } } } - return position; + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index a15d3ffad..4cc6233d0 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2014 - 2024 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. @@ -15,9 +15,7 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; +import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; @@ -36,13 +34,9 @@ import org.traccar.storage.query.Condition; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; import java.util.Date; -@Singleton -@ChannelHandler.Sharable -public class FilterHandler extends ChannelInboundHandlerAdapter { +public class FilterHandler extends BasePositionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(FilterHandler.class); @@ -277,16 +271,11 @@ public class FilterHandler extends ChannelInboundHandlerAdapter { } @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - if (msg instanceof Position) { - Position position = (Position) msg; - if (enabled && filter(position)) { - ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position)); - } else { - ctx.fireChannelRead(position); - } + public void handlePosition(Position position, Callback callback) { + if (enabled && filter(position)) { + callback.processed(null); } else { - super.channelRead(ctx, msg); + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/GeocoderHandler.java b/src/main/java/org/traccar/handler/GeocoderHandler.java index e4f240a90..c62bcb6f8 100644 --- a/src/main/java/org/traccar/handler/GeocoderHandler.java +++ b/src/main/java/org/traccar/handler/GeocoderHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2024 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. @@ -15,9 +15,6 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; @@ -26,8 +23,7 @@ import org.traccar.geocoder.Geocoder; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -@ChannelHandler.Sharable -public class GeocoderHandler extends ChannelInboundHandlerAdapter { +public class GeocoderHandler extends BasePositionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(GeocoderHandler.class); @@ -46,39 +42,38 @@ public class GeocoderHandler extends ChannelInboundHandlerAdapter { } @Override - public void channelRead(final ChannelHandlerContext ctx, Object message) { - if (message instanceof Position && !ignorePositions) { - final Position position = (Position) message; - if (processInvalidPositions || position.getValid()) { - if (reuseDistance != 0) { - Position lastPosition = cacheManager.getPosition(position.getDeviceId()); - if (lastPosition != null && lastPosition.getAddress() != null - && position.getDouble(Position.KEY_DISTANCE) <= reuseDistance) { - position.setAddress(lastPosition.getAddress()); - ctx.fireChannelRead(position); - return; - } + public void handlePosition(Position position, Callback callback) { + if (!ignorePositions) { + callback.processed(position); + } + + if (processInvalidPositions || position.getValid()) { + if (reuseDistance != 0) { + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); + if (lastPosition != null && lastPosition.getAddress() != null + && position.getDouble(Position.KEY_DISTANCE) <= reuseDistance) { + position.setAddress(lastPosition.getAddress()); + callback.processed(position); + return; } + } - geocoder.getAddress(position.getLatitude(), position.getLongitude(), - new Geocoder.ReverseGeocoderCallback() { - @Override - public void onSuccess(String address) { - position.setAddress(address); - ctx.fireChannelRead(position); - } + geocoder.getAddress(position.getLatitude(), position.getLongitude(), + new Geocoder.ReverseGeocoderCallback() { + @Override + public void onSuccess(String address) { + position.setAddress(address); + callback.processed(position); + } - @Override - public void onFailure(Throwable e) { - LOGGER.warn("Geocoding failed", e); - ctx.fireChannelRead(position); - } - }); - } else { - ctx.fireChannelRead(position); - } + @Override + public void onFailure(Throwable e) { + LOGGER.warn("Geocoding failed", e); + callback.processed(position); + } + }); } else { - ctx.fireChannelRead(message); + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/GeofenceHandler.java b/src/main/java/org/traccar/handler/GeofenceHandler.java index 68bc6dbf0..33b46f058 100644 --- a/src/main/java/org/traccar/handler/GeofenceHandler.java +++ b/src/main/java/org/traccar/handler/GeofenceHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2023 - 2024 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. @@ -15,20 +15,15 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; -import org.traccar.BaseDataHandler; +import jakarta.inject.Inject; import org.traccar.config.Config; import org.traccar.helper.model.GeofenceUtil; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; import java.util.List; -@Singleton -@ChannelHandler.Sharable -public class GeofenceHandler extends BaseDataHandler { +public class GeofenceHandler extends BasePositionHandler { private final Config config; private final CacheManager cacheManager; @@ -40,13 +35,13 @@ public class GeofenceHandler extends BaseDataHandler { } @Override - protected Position handlePosition(Position position) { + public void handlePosition(Position position, Callback callback) { List geofenceIds = GeofenceUtil.getCurrentGeofences(config, cacheManager, position); if (!geofenceIds.isEmpty()) { position.setGeofenceIds(geofenceIds); } - return position; + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/GeolocationHandler.java b/src/main/java/org/traccar/handler/GeolocationHandler.java index a54ea03e3..cb9c04808 100644 --- a/src/main/java/org/traccar/handler/GeolocationHandler.java +++ b/src/main/java/org/traccar/handler/GeolocationHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2024 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. @@ -15,9 +15,6 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; @@ -27,8 +24,7 @@ import org.traccar.geolocation.GeolocationProvider; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -@ChannelHandler.Sharable -public class GeolocationHandler extends ChannelInboundHandlerAdapter { +public class GeolocationHandler extends BasePositionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(GeolocationHandler.class); @@ -51,46 +47,41 @@ public class GeolocationHandler extends ChannelInboundHandlerAdapter { } @Override - public void channelRead(final ChannelHandlerContext ctx, Object message) { - if (message instanceof Position) { - final Position position = (Position) message; - if ((position.getOutdated() || processInvalidPositions && !position.getValid()) - && position.getNetwork() != null - && (!requireWifi || position.getNetwork().getWifiAccessPoints() != null)) { - if (reuse) { - Position lastPosition = cacheManager.getPosition(position.getDeviceId()); - if (lastPosition != null && position.getNetwork().equals(lastPosition.getNetwork())) { - updatePosition( - position, lastPosition.getLatitude(), lastPosition.getLongitude(), - lastPosition.getAccuracy()); - ctx.fireChannelRead(position); - return; - } + public void handlePosition(Position position, Callback callback) { + if ((position.getOutdated() || processInvalidPositions && !position.getValid()) + && position.getNetwork() != null + && (!requireWifi || position.getNetwork().getWifiAccessPoints() != null)) { + if (reuse) { + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); + if (lastPosition != null && position.getNetwork().equals(lastPosition.getNetwork())) { + updatePosition( + position, lastPosition.getLatitude(), lastPosition.getLongitude(), + lastPosition.getAccuracy()); + callback.processed(position); + return; } + } - if (statisticsManager != null) { - statisticsManager.registerGeolocationRequest(); - } + if (statisticsManager != null) { + statisticsManager.registerGeolocationRequest(); + } - geolocationProvider.getLocation(position.getNetwork(), - new GeolocationProvider.LocationProviderCallback() { - @Override - public void onSuccess(double latitude, double longitude, double accuracy) { - updatePosition(position, latitude, longitude, accuracy); - ctx.fireChannelRead(position); - } + geolocationProvider.getLocation(position.getNetwork(), + new GeolocationProvider.LocationProviderCallback() { + @Override + public void onSuccess(double latitude, double longitude, double accuracy) { + updatePosition(position, latitude, longitude, accuracy); + callback.processed(position); + } - @Override - public void onFailure(Throwable e) { - LOGGER.warn("Geolocation network error", e); - ctx.fireChannelRead(position); - } - }); - } else { - ctx.fireChannelRead(position); - } + @Override + public void onFailure(Throwable e) { + LOGGER.warn("Geolocation network error", e); + callback.processed(position); + } + }); } else { - ctx.fireChannelRead(message); + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/HemisphereHandler.java b/src/main/java/org/traccar/handler/HemisphereHandler.java index 294e449db..6b64177e4 100644 --- a/src/main/java/org/traccar/handler/HemisphereHandler.java +++ b/src/main/java/org/traccar/handler/HemisphereHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 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. @@ -15,18 +15,12 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; -import org.traccar.BaseDataHandler; +import jakarta.inject.Inject; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@ChannelHandler.Sharable -public class HemisphereHandler extends BaseDataHandler { +public class HemisphereHandler extends BasePositionHandler { private int latitudeFactor; private int longitudeFactor; @@ -52,14 +46,14 @@ public class HemisphereHandler extends BaseDataHandler { } @Override - protected Position handlePosition(Position position) { + public void handlePosition(Position position, Callback callback) { if (latitudeFactor != 0) { position.setLatitude(Math.abs(position.getLatitude()) * latitudeFactor); } if (longitudeFactor != 0) { position.setLongitude(Math.abs(position.getLongitude()) * longitudeFactor); } - return position; + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/MotionHandler.java b/src/main/java/org/traccar/handler/MotionHandler.java index 68a31a16a..bb7ff2a65 100644 --- a/src/main/java/org/traccar/handler/MotionHandler.java +++ b/src/main/java/org/traccar/handler/MotionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,19 +16,13 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; -import org.traccar.BaseDataHandler; +import jakarta.inject.Inject; import org.traccar.config.Keys; import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@ChannelHandler.Sharable -public class MotionHandler extends BaseDataHandler { +public class MotionHandler extends BasePositionHandler { private final CacheManager cacheManager; @@ -38,13 +32,13 @@ public class MotionHandler extends BaseDataHandler { } @Override - protected Position handlePosition(Position position) { + public void handlePosition(Position position, Callback callback) { if (!position.hasAttribute(Position.KEY_MOTION)) { double threshold = AttributeUtil.lookup( cacheManager, Keys.EVENT_MOTION_SPEED_THRESHOLD, position.getDeviceId()); position.set(Position.KEY_MOTION, position.getSpeed() > threshold); } - return position; + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java b/src/main/java/org/traccar/handler/NetworkForwarderHandler.java deleted file mode 100644 index 470e175ca..000000000 --- a/src/main/java/org/traccar/handler/NetworkForwarderHandler.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023 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.handler; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.socket.DatagramChannel; -import io.netty.channel.socket.DatagramPacket; -import org.traccar.forward.NetworkForwarder; - -import jakarta.inject.Inject; -import java.net.InetSocketAddress; -import java.net.SocketAddress; - -public class NetworkForwarderHandler extends ChannelInboundHandlerAdapter { - - private final int port; - - private NetworkForwarder networkForwarder; - - public NetworkForwarderHandler(int port) { - this.port = port; - } - - @Inject - public void setNetworkForwarder(NetworkForwarder networkForwarder) { - this.networkForwarder = networkForwarder; - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - boolean datagram = ctx.channel() instanceof DatagramChannel; - SocketAddress remoteAddress; - ByteBuf buffer; - if (datagram) { - DatagramPacket message = (DatagramPacket) msg; - remoteAddress = message.recipient(); - buffer = message.content(); - } else { - remoteAddress = ctx.channel().remoteAddress(); - buffer = (ByteBuf) msg; - } - - byte[] data = new byte[buffer.readableBytes()]; - buffer.getBytes(buffer.readerIndex(), data); - networkForwarder.forward((InetSocketAddress) remoteAddress, port, datagram, data); - super.channelRead(ctx, msg); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - if (!(ctx.channel() instanceof DatagramChannel)) { - networkForwarder.disconnect((InetSocketAddress) ctx.channel().remoteAddress()); - } - super.channelInactive(ctx); - } - -} diff --git a/src/main/java/org/traccar/handler/NetworkMessageHandler.java b/src/main/java/org/traccar/handler/NetworkMessageHandler.java deleted file mode 100644 index b1d926bfa..000000000 --- a/src/main/java/org/traccar/handler/NetworkMessageHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2019 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.handler; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import io.netty.channel.socket.DatagramChannel; -import io.netty.channel.socket.DatagramPacket; -import org.traccar.NetworkMessage; - -import java.net.InetSocketAddress; - -public class NetworkMessageHandler extends ChannelDuplexHandler { - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) { - if (ctx.channel() instanceof DatagramChannel) { - DatagramPacket packet = (DatagramPacket) msg; - ctx.fireChannelRead(new NetworkMessage(packet.content(), packet.sender())); - } else if (msg instanceof ByteBuf) { - ByteBuf buffer = (ByteBuf) msg; - ctx.fireChannelRead(new NetworkMessage(buffer, ctx.channel().remoteAddress())); - } - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { - if (msg instanceof NetworkMessage) { - NetworkMessage message = (NetworkMessage) msg; - if (ctx.channel() instanceof DatagramChannel) { - InetSocketAddress recipient = (InetSocketAddress) message.getRemoteAddress(); - InetSocketAddress sender = (InetSocketAddress) ctx.channel().localAddress(); - ctx.write(new DatagramPacket((ByteBuf) message.getMessage(), recipient, sender), promise); - } else { - ctx.write(message.getMessage(), promise); - } - } else { - ctx.write(msg, promise); - } - } - -} diff --git a/src/main/java/org/traccar/handler/OpenChannelHandler.java b/src/main/java/org/traccar/handler/OpenChannelHandler.java deleted file mode 100644 index e416f35ae..000000000 --- a/src/main/java/org/traccar/handler/OpenChannelHandler.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2019 - 2021 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.handler; - -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelHandlerContext; -import org.traccar.TrackerConnector; - -public class OpenChannelHandler extends ChannelDuplexHandler { - - private final TrackerConnector connector; - - public OpenChannelHandler(TrackerConnector connector) { - this.connector = connector; - } - - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - super.channelActive(ctx); - connector.getChannelGroup().add(ctx.channel()); - } - - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - super.channelInactive(ctx); - connector.getChannelGroup().remove(ctx.channel()); - } - -} diff --git a/src/main/java/org/traccar/handler/PositionForwardingHandler.java b/src/main/java/org/traccar/handler/PositionForwardingHandler.java new file mode 100644 index 000000000..be62fff37 --- /dev/null +++ b/src/main/java/org/traccar/handler/PositionForwardingHandler.java @@ -0,0 +1,137 @@ +/* + * Copyright 2015 - 2024 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.handler; + +import io.netty.util.Timeout; +import io.netty.util.Timer; +import io.netty.util.TimerTask; +import jakarta.annotation.Nullable; +import jakarta.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.forward.PositionData; +import org.traccar.forward.PositionForwarder; +import org.traccar.forward.ResultHandler; +import org.traccar.model.Device; +import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class PositionForwardingHandler extends BasePositionHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(PositionForwardingHandler.class); + + private final CacheManager cacheManager; + private final Timer timer; + + private final PositionForwarder positionForwarder; + + private final boolean retryEnabled; + private final int retryDelay; + private final int retryCount; + private final int retryLimit; + + private final AtomicInteger deliveryPending; + + @Inject + public PositionForwardingHandler( + Config config, CacheManager cacheManager, Timer timer, @Nullable PositionForwarder positionForwarder) { + + this.cacheManager = cacheManager; + this.timer = timer; + this.positionForwarder = positionForwarder; + + this.retryEnabled = config.getBoolean(Keys.FORWARD_RETRY_ENABLE); + this.retryDelay = config.getInteger(Keys.FORWARD_RETRY_DELAY); + this.retryCount = config.getInteger(Keys.FORWARD_RETRY_COUNT); + this.retryLimit = config.getInteger(Keys.FORWARD_RETRY_LIMIT); + + this.deliveryPending = new AtomicInteger(); + } + + class AsyncRequestAndCallback implements ResultHandler, TimerTask { + + private final PositionData positionData; + + private int retries = 0; + + AsyncRequestAndCallback(PositionData positionData) { + this.positionData = positionData; + deliveryPending.incrementAndGet(); + } + + private void send() { + positionForwarder.forward(positionData, this); + } + + private void retry(Throwable throwable) { + boolean scheduled = false; + try { + if (retryEnabled && deliveryPending.get() <= retryLimit && retries < retryCount) { + schedule(); + scheduled = true; + } + } finally { + int pending = scheduled ? deliveryPending.get() : deliveryPending.decrementAndGet(); + LOGGER.warn("Position forwarding failed: " + pending + " pending", throwable); + } + } + + private void schedule() { + timer.newTimeout(this, retryDelay * (long) Math.pow(2, retries++), TimeUnit.MILLISECONDS); + } + + @Override + public void onResult(boolean success, Throwable throwable) { + if (success) { + deliveryPending.decrementAndGet(); + } else { + retry(throwable); + } + } + + @Override + public void run(Timeout timeout) { + boolean sent = false; + try { + if (!timeout.isCancelled()) { + send(); + sent = true; + } + } finally { + if (!sent) { + deliveryPending.decrementAndGet(); + } + } + } + } + + @Override + public void handlePosition(Position position, Callback callback) { + if (positionForwarder != null) { + PositionData positionData = new PositionData(); + positionData.setPosition(position); + positionData.setDevice(cacheManager.getObject(Device.class, position.getDeviceId())); + new AsyncRequestAndCallback(positionData).send(); + } + callback.processed(position); + } + +} diff --git a/src/main/java/org/traccar/handler/RemoteAddressHandler.java b/src/main/java/org/traccar/handler/RemoteAddressHandler.java deleted file mode 100644 index 61ada5b91..000000000 --- a/src/main/java/org/traccar/handler/RemoteAddressHandler.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2015 - 2022 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.handler; - -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.model.Position; - -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.net.InetSocketAddress; - -@Singleton -@ChannelHandler.Sharable -public class RemoteAddressHandler extends ChannelInboundHandlerAdapter { - - private final boolean enabled; - - @Inject - public RemoteAddressHandler(Config config) { - enabled = config.getBoolean(Keys.PROCESSING_REMOTE_ADDRESS_ENABLE); - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) { - - if (enabled) { - InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); - String hostAddress = remoteAddress != null ? remoteAddress.getAddress().getHostAddress() : null; - - if (msg instanceof Position) { - Position position = (Position) msg; - position.set(Position.KEY_IP, hostAddress); - } - } - - ctx.fireChannelRead(msg); - } - -} diff --git a/src/main/java/org/traccar/handler/SpeedLimitHandler.java b/src/main/java/org/traccar/handler/SpeedLimitHandler.java index 6edb6e912..604c10ca7 100644 --- a/src/main/java/org/traccar/handler/SpeedLimitHandler.java +++ b/src/main/java/org/traccar/handler/SpeedLimitHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2020 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2020 - 2024 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. @@ -15,20 +15,13 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; +import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.model.Position; import org.traccar.speedlimit.SpeedLimitProvider; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@ChannelHandler.Sharable -public class SpeedLimitHandler extends ChannelInboundHandlerAdapter { +public class SpeedLimitHandler extends BasePositionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(SpeedLimitHandler.class); @@ -40,26 +33,22 @@ public class SpeedLimitHandler extends ChannelInboundHandlerAdapter { } @Override - public void channelRead(final ChannelHandlerContext ctx, Object message) { - if (message instanceof Position) { - final Position position = (Position) message; - speedLimitProvider.getSpeedLimit(position.getLatitude(), position.getLongitude(), - new SpeedLimitProvider.SpeedLimitProviderCallback() { - @Override - public void onSuccess(double speedLimit) { - position.set(Position.KEY_SPEED_LIMIT, speedLimit); - ctx.fireChannelRead(position); - } - - @Override - public void onFailure(Throwable e) { - LOGGER.warn("Speed limit provider failed", e); - ctx.fireChannelRead(position); - } - }); - } else { - ctx.fireChannelRead(message); - } + public void handlePosition(Position position, Callback callback) { + + speedLimitProvider.getSpeedLimit(position.getLatitude(), position.getLongitude(), + new SpeedLimitProvider.SpeedLimitProviderCallback() { + @Override + public void onSuccess(double speedLimit) { + position.set(Position.KEY_SPEED_LIMIT, speedLimit); + callback.processed(position); + } + + @Override + public void onFailure(Throwable e) { + LOGGER.warn("Speed limit provider failed", e); + callback.processed(position); + } + }); } } diff --git a/src/main/java/org/traccar/handler/StandardLoggingHandler.java b/src/main/java/org/traccar/handler/StandardLoggingHandler.java deleted file mode 100644 index 513602dd8..000000000 --- a/src/main/java/org/traccar/handler/StandardLoggingHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2019 - 2024 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.handler; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufUtil; -import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelPromise; -import jakarta.inject.Inject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.NetworkMessage; -import org.traccar.helper.NetworkUtil; -import org.traccar.model.LogRecord; -import org.traccar.session.ConnectionManager; - -public class StandardLoggingHandler extends ChannelDuplexHandler { - - private static final Logger LOGGER = LoggerFactory.getLogger(StandardLoggingHandler.class); - - private final String protocol; - private ConnectionManager connectionManager; - - public StandardLoggingHandler(String protocol) { - this.protocol = protocol; - } - - @Inject - public void setConnectionManager(ConnectionManager connectionManager) { - this.connectionManager = connectionManager; - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - LogRecord record = createLogRecord(ctx, msg); - log(ctx, false, record); - super.channelRead(ctx, msg); - if (record != null) { - connectionManager.updateLog(record); - } - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - log(ctx, true, createLogRecord(ctx, msg)); - super.write(ctx, msg, promise); - } - - private LogRecord createLogRecord(ChannelHandlerContext ctx, Object msg) { - if (msg instanceof NetworkMessage) { - NetworkMessage networkMessage = (NetworkMessage) msg; - if (networkMessage.getMessage() instanceof ByteBuf) { - LogRecord record = new LogRecord(ctx.channel().localAddress(), networkMessage.getRemoteAddress()); - record.setProtocol(protocol); - record.setData(ByteBufUtil.hexDump((ByteBuf) networkMessage.getMessage())); - return record; - } - } - return null; - } - - private void log(ChannelHandlerContext ctx, boolean downstream, LogRecord record) { - if (record != null) { - StringBuilder message = new StringBuilder(); - message.append("[").append(NetworkUtil.session(ctx.channel())).append(": "); - message.append(protocol); - message.append(downstream ? " > " : " < "); - message.append(record.getAddress().getHostString()); - message.append("] "); - message.append(record.getData()); - LOGGER.info(message.toString()); - } - } - -} diff --git a/src/main/java/org/traccar/handler/TimeHandler.java b/src/main/java/org/traccar/handler/TimeHandler.java index ef0c3445d..2e703c681 100644 --- a/src/main/java/org/traccar/handler/TimeHandler.java +++ b/src/main/java/org/traccar/handler/TimeHandler.java @@ -15,11 +15,7 @@ */ package org.traccar.handler; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; import jakarta.inject.Inject; -import jakarta.inject.Singleton; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; @@ -28,9 +24,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; -@Singleton -@ChannelHandler.Sharable -public class TimeHandler extends ChannelInboundHandlerAdapter { +public class TimeHandler extends BasePositionHandler { private final boolean enabled; private final boolean useServerTime; @@ -53,10 +47,9 @@ public class TimeHandler extends ChannelInboundHandlerAdapter { } @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) { + public void handlePosition(Position position, Callback callback) { - if (enabled && msg instanceof Position) { - Position position = (Position) msg; + if (enabled) { if (protocols == null || protocols.contains(position.getProtocol())) { if (useServerTime) { position.setDeviceTime(position.getServerTime()); @@ -66,7 +59,7 @@ public class TimeHandler extends ChannelInboundHandlerAdapter { } } } - ctx.fireChannelRead(msg); + callback.processed(position); } } diff --git a/src/main/java/org/traccar/handler/events/AlertEventHandler.java b/src/main/java/org/traccar/handler/events/AlertEventHandler.java index 531a0f957..ca580b60d 100644 --- a/src/main/java/org/traccar/handler/events/AlertEventHandler.java +++ b/src/main/java/org/traccar/handler/events/AlertEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 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. @@ -15,21 +15,13 @@ */ package org.traccar.handler.events; -import java.util.Collections; -import java.util.Map; - -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@ChannelHandler.Sharable public class AlertEventHandler extends BaseEventHandler { private final CacheManager cacheManager; @@ -42,7 +34,7 @@ public class AlertEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { + public void analyzePosition(Position position, Callback callback) { Object alarm = position.getAttributes().get(Position.KEY_ALARM); if (alarm != null) { boolean ignoreAlert = false; @@ -55,10 +47,9 @@ public class AlertEventHandler extends BaseEventHandler { if (!ignoreAlert) { Event event = new Event(Event.TYPE_ALARM, position); event.set(Position.KEY_ALARM, (String) alarm); - return Collections.singletonMap(event, position); + callback.eventDetected(event); } } - return null; } } diff --git a/src/main/java/org/traccar/handler/events/BaseEventHandler.java b/src/main/java/org/traccar/handler/events/BaseEventHandler.java index 4a4fb40ff..009c83145 100644 --- a/src/main/java/org/traccar/handler/events/BaseEventHandler.java +++ b/src/main/java/org/traccar/handler/events/BaseEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 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. @@ -15,33 +15,17 @@ */ package org.traccar.handler.events; -import java.util.Map; - -import org.traccar.BaseDataHandler; -import org.traccar.database.NotificationManager; import org.traccar.model.Event; import org.traccar.model.Position; -import jakarta.inject.Inject; - -public abstract class BaseEventHandler extends BaseDataHandler { - - private NotificationManager notificationManager; +public abstract class BaseEventHandler { - @Inject - public void setNotificationManager(NotificationManager notificationManager) { - this.notificationManager = notificationManager; + public interface Callback { + void eventDetected(Event event); } - @Override - protected Position handlePosition(Position position) { - Map events = analyzePosition(position); - if (events != null && !events.isEmpty()) { - notificationManager.updateEvents(events); - } - return position; - } - - protected abstract Map analyzePosition(Position position); - + /** + * Event handlers should be processed synchronously. + */ + public abstract void analyzePosition(Position position, Callback callback); } diff --git a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java index 08ae35fcd..d654e18ce 100644 --- a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java +++ b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 2024 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. @@ -15,7 +15,7 @@ */ package org.traccar.handler.events; -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.UnitsConverter; @@ -23,13 +23,6 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.util.Collections; -import java.util.Map; - -@Singleton -@ChannelHandler.Sharable public class BehaviorEventHandler extends BaseEventHandler { private final double accelerationThreshold; @@ -45,7 +38,7 @@ public class BehaviorEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { + public void analyzePosition(Position position, Callback callback) { Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition != null && position.getFixTime().equals(lastPosition.getFixTime())) { @@ -54,14 +47,13 @@ public class BehaviorEventHandler extends BaseEventHandler { if (accelerationThreshold != 0 && acceleration >= accelerationThreshold) { Event event = new Event(Event.TYPE_ALARM, position); event.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); - return Collections.singletonMap(event, position); + callback.eventDetected(event); } else if (brakingThreshold != 0 && acceleration <= -brakingThreshold) { Event event = new Event(Event.TYPE_ALARM, position); event.set(Position.KEY_ALARM, Position.ALARM_BRAKING); - return Collections.singletonMap(event, position); + callback.eventDetected(event); } } - return null; } } diff --git a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java index b70f8f33b..b98807b23 100644 --- a/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java +++ b/src/main/java/org/traccar/handler/events/CommandResultEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 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. @@ -15,18 +15,10 @@ */ package org.traccar.handler.events; -import java.util.Collections; -import java.util.Map; - -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.traccar.model.Event; import org.traccar.model.Position; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@ChannelHandler.Sharable public class CommandResultEventHandler extends BaseEventHandler { @Inject @@ -34,14 +26,13 @@ public class CommandResultEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { + public void analyzePosition(Position position, Callback callback) { Object commandResult = position.getAttributes().get(Position.KEY_RESULT); if (commandResult != null) { Event event = new Event(Event.TYPE_COMMAND_RESULT, position); event.set(Position.KEY_RESULT, (String) commandResult); - return Collections.singletonMap(event, position); + callback.eventDetected(event); } - return null; } } diff --git a/src/main/java/org/traccar/handler/events/DriverEventHandler.java b/src/main/java/org/traccar/handler/events/DriverEventHandler.java index b68327983..31f8d2b4b 100644 --- a/src/main/java/org/traccar/handler/events/DriverEventHandler.java +++ b/src/main/java/org/traccar/handler/events/DriverEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,19 +16,12 @@ */ package org.traccar.handler.events; -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.util.Collections; -import java.util.Map; - -@Singleton -@ChannelHandler.Sharable public class DriverEventHandler extends BaseEventHandler { private final CacheManager cacheManager; @@ -39,9 +32,9 @@ public class DriverEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { + public void analyzePosition(Position position, Callback callback) { if (!PositionUtil.isLatest(cacheManager, position)) { - return null; + return; } String driverUniqueId = position.getString(Position.KEY_DRIVER_UNIQUE_ID); if (driverUniqueId != null) { @@ -53,10 +46,9 @@ public class DriverEventHandler extends BaseEventHandler { if (!driverUniqueId.equals(oldDriverUniqueId)) { Event event = new Event(Event.TYPE_DRIVER_CHANGED, position); event.set(Position.KEY_DRIVER_UNIQUE_ID, driverUniqueId); - return Collections.singletonMap(event, position); + callback.eventDetected(event); } } - return null; } } diff --git a/src/main/java/org/traccar/handler/events/FuelEventHandler.java b/src/main/java/org/traccar/handler/events/FuelEventHandler.java index e5085ecc2..c5675f51d 100644 --- a/src/main/java/org/traccar/handler/events/FuelEventHandler.java +++ b/src/main/java/org/traccar/handler/events/FuelEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2024 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. @@ -15,7 +15,7 @@ */ package org.traccar.handler.events; -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.traccar.config.Keys; import org.traccar.helper.model.AttributeUtil; import org.traccar.helper.model.PositionUtil; @@ -24,12 +24,6 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.util.Map; - -@Singleton -@ChannelHandler.Sharable public class FuelEventHandler extends BaseEventHandler { private final CacheManager cacheManager; @@ -40,14 +34,14 @@ public class FuelEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { + public void analyzePosition(Position position, Callback callback) { Device device = cacheManager.getObject(Device.class, position.getDeviceId()); if (device == null) { - return null; + return; } if (!PositionUtil.isLatest(cacheManager, position)) { - return null; + return; } if (position.hasAttribute(Position.KEY_FUEL_LEVEL)) { @@ -61,19 +55,17 @@ public class FuelEventHandler extends BaseEventHandler { double threshold = AttributeUtil.lookup( cacheManager, Keys.EVENT_FUEL_INCREASE_THRESHOLD, position.getDeviceId()); if (threshold > 0 && change >= threshold) { - return Map.of(new Event(Event.TYPE_DEVICE_FUEL_INCREASE, position), position); + callback.eventDetected(new Event(Event.TYPE_DEVICE_FUEL_INCREASE, position)); } } else if (change < 0) { double threshold = AttributeUtil.lookup( cacheManager, Keys.EVENT_FUEL_DROP_THRESHOLD, position.getDeviceId()); if (threshold > 0 && Math.abs(change) >= threshold) { - return Map.of(new Event(Event.TYPE_DEVICE_FUEL_DROP, position), position); + callback.eventDetected(new Event(Event.TYPE_DEVICE_FUEL_DROP, position)); } } } } - - return null; } } diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java index dbe2b8118..c8ecfb1ed 100644 --- a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 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. @@ -15,7 +15,7 @@ */ package org.traccar.handler.events; -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Calendar; import org.traccar.model.Event; @@ -23,15 +23,9 @@ import org.traccar.model.Geofence; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; -@Singleton -@ChannelHandler.Sharable public class GeofenceEventHandler extends BaseEventHandler { private final CacheManager cacheManager; @@ -42,9 +36,9 @@ public class GeofenceEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { + public void analyzePosition(Position position, Callback callback) { if (!PositionUtil.isLatest(cacheManager, position)) { - return null; + return; } List oldGeofences = new ArrayList<>(); @@ -60,7 +54,6 @@ public class GeofenceEventHandler extends BaseEventHandler { oldGeofences.removeAll(position.getGeofenceIds()); } - Map events = new HashMap<>(); for (long geofenceId : oldGeofences) { Geofence geofence = cacheManager.getObject(Geofence.class, geofenceId); if (geofence != null) { @@ -69,7 +62,7 @@ public class GeofenceEventHandler extends BaseEventHandler { if (calendar == null || calendar.checkMoment(position.getFixTime())) { Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position); event.setGeofenceId(geofenceId); - events.put(event, position); + callback.eventDetected(event); } } } @@ -79,10 +72,8 @@ public class GeofenceEventHandler extends BaseEventHandler { if (calendar == null || calendar.checkMoment(position.getFixTime())) { Event event = new Event(Event.TYPE_GEOFENCE_ENTER, position); event.setGeofenceId(geofenceId); - events.put(event, position); + callback.eventDetected(event); } } - return events; } - } diff --git a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java index ba4159a42..bbf9fadd1 100644 --- a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,21 +16,13 @@ */ package org.traccar.handler.events; -import java.util.Collections; -import java.util.Map; - -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@ChannelHandler.Sharable public class IgnitionEventHandler extends BaseEventHandler { private final CacheManager cacheManager; @@ -41,14 +33,12 @@ public class IgnitionEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { + public void analyzePosition(Position position, Callback callback) { Device device = cacheManager.getObject(Device.class, position.getDeviceId()); if (device == null || !PositionUtil.isLatest(cacheManager, position)) { - return null; + return; } - Map result = null; - if (position.hasAttribute(Position.KEY_IGNITION)) { boolean ignition = position.getBoolean(Position.KEY_IGNITION); @@ -57,15 +47,12 @@ public class IgnitionEventHandler extends BaseEventHandler { boolean oldIgnition = lastPosition.getBoolean(Position.KEY_IGNITION); if (ignition && !oldIgnition) { - result = Collections.singletonMap( - new Event(Event.TYPE_IGNITION_ON, position), position); + callback.eventDetected(new Event(Event.TYPE_IGNITION_ON, position)); } else if (!ignition && oldIgnition) { - result = Collections.singletonMap( - new Event(Event.TYPE_IGNITION_OFF, position), position); + callback.eventDetected(new Event(Event.TYPE_IGNITION_OFF, position)); } } } - return result; } } diff --git a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java index 2fa2e8869..573ad4ad6 100644 --- a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java @@ -16,20 +16,12 @@ */ package org.traccar.handler.events; -import java.util.HashMap; -import java.util.Map; - -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.traccar.model.Event; import org.traccar.model.Maintenance; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -@Singleton -@ChannelHandler.Sharable public class MaintenanceEventHandler extends BaseEventHandler { private final CacheManager cacheManager; @@ -40,13 +32,12 @@ public class MaintenanceEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { + public void analyzePosition(Position position, Callback callback) { Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) < 0) { - return null; + return; } - Map events = new HashMap<>(); for (Maintenance maintenance : cacheManager.getDeviceObjects(position.getDeviceId(), Maintenance.class)) { if (maintenance.getPeriod() != 0) { double oldValue = getValue(lastPosition, maintenance.getType()); @@ -58,13 +49,11 @@ public class MaintenanceEventHandler extends BaseEventHandler { Event event = new Event(Event.TYPE_MAINTENANCE, position); event.setMaintenanceId(maintenance.getId()); event.set(maintenance.getType(), newValue); - events.put(event, position); + callback.eventDetected(event); } } } } - - return events; } private double getValue(Position position, String type) { diff --git a/src/main/java/org/traccar/handler/events/MediaEventHandler.java b/src/main/java/org/traccar/handler/events/MediaEventHandler.java index 52d8e6961..2745296c4 100644 --- a/src/main/java/org/traccar/handler/events/MediaEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MediaEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2022 - 2024 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. @@ -15,18 +15,12 @@ */ package org.traccar.handler.events; -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.traccar.model.Event; import org.traccar.model.Position; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.util.Map; -import java.util.stream.Collectors; import java.util.stream.Stream; -@Singleton -@ChannelHandler.Sharable public class MediaEventHandler extends BaseEventHandler { @Inject @@ -34,8 +28,8 @@ public class MediaEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { - return Stream.of(Position.KEY_IMAGE, Position.KEY_VIDEO, Position.KEY_AUDIO) + public void analyzePosition(Position position, Callback callback) { + Stream.of(Position.KEY_IMAGE, Position.KEY_VIDEO, Position.KEY_AUDIO) .filter(position::hasAttribute) .map(type -> { Event event = new Event(Event.TYPE_MEDIA, position); @@ -43,7 +37,7 @@ public class MediaEventHandler extends BaseEventHandler { event.set("file", position.getString(type)); return event; }) - .collect(Collectors.toMap(event -> event, event -> position)); + .forEach(callback::eventDetected); } } diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java index 15902d6d4..41d68985b 100644 --- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,14 +16,13 @@ */ package org.traccar.handler.events; -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Keys; import org.traccar.helper.model.AttributeUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; -import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.reports.common.TripsConfig; import org.traccar.session.cache.CacheManager; @@ -35,13 +34,6 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.util.Collections; -import java.util.Map; - -@Singleton -@ChannelHandler.Sharable public class MotionEventHandler extends BaseEventHandler { private static final Logger LOGGER = LoggerFactory.getLogger(MotionEventHandler.class); @@ -56,17 +48,17 @@ public class MotionEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { + public void analyzePosition(Position position, Callback callback) { long deviceId = position.getDeviceId(); Device device = cacheManager.getObject(Device.class, deviceId); if (device == null || !PositionUtil.isLatest(cacheManager, position)) { - return null; + return; } boolean processInvalid = AttributeUtil.lookup( cacheManager, Keys.EVENT_MOTION_PROCESS_INVALID_POSITIONS, deviceId); if (!processInvalid && !position.getValid()) { - return null; + return; } TripsConfig tripsConfig = new TripsConfig(new AttributeUtil.CacheProvider(cacheManager, deviceId)); @@ -82,7 +74,9 @@ public class MotionEventHandler extends BaseEventHandler { LOGGER.warn("Update device motion error", e); } } - return state.getEvent() != null ? Collections.singletonMap(state.getEvent(), position) : null; + if (state.getEvent() != null) { + callback.eventDetected(state.getEvent()); + } } } diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java index 3bb5f713c..9598581e6 100644 --- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java +++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2023 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ */ package org.traccar.handler.events; -import io.netty.channel.ChannelHandler; +import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; @@ -24,7 +24,6 @@ import org.traccar.config.Keys; import org.traccar.helper.model.AttributeUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; -import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; @@ -36,13 +35,6 @@ import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; -import java.util.Collections; -import java.util.Map; - -@Singleton -@ChannelHandler.Sharable public class OverspeedEventHandler extends BaseEventHandler { private static final Logger LOGGER = LoggerFactory.getLogger(OverspeedEventHandler.class); @@ -55,8 +47,7 @@ public class OverspeedEventHandler extends BaseEventHandler { private final double multiplier; @Inject - public OverspeedEventHandler( - Config config, CacheManager cacheManager, Storage storage) { + public OverspeedEventHandler(Config config, CacheManager cacheManager, Storage storage) { this.cacheManager = cacheManager; this.storage = storage; minimalDuration = config.getLong(Keys.EVENT_OVERSPEED_MINIMAL_DURATION) * 1000; @@ -65,15 +56,15 @@ public class OverspeedEventHandler extends BaseEventHandler { } @Override - protected Map analyzePosition(Position position) { + public void analyzePosition(Position position, Callback callback) { long deviceId = position.getDeviceId(); Device device = cacheManager.getObject(Device.class, position.getDeviceId()); if (device == null) { - return null; + return; } if (!PositionUtil.isLatest(cacheManager, position) || !position.getValid()) { - return null; + return; } double speedLimit = AttributeUtil.lookup(cacheManager, Keys.EVENT_OVERSPEED_LIMIT, deviceId); @@ -105,7 +96,7 @@ public class OverspeedEventHandler extends BaseEventHandler { } if (speedLimit == 0) { - return null; + return; } OverspeedState state = OverspeedState.fromDevice(device); @@ -120,7 +111,9 @@ public class OverspeedEventHandler extends BaseEventHandler { LOGGER.warn("Update device overspeed error", e); } } - return state.getEvent() != null ? Collections.singletonMap(state.getEvent(), position) : null; + if (state.getEvent() != null) { + callback.eventDetected(state.getEvent()); + } } } diff --git a/src/main/java/org/traccar/handler/network/AcknowledgementHandler.java b/src/main/java/org/traccar/handler/network/AcknowledgementHandler.java new file mode 100644 index 000000000..e87f5d34c --- /dev/null +++ b/src/main/java/org/traccar/handler/network/AcknowledgementHandler.java @@ -0,0 +1,121 @@ +/* + * Copyright 2023 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.handler.network; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +public class AcknowledgementHandler extends ChannelOutboundHandlerAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(AcknowledgementHandler.class); + + public interface Event { + } + + public static class EventReceived implements Event { + } + + public static class EventDecoded implements Event { + private final Collection objects; + + public EventDecoded(Collection objects) { + this.objects = objects; + } + + public Collection getObjects() { + return objects; + } + } + + public static class EventHandled implements Event { + private final Object object; + + public EventHandled(Object object) { + this.object = object; + } + + public Object getObject() { + return object; + } + } + + private static final class Entry { + private final Object message; + private final ChannelPromise promise; + + private Entry(Object message, ChannelPromise promise) { + this.message = message; + this.promise = promise; + } + + public Object getMessage() { + return message; + } + + public ChannelPromise getPromise() { + return promise; + } + } + + private List queue; + private final Set waiting = new HashSet<>(); + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + List output = new LinkedList<>(); + synchronized (this) { + if (msg instanceof Event) { + if (msg instanceof EventReceived) { + LOGGER.debug("Event received"); + if (queue == null) { + queue = new LinkedList<>(); + } + } else if (msg instanceof EventDecoded) { + EventDecoded event = (EventDecoded) msg; + LOGGER.debug("Event decoded {}", event.getObjects().size()); + waiting.addAll(event.getObjects()); + } else if (msg instanceof EventHandled) { + EventHandled event = (EventHandled) msg; + LOGGER.debug("Event handled"); + waiting.remove(event.getObject()); + } + if (!(msg instanceof EventReceived) && waiting.isEmpty()) { + output.addAll(queue); + queue = null; + } + } else if (queue != null) { + LOGGER.debug("Message queued"); + queue.add(new Entry(msg, promise)); + } else { + LOGGER.debug("Message sent"); + output.add(new Entry(msg, promise)); + } + } + for (Entry entry : output) { + ctx.write(entry.getMessage(), entry.getPromise()); + } + } + +} diff --git a/src/main/java/org/traccar/handler/network/MainEventHandler.java b/src/main/java/org/traccar/handler/network/MainEventHandler.java new file mode 100644 index 000000000..901036d44 --- /dev/null +++ b/src/main/java/org/traccar/handler/network/MainEventHandler.java @@ -0,0 +1,195 @@ +/* + * Copyright 2012 - 2022 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.handler.network; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.socket.DatagramChannel; +import io.netty.handler.codec.http.HttpRequestDecoder; +import io.netty.handler.timeout.IdleStateEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.BasePipelineFactory; +import org.traccar.BaseProtocolDecoder; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.StatisticsManager; +import org.traccar.helper.DateUtil; +import org.traccar.helper.NetworkUtil; +import org.traccar.helper.model.PositionUtil; +import org.traccar.model.Device; +import org.traccar.model.Position; +import org.traccar.session.ConnectionManager; +import org.traccar.session.cache.CacheManager; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +@Singleton +@ChannelHandler.Sharable +public class MainEventHandler extends ChannelInboundHandlerAdapter { + + private static final Logger LOGGER = LoggerFactory.getLogger(MainEventHandler.class); + + private final Set connectionlessProtocols = new HashSet<>(); + private final Set logAttributes = new LinkedHashSet<>(); + + private final CacheManager cacheManager; + private final Storage storage; + private final ConnectionManager connectionManager; + private final StatisticsManager statisticsManager; + + @Inject + public MainEventHandler( + Config config, CacheManager cacheManager, Storage storage, ConnectionManager connectionManager, + StatisticsManager statisticsManager) { + this.cacheManager = cacheManager; + this.storage = storage; + this.connectionManager = connectionManager; + this.statisticsManager = statisticsManager; + String connectionlessProtocolList = config.getString(Keys.STATUS_IGNORE_OFFLINE); + if (connectionlessProtocolList != null) { + connectionlessProtocols.addAll(Arrays.asList(connectionlessProtocolList.split("[, ]"))); + } + logAttributes.addAll(Arrays.asList(config.getString(Keys.LOGGER_ATTRIBUTES).split("[, ]"))); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + if (msg instanceof Position) { + + Position position = (Position) msg; + Device device = cacheManager.getObject(Device.class, position.getDeviceId()); + + try { + if (PositionUtil.isLatest(cacheManager, position)) { + Device updatedDevice = new Device(); + updatedDevice.setId(position.getDeviceId()); + updatedDevice.setPositionId(position.getId()); + storage.updateObject(updatedDevice, new Request( + new Columns.Include("positionId"), + new Condition.Equals("id", updatedDevice.getId()))); + + cacheManager.updatePosition(position); + connectionManager.updatePosition(true, position); + } + } catch (StorageException error) { + LOGGER.warn("Failed to update device", error); + } + + StringBuilder builder = new StringBuilder(); + builder.append("[").append(NetworkUtil.session(ctx.channel())).append("] "); + builder.append("id: ").append(device.getUniqueId()); + for (String attribute : logAttributes) { + switch (attribute) { + case "time": + builder.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false)); + break; + case "position": + builder.append(", lat: ").append(String.format("%.5f", position.getLatitude())); + builder.append(", lon: ").append(String.format("%.5f", position.getLongitude())); + break; + case "speed": + if (position.getSpeed() > 0) { + builder.append(", speed: ").append(String.format("%.1f", position.getSpeed())); + } + break; + case "course": + builder.append(", course: ").append(String.format("%.1f", position.getCourse())); + break; + case "accuracy": + if (position.getAccuracy() > 0) { + builder.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy())); + } + break; + case "outdated": + if (position.getOutdated()) { + builder.append(", outdated"); + } + break; + case "invalid": + if (!position.getValid()) { + builder.append(", invalid"); + } + break; + default: + Object value = position.getAttributes().get(attribute); + if (value != null) { + builder.append(", ").append(attribute).append(": ").append(value); + } + break; + } + } + LOGGER.info(builder.toString()); + + statisticsManager.registerMessageStored(position.getDeviceId(), position.getProtocol()); + + ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position)); + } + } + + @Override + public void channelActive(ChannelHandlerContext ctx) { + if (!(ctx.channel() instanceof DatagramChannel)) { + LOGGER.info("[{}] connected", NetworkUtil.session(ctx.channel())); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) { + LOGGER.info("[{}] disconnected", NetworkUtil.session(ctx.channel())); + closeChannel(ctx.channel()); + + boolean supportsOffline = BasePipelineFactory.getHandler(ctx.pipeline(), HttpRequestDecoder.class) == null + && !connectionlessProtocols.contains(ctx.pipeline().get(BaseProtocolDecoder.class).getProtocolName()); + connectionManager.deviceDisconnected(ctx.channel(), supportsOffline); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + while (cause.getCause() != null && cause.getCause() != cause) { + cause = cause.getCause(); + } + LOGGER.info("[{}] error", NetworkUtil.session(ctx.channel()), cause); + closeChannel(ctx.channel()); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { + if (evt instanceof IdleStateEvent) { + LOGGER.info("[{}] timed out", NetworkUtil.session(ctx.channel())); + closeChannel(ctx.channel()); + } + } + + private void closeChannel(Channel channel) { + if (!(channel instanceof DatagramChannel)) { + channel.close(); + } + } + +} diff --git a/src/main/java/org/traccar/handler/network/NetworkForwarderHandler.java b/src/main/java/org/traccar/handler/network/NetworkForwarderHandler.java new file mode 100644 index 000000000..5f07ce355 --- /dev/null +++ b/src/main/java/org/traccar/handler/network/NetworkForwarderHandler.java @@ -0,0 +1,72 @@ +/* + * Copyright 2023 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.handler.network; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.socket.DatagramChannel; +import io.netty.channel.socket.DatagramPacket; +import org.traccar.forward.NetworkForwarder; + +import jakarta.inject.Inject; +import java.net.InetSocketAddress; +import java.net.SocketAddress; + +public class NetworkForwarderHandler extends ChannelInboundHandlerAdapter { + + private final int port; + + private NetworkForwarder networkForwarder; + + public NetworkForwarderHandler(int port) { + this.port = port; + } + + @Inject + public void setNetworkForwarder(NetworkForwarder networkForwarder) { + this.networkForwarder = networkForwarder; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + boolean datagram = ctx.channel() instanceof DatagramChannel; + SocketAddress remoteAddress; + ByteBuf buffer; + if (datagram) { + DatagramPacket message = (DatagramPacket) msg; + remoteAddress = message.recipient(); + buffer = message.content(); + } else { + remoteAddress = ctx.channel().remoteAddress(); + buffer = (ByteBuf) msg; + } + + byte[] data = new byte[buffer.readableBytes()]; + buffer.getBytes(buffer.readerIndex(), data); + networkForwarder.forward((InetSocketAddress) remoteAddress, port, datagram, data); + super.channelRead(ctx, msg); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + if (!(ctx.channel() instanceof DatagramChannel)) { + networkForwarder.disconnect((InetSocketAddress) ctx.channel().remoteAddress()); + } + super.channelInactive(ctx); + } + +} diff --git a/src/main/java/org/traccar/handler/network/NetworkMessageHandler.java b/src/main/java/org/traccar/handler/network/NetworkMessageHandler.java new file mode 100644 index 000000000..c2fb9016a --- /dev/null +++ b/src/main/java/org/traccar/handler/network/NetworkMessageHandler.java @@ -0,0 +1,57 @@ +/* + * Copyright 2019 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.handler.network; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import io.netty.channel.socket.DatagramChannel; +import io.netty.channel.socket.DatagramPacket; +import org.traccar.NetworkMessage; + +import java.net.InetSocketAddress; + +public class NetworkMessageHandler extends ChannelDuplexHandler { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + if (ctx.channel() instanceof DatagramChannel) { + DatagramPacket packet = (DatagramPacket) msg; + ctx.fireChannelRead(new NetworkMessage(packet.content(), packet.sender())); + } else if (msg instanceof ByteBuf) { + ByteBuf buffer = (ByteBuf) msg; + ctx.fireChannelRead(new NetworkMessage(buffer, ctx.channel().remoteAddress())); + } + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) { + if (msg instanceof NetworkMessage) { + NetworkMessage message = (NetworkMessage) msg; + if (ctx.channel() instanceof DatagramChannel) { + InetSocketAddress recipient = (InetSocketAddress) message.getRemoteAddress(); + InetSocketAddress sender = (InetSocketAddress) ctx.channel().localAddress(); + ctx.write(new DatagramPacket((ByteBuf) message.getMessage(), recipient, sender), promise); + } else { + ctx.write(message.getMessage(), promise); + } + } else { + ctx.write(msg, promise); + } + } + +} diff --git a/src/main/java/org/traccar/handler/network/OpenChannelHandler.java b/src/main/java/org/traccar/handler/network/OpenChannelHandler.java new file mode 100644 index 000000000..21aaae676 --- /dev/null +++ b/src/main/java/org/traccar/handler/network/OpenChannelHandler.java @@ -0,0 +1,42 @@ +/* + * Copyright 2019 - 2021 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.handler.network; + +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.TrackerConnector; + +public class OpenChannelHandler extends ChannelDuplexHandler { + + private final TrackerConnector connector; + + public OpenChannelHandler(TrackerConnector connector) { + this.connector = connector; + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + super.channelActive(ctx); + connector.getChannelGroup().add(ctx.channel()); + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + super.channelInactive(ctx); + connector.getChannelGroup().remove(ctx.channel()); + } + +} diff --git a/src/main/java/org/traccar/handler/network/RemoteAddressHandler.java b/src/main/java/org/traccar/handler/network/RemoteAddressHandler.java new file mode 100644 index 000000000..d545ed799 --- /dev/null +++ b/src/main/java/org/traccar/handler/network/RemoteAddressHandler.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 - 2024 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.handler.network; + +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import jakarta.inject.Inject; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Position; + +import java.net.InetSocketAddress; + +@ChannelHandler.Sharable +public class RemoteAddressHandler extends ChannelInboundHandlerAdapter { + + private final boolean enabled; + + @Inject + public RemoteAddressHandler(Config config) { + enabled = config.getBoolean(Keys.PROCESSING_REMOTE_ADDRESS_ENABLE); + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + + if (enabled) { + InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress(); + String hostAddress = remoteAddress != null ? remoteAddress.getAddress().getHostAddress() : null; + + if (msg instanceof Position) { + Position position = (Position) msg; + position.set(Position.KEY_IP, hostAddress); + } + } + + ctx.fireChannelRead(msg); + } + +} diff --git a/src/main/java/org/traccar/handler/network/StandardLoggingHandler.java b/src/main/java/org/traccar/handler/network/StandardLoggingHandler.java new file mode 100644 index 000000000..dae93655d --- /dev/null +++ b/src/main/java/org/traccar/handler/network/StandardLoggingHandler.java @@ -0,0 +1,89 @@ +/* + * Copyright 2019 - 2024 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.handler.network; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; +import jakarta.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.NetworkMessage; +import org.traccar.helper.NetworkUtil; +import org.traccar.model.LogRecord; +import org.traccar.session.ConnectionManager; + +public class StandardLoggingHandler extends ChannelDuplexHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(StandardLoggingHandler.class); + + private final String protocol; + private ConnectionManager connectionManager; + + public StandardLoggingHandler(String protocol) { + this.protocol = protocol; + } + + @Inject + public void setConnectionManager(ConnectionManager connectionManager) { + this.connectionManager = connectionManager; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + LogRecord record = createLogRecord(ctx, msg); + log(ctx, false, record); + super.channelRead(ctx, msg); + if (record != null) { + connectionManager.updateLog(record); + } + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + log(ctx, true, createLogRecord(ctx, msg)); + super.write(ctx, msg, promise); + } + + private LogRecord createLogRecord(ChannelHandlerContext ctx, Object msg) { + if (msg instanceof NetworkMessage) { + NetworkMessage networkMessage = (NetworkMessage) msg; + if (networkMessage.getMessage() instanceof ByteBuf) { + LogRecord record = new LogRecord(ctx.channel().localAddress(), networkMessage.getRemoteAddress()); + record.setProtocol(protocol); + record.setData(ByteBufUtil.hexDump((ByteBuf) networkMessage.getMessage())); + return record; + } + } + return null; + } + + private void log(ChannelHandlerContext ctx, boolean downstream, LogRecord record) { + if (record != null) { + StringBuilder message = new StringBuilder(); + message.append("[").append(NetworkUtil.session(ctx.channel())).append(": "); + message.append(protocol); + message.append(downstream ? " > " : " < "); + message.append(record.getAddress().getHostString()); + message.append("] "); + message.append(record.getData()); + LOGGER.info(message.toString()); + } + } + +} diff --git a/src/test/java/org/traccar/handler/DistanceHandlerTest.java b/src/test/java/org/traccar/handler/DistanceHandlerTest.java index 7d2f1e2e3..04a27ad79 100644 --- a/src/test/java/org/traccar/handler/DistanceHandlerTest.java +++ b/src/test/java/org/traccar/handler/DistanceHandlerTest.java @@ -15,14 +15,15 @@ public class DistanceHandlerTest { DistanceHandler distanceHandler = new DistanceHandler(new Config(), mock(CacheManager.class)); - Position position = distanceHandler.handlePosition(new Position()); + Position position = new Position(); + distanceHandler.handlePosition(position, p -> {}); assertEquals(0.0, position.getAttributes().get(Position.KEY_DISTANCE)); assertEquals(0.0, position.getAttributes().get(Position.KEY_TOTAL_DISTANCE)); position.set(Position.KEY_DISTANCE, 100); - position = distanceHandler.handlePosition(position); + distanceHandler.handlePosition(position, p -> {}); assertEquals(100.0, position.getAttributes().get(Position.KEY_DISTANCE)); assertEquals(100.0, position.getAttributes().get(Position.KEY_TOTAL_DISTANCE)); diff --git a/src/test/java/org/traccar/handler/MotionHandlerTest.java b/src/test/java/org/traccar/handler/MotionHandlerTest.java index 10cdf6a90..927c803d9 100644 --- a/src/test/java/org/traccar/handler/MotionHandlerTest.java +++ b/src/test/java/org/traccar/handler/MotionHandlerTest.java @@ -26,7 +26,8 @@ public class MotionHandlerTest { MotionHandler motionHandler = new MotionHandler(cacheManager); - Position position = motionHandler.handlePosition(new Position()); + Position position = new Position(); + motionHandler.handlePosition(position, p -> {}); assertEquals(false, position.getAttributes().get(Position.KEY_MOTION)); diff --git a/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java b/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java index 66dc55c85..7b1991553 100644 --- a/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java @@ -7,10 +7,11 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.mockito.Mockito.mock; public class AlertEventHandlerTest extends BaseTest { @@ -22,9 +23,10 @@ public class AlertEventHandlerTest extends BaseTest { Position position = new Position(); position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); - Map events = alertEventHandler.analyzePosition(position); - assertNotNull(events); - Event event = events.keySet().iterator().next(); + List events = new ArrayList<>(); + alertEventHandler.analyzePosition(position, events::add); + assertFalse(events.isEmpty()); + Event event = events.iterator().next(); assertEquals(Event.TYPE_ALARM, event.getType()); } diff --git a/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java b/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java index bc24e42f5..58e198b7f 100644 --- a/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/CommandResultEventHandlerTest.java @@ -5,9 +5,12 @@ import org.traccar.BaseTest; import org.traccar.model.Event; import org.traccar.model.Position; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; public class CommandResultEventHandlerTest extends BaseTest { @@ -19,9 +22,10 @@ public class CommandResultEventHandlerTest extends BaseTest { Position position = new Position(); position.set(Position.KEY_RESULT, "Test Result"); - Map events = commandResultEventHandler.analyzePosition(position); - assertNotNull(events); - Event event = events.keySet().iterator().next(); + List events = new ArrayList<>(); + commandResultEventHandler.analyzePosition(position, events::add); + assertFalse(events.isEmpty()); + Event event = events.iterator().next(); assertEquals(Event.TYPE_COMMAND_RESULT, event.getType()); } diff --git a/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java index 972932df4..61ff50efa 100644 --- a/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java @@ -1,14 +1,11 @@ package org.traccar.handler.events; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.traccar.BaseTest; -import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.mock; public class IgnitionEventHandlerTest extends BaseTest { @@ -21,8 +18,7 @@ public class IgnitionEventHandlerTest extends BaseTest { Position position = new Position(); position.set(Position.KEY_IGNITION, true); position.setValid(true); - Map events = ignitionEventHandler.analyzePosition(position); - assertNull(events); + ignitionEventHandler.analyzePosition(position, Assertions::assertNull); } } diff --git a/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java b/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java index 661336d76..f0bd4a3f9 100644 --- a/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/MaintenanceEventHandlerTest.java @@ -2,11 +2,14 @@ package org.traccar.handler.events; import org.junit.jupiter.api.Test; import org.traccar.BaseTest; +import org.traccar.model.Event; import org.traccar.model.Maintenance; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -38,24 +41,30 @@ public class MaintenanceEventHandlerTest extends BaseTest { MaintenanceEventHandler eventHandler = new MaintenanceEventHandler(cacheManager); when(maintenance.getStart()).thenReturn(10000.0); - when(maintenance.getPeriod()).thenReturn(2000.0); + when(maintenance.getPeriod()).thenReturn(2000.0); + + List events = new ArrayList<>(); lastPosition.set(Position.KEY_TOTAL_DISTANCE, 1999); - position.set(Position.KEY_TOTAL_DISTANCE, 2001); - assertTrue(eventHandler.analyzePosition(position).isEmpty()); + position.set(Position.KEY_TOTAL_DISTANCE, 2001); + eventHandler.analyzePosition(position, events::add); + assertTrue(events.isEmpty()); lastPosition.set(Position.KEY_TOTAL_DISTANCE, 3999); - position.set(Position.KEY_TOTAL_DISTANCE, 4001); - assertTrue(eventHandler.analyzePosition(position).isEmpty()); + position.set(Position.KEY_TOTAL_DISTANCE, 4001); + eventHandler.analyzePosition(position, events::add); + assertTrue(events.isEmpty()); lastPosition.set(Position.KEY_TOTAL_DISTANCE, 9999); position.set(Position.KEY_TOTAL_DISTANCE, 10001); - assertEquals(1, eventHandler.analyzePosition(position).size()); + eventHandler.analyzePosition(position, events::add); + assertEquals(1, events.size()); lastPosition.set(Position.KEY_TOTAL_DISTANCE, 11999); position.set(Position.KEY_TOTAL_DISTANCE, 12001); - assertEquals(1, eventHandler.analyzePosition(position).size()); - + eventHandler.analyzePosition(position, events::add); + assertEquals(2, events.size()); + } } -- cgit v1.2.3 From 0f7ec1247cff1a68ffa57ade3f45b11f6602e262 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 30 Mar 2024 19:36:35 -0700 Subject: Make handlers nullable --- src/main/java/org/traccar/MainModule.java | 31 ++++++++++++++++++++++ .../org/traccar/handler/CopyAttributesHandler.java | 18 +++++-------- .../java/org/traccar/handler/FilterHandler.java | 4 +-- src/main/java/org/traccar/handler/TimeHandler.java | 22 +++++---------- 4 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 26654947e..791d61c61 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -72,9 +72,12 @@ import org.traccar.geolocation.GeolocationProvider; import org.traccar.geolocation.GoogleGeolocationProvider; import org.traccar.geolocation.OpenCellIdGeolocationProvider; import org.traccar.geolocation.UnwiredGeolocationProvider; +import org.traccar.handler.CopyAttributesHandler; +import org.traccar.handler.FilterHandler; import org.traccar.handler.GeocoderHandler; import org.traccar.handler.GeolocationHandler; import org.traccar.handler.SpeedLimitHandler; +import org.traccar.handler.TimeHandler; import org.traccar.helper.ObjectMapperContextResolver; import org.traccar.helper.SanitizerModule; import org.traccar.helper.WebHelper; @@ -336,6 +339,34 @@ public class MainModule extends AbstractModule { return null; } + @Singleton + @Provides + public static CopyAttributesHandler provideCopyAttributesHandler(Config config, CacheManager cacheManager) { + if (config.getBoolean(Keys.PROCESSING_COPY_ATTRIBUTES_ENABLE)) { + return new CopyAttributesHandler(config, cacheManager); + } + return null; + } + + @Singleton + @Provides + public static FilterHandler provideFilterHandler( + Config config, CacheManager cacheManager, Storage storage, StatisticsManager statisticsManager) { + if (config.getBoolean(Keys.FILTER_ENABLE)) { + return new FilterHandler(config, cacheManager, storage, statisticsManager); + } + return null; + } + + @Singleton + @Provides + public static TimeHandler provideTimeHandler(Config config) { + if (config.hasKey(Keys.TIME_OVERRIDE)) { + return new TimeHandler(config); + } + return null; + } + @Singleton @Provides public static BroadcastService provideBroadcastService( diff --git a/src/main/java/org/traccar/handler/CopyAttributesHandler.java b/src/main/java/org/traccar/handler/CopyAttributesHandler.java index 9c31bf56e..f682c99c9 100644 --- a/src/main/java/org/traccar/handler/CopyAttributesHandler.java +++ b/src/main/java/org/traccar/handler/CopyAttributesHandler.java @@ -25,26 +25,22 @@ import org.traccar.session.cache.CacheManager; public class CopyAttributesHandler extends BasePositionHandler { - private final boolean enabled; private final CacheManager cacheManager; @Inject public CopyAttributesHandler(Config config, CacheManager cacheManager) { - enabled = config.getBoolean(Keys.PROCESSING_COPY_ATTRIBUTES_ENABLE); this.cacheManager = cacheManager; } @Override public void handlePosition(Position position, Callback callback) { - if (enabled) { - String attributesString = AttributeUtil.lookup( - cacheManager, Keys.PROCESSING_COPY_ATTRIBUTES, position.getDeviceId()); - Position last = cacheManager.getPosition(position.getDeviceId()); - if (last != null && attributesString != null) { - for (String attribute : attributesString.split("[ ,]")) { - if (last.hasAttribute(attribute) && !position.hasAttribute(attribute)) { - position.getAttributes().put(attribute, last.getAttributes().get(attribute)); - } + String attributesString = AttributeUtil.lookup( + cacheManager, Keys.PROCESSING_COPY_ATTRIBUTES, position.getDeviceId()); + Position last = cacheManager.getPosition(position.getDeviceId()); + if (last != null && attributesString != null) { + for (String attribute : attributesString.split("[ ,]")) { + if (last.hasAttribute(attribute) && !position.hasAttribute(attribute)) { + position.getAttributes().put(attribute, last.getAttributes().get(attribute)); } } } diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 4cc6233d0..a9e6024c8 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -40,7 +40,6 @@ public class FilterHandler extends BasePositionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(FilterHandler.class); - private final boolean enabled; private final boolean filterInvalid; private final boolean filterZero; private final boolean filterDuplicate; @@ -65,7 +64,6 @@ public class FilterHandler extends BasePositionHandler { @Inject public FilterHandler( Config config, CacheManager cacheManager, Storage storage, StatisticsManager statisticsManager) { - enabled = config.getBoolean(Keys.FILTER_ENABLE); filterInvalid = config.getBoolean(Keys.FILTER_INVALID); filterZero = config.getBoolean(Keys.FILTER_ZERO); filterDuplicate = config.getBoolean(Keys.FILTER_DUPLICATE); @@ -272,7 +270,7 @@ public class FilterHandler extends BasePositionHandler { @Override public void handlePosition(Position position, Callback callback) { - if (enabled && filter(position)) { + if (filter(position)) { callback.processed(null); } else { callback.processed(position); diff --git a/src/main/java/org/traccar/handler/TimeHandler.java b/src/main/java/org/traccar/handler/TimeHandler.java index 2e703c681..052ad41c3 100644 --- a/src/main/java/org/traccar/handler/TimeHandler.java +++ b/src/main/java/org/traccar/handler/TimeHandler.java @@ -26,18 +26,12 @@ import java.util.Set; public class TimeHandler extends BasePositionHandler { - private final boolean enabled; private final boolean useServerTime; private final Set protocols; @Inject public TimeHandler(Config config) { - enabled = config.hasKey(Keys.TIME_OVERRIDE); - if (enabled) { - useServerTime = config.getString(Keys.TIME_OVERRIDE).equalsIgnoreCase("serverTime"); - } else { - useServerTime = false; - } + useServerTime = config.getString(Keys.TIME_OVERRIDE).equalsIgnoreCase("serverTime"); String protocolList = config.getString(Keys.TIME_PROTOCOLS); if (protocolList != null) { protocols = new HashSet<>(Arrays.asList(protocolList.split("[, ]"))); @@ -49,14 +43,12 @@ public class TimeHandler extends BasePositionHandler { @Override public void handlePosition(Position position, Callback callback) { - if (enabled) { - if (protocols == null || protocols.contains(position.getProtocol())) { - if (useServerTime) { - position.setDeviceTime(position.getServerTime()); - position.setFixTime(position.getServerTime()); - } else { - position.setFixTime(position.getDeviceTime()); - } + if (protocols == null || protocols.contains(position.getProtocol())) { + if (useServerTime) { + position.setDeviceTime(position.getServerTime()); + position.setFixTime(position.getServerTime()); + } else { + position.setFixTime(position.getDeviceTime()); } } callback.processed(position); -- cgit v1.2.3 From e7205fa3d1aa6d223cfabfabb32f027415956430 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 30 Mar 2024 19:38:06 -0700 Subject: Remove unused global timer --- src/main/java/org/traccar/GlobalTimer.java | 42 ---------------------------- src/main/java/org/traccar/ServerManager.java | 8 ++---- 2 files changed, 2 insertions(+), 48 deletions(-) delete mode 100644 src/main/java/org/traccar/GlobalTimer.java diff --git a/src/main/java/org/traccar/GlobalTimer.java b/src/main/java/org/traccar/GlobalTimer.java deleted file mode 100644 index a97321ba2..000000000 --- a/src/main/java/org/traccar/GlobalTimer.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012 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; - -import io.netty.util.HashedWheelTimer; -import io.netty.util.Timer; - -public final class GlobalTimer { - - private static Timer instance = null; - - private GlobalTimer() { - } - - public static void release() { - if (instance != null) { - instance.stop(); - } - instance = null; - } - - public static Timer getTimer() { - if (instance == null) { - instance = new HashedWheelTimer(); - } - return instance; - } - -} diff --git a/src/main/java/org/traccar/ServerManager.java b/src/main/java/org/traccar/ServerManager.java index e91be50a2..22af66b41 100644 --- a/src/main/java/org/traccar/ServerManager.java +++ b/src/main/java/org/traccar/ServerManager.java @@ -82,12 +82,8 @@ public class ServerManager implements LifecycleObject { @Override public void stop() throws Exception { - try { - for (TrackerConnector connector : connectorList) { - connector.stop(); - } - } finally { - GlobalTimer.release(); + for (TrackerConnector connector : connectorList) { + connector.stop(); } } -- cgit v1.2.3 From 2d366f0ab3d88c635bec0f1f498396cd47557f1d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 30 Mar 2024 19:41:51 -0700 Subject: Fix remote address handler --- src/main/java/org/traccar/BasePipelineFactory.java | 2 +- src/main/java/org/traccar/handler/network/RemoteAddressHandler.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java index 6d9431ad6..40360cca7 100644 --- a/src/main/java/org/traccar/BasePipelineFactory.java +++ b/src/main/java/org/traccar/BasePipelineFactory.java @@ -96,7 +96,6 @@ public abstract class BasePipelineFactory extends ChannelInitializer { pipeline.addLast(injectMembers(new NetworkForwarderHandler(port))); } pipeline.addLast(new NetworkMessageHandler()); - pipeline.addLast(new RemoteAddressHandler(config)); pipeline.addLast(injectMembers(new StandardLoggingHandler(protocol))); if (!connector.isDatagram() && !config.getBoolean(Keys.SERVER_INSTANT_ACKNOWLEDGEMENT)) { @@ -116,6 +115,7 @@ public abstract class BasePipelineFactory extends ChannelInitializer { pipeline.addLast(handler); }); + pipeline.addLast(injector.getInstance(RemoteAddressHandler.class)); pipeline.addLast(injector.getInstance(ProcessingHandler.class)); pipeline.addLast(injector.getInstance(MainEventHandler.class)); } diff --git a/src/main/java/org/traccar/handler/network/RemoteAddressHandler.java b/src/main/java/org/traccar/handler/network/RemoteAddressHandler.java index d545ed799..c52bb2be1 100644 --- a/src/main/java/org/traccar/handler/network/RemoteAddressHandler.java +++ b/src/main/java/org/traccar/handler/network/RemoteAddressHandler.java @@ -19,12 +19,14 @@ import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import jakarta.inject.Inject; +import jakarta.inject.Singleton; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; import java.net.InetSocketAddress; +@Singleton @ChannelHandler.Sharable public class RemoteAddressHandler extends ChannelInboundHandlerAdapter { -- cgit v1.2.3 From 05283e44dea22f7b928401f888289840581b28af Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 31 Mar 2024 07:14:34 -0700 Subject: Simplify main event handler --- src/main/java/org/traccar/ProcessingHandler.java | 12 +++- .../java/org/traccar/handler/DatabaseHandler.java | 6 +- .../org/traccar/handler/PostProcessHandler.java | 67 ++++++++++++++++++++++ .../traccar/handler/network/MainEventHandler.java | 40 ++----------- 4 files changed, 86 insertions(+), 39 deletions(-) create mode 100644 src/main/java/org/traccar/handler/PostProcessHandler.java diff --git a/src/main/java/org/traccar/ProcessingHandler.java b/src/main/java/org/traccar/ProcessingHandler.java index 7627c719b..09ec79f9d 100644 --- a/src/main/java/org/traccar/ProcessingHandler.java +++ b/src/main/java/org/traccar/ProcessingHandler.java @@ -26,6 +26,7 @@ import org.traccar.handler.BasePositionHandler; import org.traccar.handler.ComputedAttributesHandler; import org.traccar.handler.CopyAttributesHandler; import org.traccar.handler.DatabaseHandler; +import org.traccar.handler.PostProcessHandler; import org.traccar.handler.DistanceHandler; import org.traccar.handler.EngineHoursHandler; import org.traccar.handler.FilterHandler; @@ -65,6 +66,7 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter { private final NotificationManager notificationManager; private final List positionHandlers; private final List eventHandlers; + private final PostProcessHandler postProcessHandler; @Inject public ProcessingHandler(Injector injector, NotificationManager notificationManager) { @@ -104,14 +106,17 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter { .map((clazz) -> (BaseEventHandler) injector.getInstance(clazz)) .filter(Objects::nonNull) .collect(Collectors.toUnmodifiableList()); + + postProcessHandler = injector.getInstance(PostProcessHandler.class); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof Position) { processPositionHandlers(ctx, (Position) msg); + } else { + super.channelRead(ctx, msg); } - super.channelRead(ctx, msg); } private void processPositionHandlers(ChannelHandlerContext ctx, Position position) { @@ -139,7 +144,10 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter { } private void finishedProcessing(ChannelHandlerContext ctx, Position position) { - ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position)); + postProcessHandler.handlePosition(position, p -> { + ctx.fireChannelRead(p); + ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(p)); + }); } } diff --git a/src/main/java/org/traccar/handler/DatabaseHandler.java b/src/main/java/org/traccar/handler/DatabaseHandler.java index b1f218a1e..0c8d2717d 100644 --- a/src/main/java/org/traccar/handler/DatabaseHandler.java +++ b/src/main/java/org/traccar/handler/DatabaseHandler.java @@ -18,6 +18,7 @@ package org.traccar.handler; import jakarta.inject.Inject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.traccar.database.StatisticsManager; import org.traccar.model.Position; import org.traccar.storage.Storage; import org.traccar.storage.query.Columns; @@ -28,10 +29,12 @@ public class DatabaseHandler extends BasePositionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseHandler.class); private final Storage storage; + private final StatisticsManager statisticsManager; @Inject - public DatabaseHandler(Storage storage) { + public DatabaseHandler(Storage storage, StatisticsManager statisticsManager) { this.storage = storage; + this.statisticsManager = statisticsManager; } @Override @@ -39,6 +42,7 @@ public class DatabaseHandler extends BasePositionHandler { try { position.setId(storage.addObject(position, new Request(new Columns.Exclude("id")))); + statisticsManager.messageStoredCount(position.getDeviceId()); } catch (Exception error) { LOGGER.warn("Failed to store position", error); } diff --git a/src/main/java/org/traccar/handler/PostProcessHandler.java b/src/main/java/org/traccar/handler/PostProcessHandler.java new file mode 100644 index 000000000..2d6bc03ad --- /dev/null +++ b/src/main/java/org/traccar/handler/PostProcessHandler.java @@ -0,0 +1,67 @@ +/* + * Copyright 2024 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.handler; + +import jakarta.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.helper.model.PositionUtil; +import org.traccar.model.Device; +import org.traccar.model.Position; +import org.traccar.session.ConnectionManager; +import org.traccar.session.cache.CacheManager; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +public class PostProcessHandler extends BasePositionHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(PostProcessHandler.class); + + private final CacheManager cacheManager; + private final Storage storage; + private final ConnectionManager connectionManager; + + @Inject + public PostProcessHandler(CacheManager cacheManager, Storage storage, ConnectionManager connectionManager) { + this.cacheManager = cacheManager; + this.storage = storage; + this.connectionManager = connectionManager; + } + + @Override + public void handlePosition(Position position, Callback callback) { + try { + if (PositionUtil.isLatest(cacheManager, position)) { + Device updatedDevice = new Device(); + updatedDevice.setId(position.getDeviceId()); + updatedDevice.setPositionId(position.getId()); + storage.updateObject(updatedDevice, new Request( + new Columns.Include("positionId"), + new Condition.Equals("id", updatedDevice.getId()))); + + cacheManager.updatePosition(position); + connectionManager.updatePosition(true, position); + } + } catch (StorageException error) { + LOGGER.warn("Failed to update device", error); + } + callback.processed(position); + } + +} diff --git a/src/main/java/org/traccar/handler/network/MainEventHandler.java b/src/main/java/org/traccar/handler/network/MainEventHandler.java index 901036d44..d6407f1e5 100644 --- a/src/main/java/org/traccar/handler/network/MainEventHandler.java +++ b/src/main/java/org/traccar/handler/network/MainEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2024 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. @@ -22,28 +22,21 @@ import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.socket.DatagramChannel; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.timeout.IdleStateEvent; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.BasePipelineFactory; import org.traccar.BaseProtocolDecoder; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.database.StatisticsManager; import org.traccar.helper.DateUtil; import org.traccar.helper.NetworkUtil; -import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.session.ConnectionManager; import org.traccar.session.cache.CacheManager; -import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; @@ -59,18 +52,13 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { private final Set logAttributes = new LinkedHashSet<>(); private final CacheManager cacheManager; - private final Storage storage; private final ConnectionManager connectionManager; - private final StatisticsManager statisticsManager; @Inject public MainEventHandler( - Config config, CacheManager cacheManager, Storage storage, ConnectionManager connectionManager, - StatisticsManager statisticsManager) { + Config config, CacheManager cacheManager, ConnectionManager connectionManager) { this.cacheManager = cacheManager; - this.storage = storage; this.connectionManager = connectionManager; - this.statisticsManager = statisticsManager; String connectionlessProtocolList = config.getString(Keys.STATUS_IGNORE_OFFLINE); if (connectionlessProtocolList != null) { connectionlessProtocols.addAll(Arrays.asList(connectionlessProtocolList.split("[, ]"))); @@ -85,22 +73,6 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { Position position = (Position) msg; Device device = cacheManager.getObject(Device.class, position.getDeviceId()); - try { - if (PositionUtil.isLatest(cacheManager, position)) { - Device updatedDevice = new Device(); - updatedDevice.setId(position.getDeviceId()); - updatedDevice.setPositionId(position.getId()); - storage.updateObject(updatedDevice, new Request( - new Columns.Include("positionId"), - new Condition.Equals("id", updatedDevice.getId()))); - - cacheManager.updatePosition(position); - connectionManager.updatePosition(true, position); - } - } catch (StorageException error) { - LOGGER.warn("Failed to update device", error); - } - StringBuilder builder = new StringBuilder(); builder.append("[").append(NetworkUtil.session(ctx.channel())).append("] "); builder.append("id: ").append(device.getUniqueId()); @@ -145,10 +117,6 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { } } LOGGER.info(builder.toString()); - - statisticsManager.registerMessageStored(position.getDeviceId(), position.getProtocol()); - - ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position)); } } -- cgit v1.2.3 From 0b403da4f4fe83517110a09acb1d280396379dfb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 31 Mar 2024 08:07:22 -0700 Subject: Delete unused group tree --- src/main/java/org/traccar/database/GroupTree.java | 151 --------------------- .../java/org/traccar/database/GroupTreeTest.java | 56 -------- 2 files changed, 207 deletions(-) delete mode 100644 src/main/java/org/traccar/database/GroupTree.java delete mode 100644 src/test/java/org/traccar/database/GroupTreeTest.java diff --git a/src/main/java/org/traccar/database/GroupTree.java b/src/main/java/org/traccar/database/GroupTree.java deleted file mode 100644 index 8798f55bc..000000000 --- a/src/main/java/org/traccar/database/GroupTree.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2016 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.database; - -import org.traccar.model.Device; -import org.traccar.model.Group; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class GroupTree { - - private static class TreeNode { - - private Group group; - private Device device; - private Collection children = new HashSet<>(); - - TreeNode(Group group) { - this.group = group; - } - - TreeNode(Device device) { - this.device = device; - } - - @Override - public int hashCode() { - if (group != null) { - return (int) group.getId(); - } else { - return (int) device.getId(); - } - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof TreeNode)) { - return false; - } - TreeNode other = (TreeNode) obj; - if (other == this) { - return true; - } - if (group != null && other.group != null) { - return group.getId() == other.group.getId(); - } else if (device != null && other.device != null) { - return device.getId() == other.device.getId(); - } - return false; - } - - public Group getGroup() { - return group; - } - - public Device getDevice() { - return device; - } - - public void setParent(TreeNode parent) { - if (parent != null) { - parent.children.add(this); - } - } - - public Collection getChildren() { - return children; - } - - } - - private final Map groupMap = new HashMap<>(); - - public GroupTree(Collection groups, Collection devices) { - - for (Group group : groups) { - groupMap.put(group.getId(), new TreeNode(group)); - } - - for (TreeNode node : groupMap.values()) { - if (node.getGroup().getGroupId() != 0) { - node.setParent(groupMap.get(node.getGroup().getGroupId())); - } - } - - Map deviceMap = new HashMap<>(); - - for (Device device : devices) { - deviceMap.put(device.getId(), new TreeNode(device)); - } - - for (TreeNode node : deviceMap.values()) { - if (node.getDevice().getGroupId() != 0) { - node.setParent(groupMap.get(node.getDevice().getGroupId())); - } - } - - } - - public Collection getGroups(long groupId) { - Set results = new HashSet<>(); - getNodes(results, groupMap.get(groupId)); - Collection groups = new ArrayList<>(); - for (TreeNode node : results) { - if (node.getGroup() != null) { - groups.add(node.getGroup()); - } - } - return groups; - } - - public Collection getDevices(long groupId) { - Set results = new HashSet<>(); - getNodes(results, groupMap.get(groupId)); - Collection devices = new ArrayList<>(); - for (TreeNode node : results) { - if (node.getDevice() != null) { - devices.add(node.getDevice()); - } - } - return devices; - } - - private void getNodes(Set results, TreeNode node) { - if (node != null) { - for (TreeNode child : node.getChildren()) { - results.add(child); - getNodes(results, child); - } - } - } - -} diff --git a/src/test/java/org/traccar/database/GroupTreeTest.java b/src/test/java/org/traccar/database/GroupTreeTest.java deleted file mode 100644 index 7c0d478f8..000000000 --- a/src/test/java/org/traccar/database/GroupTreeTest.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.traccar.database; - -import org.junit.jupiter.api.Test; -import org.traccar.model.Device; -import org.traccar.model.Group; - -import java.util.ArrayList; -import java.util.Collection; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class GroupTreeTest { - - private static Group createGroup(long id, String name, long parent) { - Group group = new Group(); - group.setId(id); - group.setName(name); - group.setGroupId(parent); - return group; - } - - private static Device createDevice(long id, String name, long parent) { - Device device = new Device(); - device.setId(id); - device.setName(name); - device.setGroupId(parent); - return device; - } - - @Test - public void testGetDescendants() { - Collection groups = new ArrayList<>(); - groups.add(createGroup(1, "First", 0)); - groups.add(createGroup(2, "Second", 1)); - groups.add(createGroup(3, "Third", 2)); - groups.add(createGroup(4, "Fourth", 2)); - groups.add(createGroup(5, "Fifth", 4)); - - Collection devices = new ArrayList<>(); - devices.add(createDevice(1, "One", 3)); - devices.add(createDevice(2, "Two", 5)); - devices.add(createDevice(3, "One", 5)); - - GroupTree groupTree = new GroupTree(groups, devices); - - assertEquals(4, groupTree.getGroups(1).size()); - assertEquals(3, groupTree.getGroups(2).size()); - assertEquals(0, groupTree.getGroups(3).size()); - assertEquals(1, groupTree.getGroups(4).size()); - - assertEquals(3, groupTree.getDevices(1).size()); - assertEquals(1, groupTree.getDevices(3).size()); - assertEquals(2, groupTree.getDevices(4).size()); - } - -} -- cgit v1.2.3 From 301a643d62ccce053a1eaf10e5516a3d5bcc815f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 31 Mar 2024 08:13:18 -0700 Subject: Extract position logger --- src/main/java/org/traccar/ProcessingHandler.java | 8 +- .../traccar/handler/network/MainEventHandler.java | 69 +--------------- .../java/org/traccar/helper/PositionLogger.java | 94 ++++++++++++++++++++++ 3 files changed, 102 insertions(+), 69 deletions(-) create mode 100644 src/main/java/org/traccar/helper/PositionLogger.java diff --git a/src/main/java/org/traccar/ProcessingHandler.java b/src/main/java/org/traccar/ProcessingHandler.java index 09ec79f9d..688389d98 100644 --- a/src/main/java/org/traccar/ProcessingHandler.java +++ b/src/main/java/org/traccar/ProcessingHandler.java @@ -51,6 +51,7 @@ import org.traccar.handler.events.MediaEventHandler; import org.traccar.handler.events.MotionEventHandler; import org.traccar.handler.events.OverspeedEventHandler; import org.traccar.handler.network.AcknowledgementHandler; +import org.traccar.helper.PositionLogger; import org.traccar.model.Position; import java.util.List; @@ -64,13 +65,16 @@ import java.util.stream.Stream; public class ProcessingHandler extends ChannelInboundHandlerAdapter { private final NotificationManager notificationManager; + private final PositionLogger positionLogger; private final List positionHandlers; private final List eventHandlers; private final PostProcessHandler postProcessHandler; @Inject - public ProcessingHandler(Injector injector, NotificationManager notificationManager) { + public ProcessingHandler( + Injector injector, NotificationManager notificationManager, PositionLogger positionLogger) { this.notificationManager = notificationManager; + this.positionLogger = positionLogger; positionHandlers = Stream.of( TimeHandler.class, @@ -145,7 +149,7 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter { private void finishedProcessing(ChannelHandlerContext ctx, Position position) { postProcessHandler.handlePosition(position, p -> { - ctx.fireChannelRead(p); + positionLogger.log(ctx, p); ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(p)); }); } diff --git a/src/main/java/org/traccar/handler/network/MainEventHandler.java b/src/main/java/org/traccar/handler/network/MainEventHandler.java index d6407f1e5..f60004126 100644 --- a/src/main/java/org/traccar/handler/network/MainEventHandler.java +++ b/src/main/java/org/traccar/handler/network/MainEventHandler.java @@ -30,16 +30,11 @@ import org.traccar.BasePipelineFactory; import org.traccar.BaseProtocolDecoder; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.helper.DateUtil; import org.traccar.helper.NetworkUtil; -import org.traccar.model.Device; -import org.traccar.model.Position; import org.traccar.session.ConnectionManager; -import org.traccar.session.cache.CacheManager; import java.util.Arrays; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.Set; @Singleton @@ -48,76 +43,16 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(MainEventHandler.class); - private final Set connectionlessProtocols = new HashSet<>(); - private final Set logAttributes = new LinkedHashSet<>(); - - private final CacheManager cacheManager; private final ConnectionManager connectionManager; + private final Set connectionlessProtocols = new HashSet<>(); @Inject - public MainEventHandler( - Config config, CacheManager cacheManager, ConnectionManager connectionManager) { - this.cacheManager = cacheManager; + public MainEventHandler(Config config, ConnectionManager connectionManager) { this.connectionManager = connectionManager; String connectionlessProtocolList = config.getString(Keys.STATUS_IGNORE_OFFLINE); if (connectionlessProtocolList != null) { connectionlessProtocols.addAll(Arrays.asList(connectionlessProtocolList.split("[, ]"))); } - logAttributes.addAll(Arrays.asList(config.getString(Keys.LOGGER_ATTRIBUTES).split("[, ]"))); - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) { - if (msg instanceof Position) { - - Position position = (Position) msg; - Device device = cacheManager.getObject(Device.class, position.getDeviceId()); - - StringBuilder builder = new StringBuilder(); - builder.append("[").append(NetworkUtil.session(ctx.channel())).append("] "); - builder.append("id: ").append(device.getUniqueId()); - for (String attribute : logAttributes) { - switch (attribute) { - case "time": - builder.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false)); - break; - case "position": - builder.append(", lat: ").append(String.format("%.5f", position.getLatitude())); - builder.append(", lon: ").append(String.format("%.5f", position.getLongitude())); - break; - case "speed": - if (position.getSpeed() > 0) { - builder.append(", speed: ").append(String.format("%.1f", position.getSpeed())); - } - break; - case "course": - builder.append(", course: ").append(String.format("%.1f", position.getCourse())); - break; - case "accuracy": - if (position.getAccuracy() > 0) { - builder.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy())); - } - break; - case "outdated": - if (position.getOutdated()) { - builder.append(", outdated"); - } - break; - case "invalid": - if (!position.getValid()) { - builder.append(", invalid"); - } - break; - default: - Object value = position.getAttributes().get(attribute); - if (value != null) { - builder.append(", ").append(attribute).append(": ").append(value); - } - break; - } - } - LOGGER.info(builder.toString()); - } } @Override diff --git a/src/main/java/org/traccar/helper/PositionLogger.java b/src/main/java/org/traccar/helper/PositionLogger.java new file mode 100644 index 000000000..9f149edf4 --- /dev/null +++ b/src/main/java/org/traccar/helper/PositionLogger.java @@ -0,0 +1,94 @@ +/* + * Copyright 2024 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.helper; + +import io.netty.channel.ChannelHandlerContext; +import jakarta.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Device; +import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; + +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.Set; + +public class PositionLogger { + + private static final Logger LOGGER = LoggerFactory.getLogger(PositionLogger.class); + + private final CacheManager cacheManager; + private final Set logAttributes = new LinkedHashSet<>(); + + @Inject + public PositionLogger(Config config, CacheManager cacheManager) { + this.cacheManager = cacheManager; + logAttributes.addAll(Arrays.asList(config.getString(Keys.LOGGER_ATTRIBUTES).split("[, ]"))); + } + + public void log(ChannelHandlerContext context, Position position) { + Device device = cacheManager.getObject(Device.class, position.getDeviceId()); + + StringBuilder builder = new StringBuilder(); + builder.append("[").append(NetworkUtil.session(context.channel())).append("] "); + builder.append("id: ").append(device.getUniqueId()); + for (String attribute : logAttributes) { + switch (attribute) { + case "time": + builder.append(", time: ").append(DateUtil.formatDate(position.getFixTime(), false)); + break; + case "position": + builder.append(", lat: ").append(String.format("%.5f", position.getLatitude())); + builder.append(", lon: ").append(String.format("%.5f", position.getLongitude())); + break; + case "speed": + if (position.getSpeed() > 0) { + builder.append(", speed: ").append(String.format("%.1f", position.getSpeed())); + } + break; + case "course": + builder.append(", course: ").append(String.format("%.1f", position.getCourse())); + break; + case "accuracy": + if (position.getAccuracy() > 0) { + builder.append(", accuracy: ").append(String.format("%.1f", position.getAccuracy())); + } + break; + case "outdated": + if (position.getOutdated()) { + builder.append(", outdated"); + } + break; + case "invalid": + if (!position.getValid()) { + builder.append(", invalid"); + } + break; + default: + Object value = position.getAttributes().get(attribute); + if (value != null) { + builder.append(", ").append(attribute).append(": ").append(value); + } + break; + } + } + LOGGER.info(builder.toString()); + } + +} -- cgit v1.2.3 From ae91b2f07e88d2dea97aa4bb316cb00116b4a702 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 31 Mar 2024 08:16:28 -0700 Subject: Implement position buffering --- debug.xml | 3 + src/main/java/org/traccar/ProcessingHandler.java | 17 +++- src/main/java/org/traccar/config/Keys.java | 8 ++ .../org/traccar/database/BufferingManager.java | 103 +++++++++++++++++++++ 4 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/traccar/database/BufferingManager.java diff --git a/debug.xml b/debug.xml index 028e9210b..f3abbe9a9 100644 --- a/debug.xml +++ b/debug.xml @@ -25,6 +25,9 @@ sa + + true 6037 diff --git a/src/main/java/org/traccar/ProcessingHandler.java b/src/main/java/org/traccar/ProcessingHandler.java index 688389d98..cbb375a72 100644 --- a/src/main/java/org/traccar/ProcessingHandler.java +++ b/src/main/java/org/traccar/ProcessingHandler.java @@ -21,12 +21,13 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import jakarta.inject.Inject; import jakarta.inject.Singleton; +import org.traccar.config.Config; +import org.traccar.database.BufferingManager; import org.traccar.database.NotificationManager; import org.traccar.handler.BasePositionHandler; import org.traccar.handler.ComputedAttributesHandler; import org.traccar.handler.CopyAttributesHandler; import org.traccar.handler.DatabaseHandler; -import org.traccar.handler.PostProcessHandler; import org.traccar.handler.DistanceHandler; import org.traccar.handler.EngineHoursHandler; import org.traccar.handler.FilterHandler; @@ -36,6 +37,7 @@ import org.traccar.handler.GeolocationHandler; import org.traccar.handler.HemisphereHandler; import org.traccar.handler.MotionHandler; import org.traccar.handler.PositionForwardingHandler; +import org.traccar.handler.PostProcessHandler; import org.traccar.handler.SpeedLimitHandler; import org.traccar.handler.TimeHandler; import org.traccar.handler.events.AlertEventHandler; @@ -62,19 +64,21 @@ import java.util.stream.Stream; @Singleton @ChannelHandler.Sharable -public class ProcessingHandler extends ChannelInboundHandlerAdapter { +public class ProcessingHandler extends ChannelInboundHandlerAdapter implements BufferingManager.Callback { private final NotificationManager notificationManager; private final PositionLogger positionLogger; + private final BufferingManager bufferingManager; private final List positionHandlers; private final List eventHandlers; private final PostProcessHandler postProcessHandler; @Inject public ProcessingHandler( - Injector injector, NotificationManager notificationManager, PositionLogger positionLogger) { + Injector injector, Config config, NotificationManager notificationManager, PositionLogger positionLogger) { this.notificationManager = notificationManager; this.positionLogger = positionLogger; + bufferingManager = new BufferingManager(config, this); positionHandlers = Stream.of( TimeHandler.class, @@ -117,12 +121,17 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof Position) { - processPositionHandlers(ctx, (Position) msg); + bufferingManager.accept(ctx, (Position) msg); } else { super.channelRead(ctx, msg); } } + @Override + public void onReleased(ChannelHandlerContext context, Position position) { + processPositionHandlers(context, position); + } + private void processPositionHandlers(ChannelHandlerContext ctx, Position position) { var iterator = positionHandlers.iterator(); iterator.next().handlePosition(position, new BasePositionHandler.Callback() { diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 4aacb2cd8..d346084bd 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -292,6 +292,14 @@ public final class Keys { List.of(KeyType.CONFIG, KeyType.DEVICE), false); + /** + * If not zero, enable buffering of incoming data to handle ordering locations. The value is threshold for + * buffering in milliseconds. + */ + public static final ConfigKey SERVER_BUFFERING_THRESHOLD = new LongConfigKey( + "server.buffering.threshold", + List.of(KeyType.CONFIG)); + /** * Server wide connection timeout value in seconds. See protocol timeout for more information. */ diff --git a/src/main/java/org/traccar/database/BufferingManager.java b/src/main/java/org/traccar/database/BufferingManager.java new file mode 100644 index 000000000..ab71b2860 --- /dev/null +++ b/src/main/java/org/traccar/database/BufferingManager.java @@ -0,0 +1,103 @@ +/* + * Copyright 2024 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.database; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timeout; +import io.netty.util.Timer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Position; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeSet; +import java.util.concurrent.TimeUnit; + +public class BufferingManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(BufferingManager.class); + + public interface Callback { + void onReleased(ChannelHandlerContext context, Position position); + } + + private static class Holder implements Comparable { + + private static final Comparator COMPARATOR = Comparator + .comparing(Position::getFixTime) + .thenComparing(Position::getDeviceTime) + .thenComparing(Position::getServerTime); + + private final ChannelHandlerContext context; + private final Position position; + private Timeout timeout; + + private Holder(ChannelHandlerContext context, Position position) { + this.context = context; + this.position = position; + } + + @Override + public int compareTo(Holder other) { + return COMPARATOR.compare(position, other.position); + } + } + + private final Timer timer = new HashedWheelTimer(); + private final Callback callback; + private final long threshold; + + private final Map> buffer = new HashMap<>(); + + public BufferingManager(Config config, Callback callback) { + this.callback = callback; + threshold = config.getLong(Keys.SERVER_BUFFERING_THRESHOLD); + } + + private Timeout scheduleTimeout(Holder holder) { + return timer.newTimeout( + timeout -> { + LOGGER.info("released {}", holder.position.getFixTime()); + buffer.get(holder.position.getDeviceId()).remove(holder); + callback.onReleased(holder.context, holder.position); + }, + threshold, TimeUnit.MILLISECONDS); + } + + public void accept(ChannelHandlerContext context, Position position) { + if (threshold > 0) { + synchronized (buffer) { + LOGGER.info("queued {}", position.getFixTime()); + var queue = buffer.computeIfAbsent(position.getDeviceId(), k -> new TreeSet<>()); + Holder holder = new Holder(context, position); + holder.timeout = scheduleTimeout(holder); + queue.add(holder); + queue.tailSet(holder).forEach(h -> { + h.timeout.cancel(); + h.timeout = scheduleTimeout(h); + }); + } + } else { + callback.onReleased(context, position); + } + } + +} -- cgit v1.2.3 From 783a99cdc3ef70cb3f120ba8ef158dcd32086c1a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 31 Mar 2024 08:42:47 -0700 Subject: Fix lint issue --- src/main/java/org/traccar/database/BufferingManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/database/BufferingManager.java b/src/main/java/org/traccar/database/BufferingManager.java index ab71b2860..3e3cf587a 100644 --- a/src/main/java/org/traccar/database/BufferingManager.java +++ b/src/main/java/org/traccar/database/BufferingManager.java @@ -39,7 +39,7 @@ public class BufferingManager { void onReleased(ChannelHandlerContext context, Position position); } - private static class Holder implements Comparable { + private static final class Holder implements Comparable { private static final Comparator COMPARATOR = Comparator .comparing(Position::getFixTime) -- cgit v1.2.3 From 7de30c41131c76e6491c641cd46c76a1a3513957 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 31 Mar 2024 08:52:24 -0700 Subject: Update Sencha CMD link --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a8e4c5369..c025593e1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,7 +34,7 @@ jobs: traccar-web/package-lock.json traccar-web/modern/package-lock.json - run: | - wget -q https://trials.sencha.com/cmd/7.6.0/SenchaCmd-7.6.0.87-linux-amd64.sh.zip + wget -q https://traccar.nyc3.digitaloceanspaces.com/download/SenchaCmd-7.6.0.87-linux-amd64.sh.zip unzip SenchaCmd-*.zip ./SenchaCmd-*.sh -q echo "$HOME/bin/Sencha/Cmd/" >> $GITHUB_PATH -- cgit v1.2.3 From e4134911f17cbe6f556a8bc4d1b3f5073474a940 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 31 Mar 2024 13:39:13 -0700 Subject: Queue positions for processing --- src/main/java/org/traccar/ProcessingHandler.java | 29 +++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/ProcessingHandler.java b/src/main/java/org/traccar/ProcessingHandler.java index cbb375a72..6a97b9dea 100644 --- a/src/main/java/org/traccar/ProcessingHandler.java +++ b/src/main/java/org/traccar/ProcessingHandler.java @@ -56,9 +56,12 @@ import org.traccar.handler.network.AcknowledgementHandler; import org.traccar.helper.PositionLogger; import org.traccar.model.Position; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Queue; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -73,6 +76,12 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter implements B private final List eventHandlers; private final PostProcessHandler postProcessHandler; + private final Map> queues = new HashMap<>(); + + private synchronized Queue getQueue(long deviceId) { + return queues.computeIfAbsent(deviceId, k -> new LinkedList<>()); + } + @Inject public ProcessingHandler( Injector injector, Config config, NotificationManager notificationManager, PositionLogger positionLogger) { @@ -129,7 +138,15 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter implements B @Override public void onReleased(ChannelHandlerContext context, Position position) { - processPositionHandlers(context, position); + Queue queue = getQueue(position.getDeviceId()); + boolean queued; + synchronized (queue) { + queued = !queue.isEmpty(); + queue.offer(position); + } + if (!queued) { + processPositionHandlers(context, position); + } } private void processPositionHandlers(ChannelHandlerContext ctx, Position position) { @@ -160,6 +177,16 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter implements B postProcessHandler.handlePosition(position, p -> { positionLogger.log(ctx, p); ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(p)); + + Queue queue = getQueue(position.getDeviceId()); + Position nextPosition; + synchronized (queue) { + queue.poll(); // remove current position + nextPosition = queue.peek(); + } + if (nextPosition != null) { + processPositionHandlers(ctx, nextPosition); + } }); } -- cgit v1.2.3 From 5606f054244fc1ea2d5929152dd5c997d04f66fa Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 1 Apr 2024 20:46:28 -0700 Subject: Support binary Atrack motion --- src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java | 5 ++++- src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java index 8896dcfb0..834f4f16c 100644 --- a/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/AtrackProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2013 - 2024 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. @@ -325,6 +325,9 @@ public class AtrackProtocolDecoder extends BaseProtocolDecoder { case "SA": position.set(Position.KEY_SATELLITES, buf.readUnsignedByte()); break; + case "MT": + position.set(Position.KEY_MOTION, buf.readUnsignedByte() > 0); + break; case "MV": position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.1); break; diff --git a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java index be6fb5c45..7115e0ea6 100644 --- a/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/AtrackProtocolDecoderTest.java @@ -43,6 +43,9 @@ public class AtrackProtocolDecoderTest extends ProtocolTest { decoder.setCustom(true); + verifyPositions(decoder, binary( + "405064e503092d8600000000000f54ab660786b0660786b0660a12c4fa2e202d01cfd32a005a02000022b700070000000000000007d007d000254349254d56254256254d5400007f002800660786ec660786ec660a12c4fa2e202d01cfd32a005a02000022b700070000000000000007d007d000254349254d56254256254d5400007f0028006607872866078728660a12c4fa2e202d01cfd32a005a02000022b700070000000000000007d007d000254349254d56254256254d5400007f0028006607876466078764660a12c4fa2e202d01cfd32a005a02000022b700070000000000000007d007d000254349254d56254256254d5400007f002800660787a0660787a0660a12c4fa2e202d01cfd32a005a02000022b700060000000000000007d007d000254349254d56254256254d5400007f002800660787dc660787dc660a12c4fa2e202d01cfd32a005a02000022b700060000000000000007d007d000254349254d56254256254d5400007f0028006607881866078818660a12c4fa2e202d01cfd32a005a02000022b700060000000000000007d007d000254349254d56254256254d5400007f0028006607885466078854660a12c4fa2e202d01cfd32a005a02000022b700060000000000000007d007d000254349254d56254256254d5400007f0028006607889066078890660a12c4fa2e202d01cfd32a005a02000022b700060000000000000007d007d000254349254d56254256254d5400007f002800660788cc660788cc660a12c4fa2e202d01cfd32a005a02000022b700060000000000000007d007d000254349254d56254256254d5400007f0028006607890866078908660a12c4fa2e202d01cfd32a005a02000022b700070000000000000007d007d000254349254d56254256254d5400007f0028006607894466078944660a12c4fa2e202d01cfd32a005a02000022b700070000000000000007d007d000254349254d56254256254d5400007f0028006607898066078980660a12c4fa2e202d01cfd32a005a02000022b700070000000000000007d007d000254349254d56254256254d5400007f002800")); + verifyPositions(decoder, binary( "4050d78502e01d29000312fa45441d6d647d8e67647d8e67647eef190205437c021846e6001a020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010c0000000000000000000000000000000000000000000000000e647d8e85647d8e86647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010c0000000000000000000000000000000000000000000000000e647d8ea3647d8ea4647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010b0000000000000000000000000000000000000000000000000e647d8ec1647d8ec2647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010a0000000000000000000000000000000000000000000000000e647d8edf647d8ee0647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010a0000000000000000000000000000000000000000000000000e647d8efd647d8efe647eef190205437c021846e60019020002d7f000070000000000000007d007d000254349254d5625525025564e254d4625454c25545225455425464c254d4c25464325534d25494e3025484125484225484325415400010a0000000000000000000000000000000000000000000000000e")); -- cgit v1.2.3 From fc3a24148526b3d41ba40ed1f55cf40b54c6a255 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 3 Apr 2024 21:17:52 -0700 Subject: Handle outdated positions in buffer --- src/main/java/org/traccar/BaseProtocolDecoder.java | 19 +------- src/main/java/org/traccar/ProcessingHandler.java | 2 + .../org/traccar/database/BufferingManager.java | 26 +++++++--- .../java/org/traccar/handler/OutdatedHandler.java | 56 ++++++++++++++++++++++ 4 files changed, 78 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/traccar/handler/OutdatedHandler.java diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index 495a866c0..b764e5cdf 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2024 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. @@ -154,25 +154,8 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { public void getLastLocation(Position position, Date deviceTime) { if (position.getDeviceId() != 0) { position.setOutdated(true); - - Position last = cacheManager.getPosition(position.getDeviceId()); - if (last != null) { - position.setFixTime(last.getFixTime()); - position.setValid(last.getValid()); - position.setLatitude(last.getLatitude()); - position.setLongitude(last.getLongitude()); - position.setAltitude(last.getAltitude()); - position.setSpeed(last.getSpeed()); - position.setCourse(last.getCourse()); - position.setAccuracy(last.getAccuracy()); - } else { - position.setFixTime(new Date(0)); - } - if (deviceTime != null) { position.setDeviceTime(deviceTime); - } else { - position.setDeviceTime(new Date()); } } } diff --git a/src/main/java/org/traccar/ProcessingHandler.java b/src/main/java/org/traccar/ProcessingHandler.java index 6a97b9dea..76a698a0a 100644 --- a/src/main/java/org/traccar/ProcessingHandler.java +++ b/src/main/java/org/traccar/ProcessingHandler.java @@ -36,6 +36,7 @@ import org.traccar.handler.GeofenceHandler; import org.traccar.handler.GeolocationHandler; import org.traccar.handler.HemisphereHandler; import org.traccar.handler.MotionHandler; +import org.traccar.handler.OutdatedHandler; import org.traccar.handler.PositionForwardingHandler; import org.traccar.handler.PostProcessHandler; import org.traccar.handler.SpeedLimitHandler; @@ -90,6 +91,7 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter implements B bufferingManager = new BufferingManager(config, this); positionHandlers = Stream.of( + OutdatedHandler.class, TimeHandler.class, GeolocationHandler.class, HemisphereHandler.class, diff --git a/src/main/java/org/traccar/database/BufferingManager.java b/src/main/java/org/traccar/database/BufferingManager.java index 3e3cf587a..4d288c8d0 100644 --- a/src/main/java/org/traccar/database/BufferingManager.java +++ b/src/main/java/org/traccar/database/BufferingManager.java @@ -25,7 +25,7 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Position; -import java.util.Comparator; +import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.TreeSet; @@ -41,11 +41,6 @@ public class BufferingManager { private static final class Holder implements Comparable { - private static final Comparator COMPARATOR = Comparator - .comparing(Position::getFixTime) - .thenComparing(Position::getDeviceTime) - .thenComparing(Position::getServerTime); - private final ChannelHandlerContext context; private final Position position; private Timeout timeout; @@ -55,9 +50,26 @@ public class BufferingManager { this.position = position; } + private int compareTime(Date left, Date right) { + if (left != null && right != null) { + return left.compareTo(right); + } + return 0; + } + @Override public int compareTo(Holder other) { - return COMPARATOR.compare(position, other.position); + int fixTimeResult = compareTime(position.getFixTime(), other.position.getFixTime()); + if (fixTimeResult != 0) { + return fixTimeResult; + } + + int deviceTimeResult = compareTime(position.getDeviceTime(), other.position.getDeviceTime()); + if (deviceTimeResult != 0) { + return deviceTimeResult; + } + + return position.getServerTime().compareTo(other.position.getServerTime()); } } diff --git a/src/main/java/org/traccar/handler/OutdatedHandler.java b/src/main/java/org/traccar/handler/OutdatedHandler.java new file mode 100644 index 000000000..88f1c4a0c --- /dev/null +++ b/src/main/java/org/traccar/handler/OutdatedHandler.java @@ -0,0 +1,56 @@ +/* + * Copyright 2024 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.handler; + +import jakarta.inject.Inject; +import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; + +import java.util.Date; + +public class OutdatedHandler extends BasePositionHandler { + + private final CacheManager cacheManager; + + @Inject + public OutdatedHandler(CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + + @Override + public void handlePosition(Position position, Callback callback) { + if (position.getOutdated()) { + Position last = cacheManager.getPosition(position.getDeviceId()); + if (last != null) { + position.setFixTime(last.getFixTime()); + position.setValid(last.getValid()); + position.setLatitude(last.getLatitude()); + position.setLongitude(last.getLongitude()); + position.setAltitude(last.getAltitude()); + position.setSpeed(last.getSpeed()); + position.setCourse(last.getCourse()); + position.setAccuracy(last.getAccuracy()); + } else { + position.setFixTime(new Date(315964819000L)); // gps epoch 1980-01-06 + } + if (position.getDeviceTime() == null) { + position.setDeviceTime(position.getServerTime()); + } + } + callback.processed(position); + } + +} -- cgit v1.2.3 From 3fbdcd81566bc72e319ec05c77cf8a4120b87b8f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 4 Apr 2024 07:41:50 -0700 Subject: Update device id check --- src/main/java/org/traccar/model/Device.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java index a3088a613..c2da9be79 100644 --- a/src/main/java/org/traccar/model/Device.java +++ b/src/main/java/org/traccar/model/Device.java @@ -53,7 +53,7 @@ public class Device extends GroupedModel implements Disableable, Schedulable { } public void setUniqueId(String uniqueId) { - if (uniqueId.contains("../") || uniqueId.contains("..\\")) { + if (uniqueId.contains("..")) { throw new IllegalArgumentException("Invalid unique id"); } this.uniqueId = uniqueId.trim(); -- cgit v1.2.3 From 1c29f3a604fe13c8a337935a1a1ad966b4b62d5b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 4 Apr 2024 07:54:07 -0700 Subject: Handle explicit image types --- .../java/org/traccar/api/resource/DeviceResource.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 89bba7237..d7236fe2a 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -172,6 +172,23 @@ public class DeviceResource extends BaseObjectResource { return Response.noContent().build(); } + private String imageExtension(String type) { + switch (type) { + case "image/jpeg": + return ".jpg"; + case "image/png": + return ".png"; + case "image/gif": + return ".gif"; + case "image/webp": + return ".webp"; + case "image/svg+xml": + return ".svg"; + default: + throw new IllegalArgumentException("Unsupported image type"); + } + } + @Path("{id}/image") @POST @Consumes("image/*") @@ -186,7 +203,7 @@ public class DeviceResource extends BaseObjectResource { new Condition.Permission(User.class, getUserId(), Device.class)))); if (device != null) { String name = "device"; - String extension = type.substring("image/".length()); + String extension = imageExtension(type); try (var input = new FileInputStream(file); var output = mediaManager.createFileStream(device.getUniqueId(), name, extension)) { input.transferTo(output); -- cgit v1.2.3 From b099b298f90074c825ba68ce73532933c7b9d901 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 4 Apr 2024 08:03:16 -0700 Subject: Remove extra dot --- src/main/java/org/traccar/api/resource/DeviceResource.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index d7236fe2a..2edb0d16d 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -175,15 +175,15 @@ public class DeviceResource extends BaseObjectResource { private String imageExtension(String type) { switch (type) { case "image/jpeg": - return ".jpg"; + return "jpg"; case "image/png": - return ".png"; + return "png"; case "image/gif": - return ".gif"; + return "gif"; case "image/webp": - return ".webp"; + return "webp"; case "image/svg+xml": - return ".svg"; + return "svg"; default: throw new IllegalArgumentException("Unsupported image type"); } -- cgit v1.2.3 From e001c629d89e75fae1b13f69fb71517b134f3e09 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 4 Apr 2024 08:39:22 -0700 Subject: Limit image file size --- .../java/org/traccar/api/resource/DeviceResource.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 2edb0d16d..56253152f 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -62,6 +62,9 @@ import java.util.List; @Consumes(MediaType.APPLICATION_JSON) public class DeviceResource extends BaseObjectResource { + private static final int DEFAULT_BUFFER_SIZE = 8192; + private static final int IMAGE_SIZE_LIMIT = 500000; + @Inject private Config config; @@ -206,7 +209,17 @@ public class DeviceResource extends BaseObjectResource { String extension = imageExtension(type); try (var input = new FileInputStream(file); var output = mediaManager.createFileStream(device.getUniqueId(), name, extension)) { - input.transferTo(output); + + long transferred = 0; + byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; + int read; + while ((read = input.read(buffer, 0, buffer.length)) >= 0) { + output.write(buffer, 0, read); + transferred += read; + if (transferred > IMAGE_SIZE_LIMIT) { + throw new IllegalArgumentException("Image size limit exceeded"); + } + } } return Response.ok(name + "." + extension).build(); } -- cgit v1.2.3 From b209b3aa18db7bf3b2095ce924edb09ffb831542 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 4 Apr 2024 17:28:59 -0700 Subject: Default to registration disabled --- schema/changelog-4.0-clean.xml | 4 ++-- src/main/java/org/traccar/api/resource/UserResource.java | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/schema/changelog-4.0-clean.xml b/schema/changelog-4.0-clean.xml index b4d8ac0ba..4236e6e95 100644 --- a/schema/changelog-4.0-clean.xml +++ b/schema/changelog-4.0-clean.xml @@ -335,7 +335,7 @@ - + @@ -614,7 +614,7 @@ - + diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index 47ea9b07c..fbc31e46a 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2024 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. @@ -95,7 +95,9 @@ public class UserResource extends BaseObjectResource { } } } else { - if (!permissionsService.getServer().getRegistration()) { + if (UserUtil.isEmpty(storage)) { + entity.setAdministrator(true); + } else if (!permissionsService.getServer().getRegistration()) { throw new SecurityException("Registration disabled"); } if (permissionsService.getServer().getBoolean(Keys.WEB_TOTP_FORCE.getKey()) @@ -106,10 +108,6 @@ public class UserResource extends BaseObjectResource { } } - if (UserUtil.isEmpty(storage)) { - entity.setAdministrator(true); - } - entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); storage.updateObject(entity, new Request( new Columns.Include("hashedPassword", "salt"), -- cgit v1.2.3 From 5d571897e0d60c574cbb9ed85a04acfb40ce7f3c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 5 Apr 2024 17:39:48 -0700 Subject: Decode additional VL502 data --- .../traccar/protocol/HuabaoProtocolDecoder.java | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 2186fb91f..648c5fb42 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -979,6 +979,12 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { case 0x0103: position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedInt() * 0.01); break; + case 0x0111: + position.set("fuelTemp", buf.readUnsignedByte() - 40); + break; + case 0x012E: + position.set("oilLevel", buf.readUnsignedShort() * 0.1); + break; case 0x052A: position.set(Position.KEY_FUEL_LEVEL, buf.readUnsignedShort() * 0.01); break; @@ -1113,6 +1119,30 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { } getLastLocation(position, time); break; + case 0x15: + int event = buf.readInt(); + switch (event) { + case 51: + position.set(Position.KEY_ALARM, Position.ALARM_ACCELERATION); + break; + case 52: + position.set(Position.KEY_ALARM, Position.ALARM_BRAKING); + break; + case 53: + position.set(Position.KEY_ALARM, Position.ALARM_CORNERING); + break; + case 54: + position.set(Position.KEY_ALARM, Position.ALARM_LANE_CHANGE); + break; + case 56: + position.set(Position.KEY_ALARM, Position.ALARM_ACCIDENT); + break; + default: + position.set(Position.KEY_EVENT, event); + break; + } + getLastLocation(position, time); + break; default: return null; } -- cgit v1.2.3 From 0e006ec6f5cc9a0b7853f093b041ac55e88dcb85 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 5 Apr 2024 18:13:33 -0700 Subject: Update Java dependencies --- build.gradle | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/build.gradle b/build.gradle index 3677f8f94..d61856c1b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,5 @@ +import enforcer.rules.EnforceBytecodeVersion + plugins { id "java" id "checkstyle" @@ -14,25 +16,25 @@ compileJava.options.encoding = "UTF-8" jar.destinationDirectory = file("$projectDir/target") checkstyle { - toolVersion = "10.12.5" + toolVersion = "10.15.0" configFile = "gradle/checkstyle.xml" as File checkstyleTest.enabled = false } enforce { - rule(enforcer.rules.EnforceBytecodeVersion) { r -> + rule(EnforceBytecodeVersion) { r -> r.maxJdkVersion = "11" } } ext { guiceVersion = "7.0.0" - jettyVersion = "11.0.19" + jettyVersion = "11.0.20" jerseyVersion = "3.1.5" jacksonVersion = "2.15.3" // same version as jersey-media-json-jackson dependency - protobufVersion = "3.25.2" - jxlsVersion = "2.14.0" - junitVersion = "5.10.1" + protobufVersion = "4.26.1" + jxlsVersion = "2.14.0" // version 3 requires java 17 + junitVersion = "5.10.2" } protobuf { @@ -42,15 +44,15 @@ protobuf { } dependencies { - implementation "commons-codec:commons-codec:1.16.0" + implementation "commons-codec:commons-codec:1.16.1" implementation "com.h2database:h2:2.2.224" - implementation "com.mysql:mysql-connector-j:8.2.0" - implementation "org.mariadb.jdbc:mariadb-java-client:3.3.2" - implementation "org.postgresql:postgresql:42.7.1" - implementation "com.microsoft.sqlserver:mssql-jdbc:12.4.2.jre11" + implementation "com.mysql:mysql-connector-j:8.3.0" + implementation "org.mariadb.jdbc:mariadb-java-client:3.3.3" + implementation "org.postgresql:postgresql:42.7.3" + implementation "com.microsoft.sqlserver:mssql-jdbc:12.6.1.jre11" implementation "com.zaxxer:HikariCP:5.1.0" - implementation "io.netty:netty-all:4.1.104.Final" - implementation "org.slf4j:slf4j-jdk14:2.0.11" + implementation "io.netty:netty-all:4.1.108.Final" + implementation "org.slf4j:slf4j-jdk14:2.0.12" implementation "com.google.inject:guice:$guiceVersion" implementation "com.google.inject.extensions:guice-servlet:$guiceVersion" implementation "org.owasp.encoder:encoder:1.2.3" @@ -76,30 +78,30 @@ dependencies { implementation "org.apache.velocity:velocity-engine-core:2.3" implementation "org.apache.velocity.tools:velocity-tools-generic:3.1" implementation "org.apache.commons:commons-collections4:4.4" - implementation "org.mnode.ical4j:ical4j:3.2.14" + implementation "org.mnode.ical4j:ical4j:3.2.17" implementation "org.locationtech.spatial4j:spatial4j:0.8" implementation "org.locationtech.jts:jts-core:1.19.0" implementation "net.java.dev.jna:jna-platform:5.14.0" - implementation "com.github.jnr:jnr-posix:3.1.18" + implementation "com.github.jnr:jnr-posix:3.1.19" implementation "com.google.protobuf:protobuf-java:$protobufVersion" - implementation "com.amazonaws:aws-java-sdk-sns:1.12.636" - implementation "org.apache.kafka:kafka-clients:3.6.1" + implementation "com.amazonaws:aws-java-sdk-sns:1.12.694" + implementation "org.apache.kafka:kafka-clients:3.7.0" implementation "com.hivemq:hivemq-mqtt-client:1.3.3" - implementation "redis.clients:jedis:5.1.0" + implementation "redis.clients:jedis:5.1.2" implementation "com.google.firebase:firebase-admin:9.2.0" - implementation "com.nimbusds:oauth2-oidc-sdk:11.9.1" + implementation "com.nimbusds:oauth2-oidc-sdk:11.10.1" implementation "com.rabbitmq:amqp-client:5.20.0" implementation "com.warrenstrange:googleauth:1.5.0" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" - testImplementation "org.mockito:mockito-core:5.8.0" + testImplementation "org.mockito:mockito-core:5.11.0" } test { useJUnitPlatform() } -task copyDependencies(type: Copy) { +tasks.register('copyDependencies', Copy) { into "$projectDir/target/lib" from configurations.runtimeClasspath } -- cgit v1.2.3 From fca91e1347f48704093412d1b0218e2fcd7ce34b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 5 Apr 2024 18:16:09 -0700 Subject: Remove gradle import --- build.gradle | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index d61856c1b..ac154b345 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,3 @@ -import enforcer.rules.EnforceBytecodeVersion - plugins { id "java" id "checkstyle" @@ -22,7 +20,7 @@ checkstyle { } enforce { - rule(EnforceBytecodeVersion) { r -> + rule(enforcer.rules.EnforceBytecodeVersion) { r -> r.maxJdkVersion = "11" } } -- cgit v1.2.3 From 63010e0c534142528fe104860605c1caac13c9ee Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 08:41:24 -0700 Subject: New React based simple app --- debug.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug.xml b/debug.xml index f3abbe9a9..72ecdeb4c 100644 --- a/debug.xml +++ b/debug.xml @@ -6,7 +6,7 @@ ./setup/default.xml - ./traccar-web/web + ./traccar-web/web/simple true true -- cgit v1.2.3 From ca706fccc04af7f68efe78db1a97515f20ec35dc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 09:37:28 -0700 Subject: Update debug path --- debug.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debug.xml b/debug.xml index 72ecdeb4c..a0c179cff 100644 --- a/debug.xml +++ b/debug.xml @@ -6,7 +6,7 @@ ./setup/default.xml - ./traccar-web/web/simple + ./traccar-web/simple true true -- cgit v1.2.3 From 3454f5b8b580ef7aee121ed2d7821db7161e1bd9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 09:55:09 -0700 Subject: Update version number --- build.gradle | 2 +- setup/traccar.iss | 2 +- swagger.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index ac154b345..2fe2bfaab 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "5.12", + "Implementation-Version": "6.0", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/setup/traccar.iss b/setup/traccar.iss index 2ccee1c3e..466a40c30 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=5.12 +AppVersion=6.0 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index b2209a20e..933652cb0 100644 --- a/swagger.json +++ b/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "Traccar", - "version": "5.12", + "version": "6.0", "description": "Traccar GPS tracking server API documentation. To use the API you need to have a server instance. For testing purposes you can use one of free [demo servers](https://www.traccar.org/demo-server/). For production use you can install your own server or get a [subscription service](https://www.traccar.org/product/tracking-server/).", "contact": { "name": "Traccar Support", -- cgit v1.2.3 From bb7db069faa0ddd85589224601b02f08c2cb81b2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 12:40:21 -0700 Subject: Update CI and packaging scripts --- .github/workflows/gradle.yml | 6 +++--- .github/workflows/release.yml | 28 +++++++++++----------------- setup/default.xml | 2 +- setup/package.sh | 5 ++--- 4 files changed, 17 insertions(+), 24 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index cbe2721bb..e50354cbd 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -12,10 +12,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 with: - distribution: zulu + distribution: temurin java-version: 11 cache: gradle - run: ./gradlew build --no-daemon --warning-mode=fail diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c025593e1..7c8c0eeb8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,31 +14,25 @@ jobs: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 submodules: true - run: git checkout ${{ github.ref_name }} working-directory: ./traccar-web - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: distribution: temurin java-version: 17 cache: gradle - run: ./gradlew build - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 21 cache: npm - cache-dependency-path: | - traccar-web/package-lock.json - traccar-web/modern/package-lock.json - - run: | - wget -q https://traccar.nyc3.digitaloceanspaces.com/download/SenchaCmd-7.6.0.87-linux-amd64.sh.zip - unzip SenchaCmd-*.zip - ./SenchaCmd-*.sh -q - echo "$HOME/bin/Sencha/Cmd/" >> $GITHUB_PATH - - run: ./traccar-web/tools/package.sh + cache-dependency-path: traccar-web/package-lock.json + - run: npm ci && npm run build + working-directory: ./traccar-web - run: | sudo dpkg --add-architecture i386 sudo apt-get update @@ -48,10 +42,10 @@ jobs: working-directory: ./setup run: | wget -q http://files.jrsoftware.org/is/5/isetup-5.5.6.exe - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_windows_hotspot_17.0.6_10.zip - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_linux_hotspot_17.0.6_10.tar.gz - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_arm_linux_hotspot_17.0.6_10.tar.gz - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.6_10.tar.gz + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9+9.1/OpenJDK17U-jdk_x64_windows_hotspot_17.0.9_9.zip + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9+9.1/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9+9.1/OpenJDK17U-jdk_arm_linux_hotspot_17.0.9_9.tar.gz + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9+9.1/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.9_9.tar.gz ./package.sh ${{ github.event.inputs.version }} - name: Upload installers working-directory: ./setup diff --git a/setup/default.xml b/setup/default.xml index 95bb1f04b..092b4f494 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -11,7 +11,7 @@ --> 8082 - ./modern + ./web false false true diff --git a/setup/package.sh b/setup/package.sh index f8ec927eb..533015475 100755 --- a/setup/package.sh +++ b/setup/package.sh @@ -85,14 +85,13 @@ else fi prepare () { - mkdir -p out/{conf,data,lib,logs,legacy,modern,schema,templates} + mkdir -p out/{conf,data,lib,logs,web,schema,templates} cp ../target/tracker-server.jar out cp ../target/lib/* out/lib cp ../schema/* out/schema cp -r ../templates/* out/templates - cp -r ../traccar-web/web/* out/legacy - cp -r ../traccar-web/modern/build/* out/modern + cp -r ../traccar-web/build/* out/web cp default.xml out/conf cp traccar.xml out/conf -- cgit v1.2.3 From d2890e64010c9106871eaed5cdea5ca3681f0ac2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 12:51:36 -0700 Subject: Update CI scripts --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7c8c0eeb8..44482d3fd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,10 +42,10 @@ jobs: working-directory: ./setup run: | wget -q http://files.jrsoftware.org/is/5/isetup-5.5.6.exe - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9+9.1/OpenJDK17U-jdk_x64_windows_hotspot_17.0.9_9.zip - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9+9.1/OpenJDK17U-jdk_x64_linux_hotspot_17.0.9_9.tar.gz - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9+9.1/OpenJDK17U-jdk_arm_linux_hotspot_17.0.9_9.tar.gz - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9+9.1/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.9_9.tar.gz + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_windows_hotspot_17.0.6_10.zip + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_linux_hotspot_17.0.6_10.tar.gz + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_arm_linux_hotspot_17.0.6_10.tar.gz + wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.6_10.tar.gz ./package.sh ${{ github.event.inputs.version }} - name: Upload installers working-directory: ./setup -- cgit v1.2.3 From 4fb474e6d001f8e69e2f292026536724b17755dc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 13:25:16 -0700 Subject: Update CI script --- .github/workflows/release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 44482d3fd..db9283142 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,10 +42,10 @@ jobs: working-directory: ./setup run: | wget -q http://files.jrsoftware.org/is/5/isetup-5.5.6.exe - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_windows_hotspot_17.0.6_10.zip - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_x64_linux_hotspot_17.0.6_10.tar.gz - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_arm_linux_hotspot_17.0.6_10.tar.gz - wget -q https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.6+10/OpenJDK17U-jdk_aarch64_linux_hotspot_17.0.6_10.tar.gz + wget -q https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/OpenJDK21U-jdk_x64_windows_hotspot_21.0.2_13.zip + wget -q https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz + wget -q https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/OpenJDK21U-jdk_arm_linux_hotspot_21.0.2_13.tar.gz + wget -q https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.2_13.tar.gz ./package.sh ${{ github.event.inputs.version }} - name: Upload installers working-directory: ./setup -- cgit v1.2.3 From 502813904d238f9ab579f20e85947e1375b77820 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 13:51:31 -0700 Subject: Remove ARM 32 version --- .github/workflows/release.yml | 1 - setup/package.sh | 21 +++------------------ 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index db9283142..8f45acd84 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,7 +44,6 @@ jobs: wget -q http://files.jrsoftware.org/is/5/isetup-5.5.6.exe wget -q https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/OpenJDK21U-jdk_x64_windows_hotspot_21.0.2_13.zip wget -q https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/OpenJDK21U-jdk_x64_linux_hotspot_21.0.2_13.tar.gz - wget -q https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/OpenJDK21U-jdk_arm_linux_hotspot_21.0.2_13.tar.gz wget -q https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.2+13/OpenJDK21U-jdk_aarch64_linux_hotspot_21.0.2_13.tar.gz ./package.sh ${{ github.event.inputs.version }} - name: Upload installers diff --git a/setup/package.sh b/setup/package.sh index 533015475..5b3c9bcde 100755 --- a/setup/package.sh +++ b/setup/package.sh @@ -15,7 +15,6 @@ usage () { echo "Available platforms:" echo " * linux-64" echo " * linux-arm" - echo " * linux-arm64" echo " * windows-64" echo " * other" exit 1 @@ -65,17 +64,14 @@ if [ $PLATFORM = "all" -o $PLATFORM = "windows-64" ]; then check_requirement "Windows 64 Java" "ls OpenJDK*64_windows*.zip" "Missing Windows 64 JDK (https://adoptium.net/)" check_requirement "Wine" "which wine" "Missing wine binary" fi -if [ $PLATFORM = "all" -o $PLATFORM = "linux-64" -o $PLATFORM = "linux-arm" -o $PLATFORM = "linux-arm64" ]; then +if [ $PLATFORM = "all" -o $PLATFORM = "linux-64" -o $PLATFORM = "linux-arm" ]; then check_requirement "Makeself" "which makeself" "Missing makeself binary" fi if [ $PLATFORM = "all" -o $PLATFORM = "linux-64" ]; then check_requirement "Linux 64 Java" "ls OpenJDK*x64_linux*.tar.gz" "Missing Linux 64 JDK (https://adoptium.net/)" fi if [ $PLATFORM = "all" -o $PLATFORM = "linux-arm" ]; then - check_requirement "Linux ARM Java" "ls OpenJDK*arm_linux*.tar.gz" "Missing Linux ARM JDK (https://adoptium.net/)" -fi -if [ $PLATFORM = "all" -o $PLATFORM = "linux-arm64" ]; then - check_requirement "Linux ARM 64 Java" "ls OpenJDK*aarch64_linux*.tar.gz" "Missing Linux ARM 64 JDK (https://adoptium.net/)" + check_requirement "Linux ARM Java" "ls OpenJDK*aarch64_linux*.tar.gz" "Missing Linux ARM JDK (https://adoptium.net/)" fi if [ $PREREQ = false ]; then info "Missing build requirements, aborting..." @@ -157,23 +153,16 @@ package_linux_64 () { package_linux_arm () { info "Building Linux ARM installer" - package_linux arm arm + package_linux arm aarch64 ok "Created Linux ARM installer" } -package_linux_arm64 () { - info "Building Linux ARM 64 installer" - package_linux arm64 aarch64 - ok "Created Linux ARM 64 installer" -} - prepare case $PLATFORM in all) package_linux_64 package_linux_arm - package_linux_arm64 package_windows package_other ;; @@ -186,10 +175,6 @@ case $PLATFORM in package_linux_arm ;; - linux-arm64) - package_linux_arm64 - ;; - windows-64) package_windows ;; -- cgit v1.2.3 From def62b230501d82aeb78d6c99b4659e2393c5878 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 13:57:10 -0700 Subject: Update CI Java version --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8f45acd84..26695dbac 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: temurin - java-version: 17 + java-version: 21 cache: gradle - run: ./gradlew build - uses: actions/setup-node@v4 -- cgit v1.2.3 From 157094fef811f681f5fb87fa7fd9952ae2f4d8a4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 14:33:12 -0700 Subject: Update submodule commit --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index 42db1a41c..a3e79c657 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit 42db1a41cbf733ea4f82c86e5d45a6fbccc8b8f2 +Subproject commit a3e79c6572759f6c8f4544166ea34d0e6d789b4e -- cgit v1.2.3 From 204b0a020a4bd2c3d17754ba183c39ea3035e0ae Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 15:46:24 -0700 Subject: Handle null in post processor --- src/main/java/org/traccar/handler/PostProcessHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/handler/PostProcessHandler.java b/src/main/java/org/traccar/handler/PostProcessHandler.java index 2d6bc03ad..e1d833e46 100644 --- a/src/main/java/org/traccar/handler/PostProcessHandler.java +++ b/src/main/java/org/traccar/handler/PostProcessHandler.java @@ -47,7 +47,7 @@ public class PostProcessHandler extends BasePositionHandler { @Override public void handlePosition(Position position, Callback callback) { try { - if (PositionUtil.isLatest(cacheManager, position)) { + if (position != null && PositionUtil.isLatest(cacheManager, position)) { Device updatedDevice = new Device(); updatedDevice.setId(position.getDeviceId()); updatedDevice.setPositionId(position.getId()); -- cgit v1.2.3 From 9a285e59e580994dc9c3f80935f766f3dafdcd46 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 7 Apr 2024 07:17:09 -0700 Subject: Fix filtering handler --- src/main/java/org/traccar/ProcessingHandler.java | 44 +++++++++++++--------- .../org/traccar/handler/BasePositionHandler.java | 2 +- .../traccar/handler/ComputedAttributesHandler.java | 2 +- .../org/traccar/handler/CopyAttributesHandler.java | 2 +- .../java/org/traccar/handler/DatabaseHandler.java | 2 +- .../java/org/traccar/handler/DistanceHandler.java | 2 +- .../org/traccar/handler/EngineHoursHandler.java | 2 +- .../java/org/traccar/handler/FilterHandler.java | 6 +-- .../java/org/traccar/handler/GeocoderHandler.java | 10 ++--- .../java/org/traccar/handler/GeofenceHandler.java | 2 +- .../org/traccar/handler/GeolocationHandler.java | 8 ++-- .../org/traccar/handler/HemisphereHandler.java | 2 +- .../java/org/traccar/handler/MotionHandler.java | 2 +- .../java/org/traccar/handler/OutdatedHandler.java | 2 +- .../traccar/handler/PositionForwardingHandler.java | 2 +- .../org/traccar/handler/PostProcessHandler.java | 4 +- .../org/traccar/handler/SpeedLimitHandler.java | 4 +- src/main/java/org/traccar/handler/TimeHandler.java | 2 +- 18 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/traccar/ProcessingHandler.java b/src/main/java/org/traccar/ProcessingHandler.java index 76a698a0a..fd048d127 100644 --- a/src/main/java/org/traccar/ProcessingHandler.java +++ b/src/main/java/org/traccar/ProcessingHandler.java @@ -155,15 +155,15 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter implements B var iterator = positionHandlers.iterator(); iterator.next().handlePosition(position, new BasePositionHandler.Callback() { @Override - public void processed(Position position) { - if (position != null) { + public void processed(boolean filtered) { + if (!filtered) { if (iterator.hasNext()) { iterator.next().handlePosition(position, this); } else { processEventHandlers(ctx, position); } } else { - finishedProcessing(ctx, null); + finishedProcessing(ctx, position, true); } } }); @@ -172,24 +172,32 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter implements B private void processEventHandlers(ChannelHandlerContext ctx, Position position) { eventHandlers.forEach(handler -> handler.analyzePosition( position, (event) -> notificationManager.updateEvents(Map.of(event, position)))); - finishedProcessing(ctx, position); + finishedProcessing(ctx, position, false); } - private void finishedProcessing(ChannelHandlerContext ctx, Position position) { - postProcessHandler.handlePosition(position, p -> { - positionLogger.log(ctx, p); - ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(p)); + private void finishedProcessing(ChannelHandlerContext ctx, Position position, boolean filtered) { + if (!filtered) { + postProcessHandler.handlePosition(position, ignore -> { + positionLogger.log(ctx, position); + ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position)); + processNextPosition(ctx, position.getDeviceId()); + }); + } else { + ctx.writeAndFlush(new AcknowledgementHandler.EventHandled(position)); + processNextPosition(ctx, position.getDeviceId()); + } + } - Queue queue = getQueue(position.getDeviceId()); - Position nextPosition; - synchronized (queue) { - queue.poll(); // remove current position - nextPosition = queue.peek(); - } - if (nextPosition != null) { - processPositionHandlers(ctx, nextPosition); - } - }); + private void processNextPosition(ChannelHandlerContext ctx, long deviceId) { + Queue queue = getQueue(deviceId); + Position nextPosition; + synchronized (queue) { + queue.poll(); // remove current position + nextPosition = queue.peek(); + } + if (nextPosition != null) { + processPositionHandlers(ctx, nextPosition); + } } } diff --git a/src/main/java/org/traccar/handler/BasePositionHandler.java b/src/main/java/org/traccar/handler/BasePositionHandler.java index 2fee5c652..0a82e96b7 100644 --- a/src/main/java/org/traccar/handler/BasePositionHandler.java +++ b/src/main/java/org/traccar/handler/BasePositionHandler.java @@ -20,7 +20,7 @@ import org.traccar.model.Position; public abstract class BasePositionHandler { public interface Callback { - void processed(Position position); + void processed(boolean filtered); } public abstract void handlePosition(Position position, Callback callback); diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 8d6fb39c3..4293bd1fc 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -196,7 +196,7 @@ public class ComputedAttributesHandler extends BasePositionHandler { } } } - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/CopyAttributesHandler.java b/src/main/java/org/traccar/handler/CopyAttributesHandler.java index f682c99c9..c7452e58c 100644 --- a/src/main/java/org/traccar/handler/CopyAttributesHandler.java +++ b/src/main/java/org/traccar/handler/CopyAttributesHandler.java @@ -44,7 +44,7 @@ public class CopyAttributesHandler extends BasePositionHandler { } } } - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/DatabaseHandler.java b/src/main/java/org/traccar/handler/DatabaseHandler.java index 0c8d2717d..5d96ebb34 100644 --- a/src/main/java/org/traccar/handler/DatabaseHandler.java +++ b/src/main/java/org/traccar/handler/DatabaseHandler.java @@ -47,7 +47,7 @@ public class DatabaseHandler extends BasePositionHandler { LOGGER.warn("Failed to store position", error); } - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/DistanceHandler.java b/src/main/java/org/traccar/handler/DistanceHandler.java index ee5d64894..e8ae7753a 100644 --- a/src/main/java/org/traccar/handler/DistanceHandler.java +++ b/src/main/java/org/traccar/handler/DistanceHandler.java @@ -71,7 +71,7 @@ public class DistanceHandler extends BasePositionHandler { position.set(Position.KEY_DISTANCE, distance); position.set(Position.KEY_TOTAL_DISTANCE, totalDistance + distance); - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/EngineHoursHandler.java b/src/main/java/org/traccar/handler/EngineHoursHandler.java index ed5f9b509..5aae6f673 100644 --- a/src/main/java/org/traccar/handler/EngineHoursHandler.java +++ b/src/main/java/org/traccar/handler/EngineHoursHandler.java @@ -43,7 +43,7 @@ public class EngineHoursHandler extends BasePositionHandler { } } } - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index a9e6024c8..796c302fb 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -270,11 +270,7 @@ public class FilterHandler extends BasePositionHandler { @Override public void handlePosition(Position position, Callback callback) { - if (filter(position)) { - callback.processed(null); - } else { - callback.processed(position); - } + callback.processed(filter(position)); } } diff --git a/src/main/java/org/traccar/handler/GeocoderHandler.java b/src/main/java/org/traccar/handler/GeocoderHandler.java index c62bcb6f8..b84237856 100644 --- a/src/main/java/org/traccar/handler/GeocoderHandler.java +++ b/src/main/java/org/traccar/handler/GeocoderHandler.java @@ -44,7 +44,7 @@ public class GeocoderHandler extends BasePositionHandler { @Override public void handlePosition(Position position, Callback callback) { if (!ignorePositions) { - callback.processed(position); + callback.processed(false); } if (processInvalidPositions || position.getValid()) { @@ -53,7 +53,7 @@ public class GeocoderHandler extends BasePositionHandler { if (lastPosition != null && lastPosition.getAddress() != null && position.getDouble(Position.KEY_DISTANCE) <= reuseDistance) { position.setAddress(lastPosition.getAddress()); - callback.processed(position); + callback.processed(false); return; } } @@ -63,17 +63,17 @@ public class GeocoderHandler extends BasePositionHandler { @Override public void onSuccess(String address) { position.setAddress(address); - callback.processed(position); + callback.processed(false); } @Override public void onFailure(Throwable e) { LOGGER.warn("Geocoding failed", e); - callback.processed(position); + callback.processed(false); } }); } else { - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/GeofenceHandler.java b/src/main/java/org/traccar/handler/GeofenceHandler.java index 33b46f058..8b363057a 100644 --- a/src/main/java/org/traccar/handler/GeofenceHandler.java +++ b/src/main/java/org/traccar/handler/GeofenceHandler.java @@ -41,7 +41,7 @@ public class GeofenceHandler extends BasePositionHandler { if (!geofenceIds.isEmpty()) { position.setGeofenceIds(geofenceIds); } - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/GeolocationHandler.java b/src/main/java/org/traccar/handler/GeolocationHandler.java index cb9c04808..c46bd3250 100644 --- a/src/main/java/org/traccar/handler/GeolocationHandler.java +++ b/src/main/java/org/traccar/handler/GeolocationHandler.java @@ -57,7 +57,7 @@ public class GeolocationHandler extends BasePositionHandler { updatePosition( position, lastPosition.getLatitude(), lastPosition.getLongitude(), lastPosition.getAccuracy()); - callback.processed(position); + callback.processed(false); return; } } @@ -71,17 +71,17 @@ public class GeolocationHandler extends BasePositionHandler { @Override public void onSuccess(double latitude, double longitude, double accuracy) { updatePosition(position, latitude, longitude, accuracy); - callback.processed(position); + callback.processed(false); } @Override public void onFailure(Throwable e) { LOGGER.warn("Geolocation network error", e); - callback.processed(position); + callback.processed(false); } }); } else { - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/HemisphereHandler.java b/src/main/java/org/traccar/handler/HemisphereHandler.java index 6b64177e4..48929538f 100644 --- a/src/main/java/org/traccar/handler/HemisphereHandler.java +++ b/src/main/java/org/traccar/handler/HemisphereHandler.java @@ -53,7 +53,7 @@ public class HemisphereHandler extends BasePositionHandler { if (longitudeFactor != 0) { position.setLongitude(Math.abs(position.getLongitude()) * longitudeFactor); } - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/MotionHandler.java b/src/main/java/org/traccar/handler/MotionHandler.java index bb7ff2a65..804ffdc25 100644 --- a/src/main/java/org/traccar/handler/MotionHandler.java +++ b/src/main/java/org/traccar/handler/MotionHandler.java @@ -38,7 +38,7 @@ public class MotionHandler extends BasePositionHandler { cacheManager, Keys.EVENT_MOTION_SPEED_THRESHOLD, position.getDeviceId()); position.set(Position.KEY_MOTION, position.getSpeed() > threshold); } - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/OutdatedHandler.java b/src/main/java/org/traccar/handler/OutdatedHandler.java index 88f1c4a0c..536440f66 100644 --- a/src/main/java/org/traccar/handler/OutdatedHandler.java +++ b/src/main/java/org/traccar/handler/OutdatedHandler.java @@ -50,7 +50,7 @@ public class OutdatedHandler extends BasePositionHandler { position.setDeviceTime(position.getServerTime()); } } - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/PositionForwardingHandler.java b/src/main/java/org/traccar/handler/PositionForwardingHandler.java index be62fff37..8512d4552 100644 --- a/src/main/java/org/traccar/handler/PositionForwardingHandler.java +++ b/src/main/java/org/traccar/handler/PositionForwardingHandler.java @@ -131,7 +131,7 @@ public class PositionForwardingHandler extends BasePositionHandler { positionData.setDevice(cacheManager.getObject(Device.class, position.getDeviceId())); new AsyncRequestAndCallback(positionData).send(); } - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/PostProcessHandler.java b/src/main/java/org/traccar/handler/PostProcessHandler.java index e1d833e46..5b1b2ef86 100644 --- a/src/main/java/org/traccar/handler/PostProcessHandler.java +++ b/src/main/java/org/traccar/handler/PostProcessHandler.java @@ -47,7 +47,7 @@ public class PostProcessHandler extends BasePositionHandler { @Override public void handlePosition(Position position, Callback callback) { try { - if (position != null && PositionUtil.isLatest(cacheManager, position)) { + if (PositionUtil.isLatest(cacheManager, position)) { Device updatedDevice = new Device(); updatedDevice.setId(position.getDeviceId()); updatedDevice.setPositionId(position.getId()); @@ -61,7 +61,7 @@ public class PostProcessHandler extends BasePositionHandler { } catch (StorageException error) { LOGGER.warn("Failed to update device", error); } - callback.processed(position); + callback.processed(false); } } diff --git a/src/main/java/org/traccar/handler/SpeedLimitHandler.java b/src/main/java/org/traccar/handler/SpeedLimitHandler.java index 604c10ca7..4c0922d01 100644 --- a/src/main/java/org/traccar/handler/SpeedLimitHandler.java +++ b/src/main/java/org/traccar/handler/SpeedLimitHandler.java @@ -40,13 +40,13 @@ public class SpeedLimitHandler extends BasePositionHandler { @Override public void onSuccess(double speedLimit) { position.set(Position.KEY_SPEED_LIMIT, speedLimit); - callback.processed(position); + callback.processed(false); } @Override public void onFailure(Throwable e) { LOGGER.warn("Speed limit provider failed", e); - callback.processed(position); + callback.processed(false); } }); } diff --git a/src/main/java/org/traccar/handler/TimeHandler.java b/src/main/java/org/traccar/handler/TimeHandler.java index 052ad41c3..f6c67bb76 100644 --- a/src/main/java/org/traccar/handler/TimeHandler.java +++ b/src/main/java/org/traccar/handler/TimeHandler.java @@ -51,7 +51,7 @@ public class TimeHandler extends BasePositionHandler { position.setFixTime(position.getDeviceTime()); } } - callback.processed(position); + callback.processed(false); } } -- cgit v1.2.3