[discovery.mdns] Devices may apply a grace period for removal from the Inbox (#2635)

Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
This commit is contained in:
Andrew Fiddian-Green
2021-12-22 20:24:48 +01:00
committed by GitHub
parent 68ff739a50
commit 459dac9702
2 changed files with 56 additions and 1 deletions
@@ -66,4 +66,18 @@ public interface MDNSDiscoveryParticipant {
*/
@Nullable
ThingUID getThingUID(ServiceInfo service);
/**
* Some openHAB bindings handle devices that can sometimes be a bit late in updating their mDNS announcements, which
* means that such devices are repeatedly removed from, and (re)added to, the Inbox.
*
* To prevent this, a binding that implements an MDNSDiscoveryParticipant may OPTIONALLY implement this method to
* specify an additional delay period (grace period) to wait before the device is removed from the Inbox.
*
* @param serviceInfo the mDNS ServiceInfo describing the device on the network.
* @return the additional grace period delay in seconds before the device will be removed from the Inbox.
*/
default long getRemovalGracePeriodSeconds(ServiceInfo serviceInfo) {
return 0;
}
}
@@ -16,7 +16,9 @@ import java.time.Duration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.jmdns.ServiceEvent;
@@ -64,6 +66,11 @@ public class MDNSDiscoveryService extends AbstractDiscoveryService implements Se
private final MDNSClient mdnsClient;
/**
* Map of scheduled tasks to remove devices from the Inbox.
*/
private Map<String, ScheduledFuture<?>> deviceRemovalTasks = new ConcurrentHashMap<>();
@Activate
public MDNSDiscoveryService(final @Nullable Map<String, Object> configProperties,
final @Reference MDNSClient mdnsClient, final @Reference TranslationProvider i18nProvider,
@@ -200,7 +207,14 @@ public class MDNSDiscoveryService extends AbstractDiscoveryService implements Se
try {
ThingUID thingUID = participant.getThingUID(serviceEvent.getInfo());
if (thingUID != null) {
thingRemoved(thingUID);
ServiceInfo serviceInfo = serviceEvent.getInfo();
long gracePeriod = participant.getRemovalGracePeriodSeconds(serviceInfo);
if (gracePeriod <= 0) {
thingRemoved(thingUID);
} else {
cancelRemovalTask(serviceInfo);
scheduleRemovalTask(thingUID, serviceInfo, gracePeriod);
}
}
} catch (Exception e) {
logger.error("Participant '{}' threw an exception", participant.getClass().getName(), e);
@@ -221,6 +235,7 @@ public class MDNSDiscoveryService extends AbstractDiscoveryService implements Se
try {
DiscoveryResult result = participant.createResult(serviceEvent.getInfo());
if (result != null) {
cancelRemovalTask(serviceEvent.getInfo());
final DiscoveryResult resultNew = getLocalizedDiscoveryResult(result,
FrameworkUtil.getBundle(participant.getClass()));
thingDiscovered(resultNew);
@@ -232,4 +247,30 @@ public class MDNSDiscoveryService extends AbstractDiscoveryService implements Se
}
}
}
/**
* If the device has been scheduled to be removed, cancel its respective removal task.
*
* @param serviceInfo the mDNS ServiceInfo describing the device on the network.
*/
private void cancelRemovalTask(ServiceInfo serviceInfo) {
ScheduledFuture<?> deviceRemovalTask = deviceRemovalTasks.remove(serviceInfo.getQualifiedName());
if (deviceRemovalTask != null) {
deviceRemovalTask.cancel(false);
}
}
/**
* Schedule a task that will remove the device from the Inbox after the given grace period has expired.
*
* @param thingUID the UID of the Thing to be removed.
* @param serviceInfo the mDNS ServiceInfo describing the device on the network.
* @param gracePeriod the scheduled delay in seconds.
*/
private void scheduleRemovalTask(ThingUID thingUID, ServiceInfo serviceInfo, long gracePeriod) {
deviceRemovalTasks.put(serviceInfo.getQualifiedName(), scheduler.schedule(() -> {
thingRemoved(thingUID);
cancelRemovalTask(serviceInfo);
}, gracePeriod, TimeUnit.SECONDS));
}
}