From 4c11c653e21b7f17da654c262ea97acef1b6aac7 Mon Sep 17 00:00:00 2001 From: Holger Friedrich Date: Fri, 8 Dec 2023 01:13:18 +0100 Subject: [PATCH] Service to suggest addons based on running processes Signed-off-by: Holger Friedrich --- .../addon/process/ProcessAddonFinder.java | 119 ++++++++++++++++++ .../discovery/addon/AddonFinderConstants.java | 5 + bundles/pom.xml | 1 + 3 files changed, 125 insertions(+) create mode 100644 bundles/org.openhab.core.config.discovery.addon.process/src/main/java/org/openhab/core/config/discovery/addon/process/ProcessAddonFinder.java diff --git a/bundles/org.openhab.core.config.discovery.addon.process/src/main/java/org/openhab/core/config/discovery/addon/process/ProcessAddonFinder.java b/bundles/org.openhab.core.config.discovery.addon.process/src/main/java/org/openhab/core/config/discovery/addon/process/ProcessAddonFinder.java new file mode 100644 index 00000000000..cca401d561e --- /dev/null +++ b/bundles/org.openhab.core.config.discovery.addon.process/src/main/java/org/openhab/core/config/discovery/addon/process/ProcessAddonFinder.java @@ -0,0 +1,119 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.config.discovery.addon.process; + +import static org.openhab.core.config.discovery.addon.AddonFinderConstants.SERVICE_NAME_PROCESS; +import static org.openhab.core.config.discovery.addon.AddonFinderConstants.SERVICE_TYPE_PROCESS; + +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.core.addon.AddonDiscoveryMethod; +import org.openhab.core.addon.AddonInfo; +import org.openhab.core.config.discovery.addon.AddonFinder; +import org.openhab.core.config.discovery.addon.BaseAddonFinder; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This is a {@link ProcessAddonFinder} for finding suggested add-ons by checking processes running + * on the openHAB server. + * + * @author Holger Friedrich - Initial contribution + */ +@NonNullByDefault +@Component(service = AddonFinder.class, name = ProcessAddonFinder.SERVICE_NAME) +public class ProcessAddonFinder extends BaseAddonFinder { + + private static final String COMMAND = "command"; + + public static final String SERVICE_TYPE = SERVICE_TYPE_PROCESS; + public static final String SERVICE_NAME = SERVICE_NAME_PROCESS; + + private final Logger logger = LoggerFactory.getLogger(ProcessAddonFinder.class); + + @Activate + public ProcessAddonFinder() { + } + + // get list of running processes visible to openHAB, + // also tries to mitigate differences on different operating systems + String getProcessCommandProcess(ProcessHandle h) { + Optional command = h.info().command(); + if (command.isPresent()) + return command.get(); + Optional args = h.info().arguments(); + if (!args.isPresent()) + return ""; + String[] argsArray = args.get(); + if (argsArray.length < 1) + return ""; + return argsArray[0]; + } + + @Override + public Set getSuggestedAddons() { + Set processList = ProcessHandle.allProcesses().map(this::getProcessCommandProcess) + .filter(Predicate.not(String::isEmpty)).collect(Collectors.toUnmodifiableSet()); + Set result = new HashSet<>(); + for (AddonInfo candidate : addonCandidates) { + for (AddonDiscoveryMethod method : candidate.getDiscoveryMethods().stream() + .filter(method -> SERVICE_TYPE.equals(method.getServiceType())).toList()) { + Map matchProperties = method.getMatchProperties().stream() + .collect(Collectors.toMap(property -> property.getName(), property -> property.getPattern())); + + // make sure addon.xml specifies required match properties + Set propertyNames = new HashSet<>(matchProperties.keySet()); + if (!matchProperties.containsKey(COMMAND)) { + logger.warn("Add-on '{}' addon.xml file does not specify match property \"{}\"", candidate.getUID(), + COMMAND); + break; + } + // make sure addon.xml does not specify unknown properties + propertyNames.remove(COMMAND); + if (!propertyNames.isEmpty()) { + logger.warn("Add-on '{}' addon.xml file contains unsupported 'match-property' [{}]", + candidate.getUID(), String.join(",", propertyNames)); + break; + } + + // now check if a process matches the pattern defined in addon.xml + logger.debug("Checking candidate: {}", candidate.getUID()); + + Pattern p = matchProperties.get(COMMAND); + + boolean match = processList.stream().anyMatch(c -> p.matcher(c).matches()); + + if (match) { + result.add(candidate); + logger.debug("Suggested add-on found: {}", candidate.getUID()); + break; + } + } + } + return result; + } + + @Override + public String getServiceName() { + return SERVICE_NAME; + } +} diff --git a/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/AddonFinderConstants.java b/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/AddonFinderConstants.java index 596498898d5..bc30e87baf9 100644 --- a/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/AddonFinderConstants.java +++ b/bundles/org.openhab.core.config.discovery.addon/src/main/java/org/openhab/core/config/discovery/addon/AddonFinderConstants.java @@ -33,6 +33,11 @@ public class AddonFinderConstants { public static final String SERVICE_NAME_MDNS = SERVICE_TYPE_MDNS + ADDON_SUGGESTION_FINDER; public static final String FEATURE_MDNS = ADDON_SUGGESTION_FINDER_FEATURE + SERVICE_TYPE_MDNS; + public static final String SERVICE_TYPE_PROCESS = "process"; + public static final String CFG_FINDER_PROCESS = "suggestionFinderProcess"; + public static final String SERVICE_NAME_PROCESS = SERVICE_TYPE_PROCESS + ADDON_SUGGESTION_FINDER; + public static final String FEATURE_PROCESS = ADDON_SUGGESTION_FINDER_FEATURE + SERVICE_TYPE_PROCESS; + public static final String SERVICE_TYPE_UPNP = "upnp"; public static final String CFG_FINDER_UPNP = "suggestionFinderUpnp"; public static final String SERVICE_NAME_UPNP = SERVICE_TYPE_UPNP + ADDON_SUGGESTION_FINDER; diff --git a/bundles/pom.xml b/bundles/pom.xml index ad744143289..a796a1ad341 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -32,6 +32,7 @@ org.openhab.core.config.discovery org.openhab.core.config.discovery.addon org.openhab.core.config.discovery.addon.mdns + org.openhab.core.config.discovery.addon.process org.openhab.core.config.discovery.addon.upnp org.openhab.core.config.discovery.mdns org.openhab.core.config.discovery.usbserial