From 3d793f502e1d48eb9c1dd60005ccf6c8682d73ca Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 7 Apr 2024 14:55:48 -0700 Subject: Add Open Location Code geocoder --- build.gradle | 1 + debug.xml | 2 +- src/main/java/org/traccar/MainModule.java | 6 ++-- .../org/traccar/geocoder/PlusCodesGeocoder.java | 37 ++++++++++++++++++++++ .../java/org/traccar/geocoder/TestGeocoder.java | 36 --------------------- 5 files changed, 42 insertions(+), 40 deletions(-) create mode 100644 src/main/java/org/traccar/geocoder/PlusCodesGeocoder.java delete mode 100644 src/main/java/org/traccar/geocoder/TestGeocoder.java diff --git a/build.gradle b/build.gradle index 2fe2bfaab..e731f99ed 100644 --- a/build.gradle +++ b/build.gradle @@ -90,6 +90,7 @@ dependencies { implementation "com.nimbusds:oauth2-oidc-sdk:11.10.1" implementation "com.rabbitmq:amqp-client:5.20.0" implementation "com.warrenstrange:googleauth:1.5.0" + implementation 'com.google.openlocationcode:openlocationcode:1.0.4' testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" testImplementation "org.mockito:mockito-core:5.11.0" diff --git a/debug.xml b/debug.xml index a0c179cff..89b5a5ba3 100644 --- a/debug.xml +++ b/debug.xml @@ -10,7 +10,7 @@ true true - test + pluscodes ./target/media diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 791d61c61..d1d3d4663 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -66,7 +66,7 @@ import org.traccar.geocoder.MapmyIndiaGeocoder; import org.traccar.geocoder.NominatimGeocoder; import org.traccar.geocoder.OpenCageGeocoder; import org.traccar.geocoder.PositionStackGeocoder; -import org.traccar.geocoder.TestGeocoder; +import org.traccar.geocoder.PlusCodesGeocoder; import org.traccar.geocoder.TomTomGeocoder; import org.traccar.geolocation.GeolocationProvider; import org.traccar.geolocation.GoogleGeolocationProvider; @@ -211,8 +211,8 @@ public class MainModule extends AbstractModule { int cacheSize = config.getInteger(Keys.GEOCODER_CACHE_SIZE); Geocoder geocoder; switch (type) { - case "test": - geocoder = new TestGeocoder(); + case "pluscodes": + geocoder = new PlusCodesGeocoder(); break; case "nominatim": geocoder = new NominatimGeocoder(client, url, key, language, cacheSize, addressFormat); diff --git a/src/main/java/org/traccar/geocoder/PlusCodesGeocoder.java b/src/main/java/org/traccar/geocoder/PlusCodesGeocoder.java new file mode 100644 index 000000000..5d003192f --- /dev/null +++ b/src/main/java/org/traccar/geocoder/PlusCodesGeocoder.java @@ -0,0 +1,37 @@ +/* + * 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. + * 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.geocoder; + +import com.google.openlocationcode.OpenLocationCode; +import org.traccar.database.StatisticsManager; + +public class PlusCodesGeocoder implements Geocoder { + + @Override + public void setStatisticsManager(StatisticsManager statisticsManager) { + } + + @Override + public String getAddress(double latitude, double longitude, ReverseGeocoderCallback callback) { + String address = new OpenLocationCode(latitude, longitude).getCode(); + if (callback != null) { + callback.onSuccess(address); + return null; + } + return address; + } + +} diff --git a/src/main/java/org/traccar/geocoder/TestGeocoder.java b/src/main/java/org/traccar/geocoder/TestGeocoder.java deleted file mode 100644 index 259f13c6c..000000000 --- a/src/main/java/org/traccar/geocoder/TestGeocoder.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 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.geocoder; - -import org.traccar.database.StatisticsManager; - -public class TestGeocoder implements Geocoder { - - @Override - public void setStatisticsManager(StatisticsManager statisticsManager) { - } - - @Override - public String getAddress(double latitude, double longitude, ReverseGeocoderCallback callback) { - String address = String.format("Location %f, %f", latitude, longitude); - if (callback != null) { - callback.onSuccess(address); - return null; - } - return address; - } - -} -- cgit v1.2.3 From 569bb18dcd0d8bbde92b5efdbbb21bc02d6e90ae Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 7 Apr 2024 15:06:58 -0700 Subject: No announcements for temporary users --- src/main/java/org/traccar/api/resource/NotificationResource.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java index 43dc1fa98..5eb9f6c62 100644 --- a/src/main/java/org/traccar/api/resource/NotificationResource.java +++ b/src/main/java/org/traccar/api/resource/NotificationResource.java @@ -120,7 +120,9 @@ public class NotificationResource extends ExtendedObjectResource { } } for (User user : users) { - notificatorManager.getNotificator(notificator).send(user, message, null, null); + if (!user.getTemporary()) { + notificatorManager.getNotificator(notificator).send(user, message, null, null); + } } return Response.noContent().build(); } -- cgit v1.2.3 From b017ab22e2f612aa19d0bd62581b6e889a142dfa Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 8 Apr 2024 07:39:40 -0700 Subject: Add scheduled reports logging --- .../org/traccar/api/resource/ReportResource.java | 22 +++++++++++----------- src/main/java/org/traccar/helper/LogAction.java | 7 ++++--- .../java/org/traccar/schedule/TaskReports.java | 4 +++- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java index 55a96fa90..8b6e6dce9 100644 --- a/src/main/java/org/traccar/api/resource/ReportResource.java +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -113,7 +113,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), "combined", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "combined", from, to, deviceIds, groupIds); return combinedReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -125,7 +125,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "route", from, to, deviceIds, groupIds); return routeReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -140,7 +140,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("mail") boolean mail) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { - LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "route", from, to, deviceIds, groupIds); routeReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to); }); } @@ -166,7 +166,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "events", from, to, deviceIds, groupIds); return eventsReportProvider.getObjects(getUserId(), deviceIds, groupIds, types, from, to); } @@ -182,7 +182,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("mail") boolean mail) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { - LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "events", from, to, deviceIds, groupIds); eventsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, types, from, to); }); } @@ -209,7 +209,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("to") Date to, @QueryParam("daily") boolean daily) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "summary", from, to, deviceIds, groupIds); return summaryReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to, daily); } @@ -225,7 +225,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("mail") boolean mail) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { - LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "summary", from, to, deviceIds, groupIds); summaryReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to, daily); }); } @@ -251,7 +251,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "trips", from, to, deviceIds, groupIds); return tripsReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -266,7 +266,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("mail") boolean mail) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { - LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "trips", from, to, deviceIds, groupIds); tripsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to); }); } @@ -291,7 +291,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "stops", from, to, deviceIds, groupIds); return stopsReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -306,7 +306,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("mail") boolean mail) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { - LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds); + LogAction.logReport(getUserId(), false, "stops", from, to, deviceIds, groupIds); stopsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to); }); } diff --git a/src/main/java/org/traccar/helper/LogAction.java b/src/main/java/org/traccar/helper/LogAction.java index b255b9206..efb02b340 100644 --- a/src/main/java/org/traccar/helper/LogAction.java +++ b/src/main/java/org/traccar/helper/LogAction.java @@ -50,7 +50,7 @@ public final class LogAction { private static final String PATTERN_LOGIN = "user: %d, action: %s, from: %s"; private static final String PATTERN_LOGIN_FAILED = "login failed from: %s"; private static final String PATTERN_DEVICE_ACCUMULATORS = "user: %d, action: %s, deviceId: %d"; - private static final String PATTERN_REPORT = "user: %d, report: %s, from: %s, to: %s, devices: %s, groups: %s"; + private static final String PATTERN_REPORT = "user: %d, %s: %s, from: %s, to: %s, devices: %s, groups: %s"; public static void create(long userId, BaseModel object) { logObjectAction(ACTION_CREATE, userId, object.getClass(), object.getId()); @@ -113,10 +113,11 @@ public final class LogAction { } public static void logReport( - long userId, String report, Date from, Date to, List deviceIds, List groupIds) { + long userId, boolean scheduled, String report, + Date from, Date to, List deviceIds, List groupIds) { DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); LOGGER.info(String.format( - PATTERN_REPORT, userId, report, + PATTERN_REPORT, userId, scheduled ? "scheduled" : "report", report, dateFormat.format(from), dateFormat.format(to), deviceIds.toString(), groupIds.toString())); } diff --git a/src/main/java/org/traccar/schedule/TaskReports.java b/src/main/java/org/traccar/schedule/TaskReports.java index e0fa6f8d6..2102b2ee1 100644 --- a/src/main/java/org/traccar/schedule/TaskReports.java +++ b/src/main/java/org/traccar/schedule/TaskReports.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. @@ -21,6 +21,7 @@ import com.google.inject.servlet.ServletScopes; import net.fortuna.ical4j.model.Period; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.traccar.helper.LogAction; import org.traccar.model.BaseModel; import org.traccar.model.Calendar; import org.traccar.model.Device; @@ -110,6 +111,7 @@ public class TaskReports implements ScheduleTask { ReportMailer reportMailer = injector.getInstance(ReportMailer.class); for (User user : users) { + LogAction.logReport(user.getId(), true, report.getType(), from, to, deviceIds, groupIds); switch (report.getType()) { case "events": var eventsReportProvider = injector.getInstance(EventsReportProvider.class); -- cgit v1.2.3 From 53f1be38dc55032e73e1aae659bb94dda6414d31 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 9 Apr 2024 18:29:35 -0700 Subject: Fix GV355CEU battery decoding --- src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java | 3 +++ src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java index 775e98401..8edce9346 100644 --- a/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gl200TextProtocolDecoder.java @@ -974,6 +974,9 @@ public class Gl200TextProtocolDecoder extends BaseProtocolDecoder { if (model.startsWith("GV") && !model.startsWith("GV6")) { position.set(Position.PREFIX_ADC + 2, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1]) * 0.001); } + if (model.startsWith("GV355CEU")) { + index += 1; // reserved + } position.set(Position.KEY_BATTERY_LEVEL, v[index++].isEmpty() ? null : Integer.parseInt(v[index - 1])); if (model.startsWith("GL5")) { diff --git a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java index 4cccf8fa2..925a0da1c 100644 --- a/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gl200TextProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Gl200TextProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gl200TextProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "+RESP:GTERI,8020050704,867488060246195,,00000004,28823,10,1,1,0.0,33,10.1,10.606120,43.656780,20240408084402,0222,0010,7D53,00DD120D,02,0,0.0,,,,,100,210100,0,1,FFFFF,YS2R4X20009288827,2,H1910197,58234.30,500,1,90,H1.5,P84.00,,0,4616.20,2.28,2.16,5.64,5358,1038,0010,00,00,20240408084403,1809$"), + Position.KEY_BATTERY_LEVEL, 100); + 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); -- cgit v1.2.3 From f752a0b5990d4687e7dfb870faf7adbedd3a06c3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 10 Apr 2024 15:43:41 -0700 Subject: Fix geocoder handling --- src/main/java/org/traccar/handler/GeocoderHandler.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/handler/GeocoderHandler.java b/src/main/java/org/traccar/handler/GeocoderHandler.java index b84237856..3744700da 100644 --- a/src/main/java/org/traccar/handler/GeocoderHandler.java +++ b/src/main/java/org/traccar/handler/GeocoderHandler.java @@ -43,11 +43,7 @@ public class GeocoderHandler extends BasePositionHandler { @Override public void handlePosition(Position position, Callback callback) { - if (!ignorePositions) { - callback.processed(false); - } - - if (processInvalidPositions || position.getValid()) { + if (!ignorePositions && (processInvalidPositions || position.getValid())) { if (reuseDistance != 0) { Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition != null && lastPosition.getAddress() != null -- cgit v1.2.3 From 341eaa2886a89c247f70973f22e4416325f9f34b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 10 Apr 2024 15:47:16 -0700 Subject: Enable override by default --- setup/default.xml | 1 + .../org/traccar/web/DefaultOverrideServlet.java | 59 ++++++++++++++++++++++ .../java/org/traccar/web/ModernDefaultServlet.java | 59 ---------------------- src/main/java/org/traccar/web/WebServer.java | 2 +- 4 files changed, 61 insertions(+), 60 deletions(-) create mode 100644 src/main/java/org/traccar/web/DefaultOverrideServlet.java delete mode 100644 src/main/java/org/traccar/web/ModernDefaultServlet.java diff --git a/setup/default.xml b/setup/default.xml index 092b4f494..6be4f105d 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -12,6 +12,7 @@ 8082 ./web + ./override false false true diff --git a/src/main/java/org/traccar/web/DefaultOverrideServlet.java b/src/main/java/org/traccar/web/DefaultOverrideServlet.java new file mode 100644 index 000000000..14b441f86 --- /dev/null +++ b/src/main/java/org/traccar/web/DefaultOverrideServlet.java @@ -0,0 +1,59 @@ +/* + * 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. + * 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.web; + +import org.eclipse.jetty.servlet.DefaultServlet; +import org.eclipse.jetty.util.resource.Resource; +import org.traccar.config.Config; +import org.traccar.config.Keys; + +import jakarta.inject.Inject; +import java.io.File; +import java.io.IOException; + +public class DefaultOverrideServlet extends DefaultServlet { + + private Resource overrideResource; + + @Inject + public DefaultOverrideServlet(Config config) { + String override = config.getString(Keys.WEB_OVERRIDE); + if (override != null) { + overrideResource = Resource.newResource(new File(override)); + } + } + + @Override + public Resource getResource(String pathInContext) { + if (overrideResource != null) { + try { + Resource override = overrideResource.addPath(pathInContext); + if (override.exists()) { + return override; + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return super.getResource(pathInContext.indexOf('.') < 0 ? "/" : pathInContext); + } + + @Override + public String getWelcomeFile(String pathInContext) { + return super.getWelcomeFile("/"); + } + +} diff --git a/src/main/java/org/traccar/web/ModernDefaultServlet.java b/src/main/java/org/traccar/web/ModernDefaultServlet.java deleted file mode 100644 index a7c8cdb29..000000000 --- a/src/main/java/org/traccar/web/ModernDefaultServlet.java +++ /dev/null @@ -1,59 +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.web; - -import org.eclipse.jetty.servlet.DefaultServlet; -import org.eclipse.jetty.util.resource.Resource; -import org.traccar.config.Config; -import org.traccar.config.Keys; - -import jakarta.inject.Inject; -import java.io.File; -import java.io.IOException; - -public class ModernDefaultServlet extends DefaultServlet { - - private Resource overrideResource; - - @Inject - public ModernDefaultServlet(Config config) { - String override = config.getString(Keys.WEB_OVERRIDE); - if (override != null) { - overrideResource = Resource.newResource(new File(override)); - } - } - - @Override - public Resource getResource(String pathInContext) { - if (overrideResource != null) { - try { - Resource override = overrideResource.addPath(pathInContext); - if (override.exists()) { - return override; - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - return super.getResource(pathInContext.indexOf('.') < 0 ? "/" : pathInContext); - } - - @Override - public String getWelcomeFile(String pathInContext) { - return super.getWelcomeFile("/"); - } - -} diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java index 4759942b1..68fcf52de 100644 --- a/src/main/java/org/traccar/web/WebServer.java +++ b/src/main/java/org/traccar/web/WebServer.java @@ -139,7 +139,7 @@ public class WebServer implements LifecycleObject { } private void initWebApp(ServletContextHandler servletHandler) { - ServletHolder servletHolder = new ServletHolder(new ModernDefaultServlet(config)); + ServletHolder servletHolder = new ServletHolder(new DefaultOverrideServlet(config)); servletHolder.setInitParameter("resourceBase", new File(config.getString(Keys.WEB_PATH)).getAbsolutePath()); servletHolder.setInitParameter("dirAllowed", "false"); if (config.getBoolean(Keys.WEB_DEBUG)) { -- cgit v1.2.3 From dda156e5d0795ad61197931a0d55b190ed140dcd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 10 Apr 2024 17:24:30 -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 e731f99ed..77fe9ec36 100644 --- a/build.gradle +++ b/build.gradle @@ -110,7 +110,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "6.0", + "Implementation-Version": "6.1", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/setup/traccar.iss b/setup/traccar.iss index 466a40c30..0f5f1687e 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=6.0 +AppVersion=6.1 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index 933652cb0..0eaa1ea54 100644 --- a/swagger.json +++ b/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "Traccar", - "version": "6.0", + "version": "6.1", "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 bc2faa140a2a5ba63968b95cd8ddba7578e1b07f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 10 Apr 2024 17:24:43 -0700 Subject: Update submodule commit --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index a3e79c657..a50f998f7 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit a3e79c6572759f6c8f4544166ea34d0e6d789b4e +Subproject commit a50f998f7dbb297ca7f22a31119556d6c58494c6 -- cgit v1.2.3 From 22228ea159618627c0b6d79c1ad7e87eadbeb598 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 11 Apr 2024 17:08:24 -0700 Subject: Fix KHD ignition decoding --- src/main/java/org/traccar/protocol/KhdProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java index e88b34478..2b234ab21 100644 --- a/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/KhdProtocolDecoder.java @@ -171,7 +171,7 @@ public class KhdProtocolDecoder extends BaseProtocolDecoder { } long status = buf.readUnsignedInt(); - position.set(Position.KEY_IGNITION, BitUtil.check(status, 7 + 3 * 8)); + position.set(Position.KEY_IGNITION, !BitUtil.check(status, 7 + 3 * 8)); position.set(Position.KEY_STATUS, status); buf.readUnsignedShort(); -- cgit v1.2.3 From 725d738de64bd7df7ec05786baf6590c15a105b9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 13 Apr 2024 07:25:54 -0700 Subject: Option to block notifications for users --- src/main/java/org/traccar/config/Keys.java | 7 +++++++ src/main/java/org/traccar/database/NotificationManager.java | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index d346084bd..db3c5c9ed 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1260,6 +1260,13 @@ public final class Keys { "notification.expiration.device.reminder", List.of(KeyType.CONFIG)); + /** + * Block notifications for specific users. The value should be a comma-separated list of internal user ids. + */ + public static final ConfigKey NOTIFICATION_BLOCK_USERS = new StringConfigKey( + "notification.block.users", + List.of(KeyType.CONFIG)); + /** * Maximum time period for reports in seconds. Can be useful to prevent users to request unreasonably long reports. * By default, there is no limit. diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index 65437f0a1..60b4f246b 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -42,8 +42,10 @@ import jakarta.annotation.Nullable; import jakarta.inject.Inject; import jakarta.inject.Singleton; import java.util.Arrays; +import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.stream.Collectors; @Singleton @@ -59,6 +61,7 @@ public class NotificationManager { private final boolean geocodeOnRequest; private final long timeThreshold; + private final Set blockedUsers = new HashSet<>(); @Inject public NotificationManager( @@ -71,6 +74,12 @@ public class NotificationManager { this.geocoder = geocoder; geocodeOnRequest = config.getBoolean(Keys.GEOCODER_ON_REQUEST); timeThreshold = config.getLong(Keys.NOTIFICATOR_TIME_THRESHOLD); + String blockedUsersString = config.getString(Keys.NOTIFICATION_BLOCK_USERS); + if (blockedUsersString != null) { + for (String userIdString : blockedUsersString.split(",")) { + blockedUsers.add(Long.parseLong(userIdString)); + } + } } private void updateEvent(Event event, Position position) { @@ -122,6 +131,10 @@ public class NotificationManager { notifications.forEach(notification -> { cacheManager.getNotificationUsers(notification.getId(), event.getDeviceId()).forEach(user -> { + if (blockedUsers.contains(user.getId())) { + LOGGER.info("User {} notification blocked", user.getId()); + return; + } for (String notificator : notification.getNotificatorsTypes()) { try { notificatorManager.getNotificator(notificator).send(notification, user, event, position); -- cgit v1.2.3 From 9af6b90e51ff8e2a35fcf52381b9800e508a3edd Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 13 Apr 2024 08:33:12 -0700 Subject: Implement KR Binary v4 protocol --- setup/default.xml | 1 + .../java/org/traccar/protocol/SnapperProtocol.java | 40 +++++ .../traccar/protocol/SnapperProtocolDecoder.java | 180 +++++++++++++++++++++ .../protocol/SnapperProtocolDecoderTest.java | 21 +++ 4 files changed, 242 insertions(+) create mode 100644 src/main/java/org/traccar/protocol/SnapperProtocol.java create mode 100644 src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java create mode 100644 src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java diff --git a/setup/default.xml b/setup/default.xml index 6be4f105d..7422bdf05 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -299,5 +299,6 @@ 5253 5254 5255 + 5256 diff --git a/src/main/java/org/traccar/protocol/SnapperProtocol.java b/src/main/java/org/traccar/protocol/SnapperProtocol.java new file mode 100644 index 000000000..2e294eac6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SnapperProtocol.java @@ -0,0 +1,40 @@ +/* + * 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.protocol; + +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import jakarta.inject.Inject; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerServer; +import org.traccar.config.Config; + +import java.nio.ByteOrder; + +public class SnapperProtocol extends BaseProtocol { + + @Inject + public SnapperProtocol(Config config) { + addServer(new TrackerServer(config, getName(), false) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 12, 4, 9, 0, true)); + pipeline.addLast(new SnapperProtocolDecoder(SnapperProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java new file mode 100644 index 000000000..3119e347e --- /dev/null +++ b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java @@ -0,0 +1,180 @@ +/* + * 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.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import org.traccar.BaseProtocolDecoder; +import org.traccar.NetworkMessage; +import org.traccar.Protocol; +import org.traccar.helper.BitUtil; +import org.traccar.helper.Checksum; +import org.traccar.model.Position; +import org.traccar.session.DeviceSession; + +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.TimeZone; + +public class SnapperProtocolDecoder extends BaseProtocolDecoder { + + public SnapperProtocolDecoder(Protocol protocol) { + super(protocol); + } + + public static final int MSG_HELLO = 0x01; + public static final int MSG_SENDING_START = 0x02; + public static final int MSG_SENDING_FINISH = 0x03; + public static final int MSG_SEND_EVENTS = 0x21; + public static final int MSG_SEND_TECH_INFO = 0x23; + public static final int MSG_UPDATE_CMS_NUM = 0x24; + public static final int MSG_SEND_SYSTEM_INFO = 0x26; + public static final int MSG_SEND_USER_PHONE_NUMBERS = 0x31; + public static final int MSG_SEND_GPS_DATA = 0x32; + public static final int MSG_SEND_LBS_DATA = 0x33; + public static final int MSG_SEND_SYSTEM_STATUS = 0x34; + public static final int MSG_SEND_TRANSIT_SETTINGS = 0x35; + public static final int MSG_GET_SETTINGS = 0x36; + public static final int MSG_SEND_CONCATENATED_PACKET = 0x37; + public static final int MSG_SEND_DEBUG_INFO = 0x38; + + private void sendResponse( + Channel channel, SocketAddress remoteAddress, int index, int type, String answer) { + + if (channel != null) { + ByteBuf response = Unpooled.buffer(); + response.writeByte('K'); + response.writeByte(3); // protocol version + response.writeIntLE(0); // reserved + response.writeIntLE(0); // reserved + response.writeShortLE(0); // encryption + response.writeIntLE(answer.length()); + response.writeShortLE(index); + response.writeByte(Checksum.sum(ByteBuffer.wrap(answer.getBytes(StandardCharsets.US_ASCII)))); + response.writeByte(type); + response.writeCharSequence(answer, StandardCharsets.US_ASCII); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + ByteBuf buf = (ByteBuf) msg; + + buf.readUnsignedByte(); // header + buf.readUnsignedByte(); // protocol version + buf.readUnsignedIntLE(); // system bonus identifier + + String serialNumber = String.valueOf(buf.readUnsignedIntLE()); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, serialNumber); + if (deviceSession == null) { + return null; + } + + buf.readUnsignedShortLE(); // encryption + buf.readUnsignedIntLE(); // length + buf.readUnsignedByte(); // flags + buf.readUnsignedMediumLE(); // reserved + int index = buf.readUnsignedShortLE(); + buf.readUnsignedByte(); // checksum + int type = buf.readUnsignedShortLE(); + + if (type == MSG_HELLO) { + sendResponse(channel, remoteAddress, index, type, "hello"); + } else { + sendResponse(channel, remoteAddress, index, type, "OK"); + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + if (type == MSG_SEND_EVENTS) { + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + buf.readUnsignedByte(); // info 1 + buf.readUnsignedByte(); // info 2 + getLastLocation(position, null); // TODO read timestamp + return position; + + } else if (type == MSG_SEND_TECH_INFO) { + + buf.readUnsignedByte(); // index + int subtype = buf.readUnsignedByte(); + switch (subtype) { + case 0x00: + position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + break; + case 0x01: + position.set("interiorTemp", buf.readByte()); + position.set("engineTemp", buf.readByte()); + default: + break; + } + getLastLocation(position, null); + return position; + + } else if (type == MSG_SEND_GPS_DATA) { + + String content = buf.readCharSequence(buf.readableBytes(), StandardCharsets.US_ASCII).toString(); + JsonObject json = Json.createReader(new StringReader(content)).readObject(); + + //{"f":"DE","t":"092304.01","d":"110813","la":"5117.6370", + // "lo":"01655.3959","a":"00166.6","s":"","c":"","sv":"08","p":"01.6"} + + DateFormat dateFormat = new SimpleDateFormat("ddMMyyHHmmss.SS"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(json.getString("d") + json.getString("t"))); + + String lat = json.getString("la"); + position.setLatitude(Integer.parseInt(lat.substring(0, 2)) + Double.parseDouble(lat.substring(2)) / 60); + String lon = json.getString("lo"); + position.setLongitude(Integer.parseInt(lon.substring(0, 3)) + Double.parseDouble(lon.substring(3)) / 60); + + int flags = Integer.parseInt(json.getString("f")); + position.setValid(BitUtil.check(flags, 1)); + if (!BitUtil.check(flags, 6)) { + position.setLatitude(-position.getLatitude()); + } + if (!BitUtil.check(flags, 7)) { + position.setLongitude(-position.getLongitude()); + } + + position.setAltitude(Double.parseDouble(json.getString("a"))); + position.setSpeed(Double.parseDouble(json.getString("s"))); + position.setCourse(Double.parseDouble(json.getString("c"))); + + position.set(Position.KEY_SATELLITES, Integer.parseInt(json.getString("sv"))); + + return position; + + } + + + return null; + } + +} diff --git a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java new file mode 100644 index 000000000..c334565f9 --- /dev/null +++ b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java @@ -0,0 +1,21 @@ +package org.traccar.protocol; + +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +public class SnapperProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new SnapperProtocolDecoder(null)); + + verifyNull(decoder, binary( + "4b0341a6b0c608000040000005000000000000007d5e14010068656c6c6f")); + + // data sample + // {"f":"DE","t":"092304.01","d":"110813","la":"5117.6370","lo":"01655.3959","a":"00166.6","s":"","c":"","sv":"08","p":"01.6"} + + } + +} -- cgit v1.2.3 From 132f619e996328c6fcb68d824b63edba69c8a2d6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 15 Apr 2024 21:34:55 -0700 Subject: Handle Snapper concatenated packet --- .../traccar/protocol/SnapperProtocolDecoder.java | 163 +++++++++++++-------- .../protocol/SnapperProtocolDecoderTest.java | 4 +- 2 files changed, 100 insertions(+), 67 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java index 3119e347e..315731c20 100644 --- a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java @@ -33,6 +33,7 @@ import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.text.DateFormat; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.TimeZone; @@ -77,6 +78,68 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { } } + private void decodeEvents(Position position, ByteBuf buf) { + + position.set(Position.KEY_EVENT, buf.readUnsignedByte()); + buf.readUnsignedByte(); // info 1 + buf.readUnsignedByte(); // info 2 + buf.readUnsignedIntLE(); // timestamp + buf.readUnsignedByte(); // timezone + } + + private void decodeTechInfo(Position position, ByteBuf buf) { + + for (int i = 0; i < 5; i++) { + buf.readUnsignedByte(); // index + int type = buf.readUnsignedByte(); + switch (type) { + case 0x00: + position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); + position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); + position.set(Position.KEY_RSSI, buf.readUnsignedByte()); + break; + case 0x01: + position.set("interiorTemp", buf.readByte()); + position.set("engineTemp", buf.readByte()); + buf.readUnsignedByte(); // reserved + break; + default: + buf.skipBytes(3); + break; + } + } + } + + private void decodeGpsData(Position position, ByteBuf buf) throws ParseException { + + String content = buf.readCharSequence(buf.readableBytes(), StandardCharsets.US_ASCII).toString(); + JsonObject json = Json.createReader(new StringReader(content)).readObject(); + + DateFormat dateFormat = new SimpleDateFormat("ddMMyyHHmmss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(json.getString("d") + json.getString("t").split("\\.")[0])); + + String lat = json.getString("la"); + position.setLatitude(Integer.parseInt(lat.substring(0, 2)) + Double.parseDouble(lat.substring(2)) / 60); + String lon = json.getString("lo"); + position.setLongitude(Integer.parseInt(lon.substring(0, 3)) + Double.parseDouble(lon.substring(3)) / 60); + + int flags = Integer.parseInt(json.getString("f"), 16); + position.setValid(BitUtil.check(flags, 1)); + if (!BitUtil.check(flags, 6)) { + position.setLatitude(-position.getLatitude()); + } + if (!BitUtil.check(flags, 7)) { + position.setLongitude(-position.getLongitude()); + } + + position.setAltitude(Double.parseDouble(json.getString("a"))); + position.setSpeed(Double.parseDouble(json.getString("s"))); + position.setCourse(Double.parseDouble(json.getString("c"))); + + position.set(Position.KEY_SATELLITES, Integer.parseInt(json.getString("sv"))); + } + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -94,7 +157,7 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { } buf.readUnsignedShortLE(); // encryption - buf.readUnsignedIntLE(); // length + int length = buf.readIntLE(); buf.readUnsignedByte(); // flags buf.readUnsignedMediumLE(); // reserved int index = buf.readUnsignedShortLE(); @@ -110,71 +173,41 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); - if (type == MSG_SEND_EVENTS) { - - position.set(Position.KEY_EVENT, buf.readUnsignedByte()); - buf.readUnsignedByte(); // info 1 - buf.readUnsignedByte(); // info 2 - getLastLocation(position, null); // TODO read timestamp - return position; - - } else if (type == MSG_SEND_TECH_INFO) { - - buf.readUnsignedByte(); // index - int subtype = buf.readUnsignedByte(); - switch (subtype) { - case 0x00: - position.set(Position.KEY_POWER, buf.readUnsignedByte() * 0.1); - position.set(Position.KEY_DEVICE_TEMP, buf.readByte()); - position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - break; - case 0x01: - position.set("interiorTemp", buf.readByte()); - position.set("engineTemp", buf.readByte()); - default: - break; - } - getLastLocation(position, null); - return position; - - } else if (type == MSG_SEND_GPS_DATA) { - - String content = buf.readCharSequence(buf.readableBytes(), StandardCharsets.US_ASCII).toString(); - JsonObject json = Json.createReader(new StringReader(content)).readObject(); - - //{"f":"DE","t":"092304.01","d":"110813","la":"5117.6370", - // "lo":"01655.3959","a":"00166.6","s":"","c":"","sv":"08","p":"01.6"} - - DateFormat dateFormat = new SimpleDateFormat("ddMMyyHHmmss.SS"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - position.setTime(dateFormat.parse(json.getString("d") + json.getString("t"))); - - String lat = json.getString("la"); - position.setLatitude(Integer.parseInt(lat.substring(0, 2)) + Double.parseDouble(lat.substring(2)) / 60); - String lon = json.getString("lo"); - position.setLongitude(Integer.parseInt(lon.substring(0, 3)) + Double.parseDouble(lon.substring(3)) / 60); - - int flags = Integer.parseInt(json.getString("f")); - position.setValid(BitUtil.check(flags, 1)); - if (!BitUtil.check(flags, 6)) { - position.setLatitude(-position.getLatitude()); - } - if (!BitUtil.check(flags, 7)) { - position.setLongitude(-position.getLongitude()); - } - - position.setAltitude(Double.parseDouble(json.getString("a"))); - position.setSpeed(Double.parseDouble(json.getString("s"))); - position.setCourse(Double.parseDouble(json.getString("c"))); - - position.set(Position.KEY_SATELLITES, Integer.parseInt(json.getString("sv"))); - - return position; - + switch (type) { + case MSG_SEND_EVENTS: + decodeEvents(position, buf); + getLastLocation(position, null); // TODO read timestamp + return position; + case MSG_SEND_TECH_INFO: + decodeTechInfo(position, buf); + getLastLocation(position, null); + return position; + case MSG_SEND_GPS_DATA: + decodeGpsData(position, buf.readSlice(length)); + return position; + case MSG_SEND_CONCATENATED_PACKET: + int count = buf.readUnsignedShortLE(); + for (int i = 0; i < count; i++) { + int partType = buf.readUnsignedShortLE(); + int partLength = buf.readUnsignedShortLE(); + switch (partType) { + case MSG_SEND_EVENTS: + decodeEvents(position, buf); + break; + case MSG_SEND_TECH_INFO: + decodeTechInfo(position, buf); + break; + case MSG_SEND_GPS_DATA: + decodeGpsData(position, buf.readSlice(partLength)); + break; + default: + buf.skipBytes(partLength); + break; + } + } + default: + return null; } - - - return null; } } diff --git a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java index c334565f9..103f1f48e 100644 --- a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java @@ -13,8 +13,8 @@ public class SnapperProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "4b0341a6b0c608000040000005000000000000007d5e14010068656c6c6f")); - // data sample - // {"f":"DE","t":"092304.01","d":"110813","la":"5117.6370","lo":"01655.3959","a":"00166.6","s":"","c":"","sv":"08","p":"01.6"} + verifyNull(decoder, binary( + "4b044daff87aff5b8aad00007b010000000013ea0c006837000500210008003e000058c48fa94823001900000080000200018080000002deff0f0003404000000400000034008c007b2273223a22303034303438222c226332223a2230303030303030303030303030303030222c226132223a2230303030303030303030303030303030222c226f223a2230303030222c2274223a2230303030222c227a223a223030222c2277223a223030222c2272223a222d222c226d223a223030303030303030222c2262223a223030303030303030227d320079007b2266223a224445222c2274223a22303932383336222c2264223a22313530343234222c226c61223a22353334312e34333732222c226c6f223a2230303935342e30373036222c2261223a22382e34222c2273223a22302e3030222c2263223a2232362e3036222c227376223a223135222c2270223a22227d33003f007b2263223a22323632222c226e223a223033222c2262223a5b7b226c223a2232423334222c2263223a223030303041313231222c2273223a223132227d5d7d")); } -- cgit v1.2.3 From 8458c3f3cbf6a42fde3d455c9c231498ca0fa184 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 17 Apr 2024 06:23:32 -0700 Subject: Fix Snapper position decoding --- src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java | 1 + src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java index 315731c20..5e513d954 100644 --- a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java @@ -205,6 +205,7 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { break; } } + return position; default: return null; } diff --git a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java index 103f1f48e..7f16d6f3b 100644 --- a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java @@ -13,9 +13,12 @@ public class SnapperProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "4b0341a6b0c608000040000005000000000000007d5e14010068656c6c6f")); - verifyNull(decoder, binary( + verifyPosition(decoder, binary( "4b044daff87aff5b8aad00007b010000000013ea0c006837000500210008003e000058c48fa94823001900000080000200018080000002deff0f0003404000000400000034008c007b2273223a22303034303438222c226332223a2230303030303030303030303030303030222c226132223a2230303030303030303030303030303030222c226f223a2230303030222c2274223a2230303030222c227a223a223030222c2277223a223030222c2272223a222d222c226d223a223030303030303030222c2262223a223030303030303030227d320079007b2266223a224445222c2274223a22303932383336222c2264223a22313530343234222c226c61223a22353334312e34333732222c226c6f223a2230303935342e30373036222c2261223a22382e34222c2273223a22302e3030222c2263223a2232362e3036222c227376223a223135222c2270223a22227d33003f007b2263223a22323632222c226e223a223033222c2262223a5b7b226c223a2232423334222c2263223a223030303041313231222c2273223a223132227d5d7d")); + verifyPosition(decoder, binary( + "4b044daff87aff5b8aad0000430100000000bb870c005b37000500210008003e0100ffffffff7f2300190000007f000000018080000002deff080003404000000400000034008c007b2273223a22303034303438222c226332223a2230303030303030303030303030303030222c226132223a2230303030303030303030303030303030222c226f223a2230303030222c2274223a2230303030222c227a223a223030222c2277223a223030222c2272223a222d222c226d223a223030303030303030222c2262223a223030303030303030227d320079007b2266223a224445222c2274223a22303832303335222c2264223a22313730343234222c226c61223a22353334312e34323635222c226c6f223a2230303935342e30373935222c2261223a22362e32222c2273223a22322e3237222c2263223a2233302e3135222c227376223a223038222c2270223a22227d330007007b2262223a5d7d")); + } } -- cgit v1.2.3 From ef67a4c1577b2fbabb04c4de9b08b6d778c78952 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 17 Apr 2024 07:47:01 -0700 Subject: Move some defaults to the code --- setup/default.xml | 33 ------------ src/main/java/org/traccar/MainModule.java | 4 +- src/main/java/org/traccar/config/Keys.java | 59 ++++++++++++++-------- .../org/traccar/database/StatisticsManager.java | 2 +- .../java/org/traccar/storage/DatabaseModule.java | 5 +- 5 files changed, 43 insertions(+), 60 deletions(-) diff --git a/setup/default.xml b/setup/default.xml index 7422bdf05..02c0650c3 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -10,39 +10,6 @@ --> - 8082 - ./web - ./override - false - false - true - - true - locationiq - pk.689d849289c8c63708068b2ff1f63b2d - true - true - - info - ./logs/tracker-server.log - true - - true - 86400 - - true - - ./media - - web,mail,command - - https://www.traccar.org/analytics/ - - true - - true - ./schema/changelog-master.xml - 5001 5002 5003 diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index d1d3d4663..89d3d2fe0 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -191,7 +191,7 @@ public class MainModule extends AbstractModule { @Provides public static WebServer provideWebServer(Injector injector, Config config) { - if (config.hasKey(Keys.WEB_PORT)) { + if (config.getInteger(Keys.WEB_PORT) > 0) { return new WebServer(injector, config); } return null; @@ -201,7 +201,7 @@ public class MainModule extends AbstractModule { @Provides public static Geocoder provideGeocoder(Config config, Client client, StatisticsManager statisticsManager) { if (config.getBoolean(Keys.GEOCODER_ENABLE)) { - String type = config.getString(Keys.GEOCODER_TYPE, "google"); + String type = config.getString(Keys.GEOCODER_TYPE); String url = config.getString(Keys.GEOCODER_URL); String key = config.getString(Keys.GEOCODER_KEY); String language = config.getString(Keys.GEOCODER_LANGUAGE); diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index db3c5c9ed..0d34c75dc 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -320,7 +320,8 @@ public final class Keys { */ public static final ConfigKey SERVER_STATISTICS = new StringConfigKey( "server.statistics", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + "https://www.traccar.org/analytics/"); /** * Fuel drop threshold value. When fuel level drops from one position to another for more the value, an event is @@ -397,7 +398,8 @@ public final class Keys { */ public static final ConfigKey EVENT_IGNORE_DUPLICATE_ALERTS = new BooleanConfigKey( "event.ignoreDuplicateAlerts", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + true); /** * If set to true, invalid positions will be considered for motion logic. @@ -472,7 +474,8 @@ public final class Keys { */ public static final ConfigKey DATABASE_CHANGELOG = new StringConfigKey( "database.changelog", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + "./schema/changelog-master.xml"); /** * Database connection pool size. Default value is defined by the HikariCP library. @@ -736,7 +739,8 @@ public final class Keys { */ public static final ConfigKey MEDIA_PATH = new StringConfigKey( "media.path", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + "./media"); /** * Optional parameter to specify network interface for web interface to bind to. By default server will bind to all @@ -747,12 +751,13 @@ public final class Keys { List.of(KeyType.CONFIG)); /** - * Web interface TCP port number. By default Traccar uses port 8082. To avoid specifying port in the browser you + * Web interface TCP port number. By default, Traccar uses port 8082. To avoid specifying port in the browser you * can set it to 80 (default HTTP port). */ public static final ConfigKey WEB_PORT = new IntegerConfigKey( "web.port", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + 8082); /** * Maximum API requests per second. Above this limit requests and delayed and throttled. @@ -782,14 +787,16 @@ public final class Keys { */ public static final ConfigKey WEB_PATH = new StringConfigKey( "web.path", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + "./web"); /** * Path to a folder with overrides. It can be used for branding to keep custom logos in a separate place. */ public static final ConfigKey WEB_OVERRIDE = new StringConfigKey( "web.override", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + "./override"); /** * WebSocket connection timeout in milliseconds. Default timeout is 5 minutes. @@ -1172,7 +1179,8 @@ public final class Keys { */ public static final ConfigKey NOTIFICATOR_TYPES = new StringConfigKey( "notificator.types", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + "web,mail,command"); /** * If the event time is too old, we should not send notifications. This parameter is the threshold value in @@ -1338,7 +1346,8 @@ public final class Keys { */ public static final ConfigKey FILTER_ENABLE = new BooleanConfigKey( "filter.enable", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + true); /** * Filter invalid (valid field is set to false) positions. @@ -1376,7 +1385,8 @@ public final class Keys { */ public static final ConfigKey FILTER_FUTURE = new LongConfigKey( "filter.future", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + 86400L); /** * Filter records with fix time in the past. The value is specified in seconds. Records that have fix time more @@ -1587,15 +1597,16 @@ public final class Keys { */ public static final ConfigKey GEOCODER_ENABLE = new BooleanConfigKey( "geocoder.enable", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + true); /** - * Reverse geocoder type. Check reverse geocoding documentation for more info. By default (if the value is not - * specified) server uses Google API. + * Reverse geocoder type. Check reverse geocoding documentation for more info. */ public static final ConfigKey GEOCODER_TYPE = new StringConfigKey( "geocoder.type", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + "locationiq"); /** * Geocoder server URL. Applicable only to Nominatim and Gisgraphy providers. @@ -1609,7 +1620,8 @@ public final class Keys { */ public static final ConfigKey GEOCODER_KEY = new StringConfigKey( "geocoder.key", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + "pk.689d849289c8c63708068b2ff1f63b2d"); /** * Language parameter for providers that support localization (e.g. Google and Nominatim). @@ -1637,7 +1649,8 @@ public final class Keys { */ public static final ConfigKey GEOCODER_IGNORE_POSITIONS = new BooleanConfigKey( "geocoder.ignorePositions", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + true); /** * Boolean flag to apply reverse geocoding to invalid positions. @@ -1659,7 +1672,8 @@ public final class Keys { */ public static final ConfigKey GEOCODER_ON_REQUEST = new BooleanConfigKey( "geocoder.onRequest", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + true); /** * Boolean flag to enable LBS location resolution. Some devices send cell towers information and WiFi point when GPS @@ -1860,7 +1874,8 @@ public final class Keys { */ public static final ConfigKey LOGGER_FILE = new StringConfigKey( "logger.file", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + "./logs/tracker-server.log"); /** * Logging level. Default value is 'info'. @@ -1868,7 +1883,8 @@ public final class Keys { */ public static final ConfigKey LOGGER_LEVEL = new StringConfigKey( "logger.level", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + "info"); /** * Print full exception traces. Useful for debugging. By default shortened traces are logged. @@ -1883,7 +1899,8 @@ public final class Keys { */ public static final ConfigKey LOGGER_ROTATE = new BooleanConfigKey( "logger.rotate", - List.of(KeyType.CONFIG)); + List.of(KeyType.CONFIG), + true); /** * Log file rotation interval, the default rotation interval is once a day. diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java index 445e53e7c..8711289a0 100644 --- a/src/main/java/org/traccar/database/StatisticsManager.java +++ b/src/main/java/org/traccar/database/StatisticsManager.java @@ -121,7 +121,7 @@ public class StatisticsManager { } String url = config.getString(Keys.SERVER_STATISTICS); - if (url != null) { + if (url != null && !url.isEmpty()) { String time = DateUtil.formatDate(statistics.getCaptureTime()); Form form = new Form(); diff --git a/src/main/java/org/traccar/storage/DatabaseModule.java b/src/main/java/org/traccar/storage/DatabaseModule.java index 9d9e5bd5e..9898a2fca 100644 --- a/src/main/java/org/traccar/storage/DatabaseModule.java +++ b/src/main/java/org/traccar/storage/DatabaseModule.java @@ -78,7 +78,8 @@ public class DatabaseModule extends AbstractModule { DataSource dataSource = new HikariDataSource(hikariConfig); - if (config.hasKey(Keys.DATABASE_CHANGELOG)) { + String changelog = config.getString(Keys.DATABASE_CHANGELOG); + if (changelog != null && !changelog.isEmpty()) { ResourceAccessor resourceAccessor = new DirectoryResourceAccessor(new File(".")); @@ -89,8 +90,6 @@ public class DatabaseModule extends AbstractModule { config.getString(Keys.DATABASE_DRIVER), null, null, null, resourceAccessor); - String changelog = config.getString(Keys.DATABASE_CHANGELOG); - try (Liquibase liquibase = new Liquibase(changelog, resourceAccessor, database)) { liquibase.clearCheckSums(); liquibase.update(new Contexts()); -- cgit v1.2.3 From dc6f5d92527624afb11225e94494e6604aaf8082 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 17 Apr 2024 17:21:26 -0700 Subject: Fix comment --- src/main/java/org/traccar/config/Keys.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 0d34c75dc..44037fb2e 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -23,7 +23,7 @@ public final class Keys { } /** - * Network interface for a the protocol. If not specified, server will bind all interfaces. + * Network interface for the protocol. If not specified, server will bind all interfaces. */ public static final ConfigSuffix PROTOCOL_ADDRESS = new StringConfigSuffix( ".address", @@ -674,7 +674,7 @@ public final class Keys { /** * OpenID Connect Authorization URL. * This can usually be found in the documentation of your identity provider or by using the well-known - * configuration endpoint, e.g. https://auth.example.com//.well-known/openid-configuration + * configuration endpoint, e.g. https://auth.example.com/.well-known/openid-configuration * Required to enable SSO if openid.issuerUrl is not set. */ public static final ConfigKey OPENID_AUTH_URL = new StringConfigKey( -- cgit v1.2.3 From 93c4e0ef2f882c4818b542b7792e9b02975f9da7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 17 Apr 2024 20:53:14 -0700 Subject: Migrate default ports to code --- debug.xml | 4 - setup/default.xml | 271 -------------------- setup/traccar.xml | 16 +- src/main/java/org/traccar/ServerManager.java | 2 +- src/main/java/org/traccar/config/Keys.java | 2 +- .../java/org/traccar/config/PortConfigSuffix.java | 278 +++++++++++++++++++++ 6 files changed, 281 insertions(+), 292 deletions(-) delete mode 100644 setup/default.xml create mode 100644 src/main/java/org/traccar/config/PortConfigSuffix.java diff --git a/debug.xml b/debug.xml index 89b5a5ba3..15fa57324 100644 --- a/debug.xml +++ b/debug.xml @@ -1,11 +1,7 @@ - - - ./setup/default.xml - ./traccar-web/simple true true diff --git a/setup/default.xml b/setup/default.xml deleted file mode 100644 index 02c0650c3..000000000 --- a/setup/default.xml +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - - - - 5001 - 5002 - 5003 - 5004 - 5005 - 5006 - false - 5007 - 5008 - 5009 - 5010 - 5011 - 5012 - 5013 - 5014 - 5015 - 5016 - 5017 - 5018 - 5019 - 5020 - 5021 - 5022 - 5023 - 5024 - 5025 - 5026 - 5027 - 5028 - 5029 - 5030 - 5031 - 5032 - 5033 - 5034 - 5035 - 5036 - 5037 - 5038 - 5039 - 5040 - 5041 - 5042 - 5043 - 5044 - 5045 - 5046 - 5047 - 5048 - 5049 - 5050 - 5051 - 5052 - 5053 - 5054 - 5055 - 5056 - 5057 - 5058 - 5059 - 5060 - 5061 - 5062 - 5063 - 5064 - 5065 - 5066 - 5067 - 5068 - 5069 - 5070 - 5071 - 5072 - 5073 - 5074 - 5075 - 5076 - 5077 - 5078 - 5079 - 5080 - 5081 - 5082 - 5083 - 5084 - 5085 - 5086 - 5087 - 5088 - 5089 - 5090 - 5091 - 5092 - 5093 - 5094 - 5095 - 5096 - 5097 - 5098 - 5099 - 5100 - 5101 - 5102 - 5103 - 5104 - 5105 - 5106 - 5107 - 5108 - 5109 - 5110 - 5111 - 5112 - 5113 - 5114 - 5115 - 5116 - 5117 - 5118 - 5119 - 5120 - 5121 - 5122 - 5123 - 5124 - 5125 - 5126 - 5127 - 5128 - 5129 - 5130 - 5131 - 5132 - 5133 - 5134 - 5135 - 5136 - 5137 - 5138 - 5139 - 5140 - 5141 - 5142 - 5143 - 5144 - 5145 - 5146 - 5147 - 5148 - 5149 - 5150 - 5151 - 5152 - 5153 - 5154 - 5155 - 5156 - 5157 - 5158 - 5159 - 5160 - 5161 - 5162 - 5163 - 5164 - 5165 - 5166 - 5167 - 5168 - 5169 - 5170 - 5171 - 5172 - 5173 - 5174 - 5175 - 5176 - 5177 - 5178 - 5179 - 5180 - 5181 - 5182 - 5183 - 5184 - 5185 - 5186 - 5187 - 5188 - 5189 - 5190 - 5191 - 5192 - 5193 - 5194 - 5195 - 5196 - 5197 - 5198 - 5199 - 5200 - 5201 - 5202 - 5203 - 5204 - 5205 - 5206 - 5207 - 5208 - 5209 - 5210 - 5211 - 5212 - 5213 - 5214 - 5215 - 5216 - 5217 - 5218 - 5219 - 5220 - 5221 - 5222 - 5223 - 5224 - 5225 - 5226 - 5227 - 5228 - 5229 - 5230 - 5231 - 5232 - 5233 - 5234 - 5235 - 5236 - 5237 - 5238 - 5239 - 5240 - 5241 - 5242 - 5243 - 5244 - 5245 - 5246 - 5247 - 5248 - 5249 - 5250 - 5251 - 5252 - 5253 - 5254 - 5255 - 5256 - - diff --git a/setup/traccar.xml b/setup/traccar.xml index aab9ba311..d5bd87e9c 100644 --- a/setup/traccar.xml +++ b/setup/traccar.xml @@ -1,22 +1,8 @@ - - - ./conf/default.xml - - + org.h2.Driver jdbc:h2:./data/database diff --git a/src/main/java/org/traccar/ServerManager.java b/src/main/java/org/traccar/ServerManager.java index 22af66b41..1b0c441cf 100644 --- a/src/main/java/org/traccar/ServerManager.java +++ b/src/main/java/org/traccar/ServerManager.java @@ -54,7 +54,7 @@ public class ServerManager implements LifecycleObject { for (Class protocolClass : ClassScanner.findSubclasses(BaseProtocol.class, "org.traccar.protocol")) { String protocolName = BaseProtocol.nameFromClass(protocolClass); if (enabledProtocols == null || enabledProtocols.contains(protocolName)) { - if (config.hasKey(Keys.PROTOCOL_PORT.withPrefix(protocolName))) { + if (config.getInteger(Keys.PROTOCOL_PORT.withPrefix(protocolName)) > 0) { BaseProtocol protocol = (BaseProtocol) injector.getInstance(protocolClass); connectorList.addAll(protocol.getConnectorList()); protocolList.put(protocol.getName(), protocol); diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 44037fb2e..a2aa42e1c 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -33,7 +33,7 @@ public final class Keys { * Port number for the protocol. Most protocols use TCP on the transport layer. Some protocols use UDP. Some * support both TCP and UDP. */ - public static final ConfigSuffix PROTOCOL_PORT = new IntegerConfigSuffix( + public static final ConfigSuffix PROTOCOL_PORT = new PortConfigSuffix( ".port", List.of(KeyType.CONFIG)); diff --git a/src/main/java/org/traccar/config/PortConfigSuffix.java b/src/main/java/org/traccar/config/PortConfigSuffix.java new file mode 100644 index 000000000..11d6f2dbb --- /dev/null +++ b/src/main/java/org/traccar/config/PortConfigSuffix.java @@ -0,0 +1,278 @@ +package org.traccar.config; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class PortConfigSuffix extends ConfigSuffix { + + private static final Map PORTS = new HashMap<>(); + + static { + PORTS.put("gps103", 5001); + PORTS.put("tk103", 5002); + PORTS.put("gl100", 5003); + PORTS.put("gl200", 5004); + PORTS.put("t55", 5005); + PORTS.put("xexun", 5006); + PORTS.put("totem", 5007); + PORTS.put("enfora", 5008); + PORTS.put("meiligao", 5009); + PORTS.put("trv", 5010); + PORTS.put("suntech", 5011); + PORTS.put("progress", 5012); + PORTS.put("h02", 5013); + PORTS.put("jt600", 5014); + PORTS.put("huabao", 5015); + PORTS.put("v680", 5016); + PORTS.put("pt502", 5017); + PORTS.put("tr20", 5018); + PORTS.put("navis", 5019); + PORTS.put("meitrack", 5020); + PORTS.put("skypatrol", 5021); + PORTS.put("gt02", 5022); + PORTS.put("gt06", 5023); + PORTS.put("megastek", 5024); + PORTS.put("navigil", 5025); + PORTS.put("gpsgate", 5026); + PORTS.put("teltonika", 5027); + PORTS.put("mta6", 5028); + PORTS.put("tzone", 5029); + PORTS.put("tlt2h", 5030); + PORTS.put("taip", 5031); + PORTS.put("wondex", 5032); + PORTS.put("cellocator", 5033); + PORTS.put("galileo", 5034); + PORTS.put("ywt", 5035); + PORTS.put("tk102", 5036); + PORTS.put("intellitrac", 5037); + PORTS.put("gpsmta", 5038); + PORTS.put("wialon", 5039); + PORTS.put("carscop", 5040); + PORTS.put("apel", 5041); + PORTS.put("manpower", 5042); + PORTS.put("globalsat", 5043); + PORTS.put("atrack", 5044); + PORTS.put("pt3000", 5045); + PORTS.put("ruptela", 5046); + PORTS.put("topflytech", 5047); + PORTS.put("laipac", 5048); + PORTS.put("aplicom", 5049); + PORTS.put("gotop", 5050); + PORTS.put("sanav", 5051); + PORTS.put("gator", 5052); + PORTS.put("noran", 5053); + PORTS.put("m2m", 5054); + PORTS.put("osmand", 5055); + PORTS.put("easytrack", 5056); + PORTS.put("gpsmarker", 5057); + PORTS.put("khd", 5058); + PORTS.put("piligrim", 5059); + PORTS.put("stl060", 5060); + PORTS.put("cartrack", 5061); + PORTS.put("minifinder", 5062); + PORTS.put("haicom", 5063); + PORTS.put("eelink", 5064); + PORTS.put("box", 5065); + PORTS.put("freedom", 5066); + PORTS.put("telic", 5067); + PORTS.put("trackbox", 5068); + PORTS.put("visiontek", 5069); + PORTS.put("orion", 5070); + PORTS.put("riti", 5071); + PORTS.put("ulbotech", 5072); + PORTS.put("tramigo", 5073); + PORTS.put("tr900", 5074); + PORTS.put("ardi01", 5075); + PORTS.put("xt013", 5076); + PORTS.put("autofon", 5077); + PORTS.put("gosafe", 5078); + PORTS.put("tt8850", 5079); + PORTS.put("bce", 5080); + PORTS.put("xirgo", 5081); + PORTS.put("calamp", 5082); + PORTS.put("mtx", 5083); + PORTS.put("tytan", 5084); + PORTS.put("avl301", 5085); + PORTS.put("castel", 5086); + PORTS.put("mxt", 5087); + PORTS.put("cityeasy", 5088); + PORTS.put("aquila", 5089); + PORTS.put("flextrack", 5090); + PORTS.put("blackkite", 5091); + PORTS.put("adm", 5092); + PORTS.put("watch", 5093); + PORTS.put("t800x", 5094); + PORTS.put("upro", 5095); + PORTS.put("auro", 5096); + PORTS.put("disha", 5097); + PORTS.put("thinkrace", 5098); + PORTS.put("pathaway", 5099); + PORTS.put("arnavi", 5100); + PORTS.put("nvs", 5101); + PORTS.put("kenji", 5102); + PORTS.put("astra", 5103); + PORTS.put("homtecs", 5104); + PORTS.put("fox", 5105); + PORTS.put("gnx", 5106); + PORTS.put("arknav", 5107); + PORTS.put("supermate", 5108); + PORTS.put("appello", 5109); + PORTS.put("idpl", 5110); + PORTS.put("huasheng", 5111); + PORTS.put("l100", 5112); + PORTS.put("granit", 5113); + PORTS.put("carcell", 5114); + PORTS.put("obddongle", 5115); + PORTS.put("hunterpro", 5116); + PORTS.put("raveon", 5117); + PORTS.put("cradlepoint", 5118); + PORTS.put("arknavx8", 5119); + PORTS.put("autograde", 5120); + PORTS.put("oigo", 5121); + PORTS.put("jpkorjar", 5122); + PORTS.put("cguard", 5123); + PORTS.put("fifotrack", 5124); + PORTS.put("smokey", 5125); + PORTS.put("extremtrac", 5126); + PORTS.put("trakmate", 5127); + PORTS.put("at2000", 5128); + PORTS.put("maestro", 5129); + PORTS.put("ais", 5130); + PORTS.put("gt30", 5131); + PORTS.put("tmg", 5132); + PORTS.put("pretrace", 5133); + PORTS.put("pricol", 5134); + PORTS.put("siwi", 5135); + PORTS.put("starlink", 5136); + PORTS.put("dmt", 5137); + PORTS.put("xt2400", 5138); + PORTS.put("dmthttp", 5139); + PORTS.put("alematics", 5140); + PORTS.put("gps056", 5141); + PORTS.put("flexcomm", 5142); + PORTS.put("vt200", 5143); + PORTS.put("owntracks", 5144); + PORTS.put("vtfms", 5145); + PORTS.put("tlv", 5146); + PORTS.put("esky", 5147); + PORTS.put("genx", 5148); + PORTS.put("flespi", 5149); + PORTS.put("dway", 5150); + PORTS.put("recoda", 5151); + PORTS.put("oko", 5152); + PORTS.put("ivt401", 5153); + PORTS.put("sigfox", 5154); + PORTS.put("t57", 5155); + PORTS.put("spot", 5156); + PORTS.put("m2c", 5157); + PORTS.put("austinnb", 5158); + PORTS.put("opengts", 5159); + PORTS.put("cautela", 5160); + PORTS.put("continental", 5161); + PORTS.put("egts", 5162); + PORTS.put("robotrack", 5163); + PORTS.put("pt60", 5164); + PORTS.put("telemax", 5165); + PORTS.put("sabertek", 5166); + PORTS.put("retranslator", 5167); + PORTS.put("svias", 5168); + PORTS.put("eseal", 5169); + PORTS.put("freematics", 5170); + PORTS.put("avema", 5171); + PORTS.put("autotrack", 5172); + PORTS.put("tek", 5173); + PORTS.put("wristband", 5174); + PORTS.put("lacak", 5175); + PORTS.put("milesmate", 5176); + PORTS.put("anytrek", 5177); + PORTS.put("smartsole", 5178); + PORTS.put("its", 5179); + PORTS.put("xrb28", 5180); + PORTS.put("c2stek", 5181); + PORTS.put("nyitech", 5182); + PORTS.put("neos", 5183); + PORTS.put("satsol", 5184); + PORTS.put("globalstar", 5185); + PORTS.put("sanul", 5186); + PORTS.put("minifinder2", 5187); + PORTS.put("radar", 5188); + PORTS.put("techtlt", 5189); + PORTS.put("starcom", 5190); + PORTS.put("mictrack", 5191); + PORTS.put("plugin", 5192); + PORTS.put("leafspy", 5193); + PORTS.put("naviset", 5194); + PORTS.put("racedynamics", 5195); + PORTS.put("rst", 5196); + PORTS.put("pt215", 5197); + PORTS.put("pacifictrack", 5198); + PORTS.put("topin", 5199); + PORTS.put("outsafe", 5200); + PORTS.put("solarpowered", 5201); + PORTS.put("motor", 5202); + PORTS.put("omnicomm", 5203); + PORTS.put("s168", 5204); + PORTS.put("vnet", 5205); + PORTS.put("blue", 5206); + PORTS.put("pst", 5207); + PORTS.put("dingtek", 5208); + PORTS.put("wli", 5209); + PORTS.put("niot", 5210); + PORTS.put("portman", 5211); + PORTS.put("moovbox", 5212); + PORTS.put("futureway", 5213); + PORTS.put("polte", 5214); + PORTS.put("net", 5215); + PORTS.put("mobilogix", 5216); + PORTS.put("swiftech", 5217); + PORTS.put("iotm", 5218); + PORTS.put("dolphin", 5219); + PORTS.put("ennfu", 5220); + PORTS.put("navtelecom", 5221); + PORTS.put("startek", 5222); + PORTS.put("gs100", 5223); + PORTS.put("mavlink2", 5224); + PORTS.put("uux", 5225); + PORTS.put("r12w", 5226); + PORTS.put("flexiblereport", 5227); + PORTS.put("thinkpower", 5228); + PORTS.put("stb", 5229); + PORTS.put("b2316", 5230); + PORTS.put("hoopo", 5231); + PORTS.put("dualcam", 5232); + PORTS.put("xexun2", 5233); + PORTS.put("techtocruz", 5234); + PORTS.put("flexapi", 5235); + PORTS.put("dsf22", 5236); + PORTS.put("jido", 5237); + PORTS.put("armoli", 5238); + PORTS.put("teratrack", 5239); + PORTS.put("envotech", 5240); + PORTS.put("bstpl", 5241); + PORTS.put("thuraya", 5242); + PORTS.put("ndtpv6", 5243); + PORTS.put("g1rus", 5244); + PORTS.put("rftrack", 5245); + PORTS.put("vlt", 5246); + PORTS.put("transync", 5247); + PORTS.put("t622iridium", 5248); + PORTS.put("pui", 5249); + PORTS.put("nto", 5250); + PORTS.put("ramac", 5251); + PORTS.put("positrex", 5252); + PORTS.put("dragino", 5253); + PORTS.put("fleetguide", 5254); + PORTS.put("valtrack", 5255); + PORTS.put("snapper", 5256); + } + + PortConfigSuffix(String key, List types) { + super(key, types, null); + } + + @Override + public ConfigKey withPrefix(String protocol) { + return new IntegerConfigKey(protocol + keySuffix, types, PORTS.get(protocol)); + } +} -- cgit v1.2.3 From 3f0540021a73ab1c54448e267c5088a00cc47bd4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 17 Apr 2024 20:56:24 -0700 Subject: Remove default properties support --- src/main/java/org/traccar/config/Config.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/traccar/config/Config.java b/src/main/java/org/traccar/config/Config.java index 47e1f0707..409a3f16a 100644 --- a/src/main/java/org/traccar/config/Config.java +++ b/src/main/java/org/traccar/config/Config.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. @@ -41,20 +41,10 @@ public class Config { @Inject public Config(@Named("configFile") String file) throws IOException { try { - Properties mainProperties = new Properties(); try (InputStream inputStream = new FileInputStream(file)) { - mainProperties.loadFromXML(inputStream); + properties.loadFromXML(inputStream); } - String defaultConfigFile = mainProperties.getProperty("config.default"); - if (defaultConfigFile != null) { - try (InputStream inputStream = new FileInputStream(defaultConfigFile)) { - properties.loadFromXML(inputStream); - } - } - - properties.putAll(mainProperties); // override defaults - useEnvironmentVariables = Boolean.parseBoolean(System.getenv("CONFIG_USE_ENVIRONMENT_VARIABLES")) || Boolean.parseBoolean(properties.getProperty("config.useEnvironmentVariables")); -- cgit v1.2.3 From c16b8c9d96468379fee467239a974c84e3f35ea2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 17 Apr 2024 20:58:15 -0700 Subject: Remove default xml usage --- setup/cloud-init.yaml | 4 ---- setup/package.sh | 1 - 2 files changed, 5 deletions(-) diff --git a/setup/cloud-init.yaml b/setup/cloud-init.yaml index 1246fb1b7..3d55f5f6f 100644 --- a/setup/cloud-init.yaml +++ b/setup/cloud-init.yaml @@ -5,14 +5,10 @@ write_files: - - ./conf/default.xml - com.mysql.jdbc.Driver jdbc:mysql://localhost/traccar?zeroDateTimeBehavior=round&serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=false&allowMultiQueries=true&autoReconnect=true&useUnicode=yes&characterEncoding=UTF-8&sessionVariables=sql_mode='' root root - path: /root/traccar.xml diff --git a/setup/package.sh b/setup/package.sh index 5b3c9bcde..1cac75713 100755 --- a/setup/package.sh +++ b/setup/package.sh @@ -88,7 +88,6 @@ prepare () { cp ../schema/* out/schema cp -r ../templates/* out/templates cp -r ../traccar-web/build/* out/web - cp default.xml out/conf cp traccar.xml out/conf if [ $PLATFORM = "all" -o $PLATFORM = "windows-64" ]; then -- cgit v1.2.3 From 9e41b5f94063fa9f40725d115d16b9a2c1842720 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 19 Apr 2024 08:15:23 -0700 Subject: Additional GPS Watch data --- .../org/traccar/protocol/TrvProtocolDecoder.java | 93 ++++++++++++++++++++-- .../traccar/protocol/TrvProtocolDecoderTest.java | 27 ++++++- 2 files changed, 114 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java index 02744f8ab..8b2e755b2 100644 --- a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2019 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. @@ -64,6 +64,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { .number("(d+),") // mnc .number("(d+),") // lac .number("(d+)") // cell + .number(",(dd)").optional() // alarm .groupBegin() .text(",") .expression("(") @@ -77,7 +78,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { .any() .compile(); - private static final Pattern PATTERN_HEARTBEAT = new PatternBuilder() + private static final Pattern PATTERN_CP01 = new PatternBuilder() .expression("[A-Z]{2,3}") .text("CP01,") .number("(ddd)") // gsm @@ -99,7 +100,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { .any() .compile(); - private static final Pattern PATTERN_LBS = new PatternBuilder() + private static final Pattern PATTERN_AP02 = new PatternBuilder() .expression("[A-Z]{2,3}") .text("AP02,") .expression("[^,]+,") // language @@ -118,6 +119,19 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { .expression("(.*)") // wifi .compile(); + private static final Pattern PATTERN_AP03 = new PatternBuilder() + .expression("[A-Z]{2,3}") + .text("AP03,") + .number("(ddd)") // rssi + .number("(ddd)") // satellites + .number("(ddd)") // battery level + .number("d") // space + .number("xx") // fortification state + .number("dd,") // working mode + .number("(d+),") // steps + .number("d+") // rolls frequency + .compile(); + private Boolean decodeOptionalValue(Parser parser, int activeValue) { int value = parser.nextInt(); if (value != 0) { @@ -183,7 +197,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { if (type.equals("CP01")) { - Parser parser = new Parser(PATTERN_HEARTBEAT, sentence); + Parser parser = new Parser(PATTERN_CP01, sentence); if (!parser.matches()) { return null; } @@ -233,6 +247,20 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { network.addCellTower(CellTower.from( parser.nextInt(), parser.nextInt(), parser.nextInt(), parser.nextInt())); + if (parser.hasNext()) { + switch (parser.nextInt()) { + case 1: + position.set(Position.KEY_ALARM, Position.ALARM_SOS); + break; + case 5: + case 6: + position.set(Position.KEY_ALARM, Position.ALARM_FALL_DOWN); + break; + default: + break; + } + } + if (parser.hasNext()) { decodeWifi(network, parser.next()); } @@ -243,7 +271,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { } else if (type.equals("AP02")) { - Parser parser = new Parser(PATTERN_LBS, sentence); + Parser parser = new Parser(PATTERN_AP02, sentence); if (!parser.matches()) { return null; } @@ -275,6 +303,61 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { return position; + } else if (type.equals("AP03")) { + + Parser parser = new Parser(PATTERN_AP03, sentence); + if (!parser.matches()) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + position.set(Position.KEY_RSSI, parser.nextInt()); + position.set(Position.KEY_SATELLITES, parser.nextInt()); + position.set(Position.KEY_BATTERY_LEVEL, parser.nextInt()); + position.set(Position.KEY_STEPS, parser.nextInt()); + + return position; + + } else if (type.equals("AP49") || type.equals("APHT") || type.equals("APHP") || type.equals("AP50")) { + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + String[] values = sentence.split(","); + + switch (type) { + case "AP49": + position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[1])); + break; + case "APHT": + position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[1])); + position.set("pressureSystolic", Integer.parseInt(values[2])); + position.set("pressureDiastolic", Integer.parseInt(values[3])); + break; + case "APHP": + position.set(Position.KEY_HEART_RATE, Integer.parseInt(values[1])); + position.set("pressureSystolic", Integer.parseInt(values[2])); + position.set("pressureDiastolic", Integer.parseInt(values[3])); + position.set("spo2", Integer.parseInt(values[4])); + position.set("bloodSugar", Integer.parseInt(values[5])); + position.set("temperature", Double.parseDouble(values[6])); + break; + case "AP50": + position.set("temperature", Double.parseDouble(values[1])); + position.set(Position.KEY_BATTERY_LEVEL, Integer.parseInt(values[2])); + break; + default: + break; + } + + return position; + } return null; diff --git a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java index 370775735..a17fc341f 100644 --- a/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/TrvProtocolDecoderTest.java @@ -2,6 +2,7 @@ package org.traccar.protocol; import org.junit.jupiter.api.Test; import org.traccar.ProtocolTest; +import org.traccar.model.Position; public class TrvProtocolDecoderTest extends ProtocolTest { @@ -13,6 +14,30 @@ public class TrvProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, text( "TRVAP00352121088015548")); + verifyAttribute(decoder, text( + "IWAP10080524A2232.9806N11404.9355E000.1061830323.8706000908000502,460,0,9520,3671,01,zhcn,00,HOME|74-DE-2B-44-88-8C|97&HOME1|74-DE-2B-44-88-8C|97&HOME2|74-DE-2B-44-88-8C|97&HOME3|74-DE-2B-44-88-8C|97"), + Position.KEY_ALARM, Position.ALARM_SOS); + + verifyAttribute(decoder, text( + "IWAP49,68"), + Position.KEY_HEART_RATE, 68); + + verifyAttribute(decoder, text( + "IWAPHT,60,130,85"), + "pressureDiastolic", 85); + + verifyAttribute(decoder, text( + "IWAPHP,60,130,85,95,90,36.5,,,,,,,"), + "temperature", 36.5); + + verifyAttribute(decoder, text( + "IWAP50,36.7,90"), + Position.KEY_BATTERY_LEVEL, 90); + + verifyAttribute(decoder, text( + "IWAP03,06000908000102,5555,30"), + Position.KEY_STEPS, 5555); + verifyPosition(decoder, text( "TRVYP14080524A2232.9806N11404.9355E000.1061830323.870600090800010200011,460,0,9520,3671,Home|74-DE-2B-44-88-8C|97&Home1|74-DE-2B-44-88-8C|97&Home2|74-DE-2B-44-88-8C|97& Home3|74-DE-2B-44-88-8C|97")); @@ -40,7 +65,7 @@ public class TrvProtocolDecoderTest extends ProtocolTest { verifyPosition(decoder, text( "IWAP10080524A2232.9806N11404.9355E000.1061830323.8706000908000502,460,0,9520,3671,00,zh-cn,00,HOME|74-DE-2B-44-88-8C|97&HOME1|74-DE-2B-44-88-8C|97&HOME2|74-DE-2B-44-88-8C|97&HOME3|74-DE-2B-44-88-8C|97")); - verifyNull(decoder, text( + verifyAttributes(decoder, text( "IWAP03,06000908000102,5555,30")); verifyNull(decoder, text( -- cgit v1.2.3 From fb7a817440f3734e465c7843024d676c13f82d24 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 20 Apr 2024 07:28:01 -0700 Subject: Fix configuration issues --- src/main/java/org/traccar/config/Keys.java | 2 +- src/main/java/org/traccar/schedule/TaskExpirations.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index a2aa42e1c..0898e8f0a 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -601,7 +601,7 @@ public final class Keys { "uid"); /** - * LDAP attribute used as user name. Default value is 'cn'. + * LDAP attribute used as username. Default value is 'cn'. */ public static final ConfigKey LDAP_NAME_ATTRIBUTE = new StringConfigKey( "ldap.nameAttribute", diff --git a/src/main/java/org/traccar/schedule/TaskExpirations.java b/src/main/java/org/traccar/schedule/TaskExpirations.java index 94f855c5f..e16dcd86c 100644 --- a/src/main/java/org/traccar/schedule/TaskExpirations.java +++ b/src/main/java/org/traccar/schedule/TaskExpirations.java @@ -111,7 +111,7 @@ public class TaskExpirations implements ScheduleTask { } if (config.getBoolean(Keys.NOTIFICATION_EXPIRATION_DEVICE)) { - long reminder = config.getLong(Keys.NOTIFICATION_EXPIRATION_USER_REMINDER); + long reminder = config.getLong(Keys.NOTIFICATION_EXPIRATION_DEVICE_REMINDER); var devices = storage.getObjects(Device.class, new Request(new Columns.All())); for (Device device : devices) { if (checkTimeTrigger(device, currentTime, 0)) { -- cgit v1.2.3 From 0a5683733c7b01a0af07cee7a4340c45e19b6ceb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 20 Apr 2024 08:03:50 -0700 Subject: Update config documentation script --- tools/config-doc.py | 54 +++++++++++++++++++++++------------------------------ 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/tools/config-doc.py b/tools/config-doc.py index c55b2b5ef..9d9177070 100755 --- a/tools/config-doc.py +++ b/tools/config-doc.py @@ -19,40 +19,32 @@ def get_config_keys(): 'key': A dot separated name of the config key 'description': A list of str """ - desc_re = re.compile(r"(/\*\*\n|\s+\*/|\s+\*)") - key_match_re = re.compile(r"\(\n(.+)\);", re.DOTALL) - key_split_re = re.compile(r",\s+", re.DOTALL) types_match_re = re.compile(r"List\.of\(([^)]+)\)", re.DOTALL) keys = [] with open(_KEYS_FILE, "r") as f: - config = re.findall( - r"(/\*\*.*?\*/)\n\s+(public static final Config.*?;)", f.read(), re.DOTALL - ) + config = re.findall(r"/\*\*\s.*?\);", f.read(), re.DOTALL) for i in config: - try: - key_match = key_match_re.search(i[1]) - if key_match: - terms = [x.strip() for x in key_split_re.split(key_match.group(1))] - key = terms[0].replace('"', "") - key = "[protocol]" + key if key.startswith('.') else key - description = [ - x.strip().replace("\n", "") - for x in desc_re.sub("\n", i[0]).strip().split("\n\n") - ] - types_match = types_match_re.search(i[1]) - types = map(lambda x: x[8:].lower(), types_match[1].split(", ")) - keys.append( - { - "key": key, - "description": description, - "types": types, - } - ) - except IndexError: - # will continue if key_match.group(1) or terms[0] does not exist - # for some reason - pass + lines = i.splitlines() + index = -1 + default = None + if "List.of" not in lines[index]: + default = lines[index].strip()[:-2] + index -= 1 + types_match = types_match_re.search(lines[index]) + types = map(lambda x: x[8:].lower(), types_match[1].split(", ")) + index -= 1 + key = lines[index].strip()[1:-2] + key = "[protocol]" + key if key.startswith('.') else key + description = " ".join([l.strip()[2:] for l in lines if l.startswith(" * ")]) + keys.append( + { + "key": key, + "description": description, + "types": types, + "default": default, + } + ) return keys @@ -66,7 +58,7 @@ def get_html(): {x["key"]}

- {"
".join(x["description"])} + {x["description"]}

""" @@ -81,7 +73,7 @@ def get_pug(): f""" div(class='card mt-3') div(class='card-body') h5(class='card-title') {x["key"]} {" ".join(map("#[span(class='badge badge-dark') {:}]".format, x["types"]))} - p(class='card-text') {"#[br] ".join(x["description"])}""" + p(class='card-text') {x["description"]}{f"\n p(class='card-text') Default value: {x["default"]}" if x["default"] is not None else ""}""" for x in get_config_keys() ] ) -- cgit v1.2.3 From 7b3fda2da562ce7b259a232bf9fc5f519c138283 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 20 Apr 2024 09:28:20 -0700 Subject: Fix overlapping report schedules --- src/main/java/org/traccar/model/Calendar.java | 5 ++- .../java/org/traccar/schedule/TaskReports.java | 2 +- .../java/org/traccar/calendar/CalendarTest.java | 38 ++++++++++++++++++++-- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/traccar/model/Calendar.java b/src/main/java/org/traccar/model/Calendar.java index 03f1995ba..feef7286f 100644 --- a/src/main/java/org/traccar/model/Calendar.java +++ b/src/main/java/org/traccar/model/Calendar.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"); @@ -79,9 +79,8 @@ public class Calendar extends ExtendedModel { } public Collection findPeriods(Date date) { - var calendarDate = new net.fortuna.ical4j.model.Date(date); return findEvents(date).stream() - .flatMap((event) -> event.getConsumedTime(calendarDate, calendarDate).stream()) + .flatMap((e) -> e.calculateRecurrenceSet(new Period(new DateTime(date), Duration.ZERO)).stream()) .collect(Collectors.toSet()); } diff --git a/src/main/java/org/traccar/schedule/TaskReports.java b/src/main/java/org/traccar/schedule/TaskReports.java index 2102b2ee1..3989cd6a0 100644 --- a/src/main/java/org/traccar/schedule/TaskReports.java +++ b/src/main/java/org/traccar/schedule/TaskReports.java @@ -81,7 +81,7 @@ public class TaskReports implements ScheduleTask { var lastEvents = calendar.findPeriods(lastCheck); var currentEvents = calendar.findPeriods(currentCheck); - if (!lastEvents.isEmpty() && currentEvents.isEmpty()) { + if (!lastEvents.isEmpty() && !currentEvents.equals(lastEvents)) { Period period = lastEvents.iterator().next(); RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap()); try (RequestScoper.CloseableScope ignored = scope.open()) { diff --git a/src/test/java/org/traccar/calendar/CalendarTest.java b/src/test/java/org/traccar/calendar/CalendarTest.java index 4106f89a9..d2c2b251c 100644 --- a/src/test/java/org/traccar/calendar/CalendarTest.java +++ b/src/test/java/org/traccar/calendar/CalendarTest.java @@ -5,19 +5,19 @@ import org.junit.jupiter.api.Test; import org.traccar.model.Calendar; import java.io.IOException; -import java.sql.SQLException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.Date; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; public class CalendarTest { @Test - public void testCalendar() throws IOException, ParserException, ParseException, SQLException { + public void testCalendar() throws IOException, ParserException, ParseException { String calendarString = "BEGIN:VCALENDAR\n" + "PRODID:-//Mozilla.org/NONSGML Mozilla Calendar V1.1//EN\n" + "VERSION:2.0\n" + @@ -54,4 +54,36 @@ public class CalendarTest { var periods = calendar.findPeriods(format.parse("2016-12-13 06:59:59+05")); assertFalse(periods.isEmpty()); } + + @Test + public void testCalendarOverlap() throws IOException, ParserException, ParseException { + String calendarString = "BEGIN:VCALENDAR\n" + + "VERSION:2.0\n" + + "PRODID:-//Traccar//NONSGML Traccar//EN\n" + + "BEGIN:VEVENT\n" + + "UID:00000000-0000-0000-0000-000000000000\n" + + "DTSTART;TZID=America/Los_Angeles:20240420T060000\n" + + "DTEND;TZID=America/Los_Angeles:20240421T060000\n" + + "RRULE:FREQ=DAILY\n" + + "SUMMARY:Event\n" + + "END:VEVENT\n" + + "END:VCALENDAR"; + Calendar calendar = new Calendar(); + calendar.setData(calendarString.getBytes()); + DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssX"); + + var periods0 = calendar.findPeriods(format.parse("2014-05-13 07:00:00-07")); + var periods1 = calendar.findPeriods(format.parse("2024-05-13 05:00:00-07")); + var periods2 = calendar.findPeriods(format.parse("2024-05-13 07:00:00-07")); + var periods3 = calendar.findPeriods(format.parse("2024-05-13 08:00:00-07")); + + assertEquals(periods0.size(), 0); + assertEquals(periods1.size(), 1); + assertEquals(periods2.size(), 1); + assertEquals(periods3.size(), 1); + + assertNotEquals(periods0, periods1); + assertNotEquals(periods1, periods2); + assertEquals(periods2, periods3); + } } -- cgit v1.2.3 From 8e4e92f84f149ec9f9da6dd601fab06ed55c544c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 20 Apr 2024 09:36:05 -0700 Subject: Improve report schedules logic --- src/main/java/org/traccar/model/Calendar.java | 3 ++- src/main/java/org/traccar/schedule/TaskReports.java | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/model/Calendar.java b/src/main/java/org/traccar/model/Calendar.java index feef7286f..76c9a2cc1 100644 --- a/src/main/java/org/traccar/model/Calendar.java +++ b/src/main/java/org/traccar/model/Calendar.java @@ -34,6 +34,7 @@ import java.time.Duration; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; @StorageName("tc_calendars") @@ -78,7 +79,7 @@ public class Calendar extends ExtendedModel { } } - public Collection findPeriods(Date date) { + public Set findPeriods(Date date) { return findEvents(date).stream() .flatMap((e) -> e.calculateRecurrenceSet(new Period(new DateTime(date), Duration.ZERO)).stream()) .collect(Collectors.toSet()); diff --git a/src/main/java/org/traccar/schedule/TaskReports.java b/src/main/java/org/traccar/schedule/TaskReports.java index 3989cd6a0..1d074214c 100644 --- a/src/main/java/org/traccar/schedule/TaskReports.java +++ b/src/main/java/org/traccar/schedule/TaskReports.java @@ -43,7 +43,9 @@ import org.traccar.storage.query.Request; import jakarta.inject.Inject; import java.util.Collections; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -81,8 +83,9 @@ public class TaskReports implements ScheduleTask { var lastEvents = calendar.findPeriods(lastCheck); var currentEvents = calendar.findPeriods(currentCheck); - if (!lastEvents.isEmpty() && !currentEvents.equals(lastEvents)) { - Period period = lastEvents.iterator().next(); + Set finishedEvents = new HashSet<>(lastEvents); + finishedEvents.removeAll(currentEvents); + for (Period period : finishedEvents) { RequestScoper scope = ServletScopes.scopeRequest(Collections.emptyMap()); try (RequestScoper.CloseableScope ignored = scope.open()) { executeReport(report, period.getStart(), period.getEnd()); -- cgit v1.2.3 From 35ae557526d8613e9658375e7f846e644fca4d83 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 21 Apr 2024 15:52:44 -0700 Subject: Hide missing values in reports --- .../org/traccar/reports/SummaryReportProvider.java | 14 +++----------- templates/export/stops.xlsx | Bin 15643 -> 13212 bytes templates/export/summary.xlsx | Bin 16889 -> 13233 bytes templates/export/trips.xlsx | Bin 15944 -> 13511 bytes 4 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/reports/SummaryReportProvider.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java index ffde0b067..5f155552b 100644 --- a/src/main/java/org/traccar/reports/SummaryReportProvider.java +++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java @@ -105,15 +105,9 @@ public class SummaryReportProvider { result.setDistance(PositionUtil.calculateDistance(first, last, !ignoreOdometer)); result.setSpentFuel(reportUtils.calculateFuel(first, last)); - long durationMilliseconds; if (first.hasAttribute(Position.KEY_HOURS) && last.hasAttribute(Position.KEY_HOURS)) { - durationMilliseconds = last.getLong(Position.KEY_HOURS) - first.getLong(Position.KEY_HOURS); + long durationMilliseconds = last.getLong(Position.KEY_HOURS) - first.getLong(Position.KEY_HOURS); result.setEngineHours(durationMilliseconds); - } else { - durationMilliseconds = last.getFixTime().getTime() - first.getFixTime().getTime(); - } - - if (durationMilliseconds > 0) { result.setAverageSpeed(UnitsConverter.knotsFromMps(result.getDistance() * 1000 / durationMilliseconds)); } @@ -142,15 +136,13 @@ public class SummaryReportProvider { if (daily) { while (from.truncatedTo(ChronoUnit.DAYS).isBefore(to.truncatedTo(ChronoUnit.DAYS))) { ZonedDateTime fromDay = from.truncatedTo(ChronoUnit.DAYS); - ZonedDateTime nextDay = fromDay.plus(1, ChronoUnit.DAYS); + ZonedDateTime nextDay = fromDay.plusDays(1); results.addAll(calculateDeviceResult( device, Date.from(from.toInstant()), Date.from(nextDay.toInstant()), fast)); from = nextDay; } - results.addAll(calculateDeviceResult(device, Date.from(from.toInstant()), Date.from(to.toInstant()), fast)); - } else { - results.addAll(calculateDeviceResult(device, Date.from(from.toInstant()), Date.from(to.toInstant()), fast)); } + results.addAll(calculateDeviceResult(device, Date.from(from.toInstant()), Date.from(to.toInstant()), fast)); return results; } diff --git a/templates/export/stops.xlsx b/templates/export/stops.xlsx index 967d26309..4e7aaf422 100644 Binary files a/templates/export/stops.xlsx and b/templates/export/stops.xlsx differ diff --git a/templates/export/summary.xlsx b/templates/export/summary.xlsx index 47a6241b1..528b99f55 100644 Binary files a/templates/export/summary.xlsx and b/templates/export/summary.xlsx differ diff --git a/templates/export/trips.xlsx b/templates/export/trips.xlsx index 3201c66bb..3549a372e 100644 Binary files a/templates/export/trips.xlsx and b/templates/export/trips.xlsx differ -- cgit v1.2.3 From 8986af8e65cf92c8cb5daa66a0e852e891dacf2b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 23 Apr 2024 18:32:22 -0700 Subject: Fix Snapper protocol response --- src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java index 5e513d954..25cc1a431 100644 --- a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java @@ -66,13 +66,13 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { ByteBuf response = Unpooled.buffer(); response.writeByte('K'); response.writeByte(3); // protocol version - response.writeIntLE(0); // reserved - response.writeIntLE(0); // reserved + response.writeLongLE(0); // reserved response.writeShortLE(0); // encryption + response.writeIntLE(0); // reserved response.writeIntLE(answer.length()); response.writeShortLE(index); response.writeByte(Checksum.sum(ByteBuffer.wrap(answer.getBytes(StandardCharsets.US_ASCII)))); - response.writeByte(type); + response.writeShortLE(type); response.writeCharSequence(answer, StandardCharsets.US_ASCII); channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); } -- cgit v1.2.3 From 660b455a2aa7995cf1c852f897bbfd9522f72ded Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 25 Apr 2024 10:22:07 -0700 Subject: Fix Snapper protocol response --- src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java index 25cc1a431..e60ddc431 100644 --- a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java @@ -68,8 +68,8 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { response.writeByte(3); // protocol version response.writeLongLE(0); // reserved response.writeShortLE(0); // encryption - response.writeIntLE(0); // reserved response.writeIntLE(answer.length()); + response.writeIntLE(0); // reserved response.writeShortLE(index); response.writeByte(Checksum.sum(ByteBuffer.wrap(answer.getBytes(StandardCharsets.US_ASCII)))); response.writeShortLE(type); -- cgit v1.2.3 From 3b739942dafea3c9d2bb3f061fb6ee98a33c747a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 26 Apr 2024 08:50:08 -0700 Subject: Teltonika FMB150 attributes --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index 6197c6c13..c8a944980 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -199,7 +199,8 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { var fmbXXX = Set.of( "FMB001", "FMB010", "FMB002", "FMB020", "FMB003", "FMB110", "FMB120", "FMB122", "FMB125", "FMB130", "FMB140", "FMU125", "FMB900", "FMB920", "FMB962", "FMB964", "FM3001", "FMB202", "FMB204", "FMB206", - "FMT100", "MTB100", "FMP100", "MSP500"); + "FMT100", "MTB100", "FMP100", "MSP500", "FMC125", "FMM125", "FMU130", "FMC130", "FMM130", "FMB150", + "FMC150", "FMM150"); register(1, null, (p, b) -> p.set(Position.PREFIX_IN + 1, b.readUnsignedByte() > 0)); register(2, null, (p, b) -> p.set(Position.PREFIX_IN + 2, b.readUnsignedByte() > 0)); @@ -243,9 +244,9 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(85, fmbXXX, (p, b) -> p.set(Position.KEY_RPM, b.readUnsignedShort())); register(87, fmbXXX, (p, b) -> p.set(Position.KEY_OBD_ODOMETER, b.readUnsignedInt())); register(89, fmbXXX, (p, b) -> p.set("fuelLevelPercentage", b.readUnsignedByte())); - register(90, null, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedShort())); register(110, fmbXXX, (p, b) -> p.set(Position.KEY_FUEL_CONSUMPTION, b.readUnsignedShort() * 0.1)); register(113, fmbXXX, (p, b) -> p.set(Position.KEY_BATTERY_LEVEL, b.readUnsignedByte())); + register(115, fmbXXX, (p, b) -> p.set("engineTemp", b.readShort() * 0.1)); register(179, null, (p, b) -> p.set(Position.PREFIX_OUT + 1, b.readUnsignedByte() > 0)); register(180, null, (p, b) -> p.set(Position.PREFIX_OUT + 2, b.readUnsignedByte() > 0)); register(181, null, (p, b) -> p.set(Position.KEY_PDOP, b.readUnsignedShort() * 0.1)); @@ -292,6 +293,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { } }); register(636, fmbXXX, (p, b) -> p.set("cid4g", b.readUnsignedInt())); + register(662, fmbXXX, (p, b) -> p.set(Position.KEY_DOOR, b.readUnsignedByte() > 0)); } private void decodeGh3000Parameter(Position position, int id, ByteBuf buf, int length) { -- cgit v1.2.3 From 8da81efe902ceb9a106dff15ce44638c6be1eecc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 27 Apr 2024 07:46:24 -0700 Subject: Better DB lock error message --- src/main/java/org/traccar/Main.java | 11 +++++-- .../java/org/traccar/storage/DatabaseModule.java | 35 ++++++++++++++++------ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java index 33fcf654f..943b5bd7d 100644 --- a/src/main/java/org/traccar/Main.java +++ b/src/main/java/org/traccar/Main.java @@ -17,6 +17,7 @@ package org.traccar; import com.google.inject.Guice; import com.google.inject.Injector; +import com.google.inject.ProvisionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.broadcast.BroadcastService; @@ -142,8 +143,14 @@ public final class Main { } })); } catch (Exception e) { - LOGGER.error("Main method error", e); - throw new RuntimeException(e); + Throwable unwrapped; + if (e instanceof ProvisionException) { + unwrapped = e.getCause(); + } else { + unwrapped = e; + } + LOGGER.error("Main method error", unwrapped); + System.exit(1); } } diff --git a/src/main/java/org/traccar/storage/DatabaseModule.java b/src/main/java/org/traccar/storage/DatabaseModule.java index 9898a2fca..86e5267d4 100644 --- a/src/main/java/org/traccar/storage/DatabaseModule.java +++ b/src/main/java/org/traccar/storage/DatabaseModule.java @@ -20,10 +20,12 @@ import com.google.inject.Provides; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import liquibase.Contexts; +import liquibase.GlobalConfiguration; import liquibase.Liquibase; import liquibase.database.Database; import liquibase.database.DatabaseFactory; import liquibase.exception.LiquibaseException; +import liquibase.exception.LockException; import liquibase.resource.DirectoryResourceAccessor; import liquibase.resource.ResourceAccessor; import org.traccar.config.Config; @@ -83,16 +85,22 @@ public class DatabaseModule extends AbstractModule { ResourceAccessor resourceAccessor = new DirectoryResourceAccessor(new File(".")); - Database database = DatabaseFactory.getInstance().openDatabase( - config.getString(Keys.DATABASE_URL), - config.getString(Keys.DATABASE_USER), - config.getString(Keys.DATABASE_PASSWORD), - config.getString(Keys.DATABASE_DRIVER), - null, null, null, resourceAccessor); + System.setProperty("liquibase.changelogLockWaitTimeInMinutes", "1"); - try (Liquibase liquibase = new Liquibase(changelog, resourceAccessor, database)) { - liquibase.clearCheckSums(); - liquibase.update(new Contexts()); + try { + Database database = DatabaseFactory.getInstance().openDatabase( + config.getString(Keys.DATABASE_URL), + config.getString(Keys.DATABASE_USER), + config.getString(Keys.DATABASE_PASSWORD), + config.getString(Keys.DATABASE_DRIVER), + null, null, null, resourceAccessor); + + try (Liquibase liquibase = new Liquibase(changelog, resourceAccessor, database)) { + liquibase.clearCheckSums(); + liquibase.update(new Contexts()); + } + } catch (LockException e) { + throw new DatabaseLockException(); } } @@ -100,3 +108,12 @@ public class DatabaseModule extends AbstractModule { } } + +class DatabaseLockException extends RuntimeException { + DatabaseLockException() { + super("Database is in a locked state. " + + "It could be due to early service termination on a previous launch. " + + "To unlock you can run this query: 'UPDATE DATABASECHANGELOGLOCK SET locked = 0'. " + + "Make sure the schema is up to date before unlocking the database."); + } +} -- cgit v1.2.3 From ce08bd530579765c38a84eba1f57863fb5907f89 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 27 Apr 2024 08:04:33 -0700 Subject: Fix lint issues --- src/main/java/org/traccar/storage/DatabaseModule.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/traccar/storage/DatabaseModule.java b/src/main/java/org/traccar/storage/DatabaseModule.java index 86e5267d4..cd66d7298 100644 --- a/src/main/java/org/traccar/storage/DatabaseModule.java +++ b/src/main/java/org/traccar/storage/DatabaseModule.java @@ -20,7 +20,6 @@ import com.google.inject.Provides; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import liquibase.Contexts; -import liquibase.GlobalConfiguration; import liquibase.Liquibase; import liquibase.database.Database; import liquibase.database.DatabaseFactory; -- cgit v1.2.3 From 0173d53e967a461560302772c35bcea0251426ed Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 1 May 2024 07:14:41 -0700 Subject: Handle Snapper no GPS data --- .../traccar/protocol/SnapperProtocolDecoder.java | 25 ++++++++++++++-------- .../protocol/SnapperProtocolDecoderTest.java | 3 +++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java index e60ddc431..e60736667 100644 --- a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java @@ -115,16 +115,11 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { String content = buf.readCharSequence(buf.readableBytes(), StandardCharsets.US_ASCII).toString(); JsonObject json = Json.createReader(new StringReader(content)).readObject(); - DateFormat dateFormat = new SimpleDateFormat("ddMMyyHHmmss"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - position.setTime(dateFormat.parse(json.getString("d") + json.getString("t").split("\\.")[0])); - - String lat = json.getString("la"); - position.setLatitude(Integer.parseInt(lat.substring(0, 2)) + Double.parseDouble(lat.substring(2)) / 60); - String lon = json.getString("lo"); - position.setLongitude(Integer.parseInt(lon.substring(0, 3)) + Double.parseDouble(lon.substring(3)) / 60); - int flags = Integer.parseInt(json.getString("f"), 16); + if (!BitUtil.check(flags, 3)) { + return; + } + position.setValid(BitUtil.check(flags, 1)); if (!BitUtil.check(flags, 6)) { position.setLatitude(-position.getLatitude()); @@ -133,6 +128,15 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { position.setLongitude(-position.getLongitude()); } + DateFormat dateFormat = new SimpleDateFormat("ddMMyyHHmmss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + position.setTime(dateFormat.parse(json.getString("d") + json.getString("t").split("\\.")[0])); + + String lat = json.getString("la"); + position.setLatitude(Integer.parseInt(lat.substring(0, 2)) + Double.parseDouble(lat.substring(2)) / 60); + String lon = json.getString("lo"); + position.setLongitude(Integer.parseInt(lon.substring(0, 3)) + Double.parseDouble(lon.substring(3)) / 60); + position.setAltitude(Double.parseDouble(json.getString("a"))); position.setSpeed(Double.parseDouble(json.getString("s"))); position.setCourse(Double.parseDouble(json.getString("c"))); @@ -205,6 +209,9 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { break; } } + if (position.getFixTime() == null) { + getLastLocation(position, null); + } return position; default: return null; diff --git a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java index 7f16d6f3b..bb79194eb 100644 --- a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java @@ -13,6 +13,9 @@ public class SnapperProtocolDecoderTest extends ProtocolTest { verifyNull(decoder, binary( "4b0341a6b0c608000040000005000000000000007d5e14010068656c6c6f")); + verifyAttributes(decoder, binary( + "4b044daff87aff5b8aad0000d4000000000000000b001337000500210008000d0000ffffffff7f2300190000000000000001000000000224ff000003404000000400000034008c007b2273223a22303034313438222c226332223a2230303030303030303030303030303030222c226132223a2230303030303030303030303830304530222c226f223a2230303030222c2274223a2230303030222c227a223a223030222c2277223a223030222c2272223a222d222c226d223a223030303030303030222c2262223a223030303030303030227d32000a007b2266223a223234227d330007007b2262223a5d7d")); + verifyPosition(decoder, binary( "4b044daff87aff5b8aad00007b010000000013ea0c006837000500210008003e000058c48fa94823001900000080000200018080000002deff0f0003404000000400000034008c007b2273223a22303034303438222c226332223a2230303030303030303030303030303030222c226132223a2230303030303030303030303030303030222c226f223a2230303030222c2274223a2230303030222c227a223a223030222c2277223a223030222c2272223a222d222c226d223a223030303030303030222c2262223a223030303030303030227d320079007b2266223a224445222c2274223a22303932383336222c2264223a22313530343234222c226c61223a22353334312e34333732222c226c6f223a2230303935342e30373036222c2261223a22382e34222c2273223a22302e3030222c2263223a2232362e3036222c227376223a223135222c2270223a22227d33003f007b2263223a22323632222c226e223a223033222c2262223a5b7b226c223a2232423334222c2263223a223030303041313231222c2273223a223132227d5d7d")); -- cgit v1.2.3 From 31c266483f0fc0507e2b5482c0b81bbc4b1f2857 Mon Sep 17 00:00:00 2001 From: Nikutrax <112165998+Nikutrax@users.noreply.github.com> Date: Thu, 2 May 2024 10:24:44 +0200 Subject: Update TrvProtocolDecoder.java because i think the documention was fail (bloodSugar value is in with point) and should so because the server received following: IWAPHP,0,0,0,93,0.0,0.0# 2024-04-30 14:35:36 INFO: [T37978d9e: trv < 109.43.243.234] 4957415048502c302c302c302c39332c302e302c302e3023 2024-04-30 14:35:36 INFO: [T37978d9e] error - For input string: "0.0" - NumberFormatException (... < TrvProtocolDecoder:348 < ExtendedObjectDecoder:75 < ... < WrapperContext:102 < ...) --- src/main/java/org/traccar/protocol/TrvProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java index 8b2e755b2..1187250f8 100644 --- a/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TrvProtocolDecoder.java @@ -345,7 +345,7 @@ public class TrvProtocolDecoder extends BaseProtocolDecoder { position.set("pressureSystolic", Integer.parseInt(values[2])); position.set("pressureDiastolic", Integer.parseInt(values[3])); position.set("spo2", Integer.parseInt(values[4])); - position.set("bloodSugar", Integer.parseInt(values[5])); + position.set("bloodSugar", Double.parseDouble(values[5])); position.set("temperature", Double.parseDouble(values[6])); break; case "AP50": -- cgit v1.2.3 From 93828126208b569b360fedecb1e87b4ed809b298 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 3 May 2024 13:51:56 -0700 Subject: Fix Teltonika driver id --- src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java index c8a944980..de42031d7 100644 --- a/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/TeltonikaProtocolDecoder.java @@ -232,7 +232,7 @@ public class TeltonikaProtocolDecoder extends BaseProtocolDecoder { register(75, fmbXXX, (p, b) -> p.set(Position.PREFIX_TEMP + 4, b.readInt() * 0.1)); register(78, null, (p, b) -> { long driverUniqueId = b.readLongLE(); - if (driverUniqueId > 0) { + if (driverUniqueId != 0) { p.set(Position.KEY_DRIVER_UNIQUE_ID, String.format("%016X", driverUniqueId)); } }); -- cgit v1.2.3 From c2993f0451749f3b127aa64892eb3db60360a4b6 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 4 May 2024 19:35:52 -0700 Subject: Support true as boolean default --- src/main/java/org/traccar/config/Config.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/config/Config.java b/src/main/java/org/traccar/config/Config.java index 409a3f16a..2d76a5c70 100644 --- a/src/main/java/org/traccar/config/Config.java +++ b/src/main/java/org/traccar/config/Config.java @@ -92,7 +92,13 @@ public class Config { } public boolean getBoolean(ConfigKey key) { - return Boolean.parseBoolean(getString(key.getKey())); + String value = getString(key.getKey()); + if (value != null) { + return Boolean.parseBoolean(value); + } else { + Boolean defaultValue = key.getDefaultValue(); + return Objects.requireNonNullElse(defaultValue, false); + } } public int getInteger(ConfigKey key) { -- cgit v1.2.3 From 5d131bdb8f9a49d5da508eb5073d21014f7185a2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 4 May 2024 19:50:32 -0700 Subject: Fix stored message count --- src/main/java/org/traccar/handler/DatabaseHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/handler/DatabaseHandler.java b/src/main/java/org/traccar/handler/DatabaseHandler.java index 5d96ebb34..4619e9d34 100644 --- a/src/main/java/org/traccar/handler/DatabaseHandler.java +++ b/src/main/java/org/traccar/handler/DatabaseHandler.java @@ -42,7 +42,7 @@ public class DatabaseHandler extends BasePositionHandler { try { position.setId(storage.addObject(position, new Request(new Columns.Exclude("id")))); - statisticsManager.messageStoredCount(position.getDeviceId()); + statisticsManager.registerMessageStored(position.getDeviceId(), position.getProtocol()); } catch (Exception error) { LOGGER.warn("Failed to store position", error); } -- cgit v1.2.3 From 5d647be37332790aab41731d52e8dcadac9d5eb4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 4 May 2024 19:56:42 -0700 Subject: Improve daily limit throttling --- src/main/java/org/traccar/config/Keys.java | 9 +++++++- .../java/org/traccar/handler/FilterHandler.java | 24 ++++++++++++++-------- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 0898e8f0a..5d9a43c01 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1443,12 +1443,19 @@ public final class Keys { List.of(KeyType.CONFIG)); /** - * Filter position if the daily limit is exceeded for the device. + * Throttle positions if the daily limit is exceeded for the device. */ public static final ConfigKey FILTER_DAILY_LIMIT = new IntegerConfigKey( "filter.dailyLimit", List.of(KeyType.CONFIG)); + /** + * Throttling interval if the limit exceeded. The value is in seconds. + */ + public static final ConfigKey FILTER_DAILY_LIMIT_INTERVAL = new IntegerConfigKey( + "filter.dailyLimitInterval", + List.of(KeyType.CONFIG)); + /** * If false, the server expects all locations to come sequentially (for each device). Filter checks for duplicates, * distance, speed, or time period only against the location that was last received by server. diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 796c302fb..3bb7ef426 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -53,6 +53,7 @@ public class FilterHandler extends BasePositionHandler { private final int filterMaxSpeed; private final long filterMinPeriod; private final int filterDailyLimit; + private final long filterDailyLimitInterval; private final boolean filterRelative; private final long skipLimit; private final boolean skipAttributes; @@ -77,6 +78,7 @@ public class FilterHandler extends BasePositionHandler { filterMaxSpeed = config.getInteger(Keys.FILTER_MAX_SPEED); filterMinPeriod = config.getInteger(Keys.FILTER_MIN_PERIOD) * 1000L; filterDailyLimit = config.getInteger(Keys.FILTER_DAILY_LIMIT); + filterDailyLimitInterval = config.getInteger(Keys.FILTER_DAILY_LIMIT_INTERVAL) * 1000L; filterRelative = config.getBoolean(Keys.FILTER_RELATIVE); skipLimit = config.getLong(Keys.FILTER_SKIP_LIMIT) * 1000; skipAttributes = config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE); @@ -164,9 +166,12 @@ public class FilterHandler extends BasePositionHandler { return false; } - private boolean filterDailyLimit(Position position) { - if (filterDailyLimit != 0) { - return statisticsManager.messageStoredCount(position.getDeviceId()) >= filterDailyLimit; + private boolean filterDailyLimit(Position position, Position last) { + if (filterDailyLimit != 0 + && statisticsManager.messageStoredCount(position.getDeviceId()) >= filterDailyLimit) { + long lastTime = last != null ? last.getFixTime().getTime() : 0; + long interval = position.getFixTime().getTime() - lastTime; + return filterDailyLimitInterval <= 0 || interval < filterDailyLimitInterval; } return false; } @@ -216,20 +221,18 @@ public class FilterHandler extends BasePositionHandler { if (filterApproximate(position)) { filterType.append("Approximate "); } - if (filterDailyLimit(position)) { - filterType.append("DailyLimit "); - } // filter out excessive data long deviceId = position.getDeviceId(); - if (filterDuplicate || filterStatic || filterDistance > 0 || filterMaxSpeed > 0 || filterMinPeriod > 0) { - Position preceding = null; + if (filterDuplicate || filterStatic + || filterDistance > 0 || filterMaxSpeed > 0 || filterMinPeriod > 0 || filterDailyLimit > 0) { + Position preceding; if (filterRelative) { try { Date newFixTime = position.getFixTime(); preceding = getPrecedingPosition(deviceId, newFixTime); } catch (StorageException e) { - LOGGER.warn("Error retrieving preceding position; fallbacking to last received position.", e); + LOGGER.warn("Error retrieving preceding position; fall backing to last received position.", e); preceding = cacheManager.getPosition(deviceId); } } else { @@ -250,6 +253,9 @@ public class FilterHandler extends BasePositionHandler { if (filterMinPeriod(position, preceding)) { filterType.append("MinPeriod "); } + if (filterDailyLimit(position, preceding)) { + filterType.append("DailyLimit "); + } } Device device = cacheManager.getObject(Device.class, deviceId); -- cgit v1.2.3 From 25bda2559356b7fc4388069b641da16a35bcd0cc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 5 May 2024 07:52:39 -0700 Subject: Refactor scheme login --- .../org/traccar/api/security/LoginService.java | 18 +++++++++++++++++- .../api/security/SecurityRequestFilter.java | 22 +++------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 930c4fa46..507288c31 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 - 2023 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. @@ -20,6 +20,7 @@ import org.traccar.api.signature.TokenManager; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.LdapProvider; +import org.traccar.helper.DataConverter; import org.traccar.helper.model.UserUtil; import org.traccar.model.User; import org.traccar.storage.Storage; @@ -32,6 +33,7 @@ import jakarta.annotation.Nullable; import jakarta.inject.Inject; import jakarta.inject.Singleton; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; @Singleton @@ -58,6 +60,20 @@ public class LoginService { forceOpenId = config.getBoolean(Keys.OPENID_FORCE); } + public LoginResult login( + String scheme, String credentials) throws StorageException, GeneralSecurityException, IOException { + switch (scheme.toLowerCase()) { + case "bearer": + return login(credentials); + case "basic": + byte[] decodedBytes = DataConverter.parseBase64(credentials); + String[] auth = new String(decodedBytes, StandardCharsets.US_ASCII).split(":", 2); + return login(auth[0], auth[1], null); + default: + throw new SecurityException("Unsupported authorization scheme"); + } + } + public LoginResult login(String token) throws StorageException, GeneralSecurityException, IOException { if (serviceAccountToken != null && serviceAccountToken.equals(token)) { return new LoginResult(new ServiceAccountUser()); diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index 12a5dbecf..07083e7a8 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.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. @@ -20,7 +20,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.api.resource.SessionResource; import org.traccar.database.StatisticsManager; -import org.traccar.helper.DataConverter; import org.traccar.model.User; import org.traccar.storage.StorageException; @@ -36,7 +35,6 @@ import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.SecurityContext; import java.io.IOException; import java.lang.reflect.Method; -import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.util.Date; @@ -44,15 +42,6 @@ public class SecurityRequestFilter implements ContainerRequestFilter { private static final Logger LOGGER = LoggerFactory.getLogger(SecurityRequestFilter.class); - public static String[] decodeBasicAuth(String auth) { - auth = auth.replaceFirst("[B|b]asic ", ""); - byte[] decodedBytes = DataConverter.parseBase64(auth); - if (decodedBytes != null && decodedBytes.length > 0) { - return new String(decodedBytes, StandardCharsets.US_ASCII).split(":", 2); - } - return null; - } - @Context private HttpServletRequest request; @@ -83,13 +72,8 @@ public class SecurityRequestFilter implements ContainerRequestFilter { if (authHeader != null) { try { - LoginResult loginResult; - if (authHeader.startsWith("Bearer ")) { - loginResult = loginService.login(authHeader.substring(7)); - } else { - String[] auth = decodeBasicAuth(authHeader); - loginResult = loginService.login(auth[0], auth[1], null); - } + String[] auth = authHeader.split(" "); + LoginResult loginResult = loginService.login(auth[0], auth[1]); if (loginResult != null) { User user = loginResult.getUser(); statisticsManager.registerRequest(user.getId()); -- cgit v1.2.3 From 49483e0420ca8c7ff1afb31dacc7a427f93c7a3a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 5 May 2024 09:50:19 -0700 Subject: Support WebSocket auth token --- .../java/org/traccar/api/AsyncSocketServlet.java | 30 +++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/traccar/api/AsyncSocketServlet.java b/src/main/java/org/traccar/api/AsyncSocketServlet.java index cd2c1639e..e1e7ee977 100644 --- a/src/main/java/org/traccar/api/AsyncSocketServlet.java +++ b/src/main/java/org/traccar/api/AsyncSocketServlet.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. @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.eclipse.jetty.websocket.server.JettyWebSocketServlet; import org.eclipse.jetty.websocket.server.JettyWebSocketServletFactory; import org.traccar.api.resource.SessionResource; +import org.traccar.api.security.LoginService; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.session.ConnectionManager; @@ -27,7 +28,12 @@ import org.traccar.storage.Storage; import jakarta.inject.Inject; import jakarta.inject.Singleton; import jakarta.servlet.http.HttpSession; +import org.traccar.storage.StorageException; + +import java.io.IOException; +import java.security.GeneralSecurityException; import java.time.Duration; +import java.util.List; @Singleton public class AsyncSocketServlet extends JettyWebSocketServlet { @@ -36,25 +42,37 @@ public class AsyncSocketServlet extends JettyWebSocketServlet { private final ObjectMapper objectMapper; private final ConnectionManager connectionManager; private final Storage storage; + private final LoginService loginService; @Inject public AsyncSocketServlet( - Config config, ObjectMapper objectMapper, ConnectionManager connectionManager, Storage storage) { + Config config, ObjectMapper objectMapper, ConnectionManager connectionManager, Storage storage, + LoginService loginService) { this.config = config; this.objectMapper = objectMapper; this.connectionManager = connectionManager; this.storage = storage; + this.loginService = loginService; } @Override public void configure(JettyWebSocketServletFactory factory) { factory.setIdleTimeout(Duration.ofMillis(config.getLong(Keys.WEB_TIMEOUT))); factory.setCreator((req, resp) -> { - if (req.getSession() != null) { - Long userId = (Long) ((HttpSession) req.getSession()).getAttribute(SessionResource.USER_ID_KEY); - if (userId != null) { - return new AsyncSocket(objectMapper, connectionManager, storage, userId); + Long userId = null; + List tokens = req.getParameterMap().get("token"); + if (tokens != null && !tokens.isEmpty()) { + String token = tokens.iterator().next(); + try { + userId = loginService.login(token).getUser().getId(); + } catch (StorageException | GeneralSecurityException | IOException e) { + throw new RuntimeException(e); } + } else if (req.getSession() != null) { + userId = (Long) ((HttpSession) req.getSession()).getAttribute(SessionResource.USER_ID_KEY); + } + if (userId != null) { + return new AsyncSocket(objectMapper, connectionManager, storage, userId); } return null; }); -- cgit v1.2.3 From a8a8036fc87076c910196c290b8ea551c7be9a52 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 6 May 2024 17:37:27 -0700 Subject: Add G1C 5W ICCID support --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 4 ++++ src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index 648c5fb42..fd3015e66 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -668,6 +668,10 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set("fuel2", Double.parseDouble( buf.readCharSequence(6, StandardCharsets.US_ASCII).toString())); break; + case 0x00B2: + position.set(Position.KEY_ICCID, ByteBufUtil.hexDump( + buf.readSlice(10)).replaceAll("f", "")); + break; case 0x00CE: position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); break; diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 7fd7cc599..425c88785 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { var decoder = inject(new HuabaoProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "7e020000460100503769640002000001000000001a01b9eaf804d8ee86001800000000240507035152010400000000300100310107eb1c00060089fffffffe000400ce0000000c00b28942310221007544309f5f7e"), + Position.KEY_ICCID, "8942310221007544309"); + verifyAttribute(decoder, binary( "7E0200005300959000194400080000000000000003015DA64806CCB4A8001100000000230816014137010400005B3F30011F310112EB29000C00B28986049910219020787400060089FFFFFFFF000600C5FFFFFFEF0004002D0F4E000300A84CE07E"), Position.KEY_BATTERY_LEVEL, 76); -- cgit v1.2.3 From ee026cdce3e8191cba2628cd7245de3dd6e2b3e5 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 8 May 2024 07:49:27 -0700 Subject: Fix unit test formatting --- src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java index 5fd0ede44..5c61d5426 100644 --- a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java @@ -18,7 +18,7 @@ public class WatchProtocolDecoderTest extends ProtocolTest { var decoder = inject(new WatchProtocolDecoder(null)); verifyAttribute(decoder, buffer( - "[3G*9705141740*000B*oxygen,0,98]"), + "[3G*9705141740*000B*oxygen,0,98]"), "bloodOxygen", 98); verifyPosition(decoder, buffer( -- cgit v1.2.3 From 7d4fabd576068cc968085bdfbd8e91035242a487 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 9 May 2024 07:28:07 -0700 Subject: Remove unused time configuration --- schema/changelog-6.2.xml | 16 ++++++++++++++++ schema/changelog-master.xml | 2 ++ src/main/java/org/traccar/model/Server.java | 12 +----------- src/main/java/org/traccar/model/User.java | 12 +----------- 4 files changed, 20 insertions(+), 22 deletions(-) create mode 100644 schema/changelog-6.2.xml diff --git a/schema/changelog-6.2.xml b/schema/changelog-6.2.xml new file mode 100644 index 000000000..471987d12 --- /dev/null +++ b/schema/changelog-6.2.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/schema/changelog-master.xml b/schema/changelog-master.xml index 559d90923..e9ae52569 100644 --- a/schema/changelog-master.xml +++ b/schema/changelog-master.xml @@ -43,4 +43,6 @@ + + diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java index 6442186b6..b29fe27cc 100644 --- a/src/main/java/org/traccar/model/Server.java +++ b/src/main/java/org/traccar/model/Server.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. @@ -126,16 +126,6 @@ public class Server extends ExtendedModel implements UserRestrictions { this.zoom = zoom; } - private boolean twelveHourFormat; - - public boolean getTwelveHourFormat() { - return twelveHourFormat; - } - - public void setTwelveHourFormat(boolean twelveHourFormat) { - this.twelveHourFormat = twelveHourFormat; - } - private boolean forceSettings; public boolean getForceSettings() { diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java index 8cfee0f48..9b8ee3e53 100644 --- a/src/main/java/org/traccar/model/User.java +++ b/src/main/java/org/traccar/model/User.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 - 2022 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. @@ -133,16 +133,6 @@ public class User extends ExtendedModel implements UserRestrictions, Disableable this.zoom = zoom; } - private boolean twelveHourFormat; - - public boolean getTwelveHourFormat() { - return twelveHourFormat; - } - - public void setTwelveHourFormat(boolean twelveHourFormat) { - this.twelveHourFormat = twelveHourFormat; - } - private String coordinateFormat; public String getCoordinateFormat() { -- cgit v1.2.3 From 69046d9d687997f3631019adfcb6bf437c4805f9 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 13 May 2024 19:57:24 -0700 Subject: Update processing order --- src/main/java/org/traccar/ProcessingHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/ProcessingHandler.java b/src/main/java/org/traccar/ProcessingHandler.java index fd048d127..bb040bfff 100644 --- a/src/main/java/org/traccar/ProcessingHandler.java +++ b/src/main/java/org/traccar/ProcessingHandler.java @@ -101,8 +101,8 @@ public class ProcessingHandler extends ChannelInboundHandlerAdapter implements B GeocoderHandler.class, SpeedLimitHandler.class, MotionHandler.class, - EngineHoursHandler.class, ComputedAttributesHandler.class, + EngineHoursHandler.class, CopyAttributesHandler.class, PositionForwardingHandler.class, DatabaseHandler.class) -- cgit v1.2.3 From 6016ef5effa5a5f826e8f77bc8277897fec6e878 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 14 May 2024 06:56:34 -0700 Subject: Fix typo --- src/main/java/org/traccar/api/resource/ReportResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java index 8b6e6dce9..2ed119298 100644 --- a/src/main/java/org/traccar/api/resource/ReportResource.java +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -326,7 +326,7 @@ public class ReportResource extends SimpleObjectResource { @Path("devices/{type:xlsx|mail}") @GET @Produces(EXCEL) - public Response geDevicesExcel( + public Response getDevicesExcel( @PathParam("type") String type) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), type.equals("mail"), stream -> { -- cgit v1.2.3 From 6879f2bcd6026d279826d3672e58ffca2b2e947e Mon Sep 17 00:00:00 2001 From: memesaregood Date: Thu, 16 May 2024 18:40:23 +0300 Subject: Allow Date class in a JEXL whitelist --- src/main/java/org/traccar/handler/ComputedAttributesHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 4293bd1fc..7c2fd70a5 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -41,6 +41,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Date; public class ComputedAttributesHandler extends BasePositionHandler { @@ -63,7 +64,7 @@ public class ComputedAttributesHandler extends BasePositionHandler { sandbox.allow(Math.class.getName()); List.of( Double.class, Float.class, Integer.class, Long.class, Short.class, - Character.class, Boolean.class, String.class, Byte.class) + Character.class, Boolean.class, String.class, Byte.class, Date.class) .forEach((type) -> sandbox.allow(type.getName())); features = new JexlFeatures() .localVar(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES)) -- cgit v1.2.3 From f1a3367864fde22c1df3ee1a5a5e886be496031d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 16 May 2024 15:30:36 -0700 Subject: Support JT/T808 temperature sensors --- src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java | 7 +++++++ src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java index fd3015e66..d010a8fe0 100644 --- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java @@ -492,6 +492,13 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_BATTERY, Integer.parseInt(lockStatus.substring(2, 5)) * 0.01); } break; + case 0x51: + if (length == 16) { + for (int i = 1; i <= 8; i++) { + position.set(Position.PREFIX_TEMP + i, buf.readShort()); + } + } + break; case 0x56: position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte() * 10); buf.readUnsignedByte(); // reserved diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java index 425c88785..2ba37ab09 100644 --- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest { var decoder = inject(new HuabaoProtocolDecoder(null)); + verifyAttribute(decoder, binary( + "7e020000520198080908740af300000000000c000f016602a302c662f802fc000000cc24051618132401040000020f30011e310109f30100610204b056020acd5d0b0102d40379b8011423033c51108017ffffffffffffffffffffffffffffc87e"), + Position.PREFIX_TEMP + 1, -32745); + verifyAttribute(decoder, binary( "7e020000460100503769640002000001000000001a01b9eaf804d8ee86001800000000240507035152010400000000300100310107eb1c00060089fffffffe000400ce0000000c00b28942310221007544309f5f7e"), Position.KEY_ICCID, "8942310221007544309"); -- cgit v1.2.3 From bb1cded19d54cd7733b6ab29240c79b9c0e1e7b7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 17 May 2024 15:28:09 -0700 Subject: Support ET01 OBD data --- src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java | 4 ++-- src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java index b10ff4c64..c3ff473bf 100644 --- a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java @@ -92,7 +92,7 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { .number("C(d+);") // coolant temperature .number("L(d+.d);") // fuel level .number("[XY][MH]d+.d+;") - .number("M(d+);") // mileage + .number("M(d+.?d*);") // mileage .number("F(d+.d+);") // fuel consumption .number("T(d+);") // engine time .any() @@ -264,7 +264,7 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ENGINE_LOAD, parser.nextDouble()); position.set(Position.KEY_COOLANT_TEMP, parser.nextInt()); position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble()); - position.set(Position.KEY_ODOMETER, parser.nextInt()); + position.set(Position.KEY_ODOMETER, parser.nextDouble()); position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextDouble()); position.set(Position.KEY_HOURS, parser.nextInt()); diff --git a/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java index d40463c1e..fee0252b7 100644 --- a/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EasyTrackProtocolDecoderTest.java @@ -10,6 +10,9 @@ public class EasyTrackProtocolDecoderTest extends ProtocolTest { var decoder = inject(new EasyTrackProtocolDecoder(null)); + verifyAttributes(decoder, text( + "*ET,358162092884226,OB,BD$V13.6;R01510;S023;P034.9;O035.2;C085;L000.0;XM035.170;M4.25;F001.197;T0000730;A09;B00;D00;GX0;GY0;GZ0;")); + verifyAttributes(decoder, text( "*ET,358999999999916,OB,BD$V14.2;R08258;S166;P058.4;O079.2;C025;L081.5;XM091.393;M722379;F352.956;T0037184;A01;B00;D00;GX3;GY-6;GZ-268;@4#")); -- cgit v1.2.3 From 445a2c5d0763bb42880ff1f9db93d755f6fdfa62 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 20 May 2024 07:01:49 -0700 Subject: Filter announcement channels --- .../java/org/traccar/api/resource/NotificationResource.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java index 5eb9f6c62..a41d00cf3 100644 --- a/src/main/java/org/traccar/api/resource/NotificationResource.java +++ b/src/main/java/org/traccar/api/resource/NotificationResource.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. @@ -46,6 +46,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; @Path("notifications") @Produces(MediaType.APPLICATION_JSON) @@ -80,8 +82,11 @@ public class NotificationResource extends ExtendedObjectResource { @GET @Path("notificators") - public Collection getNotificators() { - return notificatorManager.getAllNotificatorTypes(); + public Collection getNotificators(@QueryParam("announcement") boolean announcement) { + Set announcementsUnsupported = Set.of("command", "web"); + return notificatorManager.getAllNotificatorTypes().stream() + .filter(typed -> !announcement || !announcementsUnsupported.contains(typed.getType())) + .collect(Collectors.toUnmodifiableSet()); } @POST -- cgit v1.2.3 From c2c27617fa4392c3a25a6c4ad62bd24060f1c0c1 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 21 May 2024 06:41:44 -0700 Subject: Handle Snapper protocol ping --- .../org/traccar/protocol/SnapperFrameDecoder.java | 44 ++++++++++++++++++++++ .../java/org/traccar/protocol/SnapperProtocol.java | 5 +-- .../traccar/protocol/SnapperProtocolDecoder.java | 10 ++++- .../traccar/protocol/SnapperFrameDecoderTest.java | 23 +++++++++++ .../protocol/SnapperProtocolDecoderTest.java | 3 ++ 5 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/traccar/protocol/SnapperFrameDecoder.java create mode 100644 src/test/java/org/traccar/protocol/SnapperFrameDecoderTest.java diff --git a/src/main/java/org/traccar/protocol/SnapperFrameDecoder.java b/src/main/java/org/traccar/protocol/SnapperFrameDecoder.java new file mode 100644 index 000000000..be45346a6 --- /dev/null +++ b/src/main/java/org/traccar/protocol/SnapperFrameDecoder.java @@ -0,0 +1,44 @@ +/* + * 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.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import org.traccar.BaseFrameDecoder; + +public class SnapperFrameDecoder extends BaseFrameDecoder { + + @Override + protected Object decode( + ChannelHandlerContext ctx, Channel channel, ByteBuf buf) throws Exception { + + byte header = buf.getByte(buf.readerIndex()); + if (header == 'P') { + if (buf.readableBytes() >= 2) { + return buf.readRetainedSlice(2); + } + } else if (buf.readableBytes() >= 16) { + int length = buf.getIntLE(buf.readerIndex() + 12) + 12 + 4 + 9; + if (buf.readableBytes() >= length) { + return buf.readRetainedSlice(length); + } + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/SnapperProtocol.java b/src/main/java/org/traccar/protocol/SnapperProtocol.java index 2e294eac6..25a11ed3a 100644 --- a/src/main/java/org/traccar/protocol/SnapperProtocol.java +++ b/src/main/java/org/traccar/protocol/SnapperProtocol.java @@ -15,15 +15,12 @@ */ package org.traccar.protocol; -import io.netty.handler.codec.LengthFieldBasedFrameDecoder; import jakarta.inject.Inject; import org.traccar.BaseProtocol; import org.traccar.PipelineBuilder; import org.traccar.TrackerServer; import org.traccar.config.Config; -import java.nio.ByteOrder; - public class SnapperProtocol extends BaseProtocol { @Inject @@ -31,7 +28,7 @@ public class SnapperProtocol extends BaseProtocol { addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { - pipeline.addLast(new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 12, 4, 9, 0, true)); + pipeline.addLast(new SnapperFrameDecoder()); pipeline.addLast(new SnapperProtocolDecoder(SnapperProtocol.this)); } }); diff --git a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java index e60736667..ef1a4426a 100644 --- a/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SnapperProtocolDecoder.java @@ -150,7 +150,15 @@ public class SnapperProtocolDecoder extends BaseProtocolDecoder { ByteBuf buf = (ByteBuf) msg; - buf.readUnsignedByte(); // header + byte header = buf.readByte(); + if (header == 'P') { + if (channel != null) { + ByteBuf response = Unpooled.wrappedBuffer(new byte[] {0x50, 0x4f}); + channel.writeAndFlush(new NetworkMessage(response, remoteAddress)); + } + return null; + } + buf.readUnsignedByte(); // protocol version buf.readUnsignedIntLE(); // system bonus identifier diff --git a/src/test/java/org/traccar/protocol/SnapperFrameDecoderTest.java b/src/test/java/org/traccar/protocol/SnapperFrameDecoderTest.java new file mode 100644 index 000000000..260a18032 --- /dev/null +++ b/src/test/java/org/traccar/protocol/SnapperFrameDecoderTest.java @@ -0,0 +1,23 @@ +package org.traccar.protocol; + +import org.junit.jupiter.api.Test; +import org.traccar.ProtocolTest; + +public class SnapperFrameDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = inject(new SnapperFrameDecoder()); + + verifyFrame( + binary("4b0341a6b0c608000040000005000000000000007d5e14010068656c6c6f"), + decoder.decode(null, null, binary("4b0341a6b0c608000040000005000000000000007d5e14010068656c6c6f"))); + + verifyFrame( + binary("5012"), + decoder.decode(null, null, binary("5012"))); + + } + +} diff --git a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java index bb79194eb..43df24316 100644 --- a/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SnapperProtocolDecoderTest.java @@ -22,6 +22,9 @@ public class SnapperProtocolDecoderTest extends ProtocolTest { verifyPosition(decoder, binary( "4b044daff87aff5b8aad0000430100000000bb870c005b37000500210008003e0100ffffffff7f2300190000007f000000018080000002deff080003404000000400000034008c007b2273223a22303034303438222c226332223a2230303030303030303030303030303030222c226132223a2230303030303030303030303030303030222c226f223a2230303030222c2274223a2230303030222c227a223a223030222c2277223a223030222c2272223a222d222c226d223a223030303030303030222c2262223a223030303030303030227d320079007b2266223a224445222c2274223a22303832303335222c2264223a22313730343234222c226c61223a22353334312e34323635222c226c6f223a2230303935342e30373935222c2261223a22362e32222c2273223a22322e3237222c2263223a2233302e3135222c227376223a223038222c2270223a22227d330007007b2262223a5d7d")); + verifyNull(decoder, binary( + "5003")); + } } -- cgit v1.2.3 From c466a8d2baea1913e5623b4dff13e8256220e648 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 May 2024 07:05:11 -0700 Subject: Remove ET OBD mileage value --- src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java index c3ff473bf..ff192807b 100644 --- a/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EasyTrackProtocolDecoder.java @@ -92,7 +92,7 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { .number("C(d+);") // coolant temperature .number("L(d+.d);") // fuel level .number("[XY][MH]d+.d+;") - .number("M(d+.?d*);") // mileage + .number("Md+.?d*;") // mileage .number("F(d+.d+);") // fuel consumption .number("T(d+);") // engine time .any() @@ -264,7 +264,6 @@ public class EasyTrackProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ENGINE_LOAD, parser.nextDouble()); position.set(Position.KEY_COOLANT_TEMP, parser.nextInt()); position.set(Position.KEY_FUEL_LEVEL, parser.nextDouble()); - position.set(Position.KEY_ODOMETER, parser.nextDouble()); position.set(Position.KEY_FUEL_CONSUMPTION, parser.nextDouble()); position.set(Position.KEY_HOURS, parser.nextInt()); -- cgit v1.2.3 From 7df59714609a62d76ca2f34f2a9d9aed9feb956b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 May 2024 16:41:52 -0700 Subject: Model-based Globalstar Atlas decoding --- .../traccar/protocol/GlobalstarProtocolDecoder.java | 19 ++++--------------- .../protocol/GlobalstarProtocolDecoderTest.java | 4 ++-- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java index b75e612b8..654071d22 100644 --- a/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/GlobalstarProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2023 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. @@ -27,7 +27,6 @@ import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.config.Keys; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -65,12 +64,6 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { private final XPath xPath; private final XPathExpression messageExpression; - private boolean alternative; - - public void setAlternative(boolean alternative) { - this.alternative = alternative; - } - public GlobalstarProtocolDecoder(Protocol protocol) { super(protocol); try { @@ -89,11 +82,6 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { } } - @Override - protected void init() { - this.alternative = getConfig().getBoolean(Keys.PROTOCOL_ALTERNATIVE.withPrefix(getProtocolName())); - } - private void sendResponse(Channel channel, String messageId) throws TransformerException { Document document = documentBuilder.newDocument(); @@ -144,6 +132,7 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, xPath.evaluate("esn", node)); if (deviceSession != null) { + boolean atlas = "AtlasTrax".equalsIgnoreCase(getDeviceModel(deviceSession)); Position position = new Position(getProtocolName()); position.setDeviceId(deviceSession.getDeviceId()); @@ -154,7 +143,7 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { int flags = buf.readUnsignedByte(); int type; - if (alternative) { + if (atlas) { type = BitUtil.to(flags, 1); position.setValid(true); position.set(Position.PREFIX_IN + 1, !BitUtil.check(flags, 1)); @@ -179,7 +168,7 @@ public class GlobalstarProtocolDecoder extends BaseHttpProtocolDecoder { position.setLongitude(longitude > 180 ? longitude - 360 : longitude); int speed = 0; - if (alternative) { + if (atlas) { speed = buf.readUnsignedByte(); position.setSpeed(UnitsConverter.knotsFromKph(speed)); position.set("batteryReplace", BitUtil.check(buf.readUnsignedByte(), 7)); diff --git a/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java index 995fffad0..e78c6c7e7 100644 --- a/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/GlobalstarProtocolDecoderTest.java @@ -11,7 +11,7 @@ public class GlobalstarProtocolDecoderTest extends ProtocolTest { var decoder = inject(new GlobalstarProtocolDecoder(null)); - decoder.setAlternative(true); + decoder.setModelOverride("AtlasTrax"); verifyNull(decoder, request(HttpMethod.POST, "/", buffer( "\n", @@ -24,7 +24,7 @@ public class GlobalstarProtocolDecoderTest extends ProtocolTest { "\n", ""))); - decoder.setAlternative(false); + decoder.setModelOverride(null); verifyPositions(decoder, request(HttpMethod.POST, "/", buffer( "", -- cgit v1.2.3 From b9445651c5b9803476d0f96702ff3a293a327e20 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 May 2024 17:27:49 -0700 Subject: Support LynkWorld driving alarms --- .../org/traccar/protocol/Gt06ProtocolDecoder.java | 26 +++++++++++++--------- .../traccar/protocol/Gt06ProtocolDecoderTest.java | 6 +++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 6c0380278..71c37b27c 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -410,7 +410,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } } - private String decodeAlarm(short value) { + private String decodeAlarm(short value, String model) { + boolean modelLW = model != null && model.startsWith("LW"); switch (value) { case 0x01: return Position.ALARM_SOS; @@ -427,7 +428,6 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { return Position.ALARM_OVERSPEED; case 0x0E: case 0x0F: - case 0x19: return Position.ALARM_LOW_BATTERY; case 0x11: return Position.ALARM_POWER_OFF; @@ -438,17 +438,21 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { case 0x14: return Position.ALARM_DOOR; case 0x18: - return Position.ALARM_REMOVING; - case 0x23: - return Position.ALARM_FALL_DOWN; + return modelLW ? Position.ALARM_ACCIDENT : Position.ALARM_REMOVING; + case 0x19: + return modelLW ? Position.ALARM_ACCELERATION : Position.ALARM_LOW_BATTERY; + case 0x1A: case 0x28: return Position.ALARM_BRAKING; - case 0x29: - return Position.ALARM_ACCELERATION; + case 0x1B: case 0x2A: case 0x2B: case 0x2E: return Position.ALARM_CORNERING; + case 0x23: + return Position.ALARM_FALL_DOWN; + case 0x29: + return Position.ALARM_ACCELERATION; case 0x2C: return Position.ALARM_ACCIDENT; case 0x30: @@ -831,7 +835,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { int satellites = BitUtil.between(signal, 10, 15) + BitUtil.between(signal, 5, 10); position.set(Position.KEY_SATELLITES, satellites); position.set(Position.KEY_RSSI, BitUtil.to(signal, 5)); - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + position.set(Position.KEY_ALARM, decodeAlarm( + buf.readUnsignedByte(), getDeviceModel(deviceSession))); buf.readUnsignedByte(); // language position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte()); buf.readUnsignedByte(); // working mode @@ -842,7 +847,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_RSSI, buf.readUnsignedByte()); short alarmExtension = buf.readUnsignedByte(); if (variant != Variant.VXT01) { - position.set(Position.KEY_ALARM, decodeAlarm(alarmExtension)); + position.set(Position.KEY_ALARM, decodeAlarm(alarmExtension, getDeviceModel(deviceSession))); } } } @@ -881,7 +886,8 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { decodeStatus(position, buf); position.set(Position.KEY_POWER, buf.readUnsignedShort() * 0.01); position.set(Position.KEY_RSSI, buf.readUnsignedByte()); - position.set(Position.KEY_ALARM, decodeAlarm(buf.readUnsignedByte())); + position.set(Position.KEY_ALARM, decodeAlarm( + buf.readUnsignedByte(), getDeviceModel(deviceSession))); position.set("oil", buf.readUnsignedShort()); int temperature = buf.readUnsignedByte(); if (BitUtil.check(temperature, 7)) { diff --git a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java index 04d7fafb3..05a33cc72 100644 --- a/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gt06ProtocolDecoderTest.java @@ -494,6 +494,12 @@ public class Gt06ProtocolDecoderTest extends ProtocolTest { "78785195140a020c2914055D4A800209D9C014009300004556454e545f3335333337363131303032333139365f30303030303030305f323032305f31305f30325f31345f34315f32305f30352e6d70340004e3a60d0a"), Position.KEY_ALARM, Position.ALARM_ACCIDENT); + decoder.setModelOverride("LW4G-4B"); + + verifyAttribute(decoder, binary( + "78782516180516150812c804b50ee80880e40805dcf909012e000000986633460604190106c393490d0a"), + Position.KEY_ALARM, Position.ALARM_ACCELERATION); + } } -- cgit v1.2.3 From bcbc08150700c2cc68d8b894bdd1dd38ad65ca62 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 23 May 2024 18:18:51 -0700 Subject: Summary report start and end hours --- .../org/traccar/reports/SummaryReportProvider.java | 9 ++++---- .../traccar/reports/model/SummaryReportItem.java | 27 +++++++++++++++++----- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/traccar/reports/SummaryReportProvider.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java index 5f155552b..5bd7e51b3 100644 --- a/src/main/java/org/traccar/reports/SummaryReportProvider.java +++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2023 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"); @@ -106,9 +106,10 @@ public class SummaryReportProvider { result.setSpentFuel(reportUtils.calculateFuel(first, last)); if (first.hasAttribute(Position.KEY_HOURS) && last.hasAttribute(Position.KEY_HOURS)) { - long durationMilliseconds = last.getLong(Position.KEY_HOURS) - first.getLong(Position.KEY_HOURS); - result.setEngineHours(durationMilliseconds); - result.setAverageSpeed(UnitsConverter.knotsFromMps(result.getDistance() * 1000 / durationMilliseconds)); + result.setStartHours(first.getLong(Position.KEY_HOURS)); + result.setEndHours(last.getLong(Position.KEY_HOURS)); + result.setAverageSpeed(UnitsConverter.knotsFromMps( + result.getDistance() * 1000 / result.getEngineHours())); } if (!ignoreOdometer diff --git a/src/main/java/org/traccar/reports/model/SummaryReportItem.java b/src/main/java/org/traccar/reports/model/SummaryReportItem.java index 44a15cf1d..b88cabe49 100644 --- a/src/main/java/org/traccar/reports/model/SummaryReportItem.java +++ b/src/main/java/org/traccar/reports/model/SummaryReportItem.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2020 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"); @@ -18,13 +18,28 @@ package org.traccar.reports.model; public class SummaryReportItem extends BaseReportItem { - private long engineHours; // milliseconds - public long getEngineHours() { - return engineHours; + return endHours - startHours; + } + + private long startHours; // milliseconds + + public long getStartHours() { + return startHours; + } + + public void setStartHours(long startHours) { + this.startHours = startHours; } - public void setEngineHours(long engineHours) { - this.engineHours = engineHours; + private long endHours; // milliseconds + + public long getEndHours() { + return endHours; } + + public void setEndHours(long endHours) { + this.endHours = endHours; + } + } -- cgit v1.2.3 From 248a3927ddd6606034ac10d2174946c84fee04f0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 24 May 2024 14:31:57 -0700 Subject: Ignore model name case --- src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java index 71c37b27c..a1a9c3773 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolDecoder.java @@ -411,7 +411,7 @@ public class Gt06ProtocolDecoder extends BaseProtocolDecoder { } private String decodeAlarm(short value, String model) { - boolean modelLW = model != null && model.startsWith("LW"); + boolean modelLW = model != null && model.toUpperCase().startsWith("LW"); switch (value) { case 0x01: return Position.ALARM_SOS; -- cgit v1.2.3 From 4ebc4c6ee6539af45aacf284e331de1fd79b0d0c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 27 May 2024 16:24:14 -0700 Subject: Add computed attributes priority --- schema/changelog-6.2.xml | 6 ++++++ .../java/org/traccar/handler/ComputedAttributesHandler.java | 7 +++++-- src/main/java/org/traccar/model/Attribute.java | 10 ++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/schema/changelog-6.2.xml b/schema/changelog-6.2.xml index 471987d12..568d9a3a0 100644 --- a/schema/changelog-6.2.xml +++ b/schema/changelog-6.2.xml @@ -11,6 +11,12 @@ + + + + + + diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java index 7c2fd70a5..d286866a5 100644 --- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java +++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java @@ -35,13 +35,14 @@ import org.traccar.session.cache.CacheManager; 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.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Date; +import java.util.stream.Collectors; public class ComputedAttributesHandler extends BasePositionHandler { @@ -140,7 +141,9 @@ public class ComputedAttributesHandler extends BasePositionHandler { @Override public void handlePosition(Position position, Callback callback) { - Collection attributes = cacheManager.getDeviceObjects(position.getDeviceId(), Attribute.class); + var attributes = cacheManager.getDeviceObjects(position.getDeviceId(), Attribute.class).stream() + .sorted(Comparator.comparing(Attribute::getPriority).reversed()) + .collect(Collectors.toUnmodifiableList()); for (Attribute attribute : attributes) { if (attribute.getAttribute() != null) { Object result = null; diff --git a/src/main/java/org/traccar/model/Attribute.java b/src/main/java/org/traccar/model/Attribute.java index 65f2e3881..573207170 100644 --- a/src/main/java/org/traccar/model/Attribute.java +++ b/src/main/java/org/traccar/model/Attribute.java @@ -61,4 +61,14 @@ public class Attribute extends BaseModel { this.type = type; } + private int priority; + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + } -- cgit v1.2.3 From 1ed6886245859754efac76ba8cc412d3ec61523b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 29 May 2024 17:35:48 -0700 Subject: Allow regular users edit accumulators --- src/main/java/org/traccar/api/resource/DeviceResource.java | 8 +++----- src/main/java/org/traccar/helper/LogAction.java | 8 ++++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 56253152f..971c29c60 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -137,10 +137,8 @@ public class DeviceResource extends BaseObjectResource { @Path("{id}/accumulators") @PUT public Response updateAccumulators(DeviceAccumulators entity) throws Exception { - if (permissionsService.notAdmin(getUserId())) { - permissionsService.checkManager(getUserId()); - permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); - } + permissionsService.checkEdit(getUserId(), Device.class, false); + permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); Position position = storage.getObject(Position.class, new Request( new Columns.All(), new Condition.LatestPositions(entity.getDeviceId()))); @@ -171,7 +169,7 @@ public class DeviceResource extends BaseObjectResource { throw new IllegalArgumentException(); } - LogAction.resetDeviceAccumulators(getUserId(), entity.getDeviceId()); + LogAction.resetAccumulators(getUserId(), entity.getDeviceId()); return Response.noContent().build(); } diff --git a/src/main/java/org/traccar/helper/LogAction.java b/src/main/java/org/traccar/helper/LogAction.java index efb02b340..adbe33916 100644 --- a/src/main/java/org/traccar/helper/LogAction.java +++ b/src/main/java/org/traccar/helper/LogAction.java @@ -43,13 +43,13 @@ public final class LogAction { private static final String ACTION_LOGIN = "login"; private static final String ACTION_LOGOUT = "logout"; - private static final String ACTION_DEVICE_ACCUMULATORS = "resetDeviceAccumulators"; + private static final String ACTION_ACCUMULATORS = "accumulators"; private static final String PATTERN_OBJECT = "user: %d, action: %s, object: %s, id: %d"; private static final String PATTERN_LINK = "user: %d, action: %s, owner: %s, id: %d, property: %s, id: %d"; private static final String PATTERN_LOGIN = "user: %d, action: %s, from: %s"; private static final String PATTERN_LOGIN_FAILED = "login failed from: %s"; - private static final String PATTERN_DEVICE_ACCUMULATORS = "user: %d, action: %s, deviceId: %d"; + private static final String PATTERN_ACCUMULATORS = "user: %d, action: %s, deviceId: %d"; private static final String PATTERN_REPORT = "user: %d, %s: %s, from: %s, to: %s, devices: %s, groups: %s"; public static void create(long userId, BaseModel object) { @@ -87,9 +87,9 @@ public final class LogAction { LOGGER.info(String.format(PATTERN_LOGIN_FAILED, remoteAddress)); } - public static void resetDeviceAccumulators(long userId, long deviceId) { + public static void resetAccumulators(long userId, long deviceId) { LOGGER.info(String.format( - PATTERN_DEVICE_ACCUMULATORS, userId, ACTION_DEVICE_ACCUMULATORS, deviceId)); + PATTERN_ACCUMULATORS, userId, ACTION_ACCUMULATORS, deviceId)); } private static void logObjectAction(String action, long userId, Class clazz, long objectId) { -- cgit v1.2.3 From c5833f49feae54b453d667ea02a82fada43a7d46 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 30 May 2024 18:24:06 -0700 Subject: Add Suntech universal serial type --- .../traccar/protocol/SuntechProtocolDecoder.java | 158 +++++++++++---------- .../protocol/SuntechProtocolDecoderTest.java | 4 + 2 files changed, 89 insertions(+), 73 deletions(-) diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java index 53c4a5d02..c9d6f16ef 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -295,6 +295,60 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { return position; } + private int decodeSerialData(Position position, String[] values, int index) { + + int remaining = Integer.parseInt(values[index++]); + double totalFuel = 0; + while (remaining > 0) { + String attribute = values[index++]; + if (attribute.startsWith("CabAVL")) { + String[] data = attribute.split(","); + double fuel1 = Double.parseDouble(data[2]); + if (fuel1 > 0) { + totalFuel += fuel1; + position.set("fuel1", fuel1); + } + double fuel2 = Double.parseDouble(data[3]); + if (fuel2 > 0) { + totalFuel += fuel2; + position.set("fuel2", fuel2); + } + } else if (attribute.startsWith("GTSL")) { + position.set(Position.KEY_DRIVER_UNIQUE_ID, attribute.split("\\|")[4]); + } else if (attribute.contains("=")) { + String[] pair = attribute.split("="); + if (pair.length >= 2) { + String value = pair[1].trim(); + if (value.contains(".")) { + value = value.substring(0, value.indexOf('.')); + } + switch (pair[0].charAt(0)) { + case 't': + position.set(Position.PREFIX_TEMP + pair[0].charAt(2), Integer.parseInt(value, 16)); + break; + case 'N': + int fuel = Integer.parseInt(value, 16); + totalFuel += fuel; + position.set("fuel" + pair[0].charAt(2), fuel); + break; + case 'Q': + position.set("drivingQuality", Integer.parseInt(value, 16)); + break; + default: + break; + } + } + } else { + position.set("serial", attribute.trim()); + } + remaining -= attribute.length() + 1; + } + if (totalFuel > 0) { + position.set(Position.KEY_FUEL_LEVEL, totalFuel); + } + return index + 1; // checksum + } + private Position decode2356( Channel channel, SocketAddress remoteAddress, String protocol, String[] values) throws ParseException { int index = 0; @@ -371,56 +425,7 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_ALARM, decodeAlert(Integer.parseInt(values[index++]))); break; case "UEX": - int remaining = Integer.parseInt(values[index++]); - double totalFuel = 0; - while (remaining > 0) { - String attribute = values[index++]; - if (attribute.startsWith("CabAVL")) { - String[] data = attribute.split(","); - double fuel1 = Double.parseDouble(data[2]); - if (fuel1 > 0) { - totalFuel += fuel1; - position.set("fuel1", fuel1); - } - double fuel2 = Double.parseDouble(data[3]); - if (fuel2 > 0) { - totalFuel += fuel2; - position.set("fuel2", fuel2); - } - } else if (attribute.startsWith("GTSL")) { - position.set(Position.KEY_DRIVER_UNIQUE_ID, attribute.split("\\|")[4]); - } else if (attribute.contains("=")) { - String[] pair = attribute.split("="); - if (pair.length >= 2) { - String value = pair[1].trim(); - if (value.contains(".")) { - value = value.substring(0, value.indexOf('.')); - } - switch (pair[0].charAt(0)) { - case 't': - position.set(Position.PREFIX_TEMP + pair[0].charAt(2), Integer.parseInt(value, 16)); - break; - case 'N': - int fuel = Integer.parseInt(value, 16); - totalFuel += fuel; - position.set("fuel" + pair[0].charAt(2), fuel); - break; - case 'Q': - position.set("drivingQuality", Integer.parseInt(value, 16)); - break; - default: - break; - } - } - } else { - position.set("serial", attribute.trim()); - } - remaining -= attribute.length() + 1; - } - if (totalFuel > 0) { - position.set(Position.KEY_FUEL_LEVEL, totalFuel); - } - index += 1; // checksum + index = decodeSerialData(position, values, index); break; default: break; @@ -482,7 +487,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { String type = values[index++]; - if (!type.equals("STT") && !type.equals("ALT") && !type.equals("BLE") && !type.equals("RES")) { + if (!type.equals("STT") && !type.equals("ALT") && !type.equals("BLE") && !type.equals("RES") + && !type.equals("UEX")) { return null; } @@ -601,34 +607,40 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { position.set(Position.KEY_OUTPUT, Integer.parseInt(values[index++])); } - if (type.equals("ALT")) { - if (BitUtil.check(mask, 19)) { - int alertId = Integer.parseInt(values[index++]); - position.set(Position.KEY_ALARM, decodeAlert(alertId)); - } - if (BitUtil.check(mask, 20)) { - position.set("alertModifier", values[index++]); - } - if (BitUtil.check(mask, 21)) { - position.set("alertData", values[index++]); - } - } else { - if (BitUtil.check(mask, 19)) { - position.set("mode", Integer.parseInt(values[index++])); - } - if (BitUtil.check(mask, 20)) { - position.set("reason", Integer.parseInt(values[index++])); - } - if (BitUtil.check(mask, 21)) { - position.set(Position.KEY_INDEX, Integer.parseInt(values[index++])); - } + switch (type) { + case "ALT": + if (BitUtil.check(mask, 19)) { + int alertId = Integer.parseInt(values[index++]); + position.set(Position.KEY_ALARM, decodeAlert(alertId)); + } + if (BitUtil.check(mask, 20)) { + position.set("alertModifier", values[index++]); + } + if (BitUtil.check(mask, 21)) { + position.set("alertData", values[index++]); + } + break; + case "UEX": + index = decodeSerialData(position, values, index); + break; + default: + if (BitUtil.check(mask, 19)) { + position.set("mode", Integer.parseInt(values[index++])); + } + if (BitUtil.check(mask, 20)) { + position.set("reason", Integer.parseInt(values[index++])); + } + if (BitUtil.check(mask, 21)) { + position.set(Position.KEY_INDEX, Integer.parseInt(values[index++])); + } + break; } if (BitUtil.check(mask, 22)) { index += 1; // reserved } - if (BitUtil.check(mask, 23)) { + if (BitUtil.check(mask, 23) && !type.equals("UEX")) { int assignMask = Integer.parseInt(values[index++], 16); for (int i = 0; i <= 30; i++) { if (BitUtil.check(assignMask, i)) { diff --git a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java index d656bba13..67fa43dec 100644 --- a/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/SuntechProtocolDecoderTest.java @@ -12,6 +12,10 @@ public class SuntechProtocolDecoderTest extends ProtocolTest { var decoder = inject(new SuntechProtocolDecoder(null)); + verifyAttribute(decoder, buffer( + "UEX;1610020241;03FFFFFF;161;3.0.9;0;20240506;15:52:55;00006697;724;11;4EDA;33;-5.129240;-42.797868;0.00;0.00;11;1;00000001;00000000;24;GTSL|6|1|0|22574684|1|\r\n;A7;;164;0;11.82"), + Position.KEY_DRIVER_UNIQUE_ID, "22574684"); + verifyAttributes(decoder, buffer( "ST410STT;109815653;445;03;16531;724;10;-77;6011;7;16273;724;10;7511;0;0;13903;724;10;6011;0;0;7671;724;10;7111;0;0;16533;724;10;6011;0;0;0;0;0;0;0;0;0;0;0;0;0;0;3.86;0;0098;1;003;;;;;;;;;")); -- cgit v1.2.3 From 6bfcdcc8640cac20900383dd38b55cfe9225a567 Mon Sep 17 00:00:00 2001 From: jcardus Date: Sat, 1 Jun 2024 01:59:59 +0100 Subject: check time > 0 in speed filter --- src/main/java/org/traccar/handler/FilterHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 3bb7ef426..700fdbc13 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -153,7 +153,7 @@ public class FilterHandler extends BasePositionHandler { if (filterMaxSpeed != 0 && last != null) { double distance = position.getDouble(Position.KEY_DISTANCE); double time = position.getFixTime().getTime() - last.getFixTime().getTime(); - return UnitsConverter.knotsFromMps(distance / (time / 1000)) > filterMaxSpeed; + return time > 0 && UnitsConverter.knotsFromMps(distance / (time / 1000)) > filterMaxSpeed; } return false; } -- cgit v1.2.3 From 78770c3ddc9f0073e1993e6a635e2f469d940216 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 06:41:11 -0700 Subject: Fix log formatting --- src/main/java/org/traccar/Main.java | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java index 943b5bd7d..a22194d9e 100644 --- a/src/main/java/org/traccar/Main.java +++ b/src/main/java/org/traccar/Main.java @@ -52,23 +52,22 @@ public final class Main { public static void logSystemInfo() { try { OperatingSystemMXBean operatingSystemBean = ManagementFactory.getOperatingSystemMXBean(); - LOGGER.info("Operating system" - + " name: " + operatingSystemBean.getName() - + " version: " + operatingSystemBean.getVersion() - + " architecture: " + operatingSystemBean.getArch()); + LOGGER.info( + "Operating system name: {} version: {} architecture: {}", + operatingSystemBean.getName(), operatingSystemBean.getVersion(), operatingSystemBean.getArch()); RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); - LOGGER.info("Java runtime" - + " name: " + runtimeBean.getVmName() - + " vendor: " + runtimeBean.getVmVendor() - + " version: " + runtimeBean.getVmVersion()); + LOGGER.info( + "Java runtime name: {} vendor: {} version: {}", + runtimeBean.getVmName(), runtimeBean.getVmVendor(), runtimeBean.getVmVersion()); MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); - LOGGER.info("Memory limit" - + " heap: " + memoryBean.getHeapMemoryUsage().getMax() / (1024 * 1024) + "mb" - + " non-heap: " + memoryBean.getNonHeapMemoryUsage().getMax() / (1024 * 1024) + "mb"); + LOGGER.info( + "Memory limit heap: {}mb non-heap: {}mb", + memoryBean.getHeapMemoryUsage().getMax() / (1024 * 1024), + memoryBean.getNonHeapMemoryUsage().getMax() / (1024 * 1024)); - LOGGER.info("Character encoding: " + Charset.defaultCharset().displayName()); + LOGGER.info("Character encoding: {}", Charset.defaultCharset().displayName()); } catch (Exception error) { LOGGER.warn("Failed to get system info"); @@ -116,7 +115,7 @@ public final class Main { try { injector = Guice.createInjector(new MainModule(configFile), new DatabaseModule(), new WebModule()); logSystemInfo(); - LOGGER.info("Version: " + Main.class.getPackage().getImplementationVersion()); + LOGGER.info("Version: {}", Main.class.getPackage().getImplementationVersion()); LOGGER.info("Starting server..."); var services = new ArrayList(); -- cgit v1.2.3 From c2db7d421cfeead820cc58598e8a91fe84cf0286 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 07:00:13 -0700 Subject: Add final keyword --- src/main/java/org/traccar/EventLoopGroupFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/EventLoopGroupFactory.java b/src/main/java/org/traccar/EventLoopGroupFactory.java index 482559253..5c6fb7459 100644 --- a/src/main/java/org/traccar/EventLoopGroupFactory.java +++ b/src/main/java/org/traccar/EventLoopGroupFactory.java @@ -20,8 +20,8 @@ import io.netty.channel.nio.NioEventLoopGroup; public final class EventLoopGroupFactory { - private static EventLoopGroup bossGroup = new NioEventLoopGroup(); - private static EventLoopGroup workerGroup = new NioEventLoopGroup(); + private static final EventLoopGroup bossGroup = new NioEventLoopGroup(); + private static final EventLoopGroup workerGroup = new NioEventLoopGroup(); private EventLoopGroupFactory() { } -- cgit v1.2.3 From a75b3d82cda411c0a431c4fbfcaa4da3feea1131 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 07:02:56 -0700 Subject: Fix code style --- src/main/java/org/traccar/EventLoopGroupFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/EventLoopGroupFactory.java b/src/main/java/org/traccar/EventLoopGroupFactory.java index 5c6fb7459..edad4e3ff 100644 --- a/src/main/java/org/traccar/EventLoopGroupFactory.java +++ b/src/main/java/org/traccar/EventLoopGroupFactory.java @@ -20,8 +20,8 @@ import io.netty.channel.nio.NioEventLoopGroup; public final class EventLoopGroupFactory { - private static final EventLoopGroup bossGroup = new NioEventLoopGroup(); - private static final EventLoopGroup workerGroup = new NioEventLoopGroup(); + private final static EventLoopGroup bossGroup = new NioEventLoopGroup(); + private final static EventLoopGroup workerGroup = new NioEventLoopGroup(); private EventLoopGroupFactory() { } -- cgit v1.2.3 From 13b7eff68004fdc03ed4f754d65fcda1bf4f2231 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 07:34:20 -0700 Subject: Option to reboot server --- src/main/java/org/traccar/api/resource/ServerResource.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 2a72d2773..eb10ac763 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -161,4 +161,11 @@ public class ServerResource extends BaseResource { return cacheManager.toString(); } + @Path("reboot") + @POST + public void reboot() throws StorageException { + permissionsService.checkAdmin(getUserId()); + System.exit(130); + } + } -- cgit v1.2.3 From c21ca48b6b255cde193efb476f83b1fac5c894f2 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 07:41:22 -0700 Subject: Fix style issues --- src/main/java/org/traccar/EventLoopGroupFactory.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/traccar/EventLoopGroupFactory.java b/src/main/java/org/traccar/EventLoopGroupFactory.java index edad4e3ff..4087b9a02 100644 --- a/src/main/java/org/traccar/EventLoopGroupFactory.java +++ b/src/main/java/org/traccar/EventLoopGroupFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2018 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. @@ -20,18 +20,18 @@ import io.netty.channel.nio.NioEventLoopGroup; public final class EventLoopGroupFactory { - private final static EventLoopGroup bossGroup = new NioEventLoopGroup(); - private final static EventLoopGroup workerGroup = new NioEventLoopGroup(); + private final static EventLoopGroup BOSS_GROUP = new NioEventLoopGroup(); + private final static EventLoopGroup WORKER_GROUP = new NioEventLoopGroup(); private EventLoopGroupFactory() { } public static EventLoopGroup getBossGroup() { - return bossGroup; + return BOSS_GROUP; } public static EventLoopGroup getWorkerGroup() { - return workerGroup; + return WORKER_GROUP; } } -- cgit v1.2.3 From 8b46ee99757a0c0c02051bba07679a2c37be08e7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 07:57:30 -0700 Subject: Log command actions --- .../org/traccar/api/resource/CommandResource.java | 3 +++ .../org/traccar/api/resource/ReportResource.java | 22 +++++++-------- src/main/java/org/traccar/helper/LogAction.java | 31 +++++++++++++++------- .../java/org/traccar/schedule/TaskReports.java | 2 +- 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java index c23d91e77..66ec0f8a3 100644 --- a/src/main/java/org/traccar/api/resource/CommandResource.java +++ b/src/main/java/org/traccar/api/resource/CommandResource.java @@ -23,6 +23,7 @@ import org.traccar.BaseProtocol; import org.traccar.ServerManager; import org.traccar.api.ExtendedObjectResource; import org.traccar.database.CommandsManager; +import org.traccar.helper.LogAction; import org.traccar.helper.model.DeviceUtil; import org.traccar.model.Command; import org.traccar.model.Device; @@ -140,6 +141,8 @@ public class CommandResource extends ExtendedObjectResource { return Response.accepted(queuedCommand).build(); } } + + LogAction.command(getUserId(), groupId, entity.getDeviceId(), entity.getType()); return Response.ok(entity).build(); } diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java index 2ed119298..81f409c0f 100644 --- a/src/main/java/org/traccar/api/resource/ReportResource.java +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -113,7 +113,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), false, "combined", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "combined", from, to, deviceIds, groupIds); return combinedReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -125,7 +125,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), false, "route", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "route", from, to, deviceIds, groupIds); return routeReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -140,7 +140,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("mail") boolean mail) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { - LogAction.logReport(getUserId(), false, "route", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "route", from, to, deviceIds, groupIds); routeReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to); }); } @@ -166,7 +166,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), false, "events", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "events", from, to, deviceIds, groupIds); return eventsReportProvider.getObjects(getUserId(), deviceIds, groupIds, types, from, to); } @@ -182,7 +182,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("mail") boolean mail) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { - LogAction.logReport(getUserId(), false, "events", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "events", from, to, deviceIds, groupIds); eventsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, types, from, to); }); } @@ -209,7 +209,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("to") Date to, @QueryParam("daily") boolean daily) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), false, "summary", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "summary", from, to, deviceIds, groupIds); return summaryReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to, daily); } @@ -225,7 +225,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("mail") boolean mail) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { - LogAction.logReport(getUserId(), false, "summary", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "summary", from, to, deviceIds, groupIds); summaryReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to, daily); }); } @@ -251,7 +251,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), false, "trips", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "trips", from, to, deviceIds, groupIds); return tripsReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -266,7 +266,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("mail") boolean mail) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { - LogAction.logReport(getUserId(), false, "trips", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "trips", from, to, deviceIds, groupIds); tripsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to); }); } @@ -291,7 +291,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - LogAction.logReport(getUserId(), false, "stops", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "stops", from, to, deviceIds, groupIds); return stopsReportProvider.getObjects(getUserId(), deviceIds, groupIds, from, to); } @@ -306,7 +306,7 @@ public class ReportResource extends SimpleObjectResource { @QueryParam("mail") boolean mail) throws StorageException { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); return executeReport(getUserId(), mail, stream -> { - LogAction.logReport(getUserId(), false, "stops", from, to, deviceIds, groupIds); + LogAction.report(getUserId(), false, "stops", from, to, deviceIds, groupIds); stopsReportProvider.getExcel(stream, getUserId(), deviceIds, groupIds, from, to); }); } diff --git a/src/main/java/org/traccar/helper/LogAction.java b/src/main/java/org/traccar/helper/LogAction.java index adbe33916..3c4b69a2e 100644 --- a/src/main/java/org/traccar/helper/LogAction.java +++ b/src/main/java/org/traccar/helper/LogAction.java @@ -44,12 +44,15 @@ public final class LogAction { private static final String ACTION_LOGOUT = "logout"; private static final String ACTION_ACCUMULATORS = "accumulators"; + private static final String ACTION_COMMAND = "command"; private static final String PATTERN_OBJECT = "user: %d, action: %s, object: %s, id: %d"; private static final String PATTERN_LINK = "user: %d, action: %s, owner: %s, id: %d, property: %s, id: %d"; private static final String PATTERN_LOGIN = "user: %d, action: %s, from: %s"; private static final String PATTERN_LOGIN_FAILED = "login failed from: %s"; private static final String PATTERN_ACCUMULATORS = "user: %d, action: %s, deviceId: %d"; + private static final String PATTERN_COMMAND_DEVICE = "user: %d, action: %s, deviceId: %d, type: %s"; + private static final String PATTERN_COMMAND_GROUP = "user: %d, action: %s, groupId: %d, type: %s"; private static final String PATTERN_REPORT = "user: %d, %s: %s, from: %s, to: %s, devices: %s, groups: %s"; public static void create(long userId, BaseModel object) { @@ -92,6 +95,24 @@ public final class LogAction { PATTERN_ACCUMULATORS, userId, ACTION_ACCUMULATORS, deviceId)); } + public static void command(long userId, long groupId, long deviceId, String type) { + if (groupId > 0) { + LOGGER.info(String.format(PATTERN_COMMAND_GROUP, userId, ACTION_COMMAND, groupId, type)); + } else { + LOGGER.info(String.format(PATTERN_COMMAND_DEVICE, userId, ACTION_COMMAND, deviceId, type)); + } + } + + public static void report( + long userId, boolean scheduled, String report, + Date from, Date to, List deviceIds, List groupIds) { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + LOGGER.info(String.format( + PATTERN_REPORT, userId, scheduled ? "scheduled" : "report", report, + dateFormat.format(from), dateFormat.format(to), + deviceIds.toString(), groupIds.toString())); + } + private static void logObjectAction(String action, long userId, Class clazz, long objectId) { LOGGER.info(String.format( PATTERN_OBJECT, userId, action, Introspector.decapitalize(clazz.getSimpleName()), objectId)); @@ -112,14 +133,4 @@ public final class LogAction { LOGGER.info(String.format(PATTERN_LOGIN, userId, action, remoteAddress)); } - public static void logReport( - long userId, boolean scheduled, String report, - Date from, Date to, List deviceIds, List groupIds) { - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - LOGGER.info(String.format( - PATTERN_REPORT, userId, scheduled ? "scheduled" : "report", report, - dateFormat.format(from), dateFormat.format(to), - deviceIds.toString(), groupIds.toString())); - } - } diff --git a/src/main/java/org/traccar/schedule/TaskReports.java b/src/main/java/org/traccar/schedule/TaskReports.java index 1d074214c..070fa9d2b 100644 --- a/src/main/java/org/traccar/schedule/TaskReports.java +++ b/src/main/java/org/traccar/schedule/TaskReports.java @@ -114,7 +114,7 @@ public class TaskReports implements ScheduleTask { ReportMailer reportMailer = injector.getInstance(ReportMailer.class); for (User user : users) { - LogAction.logReport(user.getId(), true, report.getType(), from, to, deviceIds, groupIds); + LogAction.report(user.getId(), true, report.getType(), from, to, deviceIds, groupIds); switch (report.getType()) { case "events": var eventsReportProvider = injector.getInstance(EventsReportProvider.class); -- cgit v1.2.3 From 20983b9549388f02c609fb91db82f171b0c4efee Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 08:01:56 -0700 Subject: Fix style issues --- src/main/java/org/traccar/EventLoopGroupFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/traccar/EventLoopGroupFactory.java b/src/main/java/org/traccar/EventLoopGroupFactory.java index 4087b9a02..7f596cd83 100644 --- a/src/main/java/org/traccar/EventLoopGroupFactory.java +++ b/src/main/java/org/traccar/EventLoopGroupFactory.java @@ -20,8 +20,8 @@ import io.netty.channel.nio.NioEventLoopGroup; public final class EventLoopGroupFactory { - private final static EventLoopGroup BOSS_GROUP = new NioEventLoopGroup(); - private final static EventLoopGroup WORKER_GROUP = new NioEventLoopGroup(); + private static final EventLoopGroup BOSS_GROUP = new NioEventLoopGroup(); + private static final EventLoopGroup WORKER_GROUP = new NioEventLoopGroup(); private EventLoopGroupFactory() { } -- cgit v1.2.3 From d83502ac2885c64a9d65a17e1573dedc9b0680d4 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 13:44:30 -0700 Subject: Remove sanitization option --- build.gradle | 1 - src/main/java/org/traccar/MainModule.java | 6 +-- src/main/java/org/traccar/config/Keys.java | 8 ---- .../java/org/traccar/helper/SanitizerModule.java | 45 ---------------------- 4 files changed, 1 insertion(+), 59 deletions(-) delete mode 100644 src/main/java/org/traccar/helper/SanitizerModule.java diff --git a/build.gradle b/build.gradle index 77fe9ec36..c24e25843 100644 --- a/build.gradle +++ b/build.gradle @@ -53,7 +53,6 @@ dependencies { 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" implementation "org.glassfish:jakarta.json:2.0.1" implementation "com.sun.mail:jakarta.mail:2.0.1" implementation "org.eclipse.jetty:jetty-server:$jettyVersion" diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 89d3d2fe0..66238ab44 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -79,7 +79,6 @@ 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; import org.traccar.mail.LogMailManager; import org.traccar.mail.MailManager; @@ -132,11 +131,8 @@ public class MainModule extends AbstractModule { @Singleton @Provides - public static ObjectMapper provideObjectMapper(Config config) { + public static ObjectMapper provideObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); - if (config.getBoolean(Keys.WEB_SANITIZE)) { - objectMapper.registerModule(new SanitizerModule()); - } objectMapper.registerModule(new JSONPModule()); objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); return objectMapper; diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 5d9a43c01..91d5dac5d 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -774,14 +774,6 @@ public final class Keys { List.of(KeyType.CONFIG), 600); - /** - * Sanitize all strings returned via API. This is needed to fix XSS issues in the old web interface. New React-based - * interface doesn't require this. - */ - public static final ConfigKey WEB_SANITIZE = new BooleanConfigKey( - "web.sanitize", - List.of(KeyType.CONFIG)); - /** * Path to the web app folder. */ diff --git a/src/main/java/org/traccar/helper/SanitizerModule.java b/src/main/java/org/traccar/helper/SanitizerModule.java deleted file mode 100644 index af9ac5c2b..000000000 --- a/src/main/java/org/traccar/helper/SanitizerModule.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 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.helper; - -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; -import org.owasp.encoder.Encode; - -import java.io.IOException; - -public class SanitizerModule extends SimpleModule { - - public static class SanitizerSerializer extends StdSerializer { - - protected SanitizerSerializer() { - super(String.class); - } - - @Override - public void serialize(String value, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeString(Encode.forHtml(value)); - } - - } - - public SanitizerModule() { - addSerializer(new SanitizerSerializer()); - } - -} -- cgit v1.2.3 From 5547c8be4fc06a6c84455b7d8fb1f884853a41c0 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 13:55:45 -0700 Subject: Update Java dependencies --- build.gradle | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/build.gradle b/build.gradle index c24e25843..231012d25 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ compileJava.options.encoding = "UTF-8" jar.destinationDirectory = file("$projectDir/target") checkstyle { - toolVersion = "10.15.0" + toolVersion = "10.17.0" configFile = "gradle/checkstyle.xml" as File checkstyleTest.enabled = false } @@ -27,10 +27,10 @@ enforce { ext { guiceVersion = "7.0.0" - jettyVersion = "11.0.20" - jerseyVersion = "3.1.5" - jacksonVersion = "2.15.3" // same version as jersey-media-json-jackson dependency - protobufVersion = "4.26.1" + jettyVersion = "11.0.21" + jerseyVersion = "3.1.7" + jacksonVersion = "2.17.1" // same version as jersey-media-json-jackson dependency + protobufVersion = "4.27.0" jxlsVersion = "2.14.0" // version 3 requires java 17 junitVersion = "5.10.2" } @@ -42,15 +42,15 @@ protobuf { } dependencies { - implementation "commons-codec:commons-codec:1.16.1" + implementation "commons-codec:commons-codec:1.17.0" implementation "com.h2database:h2:2.2.224" - implementation "com.mysql:mysql-connector-j:8.3.0" - implementation "org.mariadb.jdbc:mariadb-java-client:3.3.3" + implementation "com.mysql:mysql-connector-j:8.4.0" + implementation "org.mariadb.jdbc:mariadb-java-client:3.4.0" implementation "org.postgresql:postgresql:42.7.3" - implementation "com.microsoft.sqlserver:mssql-jdbc:12.6.1.jre11" + implementation "com.microsoft.sqlserver:mssql-jdbc:12.6.2.jre11" implementation "com.zaxxer:HikariCP:5.1.0" - implementation "io.netty:netty-all:4.1.108.Final" - implementation "org.slf4j:slf4j-jdk14:2.0.12" + implementation "io.netty:netty-all:4.1.110.Final" + implementation "org.slf4j:slf4j-jdk14:2.0.13" implementation "com.google.inject:guice:$guiceVersion" implementation "com.google.inject.extensions:guice-servlet:$guiceVersion" implementation "org.glassfish:jakarta.json:2.0.1" @@ -65,7 +65,7 @@ dependencies { implementation "org.glassfish.jersey.containers:jersey-container-servlet:$jerseyVersion" implementation "org.glassfish.jersey.media:jersey-media-json-jackson:$jerseyVersion" implementation "org.glassfish.jersey.inject:jersey-hk2:$jerseyVersion" - implementation "org.glassfish.hk2:guice-bridge:3.0.5" // same version as jersey-hk2 + implementation "org.glassfish.hk2:guice-bridge:3.1.0" // same version as jersey-hk2 implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion" implementation "com.fasterxml.jackson.datatype:jackson-datatype-jakarta-jsonp:$jacksonVersion" implementation "org.liquibase:liquibase-core:4.23.2" // upgrade has issues @@ -75,24 +75,24 @@ 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.17" + implementation "org.mnode.ical4j:ical4j:3.2.18" 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.19" implementation "com.google.protobuf:protobuf-java:$protobufVersion" - implementation "com.amazonaws:aws-java-sdk-sns:1.12.694" + implementation "com.amazonaws:aws-java-sdk-sns:1.12.733" implementation "org.apache.kafka:kafka-clients:3.7.0" implementation "com.hivemq:hivemq-mqtt-client:1.3.3" - implementation "redis.clients:jedis:5.1.2" - implementation "com.google.firebase:firebase-admin:9.2.0" - implementation "com.nimbusds:oauth2-oidc-sdk:11.10.1" - implementation "com.rabbitmq:amqp-client:5.20.0" + implementation "redis.clients:jedis:5.1.3" + implementation "com.google.firebase:firebase-admin:9.3.0" + implementation "com.nimbusds:oauth2-oidc-sdk:11.12" + implementation "com.rabbitmq:amqp-client:5.21.0" implementation "com.warrenstrange:googleauth:1.5.0" - implementation 'com.google.openlocationcode:openlocationcode:1.0.4' + implementation "com.google.openlocationcode:openlocationcode:1.0.4" testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-engine:$junitVersion" - testImplementation "org.mockito:mockito-core:5.11.0" + testImplementation "org.mockito:mockito-core:5.12.0" } test { -- cgit v1.2.3 From 7d6729694e094a21b5c3c35f9c97bb2c432c5748 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 14:06:15 -0700 Subject: Update gradle and wrapper versions --- gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 43453 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 41 +++++++++++++++++++++---------- gradlew.bat | 35 ++++++++++++++------------ 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a4..e6441136f 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ae04661ee..0d1842103 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c78733..b740cf133 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +214,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd32c..25da30dbd 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal -- cgit v1.2.3 From 040066dc87fa9845726f9e8646c8a5ad9b95e22a Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 14:07:18 -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 231012d25..1964d051a 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,7 @@ jar { manifest { attributes( "Main-Class": "org.traccar.Main", - "Implementation-Version": "6.1", + "Implementation-Version": "6.2", "Class-Path": configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(" ")) } } diff --git a/setup/traccar.iss b/setup/traccar.iss index 0f5f1687e..ad8e2552b 100644 --- a/setup/traccar.iss +++ b/setup/traccar.iss @@ -1,6 +1,6 @@ [Setup] AppName=Traccar -AppVersion=6.1 +AppVersion=6.2 DefaultDirName={pf}\Traccar OutputBaseFilename=traccar-setup ArchitecturesInstallIn64BitMode=x64 diff --git a/swagger.json b/swagger.json index 0eaa1ea54..b6d1ff241 100644 --- a/swagger.json +++ b/swagger.json @@ -2,7 +2,7 @@ "openapi": "3.0.1", "info": { "title": "Traccar", - "version": "6.1", + "version": "6.2", "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 47d4ab2bad1806e3943a0e05ced7f8df7f8e1aca Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 14:13:29 -0700 Subject: Update integration test script --- tools/test-integration.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/test-integration.py b/tools/test-integration.py index f31ad7a82..29c741390 100755 --- a/tools/test-integration.py +++ b/tools/test-integration.py @@ -9,6 +9,7 @@ import json import socket import time import threading +import re messages = { 'gps103' : 'imei:123456789012345,help me,1201011201,,F,120100.000,A,6000.0000,N,13000.0000,E,0.00,;', @@ -137,11 +138,11 @@ debug = '-v' in sys.argv def load_ports(): ports = {} dir = os.path.dirname(os.path.abspath(__file__)) - root = xml.etree.ElementTree.parse(dir + '/../setup/default.xml').getroot() - for entry in root.findall('entry'): - key = entry.attrib['key'] - if key.endswith('.port'): - ports[key[:-5]] = int(entry.text) + with open(dir + '/../src/main/java/org/traccar/config/PortConfigSuffix.java', 'r') as file: + content = file.read() + pattern = re.compile(r'PORTS\.put\("([^"]+)",\s*(\d+)\);') + matches = pattern.findall(content) + ports = {protocol: int(port) for protocol, port in matches} if debug: print('\nports: {ports!r}\n') return ports -- cgit v1.2.3 From a18f7dece23790b87121102962dd370119c8dcbc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 14:22:43 -0700 Subject: Fix build issue --- .github/workflows/gradle.yml | 2 +- build.gradle | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index e50354cbd..8bc638a65 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -18,4 +18,4 @@ jobs: distribution: temurin java-version: 11 cache: gradle - - run: ./gradlew build --no-daemon --warning-mode=fail + - run: ./gradlew build --no-daemon diff --git a/build.gradle b/build.gradle index 1964d051a..029c4ae6d 100644 --- a/build.gradle +++ b/build.gradle @@ -9,13 +9,17 @@ repositories { mavenCentral() } -sourceCompatibility = "11" +java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 +} + compileJava.options.encoding = "UTF-8" jar.destinationDirectory = file("$projectDir/target") checkstyle { toolVersion = "10.17.0" - configFile = "gradle/checkstyle.xml" as File + configFile = file("gradle/checkstyle.xml") checkstyleTest.enabled = false } -- cgit v1.2.3 From 64528b96da4a742070d5845a876b07ca66ad0be3 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 1 Jun 2024 14:45:56 -0700 Subject: Update web submodule --- traccar-web | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traccar-web b/traccar-web index a50f998f7..e4840d26a 160000 --- a/traccar-web +++ b/traccar-web @@ -1 +1 @@ -Subproject commit a50f998f7dbb297ca7f22a31119556d6c58494c6 +Subproject commit e4840d26a26dd298dbd97be74373b85607a84add -- cgit v1.2.3