Added its own http server for Google Assistant api

This commit is contained in:
Ziver Koc 2020-09-05 13:38:53 +02:00
parent 9bca47d566
commit 4a31b474c5
5 changed files with 80 additions and 55 deletions

View file

@ -23,20 +23,44 @@ import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import com.google.actions.api.smarthome.*; import com.google.actions.api.smarthome.*;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.home.graph.v1.DeviceProto; import com.google.home.graph.v1.DeviceProto;
import com.google.protobuf.Struct; import com.google.protobuf.Struct;
import com.google.protobuf.util.JsonFormat; 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.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 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 @Override
public SyncResponse onSync(SyncRequest syncRequest, Map<?, ?> headers) { public SyncResponse onSync(SyncRequest syncRequest, Map<?, ?> headers) {
SyncResponse res = new SyncResponse(); SyncResponse res = new SyncResponse();
res.setRequestId(syncRequest.requestId); res.setRequestId(syncRequest.requestId);
res.setPayload(new SyncResponse.Payload()); res.setPayload(new SyncResponse.Payload());
@ -44,7 +68,6 @@ public class MySmartHomeApp extends SmartHomeApp {
int numOfDevices = 0; int numOfDevices = 0;
res.payload.devices = new SyncResponse.Payload.Device[numOfDevices]; res.payload.devices = new SyncResponse.Payload.Device[numOfDevices];
for (int i = 0; i < numOfDevices; i++) { for (int i = 0; i < numOfDevices; i++) {
SyncResponse.Payload.Device.Builder deviceBuilder = SyncResponse.Payload.Device.Builder deviceBuilder =
new SyncResponse.Payload.Device.Builder() new SyncResponse.Payload.Device.Builder()
.setId(device.getId()) .setId(device.getId())

View file

@ -41,29 +41,32 @@
package se.hal.plugin.assistant.google.endpoint; package se.hal.plugin.assistant.google.endpoint;
import se.hal.intf.HalJsonPage; import se.hal.intf.HalJsonPage;
import se.hal.plugin.assistant.google.SmartHomeImpl;
import zutil.net.http.HttpHeader; import zutil.net.http.HttpHeader;
import zutil.net.http.HttpPage;
import zutil.net.http.HttpPrintStream; import zutil.net.http.HttpPrintStream;
import zutil.parser.DataNode; import zutil.parser.DataNode;
import java.io.IOException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Map; 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 @Override
protected DataNode jsonRespond( public void respond(
HttpPrintStream out, HttpPrintStream out,
HttpHeader headers, HttpHeader headers,
Map<String, Object> session, Map<String, Object> session,
Map<String, String> cookie, Map<String, String> cookie,
Map<String,String> request) throws Exception { Map<String, String> request) throws IOException {
StringBuilder redirectURL = new StringBuilder(); StringBuilder redirectURL = new StringBuilder();
redirectURL.append(URLDecoder.decode(request.get("redirect_uri"), StandardCharsets.UTF_8)); redirectURL.append(URLDecoder.decode(request.get("redirect_uri"), StandardCharsets.UTF_8));
@ -73,7 +76,5 @@ public class FakeAuthServlet extends HalJsonPage {
out.setStatusCode(302); out.setStatusCode(302);
out.setHeader("Location", URLEncoder.encode("/login?responseurl=" + redirectURL.toString(), StandardCharsets.UTF_8)); out.setHeader("Location", URLEncoder.encode("/login?responseurl=" + redirectURL.toString(), StandardCharsets.UTF_8));
return new DataNode(DataNode.DataType.Map);
} }
} }

View file

@ -40,40 +40,47 @@
package se.hal.plugin.assistant.google.endpoint; package se.hal.plugin.assistant.google.endpoint;
import java.io.IOException;
import java.util.Map; 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.HttpHeader;
import zutil.net.http.HttpPage;
import zutil.net.http.HttpPrintStream; import zutil.net.http.HttpPrintStream;
import zutil.parser.DataNode; import zutil.parser.DataNode;
import zutil.parser.json.JSONWriter;
public class FakeTokenServlet extends HalJsonPage { public class AuthTokenServlet implements HttpPage {
private static int secondsInDay = 86400; 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 @Override
protected DataNode jsonRespond( public void respond(
HttpPrintStream out, HttpPrintStream out,
HttpHeader headers, HttpHeader headers,
Map<String, Object> session, Map<String, Object> session,
Map<String, String> cookie, Map<String, String> cookie,
Map<String,String> request) throws Exception { Map<String, String> request) throws IOException {
String grantType = request.get("grant_type"); String grantType = request.get("grant_type");
DataNode jsonRes = new DataNode(DataNode.DataType.Map); DataNode jsonRes = new DataNode(DataNode.DataType.Map);
jsonRes.set("token_type", "bearer"); jsonRes.set("token_type", "bearer");
jsonRes.set("access_token", "123access"); jsonRes.set("access_token", "123access");
jsonRes.set("expires_in", secondsInDay); jsonRes.set("expires_in", SECONDS_IN_DAY);
if (grantType.equals("authorization_code")) { if (grantType.equals("authorization_code")) {
jsonRes.set("refresh_token", "123refresh"); 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));
} }
} }

View file

@ -41,68 +41,56 @@
package se.hal.plugin.assistant.google.endpoint; package se.hal.plugin.assistant.google.endpoint;
import java.io.IOException; import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.google.actions.api.smarthome.SmartHomeApp; import com.google.actions.api.smarthome.SmartHomeApp;
import com.google.auth.oauth2.GoogleCredentials; import se.hal.plugin.assistant.google.SmartHomeImpl;
import se.hal.intf.HalJsonPage;
import se.hal.plugin.assistant.google.MySmartHomeApp;
import zutil.io.IOUtil; import zutil.io.IOUtil;
import zutil.log.LogUtil; import zutil.log.LogUtil;
import zutil.net.http.HttpHeader; import zutil.net.http.HttpHeader;
import zutil.net.http.HttpPage;
import zutil.net.http.HttpPrintStream; import zutil.net.http.HttpPrintStream;
import zutil.parser.DataNode;
/** /**
* Handles request received via HTTP POST and delegates it to your Actions app. See: [Request * Handles request received via HTTP POST and delegates it to your Actions app. See: [Request
* handling in Google App * handling in Google App
* Engine](https://cloud.google.com/appengine/docs/standard/java/how-requests-are-handled). * 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 static final Logger logger = LogUtil.getLogger();
private final SmartHomeApp actionsApp = new MySmartHomeApp(); public static final String ENDPOINT_URL = "api/assistant/google/smarthome";
{ private SmartHomeImpl smartHome;
try {
GoogleCredentials credentials =
GoogleCredentials.fromStream(getClass().getResourceAsStream("/smart-home-key.json"));
actionsApp.setCredentials(credentials);
} catch (Exception e) {
logger.severe("couldn't load credentials");
}
}
public SmartHomeServlet() { public SmartHomeServlet(SmartHomeImpl smartHome) {
super("api/assistant/google/smarthome"); this.smartHome = smartHome;
} }
@Override @Override
protected DataNode jsonRespond( public void respond(
HttpPrintStream out, HttpPrintStream out,
HttpHeader headers, HttpHeader headers,
Map<String, Object> session, Map<String, Object> session,
Map<String, String> cookie, Map<String, String> cookie,
Map<String,String> request) throws Exception { Map<String, String> request) throws IOException {
String body = IOUtil.readContentAsString(headers.getInputStream()); String body = IOUtil.readContentAsString(headers.getInputStream());
logger.info("doPost, body = " + body); logger.info("doPost, body = " + body);
try { try {
String response = actionsApp.handleRequest(body, request).get(); String response = smartHome.handleRequest(body, request).get();
System.out.println("response = " + asJson); out.setHeader("Content-Type", "application/json");
res.getWriter().write(asJson); out.setHeader("Access-Control-Allow-Origin", "*");
res.getWriter().flush(); out.setHeader("Pragma", "no-cache");
} catch (ExecutionException | InterruptedException e) { out.println(response);
logger.log(Level.SEVERE, "Failed to handle fulfillment request", e); } catch (Exception e) {
logger.log(Level.SEVERE, "Was unable to handle SmartHome request.", e);
} }
} }
} }

View file

@ -0,0 +1,6 @@
{
"version": 0.1,
"name": "Hal-Assistant-Google",
"interfaces": [
]
}