From 3c8acbd681409a068f3428ce2cbd8cf002d0b974 Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Wed, 7 Jun 2023 02:27:52 +0000 Subject: redis broadcast service --- .../traccar/broadcast/RedisBroadcastService.java | 206 +++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 src/main/java/org/traccar/broadcast/RedisBroadcastService.java diff --git a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java new file mode 100644 index 000000000..a6968c894 --- /dev/null +++ b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java @@ -0,0 +1,206 @@ +/* + * 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.broadcast; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.BaseModel; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Permission; +import org.traccar.model.Position; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPubSub; + +public class RedisBroadcastService implements BroadcastService { + + private static final Logger LOGGER = LoggerFactory.getLogger(RedisBroadcastService.class); + + private final ObjectMapper objectMapper; + + private final ExecutorService service = Executors.newSingleThreadExecutor(); + + private final Set listeners = new HashSet<>(); + + private final String url; + private final String pubsubChannel = "traccar:cast"; + + private final Jedis subscriberJedis; + private final Jedis publisherJedis; + + private final String id; + + public RedisBroadcastService(Config config, ObjectMapper objectMapper) throws IOException { + this.objectMapper = objectMapper; + url = config.getString(Keys.BROADCAST_ADDRESS); + + subscriberJedis = new Jedis(url); + publisherJedis = new Jedis(url); + + // id that will be used to identify this instance of the server + id = String.valueOf(System.currentTimeMillis()); + } + + @Override + public boolean singleInstance() { + return false; + } + + @Override + public void registerListener(BroadcastInterface listener) { + listeners.add(listener); + } + + @Override + public void updateDevice(boolean local, Device device) { + BroadcastMessage message = new BroadcastMessage(); + message.setDevice(device); + sendMessage(message); + } + + @Override + public void updatePosition(boolean local, Position position) { + BroadcastMessage message = new BroadcastMessage(); + message.setPosition(position); + sendMessage(message); + } + + @Override + public void updateEvent(boolean local, long userId, Event event) { + BroadcastMessage message = new BroadcastMessage(); + message.setUserId(userId); + message.setEvent(event); + sendMessage(message); + } + + @Override + public void updateCommand(boolean local, long deviceId) { + BroadcastMessage message = new BroadcastMessage(); + message.setCommandDeviceId(deviceId); + sendMessage(message); + } + + @Override + public void invalidateObject(boolean local, Class clazz, long id) { + BroadcastMessage message = new BroadcastMessage(); + message.setChanges(Map.of(Permission.getKey(clazz), id)); + sendMessage(message); + } + + @Override + public void invalidatePermission( + boolean local, + Class clazz1, long id1, + Class clazz2, long id2) { + BroadcastMessage message = new BroadcastMessage(); + message.setChanges(Map.of(Permission.getKey(clazz1), id1, Permission.getKey(clazz2), id2)); + sendMessage(message); + } + + private void sendMessage(BroadcastMessage message) { + try { + String payload = id + ":" + objectMapper.writeValueAsString(message); + publisherJedis.publish(pubsubChannel, payload); + } catch (IOException e) { + LOGGER.warn("Broadcast failed", e); + } + } + + private void handleMessage(BroadcastMessage message) { + if (message.getDevice() != null) { + listeners.forEach(listener -> listener.updateDevice(false, message.getDevice())); + } else if (message.getPosition() != null) { + listeners.forEach(listener -> listener.updatePosition(false, message.getPosition())); + } else if (message.getUserId() != null && message.getEvent() != null) { + listeners.forEach(listener -> listener.updateEvent(false, message.getUserId(), message.getEvent())); + } else if (message.getCommandDeviceId() != null) { + listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId())); + } else if (message.getChanges() != null) { + var iterator = message.getChanges().entrySet().iterator(); + if (iterator.hasNext()) { + var first = iterator.next(); + if (iterator.hasNext()) { + var second = iterator.next(); + listeners.forEach(listener -> listener.invalidatePermission( + false, + Permission.getKeyClass(first.getKey()), first.getValue(), + Permission.getKeyClass(second.getKey()), second.getValue())); + } else { + listeners.forEach(listener -> listener.invalidateObject( + false, + Permission.getKeyClass(first.getKey()), first.getValue())); + } + } + } + } + + @Override + public void start() throws IOException { + service.submit(receiver); + } + + @Override + public void stop() { + service.shutdown(); + } + + private final Runnable receiver = new Runnable() { + @Override + public void run() { + subscriberJedis.subscribe(new JedisPubSub() { + @Override + public void onMessage(String channel, String message) { + try { + String[] parts = message.split(":", 2); + if (channel == pubsubChannel && parts.length == 2 && !id.equals(parts[0])) { + handleMessage(objectMapper.readValue(parts[1], BroadcastMessage.class)); + } + } catch (IOException e) { + LOGGER.warn("Broadcast handleMessage failed", e); + } + } + }, pubsubChannel); + + while (!service.isShutdown()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } + } + + try { + subscriberJedis.close(); + publisherJedis.close(); + } catch (Exception e) { + LOGGER.warn("Failed to close pubsub", e); + throw new RuntimeException(e); + } + } + }; + +} -- cgit v1.2.3 From cfd91d45b6731e6632ebb8a4913f807bab510707 Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Wed, 7 Jun 2023 02:28:53 +0000 Subject: redis broadcast implementation --- src/main/java/org/traccar/MainModule.java | 11 ++++++++++- src/main/java/org/traccar/config/Keys.java | 8 ++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 6a2fe21c3..b1a8006ee 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -28,6 +28,7 @@ import io.netty.util.Timer; import org.apache.velocity.app.VelocityEngine; import org.traccar.broadcast.BroadcastService; import org.traccar.broadcast.MulticastBroadcastService; +import org.traccar.broadcast.RedisBroadcastService; import org.traccar.broadcast.NullBroadcastService; import org.traccar.config.Config; import org.traccar.config.Keys; @@ -340,8 +341,16 @@ public class MainModule extends AbstractModule { @Provides public static BroadcastService provideBroadcastService( Config config, ObjectMapper objectMapper) throws IOException { + String broadcastType = config.getString(Keys.BROADCAST_TYPE); if (config.hasKey(Keys.BROADCAST_ADDRESS)) { - return new MulticastBroadcastService(config, objectMapper); + switch (broadcastType) { + case "multicast": + return new MulticastBroadcastService(config, objectMapper); + case "redis": + return new RedisBroadcastService(config, objectMapper); + default: + return new NullBroadcastService(); + } } return new NullBroadcastService(); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index d4780ba46..6f42e8937 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1755,6 +1755,14 @@ public final class Keys { List.of(KeyType.CONFIG), "time,position,speed,course,accuracy,result"); + /** + * Broadcast method. Available options are "multicast" and "redis". Default is "multicast". + */ + public static final ConfigKey BROADCAST_TYPE = new StringConfigKey( + "broadcast.type", + List.of(KeyType.CONFIG), + "multicast"); + /** * Multicast interface. It can be either an IP address or an interface name. */ -- cgit v1.2.3 From 3397d4f07ef7fae909c0d6258dbc1263c4acc68b Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Thu, 8 Jun 2023 01:52:09 +0000 Subject: Add BaseBroadcastService pr comment adjustments --- src/main/java/org/traccar/MainModule.java | 2 +- .../traccar/broadcast/BaseBroadcastService.java | 118 ++++++++++++++ .../broadcast/MulticastBroadcastService.java | 92 +---------- .../traccar/broadcast/RedisBroadcastService.java | 176 ++++++--------------- src/main/java/org/traccar/config/Keys.java | 2 +- 5 files changed, 172 insertions(+), 218 deletions(-) create mode 100644 src/main/java/org/traccar/broadcast/BaseBroadcastService.java diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index b1a8006ee..29d846154 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -349,7 +349,7 @@ public class MainModule extends AbstractModule { case "redis": return new RedisBroadcastService(config, objectMapper); default: - return new NullBroadcastService(); + break; } } return new NullBroadcastService(); diff --git a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java new file mode 100644 index 000000000..1ed639dfd --- /dev/null +++ b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java @@ -0,0 +1,118 @@ +/* + * 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.broadcast; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.traccar.model.BaseModel; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Permission; +import org.traccar.model.Position; + +public abstract class BaseBroadcastService implements BroadcastService { + + private final Set listeners = new HashSet<>(); + + @Override + public boolean singleInstance() { + return true; + } + + @Override + public void registerListener(BroadcastInterface listener) { + listeners.add(listener); + } + + @Override + public void updateDevice(boolean local, Device device) { + BroadcastMessage message = new BroadcastMessage(); + message.setDevice(device); + sendMessage(message); + } + + @Override + public void updatePosition(boolean local, Position position) { + BroadcastMessage message = new BroadcastMessage(); + message.setPosition(position); + sendMessage(message); + } + + @Override + public void updateEvent(boolean local, long userId, Event event) { + BroadcastMessage message = new BroadcastMessage(); + message.setUserId(userId); + message.setEvent(event); + sendMessage(message); + } + + @Override + public void updateCommand(boolean local, long deviceId) { + BroadcastMessage message = new BroadcastMessage(); + message.setCommandDeviceId(deviceId); + sendMessage(message); + } + + @Override + public void invalidateObject(boolean local, Class clazz, long id) { + BroadcastMessage message = new BroadcastMessage(); + message.setChanges(Map.of(Permission.getKey(clazz), id)); + sendMessage(message); + } + + @Override + public void invalidatePermission( + boolean local, + Class clazz1, long id1, + Class clazz2, long id2) { + BroadcastMessage message = new BroadcastMessage(); + message.setChanges(Map.of(Permission.getKey(clazz1), id1, Permission.getKey(clazz2), id2)); + sendMessage(message); + } + + protected abstract void sendMessage(BroadcastMessage message); + + protected void handleMessage(BroadcastMessage message) { + if (message.getDevice() != null) { + listeners.forEach(listener -> listener.updateDevice(false, message.getDevice())); + } else if (message.getPosition() != null) { + listeners.forEach(listener -> listener.updatePosition(false, message.getPosition())); + } else if (message.getUserId() != null && message.getEvent() != null) { + listeners.forEach(listener -> listener.updateEvent(false, message.getUserId(), message.getEvent())); + } else if (message.getCommandDeviceId() != null) { + listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId())); + } else if (message.getChanges() != null) { + var iterator = message.getChanges().entrySet().iterator(); + if (iterator.hasNext()) { + var first = iterator.next(); + if (iterator.hasNext()) { + var second = iterator.next(); + listeners.forEach(listener -> listener.invalidatePermission( + false, + Permission.getKeyClass(first.getKey()), first.getValue(), + Permission.getKeyClass(second.getKey()), second.getValue())); + } else { + listeners.forEach(listener -> listener.invalidateObject( + false, + Permission.getKeyClass(first.getKey()), first.getValue())); + } + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java index b1b66f1e3..1c02b319b 100644 --- a/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java @@ -20,11 +20,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.model.BaseModel; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Permission; -import org.traccar.model.Position; import java.io.IOException; import java.net.DatagramPacket; @@ -34,13 +29,10 @@ import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.net.NetworkInterface; import java.nio.charset.StandardCharsets; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -public class MulticastBroadcastService implements BroadcastService { +public class MulticastBroadcastService extends BaseBroadcastService { private static final Logger LOGGER = LoggerFactory.getLogger(MulticastBroadcastService.class); @@ -55,8 +47,6 @@ public class MulticastBroadcastService implements BroadcastService { private final ExecutorService service = Executors.newSingleThreadExecutor(); private final byte[] receiverBuffer = new byte[4096]; - private final Set listeners = new HashSet<>(); - public MulticastBroadcastService(Config config, ObjectMapper objectMapper) throws IOException { this.objectMapper = objectMapper; port = config.getInteger(Keys.BROADCAST_PORT); @@ -76,57 +66,7 @@ public class MulticastBroadcastService implements BroadcastService { } @Override - public void registerListener(BroadcastInterface listener) { - listeners.add(listener); - } - - @Override - public void updateDevice(boolean local, Device device) { - BroadcastMessage message = new BroadcastMessage(); - message.setDevice(device); - sendMessage(message); - } - - @Override - public void updatePosition(boolean local, Position position) { - BroadcastMessage message = new BroadcastMessage(); - message.setPosition(position); - sendMessage(message); - } - - @Override - public void updateEvent(boolean local, long userId, Event event) { - BroadcastMessage message = new BroadcastMessage(); - message.setUserId(userId); - message.setEvent(event); - sendMessage(message); - } - - @Override - public void updateCommand(boolean local, long deviceId) { - BroadcastMessage message = new BroadcastMessage(); - message.setCommandDeviceId(deviceId); - sendMessage(message); - } - - @Override - public void invalidateObject(boolean local, Class clazz, long id) { - BroadcastMessage message = new BroadcastMessage(); - message.setChanges(Map.of(Permission.getKey(clazz), id)); - sendMessage(message); - } - - @Override - public void invalidatePermission( - boolean local, - Class clazz1, long id1, - Class clazz2, long id2) { - BroadcastMessage message = new BroadcastMessage(); - message.setChanges(Map.of(Permission.getKey(clazz1), id1, Permission.getKey(clazz2), id2)); - sendMessage(message); - } - - private void sendMessage(BroadcastMessage message) { + protected void sendMessage(BroadcastMessage message) { try { byte[] buffer = objectMapper.writeValueAsString(message).getBytes(StandardCharsets.UTF_8); DatagramPacket packet = new DatagramPacket(buffer, buffer.length, group); @@ -136,34 +76,6 @@ public class MulticastBroadcastService implements BroadcastService { } } - private void handleMessage(BroadcastMessage message) { - if (message.getDevice() != null) { - listeners.forEach(listener -> listener.updateDevice(false, message.getDevice())); - } else if (message.getPosition() != null) { - listeners.forEach(listener -> listener.updatePosition(false, message.getPosition())); - } else if (message.getUserId() != null && message.getEvent() != null) { - listeners.forEach(listener -> listener.updateEvent(false, message.getUserId(), message.getEvent())); - } else if (message.getCommandDeviceId() != null) { - listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId())); - } else if (message.getChanges() != null) { - var iterator = message.getChanges().entrySet().iterator(); - if (iterator.hasNext()) { - var first = iterator.next(); - if (iterator.hasNext()) { - var second = iterator.next(); - listeners.forEach(listener -> listener.invalidatePermission( - false, - Permission.getKeyClass(first.getKey()), first.getValue(), - Permission.getKeyClass(second.getKey()), second.getValue())); - } else { - listeners.forEach(listener -> listener.invalidateObject( - false, - Permission.getKeyClass(first.getKey()), first.getValue())); - } - } - } - } - @Override public void start() throws IOException { service.submit(receiver); diff --git a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java index a6968c894..e619fef60 100644 --- a/src/main/java/org/traccar/broadcast/RedisBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/RedisBroadcastService.java @@ -20,23 +20,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.model.BaseModel; -import org.traccar.model.Device; -import org.traccar.model.Event; -import org.traccar.model.Permission; -import org.traccar.model.Position; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPubSub; +import redis.clients.jedis.exceptions.JedisConnectionException; +import redis.clients.jedis.exceptions.JedisException; -public class RedisBroadcastService implements BroadcastService { +public class RedisBroadcastService extends BaseBroadcastService { private static final Logger LOGGER = LoggerFactory.getLogger(RedisBroadcastService.class); @@ -44,25 +38,25 @@ public class RedisBroadcastService implements BroadcastService { private final ExecutorService service = Executors.newSingleThreadExecutor(); - private final Set listeners = new HashSet<>(); - private final String url; - private final String pubsubChannel = "traccar:cast"; + private final String channel = "traccar"; - private final Jedis subscriberJedis; - private final Jedis publisherJedis; + private Jedis subscriber; + private Jedis publisher; - private final String id; + private final String id = UUID.randomUUID().toString(); public RedisBroadcastService(Config config, ObjectMapper objectMapper) throws IOException { this.objectMapper = objectMapper; url = config.getString(Keys.BROADCAST_ADDRESS); - subscriberJedis = new Jedis(url); - publisherJedis = new Jedis(url); - - // id that will be used to identify this instance of the server - id = String.valueOf(System.currentTimeMillis()); + try { + subscriber = new Jedis(url); + publisher = new Jedis(url); + subscriber.connect(); + } catch (JedisConnectionException e) { + throw new IOException(e); + } } @Override @@ -71,90 +65,14 @@ public class RedisBroadcastService implements BroadcastService { } @Override - public void registerListener(BroadcastInterface listener) { - listeners.add(listener); - } - - @Override - public void updateDevice(boolean local, Device device) { - BroadcastMessage message = new BroadcastMessage(); - message.setDevice(device); - sendMessage(message); - } - - @Override - public void updatePosition(boolean local, Position position) { - BroadcastMessage message = new BroadcastMessage(); - message.setPosition(position); - sendMessage(message); - } - - @Override - public void updateEvent(boolean local, long userId, Event event) { - BroadcastMessage message = new BroadcastMessage(); - message.setUserId(userId); - message.setEvent(event); - sendMessage(message); - } - - @Override - public void updateCommand(boolean local, long deviceId) { - BroadcastMessage message = new BroadcastMessage(); - message.setCommandDeviceId(deviceId); - sendMessage(message); - } - - @Override - public void invalidateObject(boolean local, Class clazz, long id) { - BroadcastMessage message = new BroadcastMessage(); - message.setChanges(Map.of(Permission.getKey(clazz), id)); - sendMessage(message); - } - - @Override - public void invalidatePermission( - boolean local, - Class clazz1, long id1, - Class clazz2, long id2) { - BroadcastMessage message = new BroadcastMessage(); - message.setChanges(Map.of(Permission.getKey(clazz1), id1, Permission.getKey(clazz2), id2)); - sendMessage(message); - } - - private void sendMessage(BroadcastMessage message) { + protected void sendMessage(BroadcastMessage message) { try { String payload = id + ":" + objectMapper.writeValueAsString(message); - publisherJedis.publish(pubsubChannel, payload); + publisher.publish(channel, payload); } catch (IOException e) { LOGGER.warn("Broadcast failed", e); - } - } - - private void handleMessage(BroadcastMessage message) { - if (message.getDevice() != null) { - listeners.forEach(listener -> listener.updateDevice(false, message.getDevice())); - } else if (message.getPosition() != null) { - listeners.forEach(listener -> listener.updatePosition(false, message.getPosition())); - } else if (message.getUserId() != null && message.getEvent() != null) { - listeners.forEach(listener -> listener.updateEvent(false, message.getUserId(), message.getEvent())); - } else if (message.getCommandDeviceId() != null) { - listeners.forEach(listener -> listener.updateCommand(false, message.getCommandDeviceId())); - } else if (message.getChanges() != null) { - var iterator = message.getChanges().entrySet().iterator(); - if (iterator.hasNext()) { - var first = iterator.next(); - if (iterator.hasNext()) { - var second = iterator.next(); - listeners.forEach(listener -> listener.invalidatePermission( - false, - Permission.getKeyClass(first.getKey()), first.getValue(), - Permission.getKeyClass(second.getKey()), second.getValue())); - } else { - listeners.forEach(listener -> listener.invalidateObject( - false, - Permission.getKeyClass(first.getKey()), first.getValue())); - } - } + } catch (JedisConnectionException e) { + LOGGER.warn("Broadcast failed", e); } } @@ -165,39 +83,45 @@ public class RedisBroadcastService implements BroadcastService { @Override public void stop() { + try { + if (subscriber != null) { + subscriber.close(); + subscriber = null; + } + } catch (JedisException e) { + LOGGER.warn("Subscriber close failed", e); + } + try { + if (publisher != null) { + publisher.close(); + publisher = null; + } + } catch (JedisException e) { + LOGGER.warn("Publisher close failed", e); + } service.shutdown(); } private final Runnable receiver = new Runnable() { @Override public void run() { - subscriberJedis.subscribe(new JedisPubSub() { - @Override - public void onMessage(String channel, String message) { - try { - String[] parts = message.split(":", 2); - if (channel == pubsubChannel && parts.length == 2 && !id.equals(parts[0])) { - handleMessage(objectMapper.readValue(parts[1], BroadcastMessage.class)); + try { + subscriber.subscribe(new JedisPubSub() { + @Override + public void onMessage(String messageChannel, String message) { + try { + String[] parts = message.split(":", 2); + if (messageChannel == channel && parts.length == 2 && !id.equals(parts[0])) { + handleMessage(objectMapper.readValue(parts[1], BroadcastMessage.class)); + } + } catch (IOException e) { + LOGGER.warn("Broadcast handleMessage failed", e); } - } catch (IOException e) { - LOGGER.warn("Broadcast handleMessage failed", e); } - } - }, pubsubChannel); - - while (!service.isShutdown()) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - break; - } - } - - try { - subscriberJedis.close(); - publisherJedis.close(); - } catch (Exception e) { - LOGGER.warn("Failed to close pubsub", e); + }, channel); + } catch (JedisConnectionException e) { + throw new RuntimeException(e); + } catch (JedisException e) { throw new RuntimeException(e); } } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 6f42e8937..381e3a108 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1771,7 +1771,7 @@ public final class Keys { List.of(KeyType.CONFIG)); /** - * Multicast address for broadcasting synchronization events. + * Multicast address or Redis URL for broadcasting synchronization events. */ public static final ConfigKey BROADCAST_ADDRESS = new StringConfigKey( "broadcast.address", -- cgit v1.2.3 From a39af3b4d72f3ed8a6dfe868d365d6bbf34e18d3 Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Fri, 9 Jun 2023 01:15:52 +0000 Subject: cleanup Breaking change: if using multicast must set broadcast.type="multicast" --- src/main/java/org/traccar/MainModule.java | 18 +++++++----------- .../org/traccar/broadcast/BaseBroadcastService.java | 2 +- src/main/java/org/traccar/config/Keys.java | 5 +++-- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 29d846154..950a7278a 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -341,18 +341,14 @@ public class MainModule extends AbstractModule { @Provides public static BroadcastService provideBroadcastService( Config config, ObjectMapper objectMapper) throws IOException { - String broadcastType = config.getString(Keys.BROADCAST_TYPE); - if (config.hasKey(Keys.BROADCAST_ADDRESS)) { - switch (broadcastType) { - case "multicast": - return new MulticastBroadcastService(config, objectMapper); - case "redis": - return new RedisBroadcastService(config, objectMapper); - default: - break; - } + switch (config.getString(Keys.BROADCAST_TYPE)) { + case "multicast": + return new MulticastBroadcastService(config, objectMapper); + case "redis": + return new RedisBroadcastService(config, objectMapper); + default: + return new NullBroadcastService(); } - return new NullBroadcastService(); } @Singleton diff --git a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java index 1ed639dfd..a95d333f2 100644 --- a/src/main/java/org/traccar/broadcast/BaseBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/BaseBroadcastService.java @@ -115,4 +115,4 @@ public abstract class BaseBroadcastService implements BroadcastService { } } -} \ No newline at end of file +} diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 381e3a108..78e081ce5 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1756,12 +1756,13 @@ public final class Keys { "time,position,speed,course,accuracy,result"); /** - * Broadcast method. Available options are "multicast" and "redis". Default is "multicast". + * Broadcast method. Available options are "multicast" and "redis". By default (if the value is not + * specified or does not matches available options) server disables broadcast. */ public static final ConfigKey BROADCAST_TYPE = new StringConfigKey( "broadcast.type", List.of(KeyType.CONFIG), - "multicast"); + ""); /** * Multicast interface. It can be either an IP address or an interface name. -- cgit v1.2.3 From dc22bc5feef7887d3baec1b2904fc18e1d067378 Mon Sep 17 00:00:00 2001 From: "Rafael E. Ajuria" Date: Sat, 10 Jun 2023 14:01:11 +0000 Subject: cleanup broadcast type --- src/main/java/org/traccar/MainModule.java | 17 ++++++++++------- src/main/java/org/traccar/config/Keys.java | 3 +-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 950a7278a..b7bdbc6bf 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -341,14 +341,17 @@ public class MainModule extends AbstractModule { @Provides public static BroadcastService provideBroadcastService( Config config, ObjectMapper objectMapper) throws IOException { - switch (config.getString(Keys.BROADCAST_TYPE)) { - case "multicast": - return new MulticastBroadcastService(config, objectMapper); - case "redis": - return new RedisBroadcastService(config, objectMapper); - default: - return new NullBroadcastService(); + if (config.hasKey(Keys.BROADCAST_TYPE)) { + switch (config.getString(Keys.BROADCAST_TYPE)) { + case "multicast": + return new MulticastBroadcastService(config, objectMapper); + case "redis": + return new RedisBroadcastService(config, objectMapper); + default: + break; + } } + return new NullBroadcastService(); } @Singleton diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 78e081ce5..1ff1d1b51 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -1761,8 +1761,7 @@ public final class Keys { */ public static final ConfigKey BROADCAST_TYPE = new StringConfigKey( "broadcast.type", - List.of(KeyType.CONFIG), - ""); + List.of(KeyType.CONFIG)); /** * Multicast interface. It can be either an IP address or an interface name. -- cgit v1.2.3