Skip to content

Commit

Permalink
Refactor Jetty HTTP client, add HTTP/2 streams and code improvements
Browse files Browse the repository at this point in the history
Signed-off-by: Jan N. Klug <[email protected]>
  • Loading branch information
J-N-K committed Oct 20, 2023
1 parent 5b9a32e commit d797ab8
Show file tree
Hide file tree
Showing 206 changed files with 6,820 additions and 5,335 deletions.
2 changes: 1 addition & 1 deletion bundles/org.smarthomej.binding.amazonechocontrol/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Upgrade notice:
Due to a wrong implementation the channel changed it's state to an empty string if the same command was received again.
This has been corrected.
If you want to be notified about every state update, please adjust your rule triggers to "received update".
If you want to be notified about state changes (i.e. different commands), use `state changed`.
If you want to be notified about state changes (i.e. different commands), use "state changed".

## What this can be used for

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,21 @@
*/
package org.smarthomej.binding.amazonechocontrol.internal;

import java.io.InputStreamReader;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.library.types.HSBType;
import org.openhab.core.thing.ThingTypeUID;
import org.smarthomej.binding.amazonechocontrol.internal.smarthome.AlexaColor;
import org.smarthomej.commons.util.ResourceUtil;

import com.google.gson.Gson;
import com.google.gson.JsonObject;

/**
* The {@link AmazonEchoControlBindingConstants} class defines common constants, which are
Expand All @@ -36,10 +46,8 @@ public class AmazonEchoControlBindingConstants {
public static final ThingTypeUID THING_TYPE_ECHO_SPOT = new ThingTypeUID(BINDING_ID, "echospot");
public static final ThingTypeUID THING_TYPE_ECHO_SHOW = new ThingTypeUID(BINDING_ID, "echoshow");
public static final ThingTypeUID THING_TYPE_ECHO_WHA = new ThingTypeUID(BINDING_ID, "wha");

public static final ThingTypeUID THING_TYPE_FLASH_BRIEFING_PROFILE = new ThingTypeUID(BINDING_ID,
"flashbriefingprofile");

public static final ThingTypeUID THING_TYPE_SMART_HOME_DEVICE = new ThingTypeUID(BINDING_ID, "smartHomeDevice");
public static final ThingTypeUID THING_TYPE_SMART_HOME_DEVICE_GROUP = new ThingTypeUID(BINDING_ID,
"smartHomeDeviceGroup");
Expand Down Expand Up @@ -93,7 +101,6 @@ public class AmazonEchoControlBindingConstants {
public static final String CHANNEL_NEXT_ALARM = "nextAlarm";
public static final String CHANNEL_NEXT_MUSIC_ALARM = "nextMusicAlarm";
public static final String CHANNEL_NEXT_TIMER = "nextTimer";

public static final String CHANNEL_SAVE = "save";
public static final String CHANNEL_ACTIVE = "active";
public static final String CHANNEL_PLAY_ON_DEVICE = "playOnDevice";
Expand All @@ -110,84 +117,18 @@ public class AmazonEchoControlBindingConstants {
// Other
public static final String FLASH_BRIEFING_COMMAND_PREFIX = "FlashBriefing.";

// DeviceTypeIds to human readable description
// originally found here: https://github.com/Apollon77/ioBroker.alexa2/blob/master/main.js
public static final Map<String, String> DEVICE_TYPES = Map.<String, String> ofEntries( //
Map.entry("A10A33FOX2NUBK", "Echo Spot"), //
Map.entry("A10L5JEZTKKCZ8", "Vobot-Clock"), //
Map.entry("A12GXV8XMS007S", "FireTV"), //
Map.entry("A15ERDAKK5HQQG", "Sonos"), //
Map.entry("A17LGWINFBUTZZ", "Anker Roav Viva Alexa"), //
Map.entry("A18O6U1UQFJ0XK", "Echo Plus 2nd Gen"), //
Map.entry("A1C66CX2XD756O", "Fire HD 8"), //
Map.entry("A1DL2DVDQVK3Q", "Apps"), //
Map.entry("A1ETW4IXK2PYBP", "Echo Auto"), //
Map.entry("A1H0CMF1XM0ZP4", "Echo Dot/Bose"), //
Map.entry("A1J16TEDOYCZTN", "Fire Tab"), //
Map.entry("A1JJ0KFC4ZPNJ3", "Echo Input"), //
Map.entry("A1NL4BVLQ4L3N3", "Echo Show"), //
Map.entry("A1P31Q3MOWSHOD", "Anker Zalo Halo Speaker"), //
Map.entry("A1Q7QCGNMXAKYW", "Fire Tab 7"), //
Map.entry("A1QKZ9D0IJY332", "Samsung QLED"), //
Map.entry("A1RABVCI4QCIKC", "Echo Dot 3rd Gen"), //
Map.entry("A1RTAM01W29CUP", "Windows App"), //
Map.entry("A1X7HJX9QL16M5", "Bespoken.io"), //
Map.entry("A1Z88NGR2BK6A2", "Echo Show 8"), //
Map.entry("A1ZB65LA390I4K", "Fire HD 10"), //
Map.entry("A21Z3CGI8UIP0F", "Apps"), //
Map.entry("A265XOI9586NML", "FireTV Stick v3"), //
Map.entry("A2825NDLA7WDZV", "Apps"), //
Map.entry("A2E0SNTXJVT7WK", "FireTV V1"), //
Map.entry("A2GFL5ZMWNE0PX", "FireTV"), //
Map.entry("A2H4LV5GIZ1JFT", "Echo 4 Clock"), //
Map.entry("A2IVLV5VM2W81", "Apps"), //
Map.entry("A2J0R2SD7G9LPA", "Tablet"), //
Map.entry("A2JKHJ0PX4J3L3", "FireTV Cube"), //
Map.entry("A2L8KG0CT86ADW", "RaspPi"), //
Map.entry("A2LWARUGJLBYEW", "FireTV Stick V2"), //
Map.entry("A2M35JJZWCQOMZ", "Echo Plus"), //
Map.entry("A2M4YX06LWP8WI", "Fire Tab"), //
Map.entry("A2OSP3UA4VC85F", "Sonos"), //
Map.entry("A2T0P32DY3F7VB", "echosim.io"), //
Map.entry("A2TF17PFR55MTB", "Apps"), //
Map.entry("A2U21SRK4QGSE1", "Echo Dot 4th Gen"), //
Map.entry("A2Z8O30CD35N8F", "Sonos Arc"), //
Map.entry("A303PJF6ISQ7IC", "Echo Auto"), //
Map.entry("A30YDR2MK8HMRV", "Echo Dot 3rd Gen Clock"), //
Map.entry("A31DTMEEVDDOIV", "FireTV Stick Lite 2020"), //
Map.entry("A32DOYMUN6DTXA", "Echo Dot 3rd Gen"), //
Map.entry("A378ND93PD0NC4", "VR Radio"), //
Map.entry("A37SHHQ3NUL7B5", "Bose Homespeaker"), //
Map.entry("A38BPK7OW001EX", "Raspberry Alexa"), //
Map.entry("A38EHHIB10L47V", "Echo Dot"), //
Map.entry("A39Y3UG1XLEJLZ", "Fitbit Sense"), //
Map.entry("A3C9PE6TNYLTCH", "Multiroom"), //
Map.entry("A3FX4UWTP28V1P", "Echo 3"), //
Map.entry("A3GZUE7F9MEB4U", "FireTV Cube"), //
Map.entry("A3H674413M2EKB", "echosim.io"), //
Map.entry("A3HF4YRA2L7XGC", "FireTV Cube"), //
Map.entry("A3NPD82ABCPIDP", "Sonos Beam"), //
Map.entry("A3R8XIAIU4HJAX", "Echo Show"), //
Map.entry("A3R9S4ZZECZ6YL", "Fire Tab HD 10"), //
Map.entry("A3RBAYBE7VM004", "Echo Studio"), //
Map.entry("A3RMGO6LYLH7YN", "Echo 4 Bridge"), //
Map.entry("A3S5BH2HU6VAYF", "Echo Dot 2nd Gen"), //
Map.entry("A3SSG6GR8UU7SN", "Echo Sub"), //
Map.entry("A3TCJ8RTT3NVI7", "Listens for Alexa"), //
Map.entry("A3V3VA38K169FO", "Fire Tab"), //
Map.entry("A3VRME03NAXFUB", "Echo Flex"), //
Map.entry("A4ZP7ZC4PI6TO", "Echo Show 5th Gen"), //
Map.entry("A7WXQPH584YP", "Echo 2nd Gen"), //
Map.entry("A8DM4FYR6D3HT", "LG WebOS TV"), //
Map.entry("AB72C64C86AW2", "Echo"), //
Map.entry("ADVBD696BHNV5", "FireTV Stick V1"), //
Map.entry("AILBSA2LNTOYL", "reverb App"), //
Map.entry("AINRG27IL8AS0", "Megablast Speaker"), //
Map.entry("AKOAGQTKAS9YB", "Echo Connect"), //
Map.entry("AKPGW064GI9HE", "FireTV Stick 4K"), //
Map.entry("AP1F6KUH00XPV", "Stereo/Subwoofer Pair"), //
Map.entry("AVD3HM0HOJAAL", "Sonos One 2nd Gen"), //
Map.entry("AVE5HX13UR5NO", "Logitech Zero Touch"), //
Map.entry("AVU7CPPF2ZRAS", "Fire HD 8"), //
Map.entry("AWZZ5CVHX2CD", "Echo Show 2nd Gen"));
public static final String API_VERSION = "2.2.556530.0";
public static final String DI_OS_VERSION = "16.6";
public static final String DI_SDK_VERSION = "6.12.4";

public static final Map<String, String> DEVICE_TYPES = ResourceUtil
.readProperties(AmazonEchoControlBindingConstants.class, "device_type.properties");

public static final JsonObject CAPABILITY_REGISTRATION = Objects.requireNonNull(
ResourceUtil.getResourceStream(AmazonEchoControlBindingConstants.class, "registration_capabilities.json")
.map(inputStream -> new Gson().fromJson(new InputStreamReader(inputStream), JsonObject.class))
.orElseThrow(() -> new IllegalStateException("resource not found")));
public static final List<AlexaColor> ALEXA_COLORS = ResourceUtil
.readProperties(AlexaColor.class, "color.properties").entrySet().stream()
.map(e -> new AlexaColor(e.getKey(), new HSBType(e.getValue()))).collect(Collectors.toList());
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.storage.Storage;
import org.openhab.core.storage.StorageService;
import org.openhab.core.thing.Bridge;
Expand All @@ -30,7 +31,6 @@
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
Expand All @@ -40,10 +40,13 @@
import org.smarthomej.binding.amazonechocontrol.internal.handler.EchoHandler;
import org.smarthomej.binding.amazonechocontrol.internal.handler.FlashBriefingProfileHandler;
import org.smarthomej.binding.amazonechocontrol.internal.handler.SmartHomeDeviceHandler;
import org.smarthomej.binding.amazonechocontrol.internal.util.NonNullListTypeAdapterFactory;
import org.smarthomej.binding.amazonechocontrol.internal.util.SerializeNullTypeAdapterFactory;
import org.smarthomej.commons.SimpleDynamicCommandDescriptionProvider;
import org.smarthomej.commons.SimpleDynamicStateDescriptionProvider;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
* The {@link AmazonEchoControlHandlerFactory} is responsible for creating things and thing
Expand All @@ -59,30 +62,38 @@ public class AmazonEchoControlHandlerFactory extends BaseThingHandlerFactory {
private final HttpService httpService;
private final StorageService storageService;

private final BindingServlet bindingServlet;
private final Gson gson;
private final HttpClient httpClient;
private final HTTP2Client http2Client;

private final SimpleDynamicCommandDescriptionProvider dynamicCommandDescriptionProvider;
private final SimpleDynamicStateDescriptionProvider dynamicStateDescriptionProvider;

@Activate
public AmazonEchoControlHandlerFactory(@Reference HttpService httpService, @Reference StorageService storageService,
@Reference SimpleDynamicCommandDescriptionProvider dynamicCommandDescriptionProvider,
@Reference SimpleDynamicStateDescriptionProvider dynamicStateDescriptionProvider) throws Exception {
@Reference SimpleDynamicStateDescriptionProvider dynamicStateDescriptionProvider,
@Reference HttpClientFactory httpClientFactory) throws Exception {
this.storageService = storageService;
this.httpService = httpService;
this.gson = new Gson();
this.gson = new GsonBuilder().registerTypeAdapterFactory(new NonNullListTypeAdapterFactory())
.registerTypeAdapterFactory(new SerializeNullTypeAdapterFactory()).create();
this.dynamicCommandDescriptionProvider = dynamicCommandDescriptionProvider;
this.dynamicStateDescriptionProvider = dynamicStateDescriptionProvider;
this.httpClient = new HttpClient(new SslContextFactory.Client());
this.bindingServlet = new BindingServlet(httpService);

this.httpClient = httpClientFactory.createHttpClient("smarthomej-aec");
this.http2Client = httpClientFactory.createHttp2Client("smarthomej-aec", httpClient.getSslContextFactory());
http2Client.setConnectTimeout(10000);
http2Client.setIdleTimeout(-1);

httpClient.start();
http2Client.start();
}

@Deactivate
@SuppressWarnings("unused")
public void deactivate() throws Exception {
http2Client.stop();
httpClient.stop();
}

Expand All @@ -92,22 +103,15 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|| SUPPORTED_SMART_HOME_THING_TYPES_UIDS.contains(thingTypeUID);
}

@Override
protected void deactivate(ComponentContext componentContext) {
bindingServlet.dispose();
super.deactivate(componentContext);
}

@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();

if (thingTypeUID.equals(THING_TYPE_ACCOUNT)) {
Storage<String> storage = storageService.getStorage(thing.getUID().toString(),
String.class.getClassLoader());
AccountHandler bridgeHandler = new AccountHandler((Bridge) thing, httpService, storage, gson, httpClient);
AccountHandler bridgeHandler = new AccountHandler((Bridge) thing, storage, gson, httpClient, http2Client);
accountHandlers.add(bridgeHandler);
bindingServlet.addAccountThing(thing);
return bridgeHandler;
} else if (thingTypeUID.equals(THING_TYPE_FLASH_BRIEFING_PROFILE)) {
Storage<String> storage = storageService.getStorage(thing.getUID().toString(),
Expand All @@ -126,8 +130,6 @@ protected void deactivate(ComponentContext componentContext) {
protected synchronized void removeHandler(ThingHandler thingHandler) {
if (thingHandler instanceof AccountHandler) {
accountHandlers.remove(thingHandler);
BindingServlet bindingServlet = this.bindingServlet;
bindingServlet.removeAccountThing(thingHandler.getThing());
}
}

Expand Down
Loading

0 comments on commit d797ab8

Please sign in to comment.