From 4a31b474c5cf6ef4b178d12fdfbb59e4b5935c24 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Sat, 5 Sep 2020 13:38:53 +0200 Subject: [PATCH] Added its own http server for Google Assistant api --- ...MySmartHomeApp.java => SmartHomeImpl.java} | 29 +++++++++-- ...{FakeAuthServlet.java => AuthServlet.java} | 21 ++++---- ...okenServlet.java => AuthTokenServlet.java} | 31 +++++++----- .../google/endpoint/SmartHomeServlet.java | 48 +++++++------------ .../hal/plugin/assistant/google/plugin.json | 6 +++ 5 files changed, 80 insertions(+), 55 deletions(-) rename plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/{MySmartHomeApp.java => SmartHomeImpl.java} (89%) rename plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/{FakeAuthServlet.java => AuthServlet.java} (85%) rename plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/{FakeTokenServlet.java => AuthTokenServlet.java} (73%) create mode 100644 plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/plugin.json diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/MySmartHomeApp.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/SmartHomeImpl.java similarity index 89% rename from plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/MySmartHomeApp.java rename to plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/SmartHomeImpl.java index 3b06c3cd..3c683995 100644 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/MySmartHomeApp.java +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/SmartHomeImpl.java @@ -23,20 +23,44 @@ import java.util.Map; import java.util.logging.Logger; import com.google.actions.api.smarthome.*; +import com.google.auth.oauth2.GoogleCredentials; import com.google.gson.Gson; import com.google.home.graph.v1.DeviceProto; import com.google.protobuf.Struct; import com.google.protobuf.util.JsonFormat; +import se.hal.HalContext; +import se.hal.plugin.assistant.google.endpoint.AuthServlet; +import se.hal.plugin.assistant.google.endpoint.AuthTokenServlet; +import se.hal.plugin.assistant.google.endpoint.SmartHomeServlet; import zutil.log.LogUtil; +import zutil.net.http.HttpServer; -public class MySmartHomeApp extends SmartHomeApp { +public class SmartHomeImpl extends SmartHomeApp { private static final Logger logger = LogUtil.getLogger(); + private static final String PARAM_PORT = "assistant.google.api_port"; + + private HttpServer httpServer; + + + public SmartHomeImpl() { + try { + GoogleCredentials credentials = GoogleCredentials.fromStream(getClass().getResourceAsStream("assistant_google.conf")); + this.setCredentials(credentials); + } catch (Exception e) { + logger.severe("couldn't load credentials"); + throw new RuntimeException(e); + } + + httpServer = new HttpServer(HalContext.getIntegerProperty(PARAM_PORT)); + httpServer.setPage(AuthServlet.ENDPOINT_URL, new AuthServlet(this)); + httpServer.setPage(AuthTokenServlet.ENDPOINT_URL, new AuthTokenServlet(this)); + httpServer.setPage(SmartHomeServlet.ENDPOINT_URL, new SmartHomeServlet(this)); + } @Override public SyncResponse onSync(SyncRequest syncRequest, Map headers) { - SyncResponse res = new SyncResponse(); res.setRequestId(syncRequest.requestId); res.setPayload(new SyncResponse.Payload()); @@ -44,7 +68,6 @@ public class MySmartHomeApp extends SmartHomeApp { int numOfDevices = 0; res.payload.devices = new SyncResponse.Payload.Device[numOfDevices]; for (int i = 0; i < numOfDevices; i++) { - SyncResponse.Payload.Device.Builder deviceBuilder = new SyncResponse.Payload.Device.Builder() .setId(device.getId()) diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/FakeAuthServlet.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/AuthServlet.java similarity index 85% rename from plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/FakeAuthServlet.java rename to plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/AuthServlet.java index 0b95d58e..804128db 100644 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/FakeAuthServlet.java +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/AuthServlet.java @@ -41,29 +41,32 @@ package se.hal.plugin.assistant.google.endpoint; import se.hal.intf.HalJsonPage; +import se.hal.plugin.assistant.google.SmartHomeImpl; import zutil.net.http.HttpHeader; +import zutil.net.http.HttpPage; import zutil.net.http.HttpPrintStream; import zutil.parser.DataNode; +import java.io.IOException; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Map; -public class FakeAuthServlet extends HalJsonPage { +public class AuthServlet implements HttpPage { + public static final String ENDPOINT_URL = "api/assistant/google/auth"; + + public AuthServlet(SmartHomeImpl smartHome) {} - public FakeAuthServlet() { - super("api/assistant/google/auth"); - } @Override - protected DataNode jsonRespond( + public void respond( HttpPrintStream out, HttpHeader headers, - Map session, - Map cookie, - Map request) throws Exception { + Map session, + Map cookie, + Map request) throws IOException { StringBuilder redirectURL = new StringBuilder(); redirectURL.append(URLDecoder.decode(request.get("redirect_uri"), StandardCharsets.UTF_8)); @@ -73,7 +76,5 @@ public class FakeAuthServlet extends HalJsonPage { out.setStatusCode(302); out.setHeader("Location", URLEncoder.encode("/login?responseurl=" + redirectURL.toString(), StandardCharsets.UTF_8)); - - return new DataNode(DataNode.DataType.Map); } } diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/FakeTokenServlet.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/AuthTokenServlet.java similarity index 73% rename from plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/FakeTokenServlet.java rename to plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/AuthTokenServlet.java index e32d579f..ec826e66 100644 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/FakeTokenServlet.java +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/AuthTokenServlet.java @@ -40,40 +40,47 @@ package se.hal.plugin.assistant.google.endpoint; +import java.io.IOException; import java.util.Map; -import se.hal.intf.HalJsonPage; +import se.hal.plugin.assistant.google.SmartHomeImpl; import zutil.net.http.HttpHeader; +import zutil.net.http.HttpPage; import zutil.net.http.HttpPrintStream; import zutil.parser.DataNode; +import zutil.parser.json.JSONWriter; -public class FakeTokenServlet extends HalJsonPage { - private static int secondsInDay = 86400; +public class AuthTokenServlet implements HttpPage { + private static final int SECONDS_IN_DAY = 86400; + public static final String ENDPOINT_URL = "api/assistant/google/auth_token"; + + + public AuthTokenServlet(SmartHomeImpl smartHome) {} - public FakeTokenServlet() { - super("api/assistant/google/auth_token"); - } @Override - protected DataNode jsonRespond( + public void respond( HttpPrintStream out, HttpHeader headers, - Map session, - Map cookie, - Map request) throws Exception { + Map session, + Map cookie, + Map request) throws IOException { String grantType = request.get("grant_type"); DataNode jsonRes = new DataNode(DataNode.DataType.Map); jsonRes.set("token_type", "bearer"); jsonRes.set("access_token", "123access"); - jsonRes.set("expires_in", secondsInDay); + jsonRes.set("expires_in", SECONDS_IN_DAY); if (grantType.equals("authorization_code")) { jsonRes.set("refresh_token", "123refresh"); } - return jsonRes; + out.setHeader("Content-Type", "application/json"); + out.setHeader("Access-Control-Allow-Origin", "*"); + out.setHeader("Pragma", "no-cache"); + out.println(JSONWriter.toString(jsonRes)); } } diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/SmartHomeServlet.java b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/SmartHomeServlet.java index 47e671ad..b47f1763 100644 --- a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/SmartHomeServlet.java +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/endpoint/SmartHomeServlet.java @@ -41,68 +41,56 @@ package se.hal.plugin.assistant.google.endpoint; import java.io.IOException; -import java.util.Enumeration; -import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; -import java.util.stream.Collectors; import com.google.actions.api.smarthome.SmartHomeApp; -import com.google.auth.oauth2.GoogleCredentials; -import se.hal.intf.HalJsonPage; -import se.hal.plugin.assistant.google.MySmartHomeApp; +import se.hal.plugin.assistant.google.SmartHomeImpl; import zutil.io.IOUtil; import zutil.log.LogUtil; import zutil.net.http.HttpHeader; +import zutil.net.http.HttpPage; import zutil.net.http.HttpPrintStream; -import zutil.parser.DataNode; /** * Handles request received via HTTP POST and delegates it to your Actions app. See: [Request * handling in Google App * Engine](https://cloud.google.com/appengine/docs/standard/java/how-requests-are-handled). */ -public class SmartHomeServlet extends HalJsonPage { +public class SmartHomeServlet implements HttpPage { private static final Logger logger = LogUtil.getLogger(); - private final SmartHomeApp actionsApp = new MySmartHomeApp(); + public static final String ENDPOINT_URL = "api/assistant/google/smarthome"; - { - try { - GoogleCredentials credentials = - GoogleCredentials.fromStream(getClass().getResourceAsStream("/smart-home-key.json")); - actionsApp.setCredentials(credentials); - } catch (Exception e) { - logger.severe("couldn't load credentials"); - } - } + private SmartHomeImpl smartHome; - public SmartHomeServlet() { - super("api/assistant/google/smarthome"); + public SmartHomeServlet(SmartHomeImpl smartHome) { + this.smartHome = smartHome; } @Override - protected DataNode jsonRespond( + public void respond( HttpPrintStream out, HttpHeader headers, - Map session, - Map cookie, - Map request) throws Exception { + Map session, + Map cookie, + Map request) throws IOException { String body = IOUtil.readContentAsString(headers.getInputStream()); logger.info("doPost, body = " + body); try { - String response = actionsApp.handleRequest(body, request).get(); + String response = smartHome.handleRequest(body, request).get(); - System.out.println("response = " + asJson); - res.getWriter().write(asJson); - res.getWriter().flush(); - } catch (ExecutionException | InterruptedException e) { - logger.log(Level.SEVERE, "Failed to handle fulfillment request", e); + out.setHeader("Content-Type", "application/json"); + out.setHeader("Access-Control-Allow-Origin", "*"); + out.setHeader("Pragma", "no-cache"); + out.println(response); + } catch (Exception e) { + logger.log(Level.SEVERE, "Was unable to handle SmartHome request.", e); } } } \ No newline at end of file diff --git a/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/plugin.json b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/plugin.json new file mode 100644 index 00000000..394e8aac --- /dev/null +++ b/plugins/hal-assistant-google/src/se/hal/plugin/assistant/google/plugin.json @@ -0,0 +1,6 @@ +{ + "version": 0.1, + "name": "Hal-Assistant-Google", + "interfaces": [ + ] +} \ No newline at end of file