aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2024-03-28 23:02:18 -0600
committerIván Ávalos <avalos@disroot.org>2024-03-28 23:02:18 -0600
commit4dec2ef603f078ff3bd18d63d1fbd992537cbb88 (patch)
tree9c1f2886390447183a64a405fb885a9923412701
parentdec9993b2e1a7801bd69f1a9d92013f83e17f253 (diff)
parent13f6415ba0a8ca76d1a2cbb3d0ea199361295f1b (diff)
downloadtrackermap-server-4dec2ef603f078ff3bd18d63d1fbd992537cbb88.tar.gz
trackermap-server-4dec2ef603f078ff3bd18d63d1fbd992537cbb88.tar.bz2
trackermap-server-4dec2ef603f078ff3bd18d63d1fbd992537cbb88.zip
Merge branch 'upstream'trackermap-v0.1.4
-rw-r--r--src/main/java/org/traccar/MainModule.java10
-rw-r--r--src/main/java/org/traccar/config/Keys.java2
-rw-r--r--src/main/java/org/traccar/forward/EventForwarderMqtt.java67
-rw-r--r--src/main/java/org/traccar/forward/MqttClient.java76
-rw-r--r--src/main/java/org/traccar/forward/PositionForwarderMqtt.java47
-rw-r--r--src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java28
-rw-r--r--src/main/java/org/traccar/handler/StandardLoggingHandler.java13
-rw-r--r--src/main/java/org/traccar/model/LogRecord.java21
-rw-r--r--src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java3
-rw-r--r--src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java3
-rw-r--r--src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java7
-rw-r--r--src/main/java/org/traccar/session/ConnectionKey.java54
-rw-r--r--src/main/java/org/traccar/session/ConnectionManager.java28
-rw-r--r--src/main/java/org/traccar/session/DeviceSession.java6
-rw-r--r--src/test/java/org/traccar/geolocation/GeolocationProviderTest.java2
-rw-r--r--src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java4
16 files changed, 244 insertions, 127 deletions
diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java
index 3fec4d1e6..26654947e 100644
--- a/src/main/java/org/traccar/MainModule.java
+++ b/src/main/java/org/traccar/MainModule.java
@@ -46,6 +46,7 @@ import org.traccar.forward.PositionForwarderAmqp;
import org.traccar.forward.PositionForwarderKafka;
import org.traccar.forward.PositionForwarderRedis;
import org.traccar.forward.PositionForwarderUrl;
+import org.traccar.forward.PositionForwarderMqtt;
import org.traccar.geocoder.AddressFormat;
import org.traccar.geocoder.BanGeocoder;
import org.traccar.geocoder.BingMapsGeocoder;
@@ -69,7 +70,6 @@ import org.traccar.geocoder.TestGeocoder;
import org.traccar.geocoder.TomTomGeocoder;
import org.traccar.geolocation.GeolocationProvider;
import org.traccar.geolocation.GoogleGeolocationProvider;
-import org.traccar.geolocation.MozillaGeolocationProvider;
import org.traccar.geolocation.OpenCellIdGeolocationProvider;
import org.traccar.geolocation.UnwiredGeolocationProvider;
import org.traccar.handler.GeocoderHandler;
@@ -276,18 +276,16 @@ public class MainModule extends AbstractModule {
@Provides
public static GeolocationProvider provideGeolocationProvider(Config config, Client client) {
if (config.getBoolean(Keys.GEOLOCATION_ENABLE)) {
- String type = config.getString(Keys.GEOLOCATION_TYPE, "mozilla");
+ String type = config.getString(Keys.GEOLOCATION_TYPE, "google");
String url = config.getString(Keys.GEOLOCATION_URL);
String key = config.getString(Keys.GEOLOCATION_KEY);
switch (type) {
- case "google":
- return new GoogleGeolocationProvider(client, key);
case "opencellid":
return new OpenCellIdGeolocationProvider(client, url, key);
case "unwired":
return new UnwiredGeolocationProvider(client, url, key);
default:
- return new MozillaGeolocationProvider(client, key);
+ return new GoogleGeolocationProvider(client, key);
}
}
return null;
@@ -386,6 +384,8 @@ public class MainModule extends AbstractModule {
return new PositionForwarderAmqp(config, objectMapper);
case "kafka":
return new PositionForwarderKafka(config, objectMapper);
+ case "mqtt":
+ return new PositionForwarderMqtt(config, objectMapper);
case "redis":
return new PositionForwarderRedis(config, objectMapper);
case "url":
diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java
index 02e684875..4aacb2cd8 100644
--- a/src/main/java/org/traccar/config/Keys.java
+++ b/src/main/java/org/traccar/config/Keys.java
@@ -1656,7 +1656,7 @@ public final class Keys {
List.of(KeyType.CONFIG));
/**
- * Provider to use for LBS location. Available options: google, mozilla and opencellid. By default opencellid is
+ * Provider to use for LBS location. Available options: google, unwired and opencellid. By default, google is
* used. You have to supply a key that you get from corresponding provider. For more information see LBS geolocation
* documentation.
*/
diff --git a/src/main/java/org/traccar/forward/EventForwarderMqtt.java b/src/main/java/org/traccar/forward/EventForwarderMqtt.java
index 7f4e29384..7fee495ac 100644
--- a/src/main/java/org/traccar/forward/EventForwarderMqtt.java
+++ b/src/main/java/org/traccar/forward/EventForwarderMqtt.java
@@ -15,86 +15,33 @@
*/
package org.traccar.forward;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.hivemq.client.mqtt.datatypes.MqttQos;
-import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient;
-import com.hivemq.client.mqtt.mqtt5.Mqtt5Client;
-import com.hivemq.client.mqtt.mqtt5.message.auth.Mqtt5SimpleAuth;
import org.traccar.config.Config;
import org.traccar.config.Keys;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.UUID;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
public class EventForwarderMqtt implements EventForwarder {
- private final Mqtt5AsyncClient client;
+ private final MqttClient mqttClient;
private final ObjectMapper objectMapper;
private final String topic;
public EventForwarderMqtt(Config config, ObjectMapper objectMapper) {
- URI url;
- try {
- url = new URI(config.getString(Keys.EVENT_FORWARD_URL));
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
-
- String userInfo = url.getUserInfo();
- Mqtt5SimpleAuth simpleAuth = null;
- if (userInfo != null) {
- int delimiter = userInfo.indexOf(':');
- if (delimiter == -1) {
- throw new IllegalArgumentException("Wrong credentials. Should be in format \"username:password\"");
- } else {
- simpleAuth = Mqtt5SimpleAuth.builder()
- .username(userInfo.substring(0, delimiter++))
- .password(userInfo.substring(delimiter).getBytes())
- .build();
- }
- }
-
- String host = url.getHost();
- int port = url.getPort();
- client = Mqtt5Client.builder()
- .identifier("traccar-" + UUID.randomUUID())
- .serverHost(host)
- .serverPort(port)
- .simpleAuth(simpleAuth)
- .automaticReconnectWithDefaultConfig()
- .buildAsync();
-
- client.connectWith()
- .send()
- .whenComplete((message, e) -> {
- if (e != null) {
- throw new RuntimeException(e);
- }
- });
-
+ this.topic = config.getString(Keys.EVENT_FORWARD_TOPIC);
+ mqttClient = new MqttClient(config.getString(Keys.EVENT_FORWARD_URL));
this.objectMapper = objectMapper;
- topic = config.getString(Keys.EVENT_FORWARD_TOPIC);
}
@Override
public void forward(EventData eventData, ResultHandler resultHandler) {
- byte[] payload;
try {
- payload = objectMapper.writeValueAsString(eventData).getBytes();
+ String payload = objectMapper.writeValueAsString(eventData);
+ mqttClient.publish(topic, payload, (message, e) -> resultHandler.onResult(e == null, e));
} catch (JsonProcessingException e) {
resultHandler.onResult(false, e);
- return;
}
-
- client.publishWith()
- .topic(topic)
- .qos(MqttQos.AT_LEAST_ONCE)
- .payload(payload)
- .send()
- .whenComplete((message, e) -> resultHandler.onResult(e == null, e));
}
}
diff --git a/src/main/java/org/traccar/forward/MqttClient.java b/src/main/java/org/traccar/forward/MqttClient.java
new file mode 100644
index 000000000..416a167ec
--- /dev/null
+++ b/src/main/java/org/traccar/forward/MqttClient.java
@@ -0,0 +1,76 @@
+/*
+ * 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.forward;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.UUID;
+import java.util.function.BiConsumer;
+
+import com.hivemq.client.mqtt.datatypes.MqttQos;
+import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient;
+import com.hivemq.client.mqtt.mqtt5.Mqtt5Client;
+import com.hivemq.client.mqtt.mqtt5.Mqtt5ClientBuilder;
+import com.hivemq.client.mqtt.mqtt5.message.auth.Mqtt5SimpleAuth;
+import com.hivemq.client.mqtt.mqtt5.message.publish.Mqtt5PublishResult;
+
+public class MqttClient {
+
+ private final Mqtt5AsyncClient client;
+
+ MqttClient(String url) {
+ URI uri;
+ try {
+ uri = new URI(url);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+
+ Mqtt5SimpleAuth simpleAuth = this.getSimpleAuth(uri);
+
+ String host = uri.getHost();
+ int port = uri.getPort();
+ Mqtt5ClientBuilder builder = Mqtt5Client.builder().identifier("traccar-" + UUID.randomUUID())
+ .serverHost(host).serverPort(port).simpleAuth(simpleAuth).automaticReconnectWithDefaultConfig();
+
+ client = builder.buildAsync();
+ client.connectWith().send().whenComplete((message, e) -> {
+ throw new RuntimeException(e);
+ });
+ }
+
+ private Mqtt5SimpleAuth getSimpleAuth(URI uri) {
+ String userInfo = uri.getUserInfo();
+ Mqtt5SimpleAuth simpleAuth = null;
+ if (userInfo != null) {
+ int delimiter = userInfo.indexOf(':');
+ if (delimiter == -1) {
+ throw new IllegalArgumentException("Wrong MQTT credentials. Should be in format \"username:password\"");
+ } else {
+ simpleAuth = Mqtt5SimpleAuth.builder().username(userInfo.substring(0, delimiter++))
+ .password(userInfo.substring(delimiter).getBytes()).build();
+ }
+ }
+ return simpleAuth;
+ }
+
+ public void publish(
+ String pubTopic, String payload, BiConsumer<? super Mqtt5PublishResult, ? super Throwable> whenComplete) {
+ client.publishWith().topic(pubTopic).qos(MqttQos.AT_LEAST_ONCE).payload(payload.getBytes()).send()
+ .whenComplete(whenComplete);
+ }
+
+}
diff --git a/src/main/java/org/traccar/forward/PositionForwarderMqtt.java b/src/main/java/org/traccar/forward/PositionForwarderMqtt.java
new file mode 100644
index 000000000..53f0ced19
--- /dev/null
+++ b/src/main/java/org/traccar/forward/PositionForwarderMqtt.java
@@ -0,0 +1,47 @@
+/*
+ * 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.forward;
+
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class PositionForwarderMqtt implements PositionForwarder {
+
+ private final MqttClient mqttClient;
+ private final ObjectMapper objectMapper;
+
+ private final String topic;
+
+ public PositionForwarderMqtt(final Config config, final ObjectMapper objectMapper) {
+ this.topic = config.getString(Keys.FORWARD_TOPIC);
+ mqttClient = new MqttClient(config.getString(Keys.FORWARD_URL));
+ this.objectMapper = objectMapper;
+ }
+
+ @Override
+ public void forward(PositionData positionData, ResultHandler resultHandler) {
+ try {
+ String payload = objectMapper.writeValueAsString(topic);
+ mqttClient.publish(topic, payload, (message, e) -> resultHandler.onResult(e == null, e));
+ } catch (JsonProcessingException e) {
+ resultHandler.onResult(false, e);
+ }
+ }
+
+}
diff --git a/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java b/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java
deleted file mode 100644
index 7eb22dcca..000000000
--- a/src/main/java/org/traccar/geolocation/MozillaGeolocationProvider.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.traccar.geolocation;
-
-import jakarta.ws.rs.client.Client;
-
-public class MozillaGeolocationProvider extends UniversalGeolocationProvider {
-
- private static final String URL = "https://location.services.mozilla.com/v1/geolocate";
-
- public MozillaGeolocationProvider(Client client, String key) {
- super(client, URL, key != null ? key : "test");
- }
-
-}
diff --git a/src/main/java/org/traccar/handler/StandardLoggingHandler.java b/src/main/java/org/traccar/handler/StandardLoggingHandler.java
index 5978d632e..513602dd8 100644
--- a/src/main/java/org/traccar/handler/StandardLoggingHandler.java
+++ b/src/main/java/org/traccar/handler/StandardLoggingHandler.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.
@@ -28,8 +28,6 @@ import org.traccar.helper.NetworkUtil;
import org.traccar.model.LogRecord;
import org.traccar.session.ConnectionManager;
-import java.net.InetSocketAddress;
-
public class StandardLoggingHandler extends ChannelDuplexHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(StandardLoggingHandler.class);
@@ -48,7 +46,7 @@ public class StandardLoggingHandler extends ChannelDuplexHandler {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
- LogRecord record = createLogRecord(msg);
+ LogRecord record = createLogRecord(ctx, msg);
log(ctx, false, record);
super.channelRead(ctx, msg);
if (record != null) {
@@ -58,16 +56,15 @@ public class StandardLoggingHandler extends ChannelDuplexHandler {
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
- log(ctx, true, createLogRecord(msg));
+ log(ctx, true, createLogRecord(ctx, msg));
super.write(ctx, msg, promise);
}
- private LogRecord createLogRecord(Object msg) {
+ private LogRecord createLogRecord(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof NetworkMessage) {
NetworkMessage networkMessage = (NetworkMessage) msg;
if (networkMessage.getMessage() instanceof ByteBuf) {
- LogRecord record = new LogRecord();
- record.setAddress((InetSocketAddress) networkMessage.getRemoteAddress());
+ LogRecord record = new LogRecord(ctx.channel().localAddress(), networkMessage.getRemoteAddress());
record.setProtocol(protocol);
record.setData(ByteBufUtil.hexDump((ByteBuf) networkMessage.getMessage()));
return record;
diff --git a/src/main/java/org/traccar/model/LogRecord.java b/src/main/java/org/traccar/model/LogRecord.java
index c19163af3..b04f51b32 100644
--- a/src/main/java/org/traccar/model/LogRecord.java
+++ b/src/main/java/org/traccar/model/LogRecord.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.
@@ -16,24 +16,33 @@
package org.traccar.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.traccar.session.ConnectionKey;
import java.net.InetSocketAddress;
+import java.net.SocketAddress;
public class LogRecord {
- private InetSocketAddress address;
+ private final InetSocketAddress localAddress;
+ private final InetSocketAddress remoteAddress;
- public void setAddress(InetSocketAddress address) {
- this.address = address;
+ public LogRecord(SocketAddress localAddress, SocketAddress remoteAddress) {
+ this.localAddress = (InetSocketAddress) localAddress;
+ this.remoteAddress = (InetSocketAddress) remoteAddress;
}
@JsonIgnore
public InetSocketAddress getAddress() {
- return address;
+ return remoteAddress;
+ }
+
+ @JsonIgnore
+ public ConnectionKey getConnectionKey() {
+ return new ConnectionKey(localAddress, remoteAddress);
}
public String getHost() {
- return address.getHostString();
+ return remoteAddress.getHostString();
}
private String protocol;
diff --git a/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java b/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java
index c072e55d0..938d170e6 100644
--- a/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/AutoTrackProtocolDecoder.java
@@ -101,10 +101,11 @@ public class AutoTrackProtocolDecoder extends BaseProtocolDecoder {
int type = buf.readUnsignedByte();
buf.readUnsignedShortLE(); // length
+ DeviceSession deviceSession;
switch (type) {
case MSG_LOGIN_REQUEST:
String imei = ByteBufUtil.hexDump(buf.readSlice(8));
- DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, imei);
+ deviceSession = getDeviceSession(channel, remoteAddress, imei);
if (deviceSession == null) {
return null;
}
diff --git a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
index 0a8540543..2186fb91f 100644
--- a/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/HuabaoProtocolDecoder.java
@@ -678,7 +678,8 @@ public class HuabaoProtocolDecoder extends BaseProtocolDecoder {
buf.readUnsignedShort(), buf.readUnsignedInt()));
position.setNetwork(network);
break;
- case 0xE1:
+ case 0x00A8:
+ case 0x00E1:
position.set(Position.KEY_BATTERY_LEVEL, buf.readUnsignedByte());
break;
default:
diff --git a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
index 64373e344..2d6bde89f 100644
--- a/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
+++ b/src/main/java/org/traccar/protocol/Minifinder2ProtocolDecoder.java
@@ -295,6 +295,13 @@ public class Minifinder2ProtocolDecoder extends BaseProtocolDecoder {
position.set(Position.KEY_HEART_RATE, heartRate);
}
break;
+ case 0x41:
+ buf.readUnsignedIntLE(); // timestamp
+ int spO2 = buf.readUnsignedByte();
+ if (spO2 > 1) {
+ position.set("spO2", spO2);
+ }
+ break;
default:
break;
}
diff --git a/src/main/java/org/traccar/session/ConnectionKey.java b/src/main/java/org/traccar/session/ConnectionKey.java
new file mode 100644
index 000000000..3b7e2ebf8
--- /dev/null
+++ b/src/main/java/org/traccar/session/ConnectionKey.java
@@ -0,0 +1,54 @@
+/*
+ * 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.session;
+
+import io.netty.channel.Channel;
+
+import java.net.SocketAddress;
+import java.util.Objects;
+
+public class ConnectionKey {
+
+ private final SocketAddress localAddress;
+ private final SocketAddress remoteAddress;
+
+ public ConnectionKey(Channel channel, SocketAddress remoteAddress) {
+ this(channel.localAddress(), remoteAddress);
+ }
+
+ public ConnectionKey(SocketAddress localAddress, SocketAddress remoteAddress) {
+ this.localAddress = localAddress;
+ this.remoteAddress = remoteAddress;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ConnectionKey that = (ConnectionKey) o;
+ return Objects.equals(localAddress, that.localAddress) && Objects.equals(remoteAddress, that.remoteAddress);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(localAddress, remoteAddress);
+ }
+
+}
diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java
index 42dcf5ce9..8431a0327 100644
--- a/src/main/java/org/traccar/session/ConnectionManager.java
+++ b/src/main/java/org/traccar/session/ConnectionManager.java
@@ -66,8 +66,8 @@ public class ConnectionManager implements BroadcastInterface {
private final boolean showUnknownDevices;
private final Map<Long, DeviceSession> sessionsByDeviceId = new ConcurrentHashMap<>();
- private final Map<SocketAddress, Map<String, DeviceSession>> sessionsByEndpoint = new ConcurrentHashMap<>();
- private final Map<SocketAddress, String> unknownByEndpoint = new ConcurrentHashMap<>();
+ private final Map<ConnectionKey, Map<String, DeviceSession>> sessionsByEndpoint = new ConcurrentHashMap<>();
+ private final Map<ConnectionKey, String> unknownByEndpoint = new ConcurrentHashMap<>();
private final Config config;
private final CacheManager cacheManager;
@@ -108,8 +108,9 @@ public class ConnectionManager implements BroadcastInterface {
Protocol protocol, Channel channel, SocketAddress remoteAddress,
String... uniqueIds) throws Exception {
+ ConnectionKey connectionKey = new ConnectionKey(channel, remoteAddress);
Map<String, DeviceSession> endpointSessions = sessionsByEndpoint.getOrDefault(
- remoteAddress, new ConcurrentHashMap<>());
+ connectionKey, new ConcurrentHashMap<>());
uniqueIds = Arrays.stream(uniqueIds).filter(Objects::nonNull).toArray(String[]::new);
if (uniqueIds.length > 0) {
@@ -133,23 +134,23 @@ public class ConnectionManager implements BroadcastInterface {
}
if (device != null) {
- unknownByEndpoint.remove(remoteAddress);
+ unknownByEndpoint.remove(connectionKey);
device.checkDisabled();
DeviceSession oldSession = sessionsByDeviceId.remove(device.getId());
if (oldSession != null) {
- Map<String, DeviceSession> oldEndpointSessions = sessionsByEndpoint.get(oldSession.getRemoteAddress());
+ Map<String, DeviceSession> oldEndpointSessions = sessionsByEndpoint.get(oldSession.getConnectionKey());
if (oldEndpointSessions != null && oldEndpointSessions.size() > 1) {
oldEndpointSessions.remove(device.getUniqueId());
} else {
- sessionsByEndpoint.remove(oldSession.getRemoteAddress());
+ sessionsByEndpoint.remove(oldSession.getConnectionKey());
}
}
DeviceSession deviceSession = new DeviceSession(
device.getId(), device.getUniqueId(), device.getModel(), protocol, channel, remoteAddress);
endpointSessions.put(device.getUniqueId(), deviceSession);
- sessionsByEndpoint.put(remoteAddress, endpointSessions);
+ sessionsByEndpoint.put(connectionKey, endpointSessions);
sessionsByDeviceId.put(device.getId(), deviceSession);
if (oldSession == null) {
@@ -158,7 +159,7 @@ public class ConnectionManager implements BroadcastInterface {
return deviceSession;
} else {
- unknownByEndpoint.put(remoteAddress, firstUniqueId);
+ unknownByEndpoint.put(connectionKey, firstUniqueId);
LOGGER.warn("Unknown device - " + String.join(" ", uniqueIds)
+ " (" + ((InetSocketAddress) remoteAddress).getHostString() + ")");
return null;
@@ -189,7 +190,8 @@ public class ConnectionManager implements BroadcastInterface {
public void deviceDisconnected(Channel channel, boolean supportsOffline) {
SocketAddress remoteAddress = channel.remoteAddress();
if (remoteAddress != null) {
- Map<String, DeviceSession> endpointSessions = sessionsByEndpoint.remove(remoteAddress);
+ ConnectionKey connectionKey = new ConnectionKey(channel, remoteAddress);
+ Map<String, DeviceSession> endpointSessions = sessionsByEndpoint.remove(connectionKey);
if (endpointSessions != null) {
for (DeviceSession deviceSession : endpointSessions.values()) {
if (supportsOffline) {
@@ -199,7 +201,7 @@ public class ConnectionManager implements BroadcastInterface {
cacheManager.removeDevice(deviceSession.getDeviceId());
}
}
- unknownByEndpoint.remove(remoteAddress);
+ unknownByEndpoint.remove(connectionKey);
}
}
@@ -212,7 +214,7 @@ public class ConnectionManager implements BroadcastInterface {
DeviceSession deviceSession = sessionsByDeviceId.remove(deviceId);
if (deviceSession != null) {
cacheManager.removeDevice(deviceId);
- sessionsByEndpoint.computeIfPresent(deviceSession.getRemoteAddress(), (e, sessions) -> {
+ sessionsByEndpoint.computeIfPresent(deviceSession.getConnectionKey(), (e, sessions) -> {
sessions.remove(deviceSession.getUniqueId());
return sessions.isEmpty() ? null : sessions;
});
@@ -345,9 +347,9 @@ public class ConnectionManager implements BroadcastInterface {
}
public synchronized void updateLog(LogRecord record) {
- var sessions = sessionsByEndpoint.getOrDefault(record.getAddress(), Map.of());
+ var sessions = sessionsByEndpoint.getOrDefault(record.getConnectionKey(), Map.of());
if (sessions.isEmpty()) {
- String unknownUniqueId = unknownByEndpoint.get(record.getAddress());
+ String unknownUniqueId = unknownByEndpoint.get(record.getConnectionKey());
if (unknownUniqueId != null && showUnknownDevices) {
record.setUniqueId(unknownUniqueId);
listeners.values().stream()
diff --git a/src/main/java/org/traccar/session/DeviceSession.java b/src/main/java/org/traccar/session/DeviceSession.java
index f124ca7f9..31d5e6a13 100644
--- a/src/main/java/org/traccar/session/DeviceSession.java
+++ b/src/main/java/org/traccar/session/DeviceSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2024 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,8 +61,8 @@ public class DeviceSession {
return channel;
}
- public SocketAddress getRemoteAddress() {
- return remoteAddress;
+ public ConnectionKey getConnectionKey() {
+ return new ConnectionKey(channel, remoteAddress);
}
public boolean supportsLiveCommands() {
diff --git a/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java
index da5ae3340..c1fa6dbbe 100644
--- a/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java
+++ b/src/test/java/org/traccar/geolocation/GeolocationProviderTest.java
@@ -19,7 +19,7 @@ public class GeolocationProviderTest extends BaseTest {
@Disabled
@Test
public void testMozilla() throws Exception {
- MozillaGeolocationProvider provider = new MozillaGeolocationProvider(client, null);
+ GoogleGeolocationProvider provider = new GoogleGeolocationProvider(client, null);
Network network = new Network(CellTower.from(208, 1, 2, 1234567));
diff --git a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java
index 164635109..7fd7cc599 100644
--- a/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java
+++ b/src/test/java/org/traccar/protocol/HuabaoProtocolDecoderTest.java
@@ -12,6 +12,10 @@ public class HuabaoProtocolDecoderTest extends ProtocolTest {
var decoder = inject(new HuabaoProtocolDecoder(null));
verifyAttribute(decoder, binary(
+ "7E0200005300959000194400080000000000000003015DA64806CCB4A8001100000000230816014137010400005B3F30011F310112EB29000C00B28986049910219020787400060089FFFFFFFF000600C5FFFFFFEF0004002D0F4E000300A84CE07E"),
+ Position.KEY_BATTERY_LEVEL, 76);
+
+ verifyAttribute(decoder, binary(
"7e55018c418560090010174701022106242122348476113550490700001c06000000074e0000000000000308100000100102020200000a030000000b0803363839363037650c0600000001000afa7e"),
"unlockResult", 0x65);