diff --git a/addons/binding/org.openhab.binding.harmonyhub/.classpath b/addons/binding/org.openhab.binding.harmonyhub/.classpath index b1f0a1d8aca8b..0d63d661ae316 100644 --- a/addons/binding/org.openhab.binding.harmonyhub/.classpath +++ b/addons/binding/org.openhab.binding.harmonyhub/.classpath @@ -3,18 +3,6 @@ - - - - - - - - - - - - - + diff --git a/addons/binding/org.openhab.binding.harmonyhub/ESH-INF/thing/thing-types.xml b/addons/binding/org.openhab.binding.harmonyhub/ESH-INF/thing/thing-types.xml index b8f6488d91708..342aac7329c6b 100644 --- a/addons/binding/org.openhab.binding.harmonyhub/ESH-INF/thing/thing-types.xml +++ b/addons/binding/org.openhab.binding.harmonyhub/ESH-INF/thing/thing-types.xml @@ -27,9 +27,9 @@ Host or IP address of hub. network-address - + - 60 + 30 Heartbeat keep alive time in seconds. diff --git a/addons/binding/org.openhab.binding.harmonyhub/META-INF/MANIFEST.MF b/addons/binding/org.openhab.binding.harmonyhub/META-INF/MANIFEST.MF index 034547bc237f0..e75a389b60f36 100644 --- a/addons/binding/org.openhab.binding.harmonyhub/META-INF/MANIFEST.MF +++ b/addons/binding/org.openhab.binding.harmonyhub/META-INF/MANIFEST.MF @@ -3,19 +3,7 @@ Automatic-Module-Name: org.openhab.binding.harmonyhub Bundle-ActivationPolicy: lazy Bundle-ClassPath: ., - lib/harmony-java-client-1.2.2.jar, - lib/jackson-annotations-2.8.0.jar, - lib/jackson-core-2.8.7.jar, - lib/jackson-databind-2.8.7.jar, - lib/jxmpp-core-0.5.0.jar, - lib/jxmpp-jid-0.5.0.jar, - lib/jxmpp-util-cache-0.5.0.jar, - lib/smack-core-4.2.0.jar, - lib/smack-java7-4.2.0.jar, - lib/smack-resolver-javax-4.2.0.jar, - lib/smack-sasl-javax-4.2.0.jar, - lib/smack-tcp-4.2.0.jar, - lib/xpp3-1.1.4c.jar + lib/harmony-client-1.0.jar Bundle-ManifestVersion: 2 Bundle-Name: HarmonyHub Binding Bundle-RequiredExecutionEnvironment: JavaSE-1.8 @@ -23,13 +11,24 @@ Bundle-SymbolicName: org.openhab.binding.harmonyhub;singleton:=true Bundle-Vendor: openHAB Bundle-Version: 2.5.0.qualifier Import-Package: - com.google.common.base, - com.google.common.collect, - com.google.common.io, + com.google.gson, + com.google.gson.annotations, com.google.inject, javax.inject, org.apache.commons.lang, org.eclipse.jdt.annotation;resolution:=optional, + org.eclipse.jetty.client, + org.eclipse.jetty.client.api, + org.eclipse.jetty.client.util, + org.eclipse.jetty.http, + org.eclipse.jetty.io, + org.eclipse.jetty.server.session, + org.eclipse.jetty.util.component, + org.eclipse.jetty.util.ssl, + org.eclipse.jetty.websocket.api, + org.eclipse.jetty.websocket.client, + org.eclipse.jetty.websocket.common, + org.eclipse.jetty.websocket.common.scopes, org.eclipse.smarthome.config.core, org.eclipse.smarthome.config.discovery, org.eclipse.smarthome.core.cache, diff --git a/addons/binding/org.openhab.binding.harmonyhub/NOTICE b/addons/binding/org.openhab.binding.harmonyhub/NOTICE index 4dd30fce45a94..e374be948c848 100644 --- a/addons/binding/org.openhab.binding.harmonyhub/NOTICE +++ b/addons/binding/org.openhab.binding.harmonyhub/NOTICE @@ -14,27 +14,7 @@ https://github.com/openhab/openhab2-addons == Third-party Content -harmony-java-client -* License: EPL 1.0 License -* Project: https://github.com/tuck182/harmony-java-client -* Source: https://github.com/tuck182/harmony-java-client - -jackson -* License: Apache 2.0 License -* Project: https://github.com/FasterXML/jackson -* Source: https://github.com/FasterXML/jackson - -jxmpp -* License: Apache 2.0 License -* Project: https://github.com/igniterealtime/jxmpp -* Source: https://github.com/igniterealtime/jxmpp - -smack -* License: Apache 2.0 License -* Project: https://www.igniterealtime.org/projects/smack/ -* Source: https://github.com/igniterealtime/Smack - -xpp3 -* License: Apache 2.0 License -* Project: http://www.extreme.indiana.edu/xgws/xsoap/xpp/mxp1 -* Source: http://www.extreme.indiana.edu/xgws/xsoap/xpp/mxp1 +harmony-client +* License: EPL 2.0 License +* Project: https://github.com/digitaldan/harmony-client +* Source: https://github.com/digitaldan/harmony-client diff --git a/addons/binding/org.openhab.binding.harmonyhub/build.properties b/addons/binding/org.openhab.binding.harmonyhub/build.properties index 6bbef1e1cde06..1908036ebf976 100644 --- a/addons/binding/org.openhab.binding.harmonyhub/build.properties +++ b/addons/binding/org.openhab.binding.harmonyhub/build.properties @@ -4,18 +4,5 @@ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ ESH-INF/,\ - lib/harmony-java-client-1.2.2.jar,\ - lib/jackson-annotations-2.8.0.jar,\ - lib/jackson-core-2.8.7.jar,\ - lib/jackson-databind-2.8.7.jar,\ - lib/jxmpp-core-0.5.0.jar,\ - lib/jxmpp-jid-0.5.0.jar,\ - lib/jxmpp-util-cache-0.5.0.jar,\ - lib/smack-core-4.2.0.jar,\ - lib/smack-java7-4.2.0.jar,\ - lib/smack-resolver-javax-4.2.0.jar,\ - lib/smack-sasl-javax-4.2.0.jar,\ - lib/smack-tcp-4.2.0.jar,\ - lib/xpp3-1.1.4c.jar,\ - NOTICE + lib/harmony-client-1.0.jar diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/harmony-client-1.0.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/harmony-client-1.0.jar new file mode 100644 index 0000000000000..3d5a9c4c6df60 Binary files /dev/null and b/addons/binding/org.openhab.binding.harmonyhub/lib/harmony-client-1.0.jar differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/harmony-java-client-1.2.2.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/harmony-java-client-1.2.2.jar deleted file mode 100644 index 60fa27d86961a..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/harmony-java-client-1.2.2.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/jackson-annotations-2.8.0.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/jackson-annotations-2.8.0.jar deleted file mode 100644 index d19b67b0f1108..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/jackson-annotations-2.8.0.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/jackson-core-2.8.7.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/jackson-core-2.8.7.jar deleted file mode 100644 index 3ddd6a0e5f48f..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/jackson-core-2.8.7.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/jackson-databind-2.8.7.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/jackson-databind-2.8.7.jar deleted file mode 100644 index 1d155d36ed954..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/jackson-databind-2.8.7.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/jxmpp-core-0.5.0.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/jxmpp-core-0.5.0.jar deleted file mode 100644 index ce5f193a045b2..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/jxmpp-core-0.5.0.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/jxmpp-jid-0.5.0.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/jxmpp-jid-0.5.0.jar deleted file mode 100644 index e65dee78d11e1..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/jxmpp-jid-0.5.0.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/jxmpp-util-cache-0.5.0.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/jxmpp-util-cache-0.5.0.jar deleted file mode 100644 index 724629a9a1420..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/jxmpp-util-cache-0.5.0.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/smack-core-4.2.0.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/smack-core-4.2.0.jar deleted file mode 100644 index 35e358846e377..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/smack-core-4.2.0.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/smack-java7-4.2.0.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/smack-java7-4.2.0.jar deleted file mode 100644 index 3191e3d768891..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/smack-java7-4.2.0.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/smack-resolver-javax-4.2.0.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/smack-resolver-javax-4.2.0.jar deleted file mode 100644 index a5c891661be40..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/smack-resolver-javax-4.2.0.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/smack-sasl-javax-4.2.0.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/smack-sasl-javax-4.2.0.jar deleted file mode 100644 index 12fc0b4bfd714..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/smack-sasl-javax-4.2.0.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/smack-tcp-4.2.0.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/smack-tcp-4.2.0.jar deleted file mode 100644 index aee63b37b911d..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/smack-tcp-4.2.0.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/lib/xpp3-1.1.4c.jar b/addons/binding/org.openhab.binding.harmonyhub/lib/xpp3-1.1.4c.jar deleted file mode 100644 index 451ac82af4a30..0000000000000 Binary files a/addons/binding/org.openhab.binding.harmonyhub/lib/xpp3-1.1.4c.jar and /dev/null differ diff --git a/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/discovery/HarmonyDeviceDiscoveryService.java b/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/discovery/HarmonyDeviceDiscoveryService.java index c8606fa506fcc..6dddd0669b887 100644 --- a/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/discovery/HarmonyDeviceDiscoveryService.java +++ b/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/discovery/HarmonyDeviceDiscoveryService.java @@ -25,8 +25,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import net.whistlingfish.harmony.config.Device; -import net.whistlingfish.harmony.config.HarmonyConfig; +import com.digitaldan.harmony.config.Device; +import com.digitaldan.harmony.config.HarmonyConfig; /** * The {@link HarmonyDeviceDiscoveryService} class discovers Harmony Devices connected to a Harmony Hub diff --git a/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/handler/HarmonyDeviceHandler.java b/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/handler/HarmonyDeviceHandler.java index 836372660fd53..6fb0923690e04 100644 --- a/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/handler/HarmonyDeviceHandler.java +++ b/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/handler/HarmonyDeviceHandler.java @@ -47,10 +47,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import net.whistlingfish.harmony.config.ControlGroup; -import net.whistlingfish.harmony.config.Device; -import net.whistlingfish.harmony.config.Function; -import net.whistlingfish.harmony.config.HarmonyConfig; +import com.digitaldan.harmony.config.ControlGroup; +import com.digitaldan.harmony.config.Device; +import com.digitaldan.harmony.config.Function; +import com.digitaldan.harmony.config.HarmonyConfig; /** * The {@link HarmonyDeviceHandler} is responsible for handling commands for Harmony Devices, which are diff --git a/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/handler/HarmonyHubHandler.java b/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/handler/HarmonyHubHandler.java index 1d0dd1fd39d1c..5754d3194adfa 100644 --- a/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/handler/HarmonyHubHandler.java +++ b/addons/binding/org.openhab.binding.harmonyhub/src/main/java/org/openhab/binding/harmonyhub/internal/handler/HarmonyHubHandler.java @@ -22,17 +22,13 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import java.util.function.Supplier; import org.apache.commons.lang.StringUtils; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.smarthome.config.core.Configuration; -import org.eclipse.smarthome.core.cache.ExpiringCacheAsync; import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.library.types.StringType; import org.eclipse.smarthome.core.thing.Bridge; @@ -56,12 +52,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import net.whistlingfish.harmony.ActivityChangeListener; -import net.whistlingfish.harmony.ActivityStatusListener; -import net.whistlingfish.harmony.HarmonyClient; -import net.whistlingfish.harmony.HarmonyHubListener; -import net.whistlingfish.harmony.config.Activity; -import net.whistlingfish.harmony.config.HarmonyConfig; +import com.digitaldan.harmony.HarmonyClient; +import com.digitaldan.harmony.HarmonyClientListener; +import com.digitaldan.harmony.config.Activity; +import com.digitaldan.harmony.config.Activity.Status; +import com.digitaldan.harmony.config.HarmonyConfig; /** * The {@link HarmonyHubHandler} is responsible for handling commands for Harmony Hubs, which are @@ -72,7 +67,7 @@ * @author Wouter Born - Add null annotations */ @NonNullByDefault -public class HarmonyHubHandler extends BaseBridgeHandler implements HarmonyHubListener { +public class HarmonyHubHandler extends BaseBridgeHandler { private final Logger logger = LoggerFactory.getLogger(HarmonyHubHandler.class); @@ -81,23 +76,19 @@ public class HarmonyHubHandler extends BaseBridgeHandler implements HarmonyHubLi private static final Comparator ACTIVITY_COMPERATOR = Comparator.comparing(Activity::getActivityOrder, Comparator.nullsFirst(Integer::compareTo)); - // one minute should be plenty short, but not overwhelm the hub with requests - private static final long CONFIG_CACHE_TIME = TimeUnit.MINUTES.toMillis(1); private static final int RETRY_TIME = 60; private static final int HEARTBEAT_INTERVAL = 30; - + // Websocket will timeout after 60 seconds, pick a sensible max under this, + private static final int HEARTBEAT_INTERVAL_MAX = 50; private List listeners = new CopyOnWriteArrayList<>(); - - private final ExpiringCacheAsync<@Nullable HarmonyConfig> configCache = new ExpiringCacheAsync<>(CONFIG_CACHE_TIME); private final HarmonyHubHandlerFactory factory; - - private @NonNullByDefault({}) ScheduledExecutorService buttonExecutor; private @NonNullByDefault({}) HarmonyHubConfig config; - private @Nullable HarmonyClient client; private @Nullable ScheduledFuture retryJob; private @Nullable ScheduledFuture heartBeatJob; + private @Nullable HarmonyClientListener harmonyClientListener; + private int heartBeatInterval; public HarmonyHubHandler(Bridge bridge, HarmonyHubHandlerFactory factory) { @@ -116,7 +107,9 @@ public void handleCommand(ChannelUID channelUID, Command command) { } if (command instanceof RefreshType) { - updateState(localClient.getCurrentActivity()); + localClient.getCurrentActivity().thenAccept(activity -> { + updateState(activity); + }); } else if (command instanceof StringType) { try { try { @@ -143,7 +136,6 @@ public void handleCommand(ChannelUID channelUID, Command command) { @Override public void initialize() { - buttonExecutor = Executors.newSingleThreadScheduledExecutor(); config = getConfigAs(HarmonyHubConfig.class); cancelRetry(); updateStatus(ThingStatus.UNKNOWN); @@ -152,7 +144,6 @@ public void initialize() { @Override public void dispose() { - buttonExecutor.shutdownNow(); listeners.clear(); cancelRetry(); disconnectFromHub(); @@ -172,39 +163,10 @@ protected void updateStatus(ThingStatus status, ThingStatusDetail detail, @Nulla public void channelLinked(ChannelUID channelUID) { HarmonyClient localClient = client; if (localClient != null) { - updateState(channelUID, new StringType(localClient.getCurrentActivity().getLabel())); - } - } - - /** - * HarmonyHubListener interface - */ - @Override - public void removeFrom(@Nullable HarmonyClient hc) { - // we have been removed from listening - } - - /** - * HarmonyHubListener interface - */ - @Override - public void addTo(@Nullable HarmonyClient hc) { - if (hc == null) { - logger.warn("Cannot add listeners to HarmonyClient that is null"); - return; + localClient.getCurrentActivity().thenAccept((activity) -> { + updateState(channelUID, new StringType(activity.getLabel())); + }); } - hc.addListener(new ActivityChangeListener() { - @Override - public void activityStarted(@Nullable Activity activity) { - updateState(activity); - } - }); - hc.addListener(new ActivityStatusListener() { - @Override - public void activityStatusChanged(@Nullable Activity activity, Activity.@Nullable Status status) { - updateActivityStatus(activity, status); - } - }); } /** @@ -213,7 +175,8 @@ public void activityStatusChanged(@Nullable Activity activity, Activity.@Nullabl private synchronized void connect() { disconnectFromHub(); - heartBeatInterval = config.heartBeatInterval > 0 ? config.heartBeatInterval : HEARTBEAT_INTERVAL; + heartBeatInterval = Math.min(config.heartBeatInterval > 0 ? config.heartBeatInterval : HEARTBEAT_INTERVAL, + HEARTBEAT_INTERVAL_MAX); String host = config.host; @@ -233,27 +196,53 @@ private synchronized void connect() { } } - HarmonyClient localClient = HarmonyClient.getInstance(); - localClient.addListener(this); - client = localClient; + HarmonyClient localClient = new HarmonyClient(); + harmonyClientListener = new HarmonyClientListener() { + + @Override + public void hubDisconnected(@Nullable String reason) { + setOfflineAndReconnect(String.format("Could not connect: %s", reason)); + } + + @Override + public void hubConnected() { + client = localClient; + heartBeatJob = scheduler.scheduleWithFixedDelay(() -> { + try { + client.sendPing(); + } catch (Exception e) { + logger.debug("heartbeat failed", e); + setOfflineAndReconnect("Hearbeat failed"); + } + }, heartBeatInterval, heartBeatInterval, TimeUnit.SECONDS); + updateStatus(ThingStatus.ONLINE); + getConfigFuture() + .thenAcceptAsync(harmonyConfig -> updateCurrentActivityChannel(harmonyConfig), scheduler) + .exceptionally(e -> { + setOfflineAndReconnect("Getting config failed: " + e.getMessage()); + return null; + }); + localClient.getCurrentActivity().thenAccept(activity -> { + updateState(activity); + }); + } + + @Override + public void activityStatusChanged(@Nullable Activity activity, @Nullable Status status) { + updateActivityStatus(activity, status); + } + + @Override + public void activityStarted(@Nullable Activity activity) { + updateState(activity); + } + }; + + localClient.addListener(harmonyClientListener); try { logger.debug("Connecting: host {}", host); localClient.connect(host); - heartBeatJob = scheduler.scheduleWithFixedDelay(() -> { - try { - localClient.sendPing(); - } catch (Exception e) { - logger.warn("heartbeat failed", e); - setOfflineAndReconnect("Hearbeat failed"); - } - }, heartBeatInterval, heartBeatInterval, TimeUnit.SECONDS); - updateStatus(ThingStatus.ONLINE); - getConfigFuture().thenAcceptAsync(harmonyConfig -> updateCurrentActivityChannel(harmonyConfig), scheduler) - .exceptionally(e -> { - setOfflineAndReconnect("Getting config failed: " + e.getMessage()); - return null; - }); } catch (Exception e) { logger.debug("Could not connect to HarmonyHub at {}", host, e); setOfflineAndReconnect("Could not connect: " + e.getMessage()); @@ -268,7 +257,7 @@ private void disconnectFromHub() { HarmonyClient localClient = client; if (localClient != null) { - localClient.removeListener(this); + localClient.removeListener(harmonyClientListener); localClient.disconnect(); } } @@ -390,12 +379,8 @@ private void updateCurrentActivityChannel(@Nullable HarmonyConfig config) { * @param button */ public void pressButton(int device, String button) { - if (!buttonExecutor.isShutdown()) { - buttonExecutor.execute(() -> { - if (client != null) { - client.pressButton(device, button); - } - }); + if (client != null) { + client.pressButton(device, button); } } @@ -406,33 +391,17 @@ public void pressButton(int device, String button) { * @param button */ public void pressButton(String device, String button) { - if (!buttonExecutor.isShutdown()) { - buttonExecutor.execute(() -> { - if (client != null) { - client.pressButton(device, button); - } - }); + if (client != null) { + client.pressButton(device, button); } } public CompletableFuture<@Nullable HarmonyConfig> getConfigFuture() { - Supplier<@Nullable HarmonyConfig> configSupplier = () -> { - HarmonyClient localClient = client; - if (localClient == null) { - throw new IllegalStateException("Client is null"); - } - try { - logger.debug("Getting config from client"); - return localClient.getConfig(); - } catch (Exception e) { - logger.debug("Could not get config from client", e); - throw e; - } - }; - - return configCache.getValue(() -> { - return CompletableFuture.supplyAsync(configSupplier, scheduler); - }); + HarmonyClient localClient = client; + if (localClient == null) { + throw new IllegalStateException("Client is null"); + } + return localClient.getConfig(); } /**