Skip to content

Commit

Permalink
Service to suggest addons based on running processes
Browse files Browse the repository at this point in the history
Signed-off-by: Holger Friedrich <[email protected]>
  • Loading branch information
holgerfriedrich committed Dec 8, 2023
1 parent 62a50a4 commit 4c11c65
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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<String> command = h.info().command();
if (command.isPresent())
return command.get();
Optional<String[]> args = h.info().arguments();
if (!args.isPresent())
return "";
String[] argsArray = args.get();
if (argsArray.length < 1)
return "";
return argsArray[0];
}

@Override
public Set<AddonInfo> getSuggestedAddons() {
Set<String> processList = ProcessHandle.allProcesses().map(this::getProcessCommandProcess)
.filter(Predicate.not(String::isEmpty)).collect(Collectors.toUnmodifiableSet());
Set<AddonInfo> result = new HashSet<>();
for (AddonInfo candidate : addonCandidates) {
for (AddonDiscoveryMethod method : candidate.getDiscoveryMethods().stream()
.filter(method -> SERVICE_TYPE.equals(method.getServiceType())).toList()) {
Map<String, Pattern> matchProperties = method.getMatchProperties().stream()
.collect(Collectors.toMap(property -> property.getName(), property -> property.getPattern()));

// make sure addon.xml specifies required match properties
Set<String> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions bundles/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<module>org.openhab.core.config.discovery</module>
<module>org.openhab.core.config.discovery.addon</module>
<module>org.openhab.core.config.discovery.addon.mdns</module>
<module>org.openhab.core.config.discovery.addon.process</module>
<module>org.openhab.core.config.discovery.addon.upnp</module>
<module>org.openhab.core.config.discovery.mdns</module>
<module>org.openhab.core.config.discovery.usbserial</module>
Expand Down

0 comments on commit 4c11c65

Please sign in to comment.