Added header parameters to JSON pages, Some cleanup of google assistant example code

This commit is contained in:
Ziver Koc 2020-09-04 01:10:55 +02:00
parent 0632804bd4
commit 9bca47d566
13 changed files with 806 additions and 15 deletions

View file

@ -0,0 +1,219 @@
/*
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.hal.plugin.assistant.google;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import com.google.actions.api.smarthome.*;
import com.google.gson.Gson;
import com.google.home.graph.v1.DeviceProto;
import com.google.protobuf.Struct;
import com.google.protobuf.util.JsonFormat;
import zutil.log.LogUtil;
public class MySmartHomeApp extends SmartHomeApp {
private static final Logger logger = LogUtil.getLogger();
@Override
public SyncResponse onSync(SyncRequest syncRequest, Map<?, ?> headers) {
SyncResponse res = new SyncResponse();
res.setRequestId(syncRequest.requestId);
res.setPayload(new SyncResponse.Payload());
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())
.setType((String) device.get("type"))
.setTraits((List<String>) device.get("traits"))
.setName(
DeviceProto.DeviceNames.newBuilder()
.addAllDefaultNames((List<String>) device.get("defaultNames"))
.setName((String) device.get("name"))
.addAllNicknames((List<String>) device.get("nicknames"))
.build())
.setWillReportState((Boolean) device.get("willReportState"))
.setRoomHint((String) device.get("roomHint"))
.setDeviceInfo(
DeviceProto.DeviceInfo.newBuilder()
.setManufacturer((String) device.get("manufacturer"))
.setModel((String) device.get("model"))
.setHwVersion((String) device.get("hwVersion"))
.setSwVersion((String) device.get("swVersion"))
.build());
if (device.contains("attributes")) {
Map<String, Object> attributes = new HashMap<>();
attributes.putAll((Map<String, Object>) device.get("attributes"));
String attributesJson = new Gson().toJson(attributes);
Struct.Builder attributeBuilder = Struct.newBuilder();
try {
JsonFormat.parser().ignoringUnknownFields().merge(attributesJson, attributeBuilder);
} catch (Exception e) {
logger.error("FAILED TO BUILD");
}
deviceBuilder.setAttributes(attributeBuilder.build());
}
if (device.contains("customData")) {
Map<String, Object> customData = new HashMap<>();
customData.putAll((Map<String, Object>) device.get("customData"));
String customDataJson = new Gson().toJson(customData);
deviceBuilder.setCustomData(customDataJson);
}
if (device.contains("otherDeviceIds")) {
deviceBuilder.setOtherDeviceIds((List) device.get("otherDeviceIds"));
}
res.payload.devices[i] = deviceBuilder.build();
}
return res;
}
@Override
public QueryResponse onQuery(QueryRequest queryRequest, Map<?, ?> headers) {
QueryRequest.Inputs.Payload.Device[] devices = ((QueryRequest.Inputs) queryRequest.getInputs()[0]).payload.devices;
QueryResponse res = new QueryResponse();
res.setRequestId(queryRequest.requestId);
res.setPayload(new QueryResponse.Payload());
Map<String, Map<String, Object>> deviceStates = new HashMap<>();
for (QueryRequest.Inputs.Payload.Device device : devices) {
try {
Map<String, Object> deviceState = database.getState(userId, device.id);
deviceState.put("status", "SUCCESS");
deviceStates.put(device.id, deviceState);
} catch (Exception e) {
logger.error("QUERY FAILED: {}", e);
Map<String, Object> failedDevice = new HashMap<>();
failedDevice.put("status", "ERROR");
failedDevice.put("errorCode", "deviceOffline");
deviceStates.put(device.id, failedDevice);
}
}
res.payload.setDevices(deviceStates);
return res;
}
@Override
public ExecuteResponse onExecute(ExecuteRequest executeRequest, Map<?, ?> headers) {
ExecuteResponse res = new ExecuteResponse();
List<ExecuteResponse.Payload.Commands> commandsResponse = new ArrayList<>();
List<String> successfulDevices = new ArrayList<>();
Map<String, Object> states = new HashMap<>();
ExecuteRequest.Inputs.Payload.Commands[] commands =
((ExecuteRequest.Inputs) executeRequest.inputs[0]).payload.commands;
for (ExecuteRequest.Inputs.Payload.Commands command : commands) {
for (ExecuteRequest.Inputs.Payload.Commands.Devices device : command.devices) {
try {
states = database.execute(userId, device.id, command.execution[0]);
successfulDevices.add(device.id);
ReportState.makeRequest(this, userId, device.id, states);
} catch (Exception e) {
if (e.getMessage().equals("PENDING")) {
ExecuteResponse.Payload.Commands pendingDevice = new ExecuteResponse.Payload.Commands();
pendingDevice.ids = new String[]{device.id};
pendingDevice.status = "PENDING";
commandsResponse.add(pendingDevice);
continue;
}
if (e.getMessage().equals("pinNeeded")) {
ExecuteResponse.Payload.Commands failedDevice = new ExecuteResponse.Payload.Commands();
failedDevice.ids = new String[]{device.id};
failedDevice.status = "ERROR";
failedDevice.setErrorCode("challengeNeeded");
failedDevice.setChallengeNeeded(
new HashMap<String, String>() {
{
put("type", "pinNeeded");
}
});
failedDevice.setErrorCode(e.getMessage());
commandsResponse.add(failedDevice);
continue;
}
if (e.getMessage().equals("challengeFailedPinNeeded")) {
ExecuteResponse.Payload.Commands failedDevice = new ExecuteResponse.Payload.Commands();
failedDevice.ids = new String[]{device.id};
failedDevice.status = "ERROR";
failedDevice.setErrorCode("challengeNeeded");
failedDevice.setChallengeNeeded(
new HashMap<String, String>() {
{
put("type", "challengeFailedPinNeeded");
}
});
failedDevice.setErrorCode(e.getMessage());
commandsResponse.add(failedDevice);
continue;
}
if (e.getMessage().equals("ackNeeded")) {
ExecuteResponse.Payload.Commands failedDevice = new ExecuteResponse.Payload.Commands();
failedDevice.ids = new String[]{device.id};
failedDevice.status = "ERROR";
failedDevice.setErrorCode("challengeNeeded");
failedDevice.setChallengeNeeded(
new HashMap<String, String>() {
{
put("type", "ackNeeded");
}
});
failedDevice.setErrorCode(e.getMessage());
commandsResponse.add(failedDevice);
continue;
}
ExecuteResponse.Payload.Commands failedDevice = new ExecuteResponse.Payload.Commands();
failedDevice.ids = new String[]{device.id};
failedDevice.status = "ERROR";
failedDevice.setErrorCode(e.getMessage());
commandsResponse.add(failedDevice);
}
}
}
ExecuteResponse.Payload.Commands successfulCommands = new ExecuteResponse.Payload.Commands();
successfulCommands.status = "SUCCESS";
successfulCommands.setStates(states);
successfulCommands.ids = successfulDevices.toArray(new String[]{});
commandsResponse.add(successfulCommands);
res.requestId = executeRequest.requestId;
ExecuteResponse.Payload payload =
new ExecuteResponse.Payload(
commandsResponse.toArray(new ExecuteResponse.Payload.Commands[]{}));
res.setPayload(payload);
return res;
}
@Override
public void onDisconnect(DisconnectRequest disconnectRequest, Map<?, ?> headers) {
}
}

View file

@ -0,0 +1,97 @@
/*
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.hal.plugin.assistant.google;
import java.util.Map;
import java.util.logging.Logger;
import com.google.actions.api.smarthome.SmartHomeApp;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.home.graph.v1.HomeGraphApiServiceProto;
import com.google.protobuf.Struct;
import com.google.protobuf.Value;
import com.google.protobuf.util.JsonFormat;
import zutil.log.LogUtil;
/**
* A singleton class to encapsulate state reporting behavior with changing ColorSetting state
* values.
*/
final class ReportState {
private static final Logger logger = LogUtil.getLogger();
private ReportState() {}
/**
* Creates and completes a ReportStateAndNotification request
*
* @param actionsApp The SmartHomeApp instance to use to make the gRPC request
* @param userId The agent user ID
* @param deviceId The device ID
* @param states A Map of state keys and their values for the provided device ID
*/
public static void makeRequest(SmartHomeApp actionsApp, String userId, String deviceId, Map<String, Object> states) {
// Convert a Map of states to a JsonObject
JsonObject jsonStates = (JsonObject) JsonParser.parseString(new Gson().toJson(states));
ReportState.makeRequest(actionsApp, userId, deviceId, jsonStates);
}
/**
* Creates and completes a ReportStateAndNotification request
*
* @param actionsApp The SmartHomeApp instance to use to make the gRPC request
* @param userId The agent user ID
* @param deviceId The device ID
* @param states A JSON object of state keys and their values for the provided device ID
*/
public static void makeRequest(SmartHomeApp actionsApp, String userId, String deviceId, JsonObject states) {
// Do state name replacement for ColorSetting trait
// See https://developers.google.com/assistant/smarthome/traits/colorsetting#device-states
JsonObject colorJson = states.getAsJsonObject("color");
if (colorJson != null && colorJson.has("spectrumRgb")) {
colorJson.add("spectrumRGB", colorJson.get("spectrumRgb"));
colorJson.remove("spectrumRgb");
}
Struct.Builder statesStruct = Struct.newBuilder();
try {
JsonFormat.parser().ignoringUnknownFields().merge(new Gson().toJson(states), statesStruct);
} catch (Exception e) {
logger.severe("Failed to build json");
e.printStackTrace();
}
HomeGraphApiServiceProto.ReportStateAndNotificationDevice.Builder deviceBuilder =
HomeGraphApiServiceProto.ReportStateAndNotificationDevice.newBuilder()
.setStates(
Struct.newBuilder()
.putFields(deviceId, Value.newBuilder().setStructValue(statesStruct).build()));
HomeGraphApiServiceProto.ReportStateAndNotificationRequest request =
HomeGraphApiServiceProto.ReportStateAndNotificationRequest.newBuilder()
.setRequestId(String.valueOf(Math.random()))
.setAgentUserId(userId) // our single user's id
.setPayload(
HomeGraphApiServiceProto.StateAndNotificationPayload.newBuilder()
.setDevices(deviceBuilder))
.build();
actionsApp.reportState(request);
}
}

View file

@ -0,0 +1,79 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ziver Koc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package se.hal.plugin.assistant.google;
/**
* Enum for https://developers.google.com/assistant/smarthome/traits
*/
public enum SmartHomeDeviceTrait {
AppSelector("action.devices.traits.AppSelector"),
ArmDisarm("action.devices.traits.ArmDisarm"),
Brightness("action.devices.traits.Brightness"),
CameraStream("action.devices.traits.CameraStream"),
Channel("action.devices.traits.Channel"),
ColorSetting("action.devices.traits.ColorSetting"),
Cook("action.devices.traits.Cook"),
Dispense("action.devices.traits.Dispense"),
Dock("action.devices.traits.Dock"),
EnergyStorage("action.devices.traits.EnergyStorage"),
FanSpeed("action.devices.traits.FanSpeed"),
Fill("action.devices.traits.Fill"),
HumiditySetting("action.devices.traits.HumiditySetting"),
InputSelector("action.devices.traits.InputSelector"),
LightEffects("action.devices.traits.LightEffects"),
Locator("action.devices.traits.Locator"),
LockUnlock("action.devices.traits.LockUnlock"),
MediaState("action.devices.traits.MediaState"),
Modes("action.devices.traits.Modes"),
NetworkControl("action.devices.traits.NetworkControl"),
OnOff("action.devices.traits.OnOff"),
OpenClose("action.devices.traits.OpenClose"),
Reboot("action.devices.traits.Reboot"),
Rotation("action.devices.traits.Rotation"),
RunCycle("action.devices.traits.RunCycle"),
SensorState("action.devices.traits.SensorState"),
Scene("action.devices.traits.Scene"),
SoftwareUpdate("action.devices.traits.SoftwareUpdate"),
StartStop("action.devices.traits.StartStop"),
StatusReport("action.devices.traits.StatusReport"),
TemperatureControl("action.devices.traits.TemperatureControl"),
TemperatureSetting("action.devices.traits.TemperatureSetting"),
Timer("action.devices.traits.Timer"),
Toggles("action.devices.traits.Toggles"),
TransportControl("action.devices.traits.TransportControl"),
Volume("action.devices.traits.Volume");
private final String typeId;
private SmartHomeDeviceTrait(String typeId) {
this.typeId = typeId;
}
public String getString() {
return typeId;
}
}

View file

@ -0,0 +1,119 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ziver Koc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package se.hal.plugin.assistant.google;
/**
* Enum for https://developers.google.com/assistant/smarthome/types
*/
public enum SmartHomeDeviceType {
AC_UNIT("action.devices.types.AC_UNIT"),
AIRCOOLER("action.devices.types.AIRCOOLER"),
AIRFRESHENER("action.devices.types.AIRFRESHENER"),
AIRPURIFIER("action.devices.types.AIRPURIFIER"),
AUDIO_VIDEO_RECEIVER("action.devices.types.AUDIO_VIDEO_RECEIVER"),
AWNING("action.devices.types.AWNING"),
BATHTUB("action.devices.types.BATHTUB"),
BED("action.devices.types.BED"),
BLENDER("action.devices.types.BLENDER"),
BLINDS("action.devices.types.BLINDS"),
BOILER("action.devices.types.BOILER"),
CAMERA("action.devices.types.CAMERA"),
CHARGER("action.devices.types.CHARGER"),
CLOSET("action.devices.types.CLOSET"),
COFFEE_MAKER("action.devices.types.COFFEE_MAKER"),
COOKTOP("action.devices.types.COOKTOP"),
CURTAIN("action.devices.types.CURTAIN"),
DEHUMIDIFIER("action.devices.types.DEHUMIDIFIER"),
DEHYDRATOR("action.devices.types.DEHYDRATOR"),
DISHWASHERv("action.devices.types.DISHWASHER"),
DOOR("action.devices.types.DOOR"),
DRAWER("action.devices.types.DRAWER"),
DRYER("action.devices.types.DRYER"),
FAN("action.devices.types.FAN"),
FAUCET("action.devices.types.FAUCET"),
FIREPLACE("action.devices.types.FIREPLACE"),
FREEZER("action.devices.types.FREEZER"),
FRYER("action.devices.types.FRYER"),
GARAGE("action.devices.types.GARAGE"),
GATE("action.devices.types.GATE"),
GRILL("action.devices.types.GRILL"),
HEATER("action.devices.types.HEATER"),
HOOD("action.devices.types.HOOD"),
HUMIDIFIER("action.devices.types.HUMIDIFIER"),
KETTLE("action.devices.types.KETTLE"),
LIGHT("action.devices.types.LIGHT"),
LOCK("action.devices.types.LOCK"),
REMOTECONTROL("action.devices.types.REMOTECONTROL"),
MOP("action.devices.types.MOP"),
MOWER("action.devices.types.MOWER"),
MICROWAVE("action.devices.types.MICROWAVE"),
MULTICOOKER("action.devices.types.MULTICOOKER"),
NETWORK("action.devices.types.NETWORK"),
OUTLET("action.devices.types.OUTLET"),
OVEN("action.devices.types.OVEN"),
PERGOLA("action.devices.types.PERGOLA"),
PETFEEDER("action.devices.types.PETFEEDER"),
PRESSURECOOKER("action.devices.types.PRESSURECOOKER"),
RADIATOR("action.devices.types.RADIATOR"),
REFRIGERATOR("action.devices.types.REFRIGERATOR"),
ROUTER("action.devices.types.ROUTER"),
SCENE("action.devices.types.SCENE"),
SENSOR("action.devices.types.SENSOR"),
SECURITYSYSTEM("action.devices.types.SECURITYSYSTEM"),
SETTOP("action.devices.types.SETTOP"),
SHUTTER("action.devices.types.SHUTTER"),
SHOWER("action.devices.types.SHOWER"),
SMOKE_DETECTOR("action.devices.types.SMOKE_DETECTOR"),
SOUSVIDE("action.devices.types.SOUSVIDE"),
SPEAKER("action.devices.types.SPEAKER"),
STREAMING_BOX("action.devices.types.STREAMING_BOX"),
STREAMING_STICK("action.devices.types.STREAMING_STICK"),
STREAMING_SOUNDBAR("action.devices.types.STREAMING_SOUNDBAR"),
SOUNDBAR("action.devices.types.SOUNDBAR"),
SPRINKLER("action.devices.types.SPRINKLER"),
STANDMIXER("action.devices.types.STANDMIXER"),
SWITCH("action.devices.types.SWITCH"),
TV("action.devices.types.TV"),
THERMOSTAT("action.devices.types.THERMOSTAT"),
VACUUM("action.devices.types.VACUUM"),
VALVE("action.devices.types.VALVE"),
WASHER("action.devices.types.WASHER"),
WATERHEATER("action.devices.types.WATERHEATER"),
WATERPURIFIER("action.devices.types.WATERPURIFIER"),
WATERSOFTENER("action.devices.types.WATERSOFTENER"),
WINDOW("action.devices.types.WINDOW"),
YOGURTMAKER("action.devices.types.YOGURTMAKER");
private final String typeId;
private SmartHomeDeviceType(String typeId) {
this.typeId = typeId;
}
public String getString() {
return typeId;
}
}

View file

@ -0,0 +1,79 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ziver Koc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.hal.plugin.assistant.google.endpoint;
import se.hal.intf.HalJsonPage;
import zutil.net.http.HttpHeader;
import zutil.net.http.HttpPrintStream;
import zutil.parser.DataNode;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
public class FakeAuthServlet extends HalJsonPage {
public FakeAuthServlet() {
super("api/assistant/google/auth");
}
@Override
protected DataNode jsonRespond(
HttpPrintStream out,
HttpHeader headers,
Map<String,Object> session,
Map<String,String> cookie,
Map<String,String> request) throws Exception {
StringBuilder redirectURL = new StringBuilder();
redirectURL.append(URLDecoder.decode(request.get("redirect_uri"), StandardCharsets.UTF_8));
redirectURL.append("?");
redirectURL.append("code=").append("xxxxxx");
redirectURL.append("state=").append(request.get("state"));
out.setStatusCode(302);
out.setHeader("Location", URLEncoder.encode("/login?responseurl=" + redirectURL.toString(), StandardCharsets.UTF_8));
return new DataNode(DataNode.DataType.Map);
}
}

View file

@ -0,0 +1,79 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ziver Koc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.hal.plugin.assistant.google.endpoint;
import java.util.Map;
import se.hal.intf.HalJsonPage;
import zutil.net.http.HttpHeader;
import zutil.net.http.HttpPrintStream;
import zutil.parser.DataNode;
public class FakeTokenServlet extends HalJsonPage {
private static int secondsInDay = 86400;
public FakeTokenServlet() {
super("api/assistant/google/auth_token");
}
@Override
protected DataNode jsonRespond(
HttpPrintStream out,
HttpHeader headers,
Map<String,Object> session,
Map<String,String> cookie,
Map<String,String> request) throws Exception {
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);
if (grantType.equals("authorization_code")) {
jsonRes.set("refresh_token", "123refresh");
}
return jsonRes;
}
}

View file

@ -0,0 +1,108 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2020 Ziver Koc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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 zutil.io.IOUtil;
import zutil.log.LogUtil;
import zutil.net.http.HttpHeader;
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 {
private static final Logger logger = LogUtil.getLogger();
private final SmartHomeApp actionsApp = new MySmartHomeApp();
{
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() {
super("api/assistant/google/smarthome");
}
@Override
protected DataNode jsonRespond(
HttpPrintStream out,
HttpHeader headers,
Map<String,Object> session,
Map<String,String> cookie,
Map<String,String> request) throws Exception {
String body = IOUtil.readContentAsString(headers.getInputStream());
logger.info("doPost, body = " + body);
try {
String response = actionsApp.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);
}
}
}