diff options
Diffstat (limited to 'src')
56 files changed, 4289 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..6bc208f --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,44 @@ +########################################################################### +# Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# 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 +# +# http://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. +########################################################################### + +# Add target to project dependency list +PROJECT_TARGET_ADD(vshl-capabilities) + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) + + # Define project Targets + add_library(${TARGET_NAME} MODULE + ${TARGET_NAME}-binding.c + ) + + set(OPENAPI_DEF "${TARGET_NAME}-apidef" CACHE STRING "name and path to the JSON API definition without extension") + + # Binder exposes a unique public entry point + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + PREFIX "afb-" + LABELS "BINDINGV3" + LINK_FLAGS ${BINDINGS_LINK_FLAG} + OUTPUT_NAME ${TARGET_NAME} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + afb-helpers + ctl-utilities + ${link_libraries}) + +add_subdirectory("plugins")
\ No newline at end of file diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt new file mode 100644 index 0000000..705b13d --- /dev/null +++ b/src/plugins/CMakeLists.txt @@ -0,0 +1,153 @@ +########################################################################### +# Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# 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 +# +# http://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. +########################################################################### + +PROJECT_TARGET_ADD(vshl-capabilities-api) + + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) + + set(VSHL_CAPABILITIES_LIB_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/VshlCapabilitiesApi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/VshlCapabilitiesApi.h + + # Interfaces + ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/afb/IAFBApi.h + ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/capabilities/ICapability.h + ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/utilities/events/IEventFilter.h + ${CMAKE_CURRENT_SOURCE_DIR}/interfaces/utilities/logging/ILogger.h + + # AFB + ${CMAKE_CURRENT_SOURCE_DIR}/afb/AFBApiImpl.h + ${CMAKE_CURRENT_SOURCE_DIR}/afb/AFBApiImpl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/afb/AFBRequestImpl.h + ${CMAKE_CURRENT_SOURCE_DIR}/afb/AFBRequestImpl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/afb/include/AFBEventImpl.h + ${CMAKE_CURRENT_SOURCE_DIR}/afb/src/AFBEventImpl.cpp + + #Capabilities + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/CapabilitiesFactory.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/CapabilitiesFactory.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/CapabilityMessagingService.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/CapabilityMessagingService.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/include/MessageChannel.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/src/MessageChannel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/include/PublisherForwarder.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/src/PublisherForwarder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/include/SubscriberForwarder.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/core/src/SubscriberForwarder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/communication/include/PhoneControlMessages.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/communication/include/PhoneControlCapability.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/communication/src/PhoneControlCapability.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/playbackcontroller/include/PlaybackControllerMessages.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/playbackcontroller/include/PlaybackControllerCapability.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/playbackcontroller/src/PlaybackControllerCapability.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/navigation/include/NavigationMessages.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/navigation/include/NavigationCapability.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/navigation/src/NavigationCapability.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/guimetadata/include/GuiMetadataMessages.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/guimetadata/include/GuiMetadataCapability.h + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/guimetadata/src/GuiMetadataCapability.cpp + + #Utilities + ${CMAKE_CURRENT_SOURCE_DIR}/utilities/events/EventRouter.h + ${CMAKE_CURRENT_SOURCE_DIR}/utilities/events/EventRouter.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/utilities/logging/Logger.h + ${CMAKE_CURRENT_SOURCE_DIR}/utilities/logging/Logger.cpp + ) + + # Define targets + ADD_LIBRARY(${TARGET_NAME} MODULE + ${VSHL_CAPABILITIES_LIB_SRC} + ) + + # VSHL Capabilities plugin properties + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "PLUGIN" + PREFIX "" + SUFFIX ".ctlso" + OUTPUT_NAME ${TARGET_NAME} + ) + + # Define target includes + TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} + PUBLIC ${GLIB_PKG_INCLUDE_DIRS} + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" + PRIVATE "${CMAKE_SOURCE_DIR}/app-controller/ctl-lib" + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + afb-helpers + ${GLIB_PKG_LIBRARIES} + ${link_libraries} + ) + + option(ENABLE_UNIT_TESTS "Build unit tests or not" OFF) + if (ENABLE_UNIT_TESTS) + execute_process( + COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/agreement.sh" + RESULT_VARIABLE AGREEMENT_RESULT + ) + message(STATUS "Agreement Result: ${AGREEMENT_RESULT}") + if (${AGREEMENT_RESULT} MATCHES "1") + message(FATAL_ERROR "User agreement not accepted. Quitting") + endif() + + include(cmake/gtest.cmake) + + set(VSHL_CAPABILITIES_TEST_SRC ${VSHL_CAPABILITIES_LIB_SRC}) + list(APPEND VSHL_CAPABILITIES_TEST_SRC + # Main + ${CMAKE_CURRENT_SOURCE_DIR}/TestMain.cpp + + # Test common + ${CMAKE_CURRENT_SOURCE_DIR}/test/common/ConsoleLogger.h + ${CMAKE_CURRENT_SOURCE_DIR}/test/common/ConsoleLogger.cpp + + # Test Mocks + ${CMAKE_CURRENT_SOURCE_DIR}/test/mocks/AFBApiMock.h + ${CMAKE_CURRENT_SOURCE_DIR}/test/mocks/AFBEventMock.h + ${CMAKE_CURRENT_SOURCE_DIR}/test/mocks/AFBRequestMock.h + ${CMAKE_CURRENT_SOURCE_DIR}/test/mocks/CapabilityMock.h + + # Capabilities + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/test/CapabilityMessagingServiceTest.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/test/PublisherForwarderTest.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/capabilities/test/SubscriberForwarderTest.cpp + ) + + ADD_EXECUTABLE(${TARGET_NAME}_Test + ${VSHL_CAPABILITIES_TEST_SRC} + ) + + TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME}_Test + PUBLIC ${GLIB_PKG_INCLUDE_DIRS} + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}" + PRIVATE "${CMAKE_SOURCE_DIR}/app-controller/ctl-lib" + ) + + TARGET_LINK_LIBRARIES(${TARGET_NAME}_Test + afb-helpers + libgtest + libgmock + ${GLIB_PKG_LIBRARIES} + ${link_libraries} + ) + + ENABLE_TESTING() + ADD_TEST(VshlCapabilitiesTest ${TARGET_NAME}_Test) + endif()
\ No newline at end of file diff --git a/src/plugins/TestMain.cpp b/src/plugins/TestMain.cpp new file mode 100644 index 0000000..d4fcbec --- /dev/null +++ b/src/plugins/TestMain.cpp @@ -0,0 +1,20 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "gtest/gtest.h" + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}
\ No newline at end of file diff --git a/src/plugins/VshlCapabilitiesApi.cpp b/src/plugins/VshlCapabilitiesApi.cpp new file mode 100644 index 0000000..c02fb8f --- /dev/null +++ b/src/plugins/VshlCapabilitiesApi.cpp @@ -0,0 +1,411 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "VshlCapabilitiesApi.h" + +#include <list> + +#include "afb/AFBApiImpl.h" +#include "afb/AFBRequestImpl.h" +#include "capabilities/CapabilitiesFactory.h" +#include "capabilities/CapabilityMessagingService.h" +#include "utilities/events/EventRouter.h" +#include "utilities/logging/Logger.h" + +#include "json.hpp" + +using namespace std; + +CTLP_CAPI_REGISTER("vshlsupport-api"); + +static std::string TAG = "vshlcapabilities::plugins::VshlCapabilitiesApi"; + +static std::string EVENTS_JSON_ATTR_VA_ID = "va_id"; +static std::string EVENTS_JSON_ATTR_EVENTS = "events"; + +static std::string CAPABILITIES_JSON_ATTR_ACTION = "action"; +static std::string CAPABILITIES_JSON_ATTR_ACTIONS = "actions"; +static std::string CAPABILITIES_JSON_ATTR_PAYLOAD = "payload"; + +static std::shared_ptr<vshlcapabilities::utilities::logging::Logger> sLogger; +static std::shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> sAfbApi; +static std::unique_ptr<vshlcapabilities::capabilities::CapabilitiesFactory> sCapabilitiesFactory; +static std::unique_ptr<vshlcapabilities::capabilities::CapabilityMessagingService> sCapabilityMessagingService; +static std::unique_ptr<vshlcapabilities::utilities::events::EventRouter> sEventRouter; + +using json = nlohmann::json; +using Level = vshlcapabilities::utilities::logging::Logger::Level; + +CTLP_ONLOAD(plugin, ret) { + if (plugin->api == nullptr) { + return -1; + } + + // Logger + sLogger = vshlcapabilities::utilities::logging::Logger::create(plugin->api); + + // AFB Wrapper + sAfbApi = vshlcapabilities::afb::AFBApiImpl::create(plugin->api); + + // EventRouter + sEventRouter = vshlcapabilities::utilities::events::EventRouter::create(sLogger); + if (!sEventRouter) { + sLogger->log(Level::ERROR, TAG, "Failed to create EventRouter"); + return -1; + } + + sCapabilitiesFactory = vshlcapabilities::capabilities::CapabilitiesFactory::create(sLogger); + if (!sCapabilitiesFactory) { + sLogger->log(Level::ERROR, TAG, "Failed to create CapabilitiesFactory"); + return -1; + } + + sCapabilityMessagingService = vshlcapabilities::capabilities::CapabilityMessagingService::create(sLogger, sAfbApi); + if (!sCapabilityMessagingService) { + sLogger->log(Level::ERROR, TAG, "Failed to create CapabilityMessagingService"); + return -1; + } + + return 0; +} + + +CTLP_CAPI(guiMetadataSubscribe, source, argsJ, eventJ) { + if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) { + return -1; + } + + shared_ptr<vshlcapabilities::common::interfaces::ICapability> guMetadataCapability = sCapabilitiesFactory->getGuiMetadata(); + if (!guMetadataCapability) { + sLogger->log( + Level::WARNING, + TAG, + "guimetadataSubscribe: Failed to " + "fetch guimetadata capability " + "object."); + return -1; + } + + if (eventJ == nullptr) { + sLogger->log(Level::WARNING, TAG, "guimetadataSubscribe: No arguments supplied."); + return -1; + } + + json subscribeJson = json::parse(json_object_to_json_string(eventJ)); + if (subscribeJson.find(CAPABILITIES_JSON_ATTR_ACTIONS) == subscribeJson.end()) { + sLogger->log(Level::ERROR, TAG, "guimetadataSubscribe: No events array found in subscribe json"); + return -1; + } + list<string> events(subscribeJson[CAPABILITIES_JSON_ATTR_ACTIONS].get<list<string>>()); + + // SUbscribe this client for the guimetadata events. + auto request = vshlcapabilities::afb::AFBRequestImpl::create(source->request); + for (auto event : events) { + if (!sCapabilityMessagingService->subscribe(*request, guMetadataCapability, event)) { + sLogger->log(Level::ERROR, TAG, "guimetadataSubscribe: Failed to subscribe to event: " + event); + return -1; + } + } + + AFB_ReqSuccess( + source->request, json_object_new_string("Subscription to guimetadata events successfully completed."), NULL); + return 0; +} + +CTLP_CAPI(guiMetadataPublish, source, argsJ, eventJ) { + if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) { + return -1; + } + + shared_ptr<vshlcapabilities::common::interfaces::ICapability> guMetadataCapability = sCapabilitiesFactory->getGuiMetadata(); + if (!guMetadataCapability) { + sLogger->log( + Level::WARNING, + TAG, + "guimetadataPublish: Failed to fetch " + "guimetadata capability object."); + return -1; + } + + if (eventJ == nullptr) { + sLogger->log(Level::WARNING, TAG, "guimetadataPublish: No arguments supplied."); + return -1; + } + + json_object* actionJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_ACTION.c_str()); + if (actionJ == nullptr) { + sLogger->log(Level::ERROR, TAG, "guimetadataPublish: No action found in publish json"); + return -1; + } + + std::string action = std::string(json_object_get_string(actionJ)); + if (action.empty()) { + sLogger->log(Level::ERROR, TAG, "guimetadataPublish: Invalid action input found in publish json"); + return -1; + } + + json_object* payloadJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_PAYLOAD.c_str()); + if (payloadJ == nullptr) { + sLogger->log(Level::ERROR, TAG, "guimetadataPublish: No playload found in publish json"); + return -1; + } + + if (!sCapabilityMessagingService->publish(guMetadataCapability, action, payloadJ)) { + sLogger->log(Level::ERROR, TAG, "guimetadataPublish: Failed to publish message: " + action); + return -1; + } + + AFB_ReqSuccess(source->request, json_object_new_string("Successfully published guimetadata messages."), NULL); + return 0; +} + +CTLP_CAPI(phonecontrolSubscribe, source, argsJ, eventJ) { + if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) { + return -1; + } + + shared_ptr<vshlcapabilities::common::interfaces::ICapability> phoneControlCapability = sCapabilitiesFactory->getPhoneControl(); + if (!phoneControlCapability) { + sLogger->log(Level::WARNING, TAG, "phoneControlSubscribe: Failed to fetch phone control capability object."); + return -1; + } + + if (eventJ == nullptr) { + sLogger->log(Level::WARNING, TAG, "phoneControlSubscribe: No arguments supplied."); + return -1; + } + + json subscribeJson = json::parse(json_object_to_json_string(eventJ)); + if (subscribeJson.find(CAPABILITIES_JSON_ATTR_ACTIONS) == subscribeJson.end()) { + sLogger->log(Level::ERROR, TAG, "phoneControlSubscribe: No events array found in subscribe json"); + return -1; + } + list<string> events(subscribeJson[CAPABILITIES_JSON_ATTR_ACTIONS].get<list<string>>()); + + // SUbscribe this client for the phone call control events. + auto request = vshlcapabilities::afb::AFBRequestImpl::create(source->request); + for (auto event : events) { + if (!sCapabilityMessagingService->subscribe(*request, phoneControlCapability, event)) { + sLogger->log(Level::ERROR, TAG, "phoneControlSubscribe: Failed to subscribe to event: " + event); + return -1; + } + } + + AFB_ReqSuccess( + source->request, json_object_new_string("Subscription to phone control events successfully completed."), NULL); + return 0; +} + +CTLP_CAPI(phonecontrolPublish, source, argsJ, eventJ) { + if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) { + return -1; + } + + shared_ptr<vshlcapabilities::common::interfaces::ICapability> phoneControlCapability = sCapabilitiesFactory->getPhoneControl(); + if (!phoneControlCapability) { + sLogger->log(Level::WARNING, TAG, "phoneControlPublish: Failed to fetch navigation capability object."); + return -1; + } + + if (eventJ == nullptr) { + sLogger->log(Level::WARNING, TAG, "phoneControlPublish: No arguments supplied."); + return -1; + } + + json_object* actionJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_ACTION.c_str()); + if (actionJ == nullptr) { + sLogger->log(Level::ERROR, TAG, "phoneControlPublish: No action found in publish json"); + return -1; + } + + std::string action = std::string(json_object_get_string(actionJ)); + if (action.empty()) { + sLogger->log(Level::ERROR, TAG, "phoneControlPublish: Invalid action input found in publish json"); + return -1; + } + + json_object* payloadJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_PAYLOAD.c_str()); + if (payloadJ == nullptr) { + sLogger->log(Level::ERROR, TAG, "phoneControlPublish: No playload found in publish json"); + return -1; + } + + if (!sCapabilityMessagingService->publish(phoneControlCapability, action, payloadJ)) { + sLogger->log(Level::ERROR, TAG, "phoneControlPublish: Failed to publish message: " + action); + return -1; + } + + AFB_ReqSuccess(source->request, json_object_new_string("Successfully published phone control messages."), NULL); + return 0; +} + +CTLP_CAPI(navigationSubscribe, source, argsJ, eventJ) { + if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) { + return -1; + } + + shared_ptr<vshlcapabilities::common::interfaces::ICapability> navigationCapability = sCapabilitiesFactory->getNavigation(); + if (!navigationCapability) { + sLogger->log(Level::WARNING, TAG, "navigationSubscribe: Failed to fetch navigation capability object."); + return -1; + } + + if (eventJ == nullptr) { + sLogger->log(Level::WARNING, TAG, "navigationSubscribe: No arguments supplied."); + return -1; + } + + json subscribeJson = json::parse(json_object_to_json_string(eventJ)); + if (subscribeJson.find(CAPABILITIES_JSON_ATTR_ACTIONS) == subscribeJson.end()) { + sLogger->log(Level::ERROR, TAG, "navigationSubscribe: No events array found in subscribe json"); + return -1; + } + list<string> events(subscribeJson[CAPABILITIES_JSON_ATTR_ACTIONS].get<list<string>>()); + + // SUbscribe this client for the navigation events. + auto request = vshlcapabilities::afb::AFBRequestImpl::create(source->request); + for (auto event : events) { + if (!sCapabilityMessagingService->subscribe(*request, navigationCapability, event)) { + sLogger->log(Level::ERROR, TAG, "navigationSubscribe: Failed to subscribe to event: " + event); + return -1; + } + } + + AFB_ReqSuccess( + source->request, json_object_new_string("Subscription to navigation events successfully completed."), NULL); + return 0; +} + +CTLP_CAPI(navigationPublish, source, argsJ, eventJ) { + if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) { + return -1; + } + + shared_ptr<vshlcapabilities::common::interfaces::ICapability> navigationCapability = sCapabilitiesFactory->getNavigation(); + if (!navigationCapability) { + sLogger->log(Level::WARNING, TAG, "navigationPublish: Failed to fetch navigation capability object."); + return -1; + } + + if (eventJ == nullptr) { + sLogger->log(Level::WARNING, TAG, "navigationPublish: No arguments supplied."); + return -1; + } + + json_object* actionJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_ACTION.c_str()); + if (actionJ == nullptr) { + sLogger->log(Level::ERROR, TAG, "navigationPublish: No action found in publish json"); + return -1; + } + + std::string action = std::string(json_object_get_string(actionJ)); + if (action.empty()) { + sLogger->log(Level::ERROR, TAG, "navigationPublish: Invalid action input found in publish json"); + return -1; + } + + json_object* payloadJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_PAYLOAD.c_str()); + if (payloadJ == nullptr) { + sLogger->log(Level::ERROR, TAG, "navigationPublish: No playload found in publish json"); + return -1; + } + + if (!sCapabilityMessagingService->publish(navigationCapability, action, payloadJ)) { + sLogger->log(Level::ERROR, TAG, "navigationPublish: Failed to publish message: " + action); + return -1; + } + + AFB_ReqSuccess(source->request, json_object_new_string("Successfully published navigation messages."), NULL); + return 0; +} + +CTLP_CAPI(playbackControllerSubscribe, source, argsJ, eventJ) { + if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) { + return -1; + } + + shared_ptr<vshlcapabilities::common::interfaces::ICapability> playbackcontrollerCapability = sCapabilitiesFactory->getPlaybackController(); + if (!playbackcontrollerCapability) { + sLogger->log(Level::WARNING, TAG, "playbackControllerSubscribe: Failed to fetch playbackcontroller capability object."); + return -1; + } + + if (eventJ == nullptr) { + sLogger->log(Level::WARNING, TAG, "playbackControllerSubscribe: No arguments supplied."); + return -1; + } + + json subscribeJson = json::parse(json_object_to_json_string(eventJ)); + if (subscribeJson.find(CAPABILITIES_JSON_ATTR_ACTIONS) == subscribeJson.end()) { + sLogger->log(Level::ERROR, TAG, "playbackControllerSubscribe: No events array found in subscribe json"); + return -1; + } + list<string> events(subscribeJson[CAPABILITIES_JSON_ATTR_ACTIONS].get<list<string>>()); + + // SUbscribe this client for the navigation events. + auto request = vshlcapabilities::afb::AFBRequestImpl::create(source->request); + for (auto event : events) { + if (!sCapabilityMessagingService->subscribe(*request, playbackcontrollerCapability, event)) { + sLogger->log(Level::ERROR, TAG, "playbackControllerSubscribe: Failed to subscribe to event: " + event); + return -1; + } + } + + AFB_ReqSuccess( + source->request, json_object_new_string("Subscription to playbackcontroller events successfully completed."), NULL); + return 0; +} + +CTLP_CAPI(playbackControllerPublish, source, argsJ, eventJ) { + if (sCapabilitiesFactory == nullptr || sCapabilityMessagingService == nullptr) { + return -1; + } + + shared_ptr<vshlcapabilities::common::interfaces::ICapability> playbackcontrollerCapability = sCapabilitiesFactory->getPlaybackController(); + if (!playbackcontrollerCapability) { + sLogger->log(Level::WARNING, TAG, "playbackControllerPublish: Failed to fetch playbackcontroller capability object."); + return -1; + } + + if (eventJ == nullptr) { + sLogger->log(Level::WARNING, TAG, "playbackControllerPublish: No arguments supplied."); + return -1; + } + + json_object* actionJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_ACTION.c_str()); + if (actionJ == nullptr) { + sLogger->log(Level::ERROR, TAG, "playbackControllerPublish: No action found in publish json"); + return -1; + } + + std::string action = std::string(json_object_get_string(actionJ)); + if (action.empty()) { + sLogger->log(Level::ERROR, TAG, "playbackControllerPublish: Invalid action input found in publish json"); + return -1; + } + + json_object* payloadJ = json_object_object_get(eventJ , CAPABILITIES_JSON_ATTR_PAYLOAD.c_str()); + if (payloadJ == nullptr) { + sLogger->log(Level::ERROR, TAG, "playbackControllerPublish: No playload found in publish json"); + return -1; + } + + if (!sCapabilityMessagingService->publish(playbackcontrollerCapability, action, payloadJ)) { + sLogger->log(Level::ERROR, TAG, "playbackControllerPublish: Failed to publish message: " + action); + return -1; + } + + AFB_ReqSuccess(source->request, json_object_new_string("Successfully published playbackcontroller messages."), NULL); + return 0; +}
\ No newline at end of file diff --git a/src/plugins/VshlCapabilitiesApi.h b/src/plugins/VshlCapabilitiesApi.h new file mode 100644 index 0000000..1ef1d71 --- /dev/null +++ b/src/plugins/VshlCapabilitiesApi.h @@ -0,0 +1,39 @@ +/* + * Copyright 2017-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_CAPABILITIES_API_INCLUDE +#define VSHL_CAPABILITIES_API_INCLUDE + +#include "ctl-plugin.h" + +#ifdef __cplusplus +extern "C" { +#endif + +CTLP_ONLOAD(plugin, ret); +CTLP_INIT(plugin, ret); +int guiMetadataSubscribe(CtlSourceT* source, json_object* argsJ, json_object* queryJ); +int guiMetadataPublish(CtlSourceT* source, json_object* argsJ, json_object* queryJ); +int phonecontrolSubscribe(CtlSourceT* source, json_object* argsJ, json_object* queryJ); +int phonecontrolPublish(CtlSourceT* source, json_object* argsJ, json_object* queryJ); +int navigationSubscribe(CtlSourceT* source, json_object* argsJ, json_object* queryJ); +int navigationPublish(CtlSourceT* source, json_object* argsJ, json_object* queryJ); +int playbackControllerSubscribe(CtlSourceT* source, json_object* argsJ, json_object* queryJ); +int playbackControllerPublish(CtlSourceT* source, json_object* argsJ, json_object* queryJ); + +#ifdef __cplusplus +} +#endif + +#endif // VSHL_CAPABILITIES_API_INCLUDE diff --git a/src/plugins/afb/AFBApiImpl.cpp b/src/plugins/afb/AFBApiImpl.cpp new file mode 100644 index 0000000..443a412 --- /dev/null +++ b/src/plugins/afb/AFBApiImpl.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ + +#include "afb/AFBApiImpl.h" + +#include "afb/include/AFBEventImpl.h" +#include "utilities/logging/Logger.h" + +extern "C" { +#define AFB_BINDING_VERSION 3 + +#include "afb-definitions.h" +} + +static std::string TAG = "vshlcapabilities::afb::AFBApiImpl"; + +/** + * Specifies the severity level of a log message + */ +using Level = vshlcapabilities::common::interfaces::ILogger::Level; +using namespace vshlcapabilities::common::interfaces; +using namespace vshlcapabilities::utilities::logging; + +namespace vshlcapabilities { +namespace afb { + +std::unique_ptr<AFBApiImpl> AFBApiImpl::create(AFB_ApiT api) { + return std::unique_ptr<AFBApiImpl>(new AFBApiImpl(api)); +} + +AFBApiImpl::AFBApiImpl(AFB_ApiT api) : mApi(api), mLogger(Logger::create(api)) { +} + +AFBApiImpl::~AFBApiImpl() { +} + +std::shared_ptr<IAFBApi::IAFBEvent> AFBApiImpl::createEvent(const std::string& eventName) { + return AFBEventImpl::create(mLogger, mApi, eventName); +} + +int AFBApiImpl::callSync( + const std::string& api, + const std::string& verb, + struct json_object* request, + struct json_object** result, + std::string& error, + std::string& info) { + char* errorStr = NULL; + char* infoStr = NULL; + int rc = AFB_ApiSync(mApi, api.c_str(), verb.c_str(), request, result, &errorStr, &infoStr); + + if (errorStr) { + error = errorStr; + free(errorStr); + } + + if (infoStr) { + info = infoStr; + free(infoStr); + } + + return rc; +} + +} // namespace afb +} // namespace vshl diff --git a/src/plugins/afb/AFBApiImpl.h b/src/plugins/afb/AFBApiImpl.h new file mode 100644 index 0000000..a8d8e08 --- /dev/null +++ b/src/plugins/afb/AFBApiImpl.h @@ -0,0 +1,61 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_AFB_AFBAPIIMPL_H_ +#define VSHL_AFB_AFBAPIIMPL_H_ + +#include <memory> + +extern "C" { +#include "ctl-plugin.h" +} + +#include "interfaces/afb/IAFBApi.h" +#include "interfaces/utilities/logging/ILogger.h" + +using namespace std; + +namespace vshlcapabilities { +namespace afb { + +class AFBApiImpl : public vshlcapabilities::common::interfaces::IAFBApi { +public: + static std::unique_ptr<AFBApiImpl> create(AFB_ApiT api); + + ~AFBApiImpl(); + + std::shared_ptr<IAFBEvent> createEvent(const std::string& eventName) override; + + int callSync( + const std::string& api, + const std::string& verb, + struct json_object* request, + struct json_object** result, + std::string& error, + std::string& info) override; + +private: + AFBApiImpl(AFB_ApiT api); + + // AFB API Binding + AFB_ApiT mApi; + + // Logger + std::shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace afb +} // namespace vshl + +#endif // VSHL_AFB_AFBAPIIMPL_H_ diff --git a/src/plugins/afb/AFBRequestImpl.cpp b/src/plugins/afb/AFBRequestImpl.cpp new file mode 100644 index 0000000..3e20172 --- /dev/null +++ b/src/plugins/afb/AFBRequestImpl.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ + +#include "afb/AFBRequestImpl.h" + +extern "C" { +#include "afb-definitions.h" +} + +namespace vshlcapabilities { +namespace afb { + +std::unique_ptr<AFBRequestImpl> AFBRequestImpl::create(AFB_ReqT afbRequest) { + return std::unique_ptr<AFBRequestImpl>(new AFBRequestImpl(afbRequest)); +} + +AFBRequestImpl::AFBRequestImpl(AFB_ReqT afbRequest) : mAfbRequest(afbRequest) { +} + +void* AFBRequestImpl::getNativeRequest() { + return mAfbRequest; +} + +} // namespace afb +} // namespace vshl diff --git a/src/plugins/afb/AFBRequestImpl.h b/src/plugins/afb/AFBRequestImpl.h new file mode 100644 index 0000000..c155f31 --- /dev/null +++ b/src/plugins/afb/AFBRequestImpl.h @@ -0,0 +1,49 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_AFB_AFBREQUESTIMPL_H_ +#define VSHL_AFB_AFBREQUESTIMPL_H_ + +#include <memory> + +extern "C" { +#include "ctl-plugin.h" +} + +#include "interfaces/afb/IAFBApi.h" + +namespace vshlcapabilities { +namespace afb { + +/** + * AFB Request impl + */ +class AFBRequestImpl : public vshlcapabilities::common::interfaces::IAFBRequest { +public: + static std::unique_ptr<AFBRequestImpl> create(AFB_ReqT afbRequest); + + // {@c IAFBRequest Implementation + void *getNativeRequest() override; + // @c IAFBRequest Implementation } + +private: + AFBRequestImpl(AFB_ReqT afbRequest); + + AFB_ReqT mAfbRequest; +}; + +} // namespace afb +} // namespace vshl + +#endif // VSHL_AFB_AFBREQUESTIMPL_H_ diff --git a/src/plugins/afb/include/AFBEventImpl.h b/src/plugins/afb/include/AFBEventImpl.h new file mode 100644 index 0000000..2dda513 --- /dev/null +++ b/src/plugins/afb/include/AFBEventImpl.h @@ -0,0 +1,77 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_AFB_EVENT_H_ +#define VSHL_AFB_EVENT_H_ + +#include <memory> +#include <string> + +#include "interfaces/afb/IAFBApi.h" +#include "interfaces/utilities/logging/ILogger.h" + +extern "C" { +#include "ctl-plugin.h" +#include <json-c/json.h> +} + +using namespace std; + +namespace vshlcapabilities { +namespace afb { +/* + * This class encapsulates AFB Event. + */ +class AFBEventImpl : public vshlcapabilities::common::interfaces::IAFBApi::IAFBEvent { +public: + static unique_ptr<AFBEventImpl> + create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, AFB_ApiT api, + const string &eventName); + + // Destructor + ~AFBEventImpl(); + + /// { @c IAFBEvent implementation + string getName() const override; + bool isValid() override; + int publishEvent(struct json_object *payload) override; + bool subscribe(vshlcapabilities::common::interfaces::IAFBRequest &request) override; + bool unsubscribe(vshlcapabilities::common::interfaces::IAFBRequest &request) override; + /// @c IAFBEvent implementation } + +private: + AFBEventImpl(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + AFB_ApiT api, const string &eventName); + + // Make the event. This is a lazy make that happens + // usually during the subscribe stage. + void makeEventIfNeccessary(); + + // Binding API reference + AFB_ApiT mAfbApi; + + // AFB Event + afb_event_t mAfbEvent; + + // Event Name + string mEventName; + + // Logger + shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace afb +} // namespace vshl + +#endif // VSHL_AFB_EVENT_H_ diff --git a/src/plugins/afb/src/AFBEventImpl.cpp b/src/plugins/afb/src/AFBEventImpl.cpp new file mode 100644 index 0000000..7ddac36 --- /dev/null +++ b/src/plugins/afb/src/AFBEventImpl.cpp @@ -0,0 +1,89 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "afb/include/AFBEventImpl.h" + +static string TAG = "vshlcapabilities::afb::Event"; + +using Level = vshlcapabilities::common::interfaces::ILogger::Level; +using namespace vshlcapabilities::common::interfaces; + +namespace vshlcapabilities { +namespace afb { + +unique_ptr<AFBEventImpl> AFBEventImpl::create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + AFB_ApiT api, + const string& eventName) { + return unique_ptr<AFBEventImpl>(new AFBEventImpl(logger, api, eventName)); +} + +AFBEventImpl::AFBEventImpl( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + AFB_ApiT api, + const string& eventName) : + mLogger(logger), + mAfbApi(api), + mEventName(eventName), + mAfbEvent(nullptr) { +} + +AFBEventImpl::~AFBEventImpl() { +} + +string AFBEventImpl::getName() const { + return mEventName; +} + +bool AFBEventImpl::isValid() { + makeEventIfNeccessary(); + return afb_event_is_valid(mAfbEvent) == 1 ? true : false; +} + +bool AFBEventImpl::subscribe(IAFBRequest& requestInterface) { + makeEventIfNeccessary(); + auto request = static_cast<AFB_ReqT>(requestInterface.getNativeRequest()); + if (isValid() && afb_req_subscribe(request, mAfbEvent) == 0) { + return true; + } + + return false; +} + +bool AFBEventImpl::unsubscribe(IAFBRequest& requestInterface) { + makeEventIfNeccessary(); + auto request = static_cast<AFB_ReqT>(requestInterface.getNativeRequest()); + if (isValid() && afb_req_unsubscribe(request, mAfbEvent) == 0) { + return true; + } + + return false; +} + +int AFBEventImpl::publishEvent(struct json_object* payload) { + makeEventIfNeccessary(); + return afb_event_push(mAfbEvent, payload); +} + +void AFBEventImpl::makeEventIfNeccessary() { + if (mAfbEvent) { + return; + } + + mLogger->log(Level::NOTICE, TAG, "Creating VSHL event: " + mEventName); + mAfbEvent = afb_api_make_event(mAfbApi, mEventName.c_str()); +} + +} // namespace afb +} // namespace vshl diff --git a/src/plugins/agreement.sh b/src/plugins/agreement.sh new file mode 100755 index 0000000..2a8eb71 --- /dev/null +++ b/src/plugins/agreement.sh @@ -0,0 +1,43 @@ +#******************************************************************************** +# Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"). +# You may not use this file except in compliance with the License. +# A copy of the License is located at +# +# http://aws.amazon.com/apache2.0/ +# +# or in the "license" file accompanying this file. This file 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. +#********************************************************************************* + +agreement_check() { + cat << EOF + +******************************************************************************* +The scripts provided herein will retrieve several third-party libraries, +environments, and/or other software packages at build-time +("External Dependencies") from third-party sources. These are terms and +conditions that you need to agree to abide by if you choose to build the +External Dependencies. Licenses for the External Dependencies may be found at +README.md. If you do not agree with every term and condition +associated with the External Dependencies, enter “QUIT” in the command line +when prompted by the script. +******************************************************************************* + +EOF + + answer="dummy" + while [ ! -z $answer ]; do + read -p "Type \"QUIT\" to exit the script now, press ENTER to continue: " -r answer + if [ "$answer" = "QUIT" ]; then + exit 1 + fi + echo "" + done +} + +agreement_check +exit 0
\ No newline at end of file diff --git a/src/plugins/capabilities/CapabilitiesFactory.cpp b/src/plugins/capabilities/CapabilitiesFactory.cpp new file mode 100644 index 0000000..7a65842 --- /dev/null +++ b/src/plugins/capabilities/CapabilitiesFactory.cpp @@ -0,0 +1,71 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ + +#include "capabilities/CapabilitiesFactory.h" + +#include "capabilities/communication/include/PhoneControlCapability.h" +#include "capabilities/guimetadata/include/GuiMetadataCapability.h" +#include "capabilities/navigation/include/NavigationCapability.h" +#include "capabilities/playbackcontroller/include/PlaybackControllerCapability.h" + +static string TAG = "vshlcapabilities::core::CapabilitiesFactory"; + +namespace vshlcapabilities { +namespace capabilities { + +// Create CapabilitiesFactory +std::unique_ptr<CapabilitiesFactory> CapabilitiesFactory::create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + auto capabilitiesFactory = std::unique_ptr<CapabilitiesFactory>(new CapabilitiesFactory(logger)); + return capabilitiesFactory; +} + +CapabilitiesFactory::CapabilitiesFactory( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + mLogger = logger; +} + +std::shared_ptr<common::interfaces::ICapability> CapabilitiesFactory::getGuiMetadata() { + if (!mGuiMetadata) { + mGuiMetadata = vshlcapabilities::capabilities::guimetadata::GuiMetadata::create(mLogger); + } + return mGuiMetadata; +} + +std::shared_ptr<common::interfaces::ICapability> CapabilitiesFactory::getPhoneControl() { + if (!mPhoneControl) { + mPhoneControl = vshlcapabilities::capabilities::phonecontrol::PhoneControl::create(mLogger); + } + return mPhoneControl; +} + +std::shared_ptr<common::interfaces::ICapability> CapabilitiesFactory::getNavigation( + ) { + if (!mNavigation) { + mNavigation = vshlcapabilities::capabilities::navigation::Navigation::create(mLogger); + } + return mNavigation; +} + +std::shared_ptr<common::interfaces::ICapability> CapabilitiesFactory::getPlaybackController( + ) { + if (!mPlaybackController) { + mPlaybackController = vshlcapabilities::capabilities::playbackcontroller::PlaybackController::create(mLogger); + } + return mPlaybackController; +} + +} // namespace capabilities +} // namespace vshl
\ No newline at end of file diff --git a/src/plugins/capabilities/CapabilitiesFactory.h b/src/plugins/capabilities/CapabilitiesFactory.h new file mode 100644 index 0000000..b97fcfe --- /dev/null +++ b/src/plugins/capabilities/CapabilitiesFactory.h @@ -0,0 +1,69 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_CAPABILITIES_CAPABILITIESFACTORY_H_ +#define VSHL_CAPABILITIES_CAPABILITIESFACTORY_H_ + +#include <memory> + +#include "interfaces/capabilities/ICapability.h" +#include "interfaces/utilities/logging/ILogger.h" + +using namespace std; + +namespace vshlcapabilities { +namespace capabilities { +/* + * Factory for creating different capability objects. + */ +class CapabilitiesFactory { +public: + // Create CapabilitiesFactory + static std::unique_ptr<CapabilitiesFactory> create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + // GUI Metadata capability + std::shared_ptr<common::interfaces::ICapability> getGuiMetadata(); + + // Phone call control capability + std::shared_ptr<common::interfaces::ICapability> getPhoneControl(); + + // Navigation capability + std::shared_ptr<common::interfaces::ICapability> getNavigation(); + + // PLaybackcontroller capability + std::shared_ptr<common::interfaces::ICapability> getPlaybackController(); + + // Destructor + ~CapabilitiesFactory() = default; + +private: + // Constructor + CapabilitiesFactory( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + // Capabilities + shared_ptr<vshlcapabilities::common::interfaces::ICapability> mGuiMetadata; + shared_ptr<vshlcapabilities::common::interfaces::ICapability> mPhoneControl; + shared_ptr<vshlcapabilities::common::interfaces::ICapability> mNavigation; + shared_ptr<vshlcapabilities::common::interfaces::ICapability> mPlaybackController; + + // Logger + shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_CAPABILITIESFACTORY_H_ diff --git a/src/plugins/capabilities/CapabilityMessagingService.cpp b/src/plugins/capabilities/CapabilityMessagingService.cpp new file mode 100644 index 0000000..8dd6e26 --- /dev/null +++ b/src/plugins/capabilities/CapabilityMessagingService.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "capabilities/CapabilityMessagingService.h" + +#include "capabilities/core/include/PublisherForwarder.h" +#include "capabilities/core/include/SubscriberForwarder.h" + +static string TAG = "vshlcapabilities::capabilities::CapabilityMessagingService"; + +using Level = vshlcapabilities::common::interfaces::ILogger::Level; + +namespace vshlcapabilities { +namespace capabilities { + +// Create a CapabilityMessagingService. +unique_ptr<CapabilityMessagingService> CapabilityMessagingService::create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi) { + if (logger == nullptr) { + return nullptr; + } + + if (afbApi == nullptr) { + logger->log(Level::ERROR, TAG, "Failed to create CapabilityMessagingService: AFB API null"); + return nullptr; + } + + auto capabilityMessageService = + std::unique_ptr<CapabilityMessagingService>(new CapabilityMessagingService(logger, afbApi)); + return capabilityMessageService; +} + +CapabilityMessagingService::~CapabilityMessagingService() { + mMessageChannelsMap.clear(); +} + +CapabilityMessagingService::CapabilityMessagingService( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi) : + mAfbApi(afbApi), + mLogger(logger) { +} + +// Subscribe to capability specific messages. +bool CapabilityMessagingService::subscribe( + vshlcapabilities::common::interfaces::IAFBRequest& request, + shared_ptr<common::interfaces::ICapability> capability, + const string action) { + auto capabilityName = capability->getName(); + + if (capabilityName.empty()) { + mLogger->log(Level::ERROR, TAG, "Failed to subscribe to message. Invalid input."); + return false; + } + + auto messageChannel = getMessageChannel(capability); + return messageChannel->subscribe(request, action); +} + +// Publish capability messages. +bool CapabilityMessagingService::publish( + shared_ptr<common::interfaces::ICapability> capability, + const string action, + json_object* payload) { + auto capabilityName = capability->getName(); + + if (capabilityName.empty()) { + mLogger->log(Level::ERROR, TAG, "Failed to publish message. Invalid input."); + return false; + } + + auto messageChannelIt = mMessageChannelsMap.find(capabilityName); + if (messageChannelIt == mMessageChannelsMap.end()) { + mLogger->log( + Level::ERROR, + TAG, + "No one subscribed for a message of capability. " + capabilityName); + return false; + } + + return messageChannelIt->second->publish(action, payload); +} + +shared_ptr<vshlcapabilities::capabilities::core::MessageChannel> CapabilityMessagingService::getMessageChannel( + shared_ptr<common::interfaces::ICapability> capability) { + auto capabilityName = capability->getName(); + + if (capabilityName.empty()) { + mLogger->log(Level::ERROR, TAG, "Failed to create message channel. Invalid input."); + return nullptr; + } + + auto messageChannelIt = mMessageChannelsMap.find(capabilityName); + if (messageChannelIt == mMessageChannelsMap.end()) { + mLogger->log(Level::INFO, TAG, "Creating new message channel for capability: " + capabilityName); + auto messageChannel = vshlcapabilities::capabilities::core::MessageChannel::create(mLogger, mAfbApi, capability); + mMessageChannelsMap.insert(make_pair(capabilityName, messageChannel)); + return messageChannel; + } + + return messageChannelIt->second; +} + +} // namespace capabilities +} // namespace vshl diff --git a/src/plugins/capabilities/CapabilityMessagingService.h b/src/plugins/capabilities/CapabilityMessagingService.h new file mode 100644 index 0000000..79edfa8 --- /dev/null +++ b/src/plugins/capabilities/CapabilityMessagingService.h @@ -0,0 +1,82 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_CAPABILITIES_CAPABILITYMESSAGINGSERVICE_H_ +#define VSHL_CAPABILITIES_CAPABILITYMESSAGINGSERVICE_H_ + +#include <memory> +#include <string> +#include <unordered_map> + +#include "capabilities/core/include/MessageChannel.h" +#include "interfaces/afb/IAFBApi.h" +#include "interfaces/capabilities/ICapability.h" +#include "interfaces/utilities/logging/ILogger.h" + +using namespace std; + +namespace vshlcapabilities { +namespace capabilities { +/* + * This hosts service APIs that clients can use to subscribe and + * forward capability messages. Each capability has a name and + * direction (upstream/downstream). Upstream messages are from + * voiceagents to Apps and downstream messages are Apps to voiceagents. + * This class will use a factory to create publisher and subcribers for + * each capability and create assiociations between them. + */ +class CapabilityMessagingService { +public: + // Create a CapabilityMessagingService. + static std::unique_ptr<CapabilityMessagingService> + create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi); + + // Subscribe to capability specific messages. + bool subscribe(vshlcapabilities::common::interfaces::IAFBRequest &request, + shared_ptr<common::interfaces::ICapability> capability, + const string action); + + // Publish capability messages. + bool publish(shared_ptr<common::interfaces::ICapability> capability, + const string action, json_object* payload); + + // Destructor + ~CapabilityMessagingService(); + +private: + // Constructor + CapabilityMessagingService( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi); + + // Binding API reference + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> mAfbApi; + + // Create a message channel for the capability. + shared_ptr<vshlcapabilities::capabilities::core::MessageChannel> + getMessageChannel(shared_ptr<common::interfaces::ICapability> capability); + + // Map of capabilities to message channels. + unordered_map<string, shared_ptr<vshlcapabilities::capabilities::core::MessageChannel>> + mMessageChannelsMap; + + // Logger + shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_CAPABILITYMESSAGINGSERVICE_H_ diff --git a/src/plugins/capabilities/communication/include/PhoneControlCapability.h b/src/plugins/capabilities/communication/include/PhoneControlCapability.h new file mode 100644 index 0000000..87dc339 --- /dev/null +++ b/src/plugins/capabilities/communication/include/PhoneControlCapability.h @@ -0,0 +1,57 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ + +#ifndef VSHL_CAPABILITIES_PHONECONTROL_CAPABILITY_H_ +#define VSHL_CAPABILITIES_PHONECONTROL_CAPABILITY_H_ + +#include <memory> + +#include "interfaces/capabilities/ICapability.h" +#include "interfaces/utilities/logging/ILogger.h" + +namespace vshlcapabilities { +namespace capabilities { +namespace phonecontrol { + +/* + * PhoneControl capability. Calls are initiated in the endpoint. + */ +class PhoneControl : public common::interfaces::ICapability { +public: + // Create a PhoneControl. + static std::shared_ptr<PhoneControl> create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + ~PhoneControl() = default; + +protected: + string getName() const override; + + list<string> getUpstreamMessages() const override; + + list<string> getDownstreamMessages() const override; + +private: + PhoneControl( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace phonecontrol +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_PHONECONTROL_CAPABILITY_H_ diff --git a/src/plugins/capabilities/communication/include/PhoneControlMessages.h b/src/plugins/capabilities/communication/include/PhoneControlMessages.h new file mode 100644 index 0000000..23d2fae --- /dev/null +++ b/src/plugins/capabilities/communication/include/PhoneControlMessages.h @@ -0,0 +1,208 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_CAPABILITIES_PHONECONTROL_MESSAGES_H_ +#define VSHL_CAPABILITIES_PHONECONTROL_MESSAGES_H_ + +#include <list> +#include <string> + +using namespace std; + +namespace vshlcapabilities { +namespace capabilities { +namespace phonecontrol { + +static string NAME = "phonecontrol"; + +/* + ****************************************************************************************************** + * Supported actions from VA -> APPS + ****************************************************************************************************** + */ + +/* Dial message sent from VA to app handling the calling. + * + * payload: + * { + * "callId": "{{STRING}}", + * "callee": { + * "details": "{{STRING}}", + * "defaultAddress": { + * "protocol": "{{STRING}}", + * "format": "{{STRING}}", + * "value": "{{STRING}}" + * }, + * "alternativeAddresses": [{ + * "protocol": "{{STRING}}", + * "format": "{{STRING}}", + * "value": {{STRING}} + * }] + * } + * } + * } + * + * callId (required): A unique identifier for the call + * callee (required): The destination of the outgoing call + * callee.details (optional): Descriptive information about the callee + * callee.defaultAddress (required): The default address to use for calling the callee + * callee.alternativeAddresses (optional): An array of alternate addresses for the existing callee + * address.protocol (required): The protocol for this address of the callee (e.g. PSTN, SIP, H323, etc.) + * address.format (optional): The format for this address of the callee (e.g. E.164, E.163, E.123, DIN5008, etc.) + * address.value (required): The address of the callee. + * + */ +static string PHONECONTROL_DIAL = "dial"; +/** + * Notifies the platform implementation to redial the last called phone number. + * + * After returning @c true, if no stored number is available to be redialed, @c PhoneCallController::callFailed with + * @c CallError::NO_NUMBER_FOR_REDIAL should be called. + * + * @param [in] payload Details of the redial request in structured JSON format. See the following + * payload: + * { + * "callId": "{{STRING}}" + * } + * @li callId (required): A unique identifier for the call + * + * @return @c true if the platform implementation successfully handled the call + */ +static string PHONECONTROL_REDIAL = "redial"; +/** + * Notifies the platform implementation to answer an inbound call + * + * @param [in] payload Details of the answer request in structured JSON format. See the following + * payload: + * { + * "callId": "{{STRING}}", + * } + * @li callId (required): The unique identifier for the call to answer + */ +static string PHONECONTROL_ANSWER = "answer"; +/** + * Notifies the platform implementation to end an ongoing call or stop inbound or outbound call setup + * + * @param [in] payload Details of the stop request in structured JSON format. See the following + * payload: + * { + * "callId": "{{STRING}}" + * } + * @li callId (required): The unique identifier for the call to be stopped + */ +static string PHONECONTROL_STOP = "stop"; +/** + * Notifies the platform implementation to send a DTMF signal to the calling device + * + * @param [in] payload Details of the DTMF request in structured JSON format. See the following + * payload: + * { + * "callId": "{{STRING}}", + * "signal": "{{STRING}}" + * } + * @li callId (required): The unique identifier for the call + * @li signal (required): The DTMF string to be sent to the calling device associated with the callId + */ +static string PHONECONTROL_SEND_DTMF = "send_dtmf"; + +/* + ****************************************************************************************************** + * Supported actions from Apps -> VA + ****************************************************************************************************** + */ + +/* + * App notifies the voiceagents of a change in connection state of a calling device. + * + * payload: + * { + * "state" : "{{STRING}}" // CONNECTED or DISCONNECTED + * } + */ +static string PHONECONTROL_CONNECTIONSTATE_CHANGED = "connection_state_changed"; +/* + * App notifies the voiceagents that call is activated + * + * callId must match the one that is sent by VA with DIAL message above. + * + * payload: + * { + * "callId" : "{{STRING}}" + * "state" : "{{STRING}}" // IDLE, ACTIVE, TRYING, INBOUND_RINGING, OUTBOUND_RINGING, INVITED + * } + */ +static string PHONECONTROL_CALL_STATE_CHANGED = "call_state_changed"; +/* + * App notifies the voiceagents of an error in initiating or maintaining a + * call on a calling device + * + * callId must match the one that is sent by VA with DIAL message above. + * error: below status codes. + * 4xx: Validation failure for the input from the DIAL message + * 500: Internal error on the platform unrelated to the cellular network + * 503: Error on the platform related to the cellular network + * + * payload : + * { + * "callId" : "{{STRING}}" + * "error" : "{{STRING}}" + * } + */ +static string PHONECONTROL_CALL_FAILED = "call_failed"; +/** + * App notifies the voiceagents that a caller id was received for an inbound call + * payload : + * { + * "callId" : "{{STRING}}" + * "callerId" : "{{STRING}}" + * } + * + * @param [in] callId The unique identifier for the call associated with the callId + * @param [in] callerId The caller's identifier or phone number + */ +static string PHONECONTROL_CALLERID_RECEIVED = "caller_id_received"; + +/** + * Notifies the Engine that sending the DTMF signal succeeded. + * payload : + * { + * "callId" : "{{STRING}}" + * } + * @param [in] callId The unique identifier for the associated call + * + * PhoneCallController::sendDTMF + */ +static string PHONECONTROL_SEND_DTMF_SUCCEEDED = "send_dtmf_succeeded"; + +// List of actions that are delivered from VA -> Apps +static list<string> PHONECONTROL_UPSTREAM_ACTIONS = { + PHONECONTROL_DIAL, + PHONECONTROL_REDIAL, + PHONECONTROL_ANSWER, + PHONECONTROL_STOP, + PHONECONTROL_SEND_DTMF +}; + +// List of actions that are delivered from Apps -> VA +static list<string> PHONECONTROL_DOWNSTREAM_ACTIONS = {PHONECONTROL_CONNECTIONSTATE_CHANGED, + PHONECONTROL_CALL_STATE_CHANGED, + PHONECONTROL_CALL_FAILED, + PHONECONTROL_CALLERID_RECEIVED, + PHONECONTROL_SEND_DTMF_SUCCEEDED}; + +} // namespace phonecontrol +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_PHONECONTROL_MESSAGES_H_ diff --git a/src/plugins/capabilities/communication/src/PhoneControlCapability.cpp b/src/plugins/capabilities/communication/src/PhoneControlCapability.cpp new file mode 100644 index 0000000..75296bf --- /dev/null +++ b/src/plugins/capabilities/communication/src/PhoneControlCapability.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "capabilities/communication/include/PhoneControlCapability.h" +#include "capabilities/communication/include/PhoneControlMessages.h" + +const string TAG = "vshlcapabilities::capabilities::phonecontrol"; + +using Level = vshlcapabilities::common::interfaces::ILogger::Level; + +namespace vshlcapabilities { +namespace capabilities { +namespace phonecontrol { + +// Create a phonecontrol. +shared_ptr<PhoneControl> PhoneControl::create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + auto phonecontrol = std::shared_ptr<PhoneControl>(new PhoneControl(logger)); + return phonecontrol; +} + +PhoneControl::PhoneControl( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + mLogger = logger; +} + +string PhoneControl::getName() const { + return NAME; +} + +list<string> PhoneControl::getUpstreamMessages() const { + return PHONECONTROL_UPSTREAM_ACTIONS; +} + +list<string> PhoneControl::getDownstreamMessages() const { + return PHONECONTROL_DOWNSTREAM_ACTIONS; +} + +} // namespace phonecontrol +} // namespace capabilities +} // namespace vshl diff --git a/src/plugins/capabilities/core/include/MessageChannel.h b/src/plugins/capabilities/core/include/MessageChannel.h new file mode 100644 index 0000000..79e4eab --- /dev/null +++ b/src/plugins/capabilities/core/include/MessageChannel.h @@ -0,0 +1,68 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_CAPABILITIES_CORE_MESSAGECHANNEL_H_ +#define VSHL_CAPABILITIES_CORE_MESSAGECHANNEL_H_ + +#include <memory> + +#include "capabilities/core/include/PublisherForwarder.h" +#include "capabilities/core/include/SubscriberForwarder.h" +#include "interfaces/afb/IAFBApi.h" +#include "interfaces/capabilities/ICapability.h" +#include "interfaces/utilities/logging/ILogger.h" + +using namespace std; + +namespace vshlcapabilities { +namespace capabilities { +namespace core { +/* + * MessageChannel has one end as publisher forwarder and the other end + * as subscriber forwarder. + */ +class MessageChannel { +public: + // Create a MessageChannel. + static std::shared_ptr<MessageChannel> + create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability); + + // Sends the message + bool publish(const string action, json_object* payload); + + // Subscribe + bool subscribe(vshlcapabilities::common::interfaces::IAFBRequest &request, + const string action); + + // Destructor + virtual ~MessageChannel() = default; + +private: + // Constructor + MessageChannel(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability); + + // Forwarders + shared_ptr<PublisherForwarder> mPublisherForwarder; + shared_ptr<SubscriberForwarder> mSubscriberForwarder; +}; + +} // namespace core +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_CORE_MESSAGECHANNEL_H_ diff --git a/src/plugins/capabilities/core/include/PublisherForwarder.h b/src/plugins/capabilities/core/include/PublisherForwarder.h new file mode 100644 index 0000000..01e9523 --- /dev/null +++ b/src/plugins/capabilities/core/include/PublisherForwarder.h @@ -0,0 +1,73 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_CAPABILITIES_CORE_PUBLISHERFORWARDER_H_ +#define VSHL_CAPABILITIES_CORE_PUBLISHERFORWARDER_H_ + +#include <memory> + +#include "capabilities/core/include/SubscriberForwarder.h" + +#include "interfaces/afb/IAFBApi.h" +#include "interfaces/capabilities/ICapability.h" +#include "interfaces/utilities/logging/ILogger.h" + +using namespace std; + +namespace vshlcapabilities { +namespace capabilities { +namespace core { +/* + * This class is responsible for forwarding the messages to be published + * to subscriber forwarder. Subscriber forwarder will deliver the messages + * as AFB Events to all the subscribed clients. + * There is one PublisherForwarder and one SubscriberForwarder per capability. + */ +class PublisherForwarder { +public: + // Create a PublisherForwarder. + static std::shared_ptr<PublisherForwarder> create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability); + + // Connect a subscriber forwarder to this publisher forwarder + void setSubscriberForwarder(shared_ptr<SubscriberForwarder> subscriberForwarder); + + // Forward message to the subscriber forwarder + bool forwardMessage(const string action, json_object* payload); + + // Destructor + ~PublisherForwarder(); + +private: + // Constructor + PublisherForwarder( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability); + + // Subscriber forwarder connected to this publisher forwarder. + shared_ptr<SubscriberForwarder> mSubscriberForwarder; + + // Capability + shared_ptr<vshlcapabilities::common::interfaces::ICapability> mCapability; + + // Logger + shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace core +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_CORE_PUBLISHERFORWARDER_H_ diff --git a/src/plugins/capabilities/core/include/SubscriberForwarder.h b/src/plugins/capabilities/core/include/SubscriberForwarder.h new file mode 100644 index 0000000..ac469b3 --- /dev/null +++ b/src/plugins/capabilities/core/include/SubscriberForwarder.h @@ -0,0 +1,84 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_CAPABILITIES_CORE_SUBSCRIBERFORWARDER_H_ +#define VSHL_CAPABILITIES_CORE_SUBSCRIBERFORWARDER_H_ + +#include <memory> +#include <string> +#include <unordered_map> + +#include "interfaces/afb/IAFBApi.h" +#include "interfaces/capabilities/ICapability.h" +#include "interfaces/utilities/logging/ILogger.h" + +using namespace std; + +namespace vshlcapabilities { +namespace capabilities { +namespace core { +/* + * This class is responsible for forwarding the messages publishing + * to the actual clients using AFB. + */ +class SubscriberForwarder { +public: + // Create a SubscriberForwarder. + static std::shared_ptr<SubscriberForwarder> + create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability); + + // Publish a capability message to the actual client. + bool forwardMessage(const string action, json_object* payload); + + // Subscribe + bool subscribe(vshlcapabilities::common::interfaces::IAFBRequest &request, + const string action); + + // Destructor + ~SubscriberForwarder(); + +private: + // Constructor + SubscriberForwarder( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability); + + // Creates both upstream and downstream events + void createEvents(); + + // Binding API reference + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> mAfbApi; + + // Capability + shared_ptr<vshlcapabilities::common::interfaces::ICapability> mCapability; + + // Maps of capability action events to its corresponding Event object. + // Event name maps to Action Name + unordered_map<string, shared_ptr<common::interfaces::IAFBApi::IAFBEvent>> + mUpstreamEventsMap; + unordered_map<string, shared_ptr<common::interfaces::IAFBApi::IAFBEvent>> + mDownstreamEventsMap; + + // Logger + shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace core +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_CORE_SUBSCRIBERFORWARDER_H_ diff --git a/src/plugins/capabilities/core/src/MessageChannel.cpp b/src/plugins/capabilities/core/src/MessageChannel.cpp new file mode 100644 index 0000000..f4e55dd --- /dev/null +++ b/src/plugins/capabilities/core/src/MessageChannel.cpp @@ -0,0 +1,51 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "capabilities/core/include/MessageChannel.h" + +namespace vshlcapabilities { +namespace capabilities { +namespace core { + +// Create a MessageChannel. +std::shared_ptr<MessageChannel> MessageChannel::create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> api, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) { + auto messageChannel = std::shared_ptr<MessageChannel>(new MessageChannel(logger, api, capability)); + return messageChannel; +} + +MessageChannel::MessageChannel( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> api, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) { + // Subscriber forwarder + mSubscriberForwarder = SubscriberForwarder::create(logger, api, capability); + // Publisher forwarder + mPublisherForwarder = PublisherForwarder::create(logger, capability); + mPublisherForwarder->setSubscriberForwarder(mSubscriberForwarder); +} + +bool MessageChannel::publish(const string action, json_object* payload) { + return mPublisherForwarder->forwardMessage(action, payload); +} + +bool MessageChannel::subscribe(vshlcapabilities::common::interfaces::IAFBRequest& request, const string action) { + return mSubscriberForwarder->subscribe(request, action); +} + +} // namespace core +} // namespace capabilities +} // namespace vshl diff --git a/src/plugins/capabilities/core/src/PublisherForwarder.cpp b/src/plugins/capabilities/core/src/PublisherForwarder.cpp new file mode 100644 index 0000000..8f8f542 --- /dev/null +++ b/src/plugins/capabilities/core/src/PublisherForwarder.cpp @@ -0,0 +1,69 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "capabilities/core/include/PublisherForwarder.h" + +static string TAG = "vshlcapabilities::capabilities::PublisherForwarder"; + +using Level = vshlcapabilities::common::interfaces::ILogger::Level; + +namespace vshlcapabilities { +namespace capabilities { +namespace core { + +// Create a PublisherForwarder. +std::shared_ptr<PublisherForwarder> PublisherForwarder::create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) { + if (logger == nullptr) { + return nullptr; + } + + if (capability == nullptr) { + logger->log(Level::ERROR, TAG, "Failed to create PublisherForwarder: Capability null"); + return nullptr; + } + + auto publisherForwarder = std::shared_ptr<PublisherForwarder>(new PublisherForwarder(logger, capability)); + return publisherForwarder; +} + +// Constructor +PublisherForwarder::PublisherForwarder( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) { + mCapability = capability; + mLogger = logger; +} + +// Destructor +PublisherForwarder::~PublisherForwarder() { +} + +void PublisherForwarder::setSubscriberForwarder(shared_ptr<SubscriberForwarder> subscriberForwarder) { + mSubscriberForwarder = subscriberForwarder; +} + +bool PublisherForwarder::forwardMessage(const string action, json_object* payload) { + if (!mSubscriberForwarder) { + mLogger->log(Level::ERROR, TAG, "Failed to forward message for capability: " + mCapability->getName()); + return false; + } + + return mSubscriberForwarder->forwardMessage(action, payload); +} + +} // namespace core +} // namespace capabilities +} // namespace vshl diff --git a/src/plugins/capabilities/core/src/SubscriberForwarder.cpp b/src/plugins/capabilities/core/src/SubscriberForwarder.cpp new file mode 100644 index 0000000..970dbf0 --- /dev/null +++ b/src/plugins/capabilities/core/src/SubscriberForwarder.cpp @@ -0,0 +1,139 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "capabilities/core/include/SubscriberForwarder.h" + +static string TAG = "vshlcapabilities::capabilities::SubscriberForwarder"; + +using Level = vshlcapabilities::common::interfaces::ILogger::Level; + +namespace vshlcapabilities { +namespace capabilities { +namespace core { + +// Create a SubscriberForwarder. +std::shared_ptr<SubscriberForwarder> SubscriberForwarder::create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) { + if (logger == nullptr) { + return nullptr; + } + + if (afbApi == nullptr) { + logger->log(Level::ERROR, TAG, "Failed to create SubscriberForwarder: AFB API null"); + return nullptr; + } + + if (capability == nullptr) { + logger->log(Level::ERROR, TAG, "Failed to create SubscriberForwarder: Capability null"); + return nullptr; + } + + auto subscriberForwarder = + std::shared_ptr<SubscriberForwarder>(new SubscriberForwarder(logger, afbApi, capability)); + return subscriberForwarder; +} + +SubscriberForwarder::SubscriberForwarder( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger, + shared_ptr<vshlcapabilities::common::interfaces::IAFBApi> afbApi, + shared_ptr<vshlcapabilities::common::interfaces::ICapability> capability) : + mAfbApi(afbApi), + mLogger(logger), + mCapability(capability) { + createEvents(); +} + +SubscriberForwarder::~SubscriberForwarder() { + mUpstreamEventsMap.clear(); + mDownstreamEventsMap.clear(); +} + +void SubscriberForwarder::createEvents() { + if (!mCapability) { + mLogger->log(Level::NOTICE, TAG, "Create Events failed. No capability assigned."); + return; + } + + // Upstream events + auto upstreamEvents = mCapability->getUpstreamMessages(); + for (auto upstreamEventName : upstreamEvents) { + auto it = mUpstreamEventsMap.find(upstreamEventName); + if (it == mUpstreamEventsMap.end() && mAfbApi) { + // create a new event and add it to the map. + shared_ptr<common::interfaces::IAFBApi::IAFBEvent> event = mAfbApi->createEvent(upstreamEventName); + if (event == nullptr) { + mLogger->log(Level::ERROR, TAG, "Failed to create upstream event: " + upstreamEventName); + } else { + mUpstreamEventsMap.insert(make_pair(upstreamEventName, event)); + } + } + } + + // Downstream events + auto downstreamEvents = mCapability->getDownstreamMessages(); + for (auto downstreamEventName : downstreamEvents) { + auto it = mDownstreamEventsMap.find(downstreamEventName); + if (it == mDownstreamEventsMap.end() && mAfbApi) { + // create a new event and add it to the map. + shared_ptr<common::interfaces::IAFBApi::IAFBEvent> event = mAfbApi->createEvent(downstreamEventName); + if (event == nullptr) { + mLogger->log(Level::ERROR, TAG, "Failed to create downstream event: " + downstreamEventName); + } else { + mDownstreamEventsMap.insert(make_pair(downstreamEventName, event)); + } + } + } +} + +bool SubscriberForwarder::forwardMessage(const string action, json_object* payload) { + auto upstreamEventIt = mUpstreamEventsMap.find(action); + if (upstreamEventIt != mUpstreamEventsMap.end()) { + mLogger->log(Level::NOTICE, TAG, "Publishing upstream event: " + action); + upstreamEventIt->second->publishEvent(payload); + return true; + } + + auto downstreamEventIt = mDownstreamEventsMap.find(action); + if (downstreamEventIt != mDownstreamEventsMap.end()) { + mLogger->log(Level::NOTICE, TAG, "Publishing downstream event: " + action); + downstreamEventIt->second->publishEvent(payload); + return true; + } + + mLogger->log(Level::NOTICE, TAG, "Failed to publish upstream event: " + action); + return false; +} + +bool SubscriberForwarder::subscribe(vshlcapabilities::common::interfaces::IAFBRequest& request, const string action) { + auto upstreamEventIt = mUpstreamEventsMap.find(action); + if (upstreamEventIt != mUpstreamEventsMap.end()) { + mLogger->log(Level::NOTICE, TAG, "Subscribing to upstream event: " + action); + return upstreamEventIt->second->subscribe(request); + } + + auto downstreamEventIt = mDownstreamEventsMap.find(action); + if (downstreamEventIt != mDownstreamEventsMap.end()) { + mLogger->log(Level::NOTICE, TAG, "Subscribing to downstream event: " + action); + return downstreamEventIt->second->subscribe(request); + } + + mLogger->log(Level::NOTICE, TAG, "Failed to subscribe to upstream event: " + action); + return false; +} + +} // namespace core +} // namespace capabilities +} // namespace vshl diff --git a/src/plugins/capabilities/guimetadata/include/GuiMetadataCapability.h b/src/plugins/capabilities/guimetadata/include/GuiMetadataCapability.h new file mode 100644 index 0000000..ecaf09f --- /dev/null +++ b/src/plugins/capabilities/guimetadata/include/GuiMetadataCapability.h @@ -0,0 +1,57 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ + +#ifndef VSHL_CAPABILITIES_GUIMETADATA_CAPABILITY_H_ +#define VSHL_CAPABILITIES_GUIMETADATA_CAPABILITY_H_ + +#include <memory> + +#include "interfaces/capabilities/ICapability.h" +#include "interfaces/utilities/logging/ILogger.h" + +namespace vshlcapabilities { +namespace capabilities { +namespace guimetadata { + +/* + * GuiMetadata capability + */ +class GuiMetadata : public common::interfaces::ICapability { +public: + // Create a GuiMetadata. + static std::shared_ptr<GuiMetadata> create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + ~GuiMetadata() = default; + +protected: + string getName() const override; + + list<string> getUpstreamMessages() const override; + + list<string> getDownstreamMessages() const override; + +private: + GuiMetadata( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace guimetadata +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_GUIMETADATA_CAPABILITY_H_ diff --git a/src/plugins/capabilities/guimetadata/include/GuiMetadataMessages.h b/src/plugins/capabilities/guimetadata/include/GuiMetadataMessages.h new file mode 100644 index 0000000..07f4725 --- /dev/null +++ b/src/plugins/capabilities/guimetadata/include/GuiMetadataMessages.h @@ -0,0 +1,59 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_CAPABILITIES_GUIMETADATA_ACTIONS_H_ +#define VSHL_CAPABILITIES_GUIMETADATA_ACTIONS_H_ + +#include <list> +#include <string> + +using namespace std; + +namespace vshlcapabilities { +namespace capabilities { +namespace guimetadata { + +static string NAME = "guimetadata"; + +/* + ****************************************************************************************************** + * Supported actions from VA -> APPS + ****************************************************************************************************** + */ +static string GUIMETADATA_RENDER_TEMPLATE = "render_template"; +static string GUIMETADATA_CLEAR_TEMPLATE = "clear_template"; +static string GUIMETADATA_RENDER_PLAYER_INFO = "render_player_info"; +static string GUIMETADATA_CLEAR_PLAYER_INFO = "clear_player_info"; + + +// List of actions that are delivered from VA -> Apps +static list<string> GUIMETADATA_UPSTREAM_ACTIONS = {GUIMETADATA_RENDER_TEMPLATE, + GUIMETADATA_CLEAR_TEMPLATE, + GUIMETADATA_RENDER_PLAYER_INFO, + GUIMETADATA_CLEAR_PLAYER_INFO}; + +/* + ****************************************************************************************************** + * Supported actions from APPS -> VA + ****************************************************************************************************** + */ + +// List of actions that are delivered from Apps -> VA +static list<string> GUIMETADATA_DOWNSTREAM_ACTIONS = {}; + +} // namespace guimetadata +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_GUIMETADATA_ACTIONS_H_ diff --git a/src/plugins/capabilities/guimetadata/src/GuiMetadataCapability.cpp b/src/plugins/capabilities/guimetadata/src/GuiMetadataCapability.cpp new file mode 100644 index 0000000..df90c91 --- /dev/null +++ b/src/plugins/capabilities/guimetadata/src/GuiMetadataCapability.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "capabilities/guimetadata/include/GuiMetadataCapability.h" +#include "capabilities/guimetadata/include/GuiMetadataMessages.h" + +const string TAG = "vshlcapabilities::capabilities::guimetadata"; + +using Level = vshlcapabilities::common::interfaces::ILogger::Level; + +namespace vshlcapabilities { +namespace capabilities { +namespace guimetadata { + +// Create a GuiMetadata. +shared_ptr<GuiMetadata> GuiMetadata::create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + auto guiMetadata = std::shared_ptr<GuiMetadata>(new GuiMetadata(logger)); + return guiMetadata; +} + +GuiMetadata::GuiMetadata( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + mLogger = logger; +} + +string GuiMetadata::getName() const { + return NAME; +} + +list<string> GuiMetadata::getUpstreamMessages() const { + return GUIMETADATA_UPSTREAM_ACTIONS; +} + +list<string> GuiMetadata::getDownstreamMessages() const { + return GUIMETADATA_DOWNSTREAM_ACTIONS; +} + +} // namespace guimetadata +} // namespace capabilities +} // namespace vshl diff --git a/src/plugins/capabilities/navigation/include/NavigationCapability.h b/src/plugins/capabilities/navigation/include/NavigationCapability.h new file mode 100644 index 0000000..bb055a8 --- /dev/null +++ b/src/plugins/capabilities/navigation/include/NavigationCapability.h @@ -0,0 +1,57 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ + +#ifndef VSHL_CAPABILITIES_NAVIGATION_CAPABILITY_H_ +#define VSHL_CAPABILITIES_NAVIGATION_CAPABILITY_H_ + +#include <memory> + +#include "interfaces/capabilities/ICapability.h" +#include "interfaces/utilities/logging/ILogger.h" + +namespace vshlcapabilities { +namespace capabilities { +namespace navigation { + +/* + * Navigation capability + */ +class Navigation : public common::interfaces::ICapability { +public: + // Create a Navigation. + static std::shared_ptr<Navigation> create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + ~Navigation() = default; + +protected: + string getName() const override; + + list<string> getUpstreamMessages() const override; + + list<string> getDownstreamMessages() const override; + +private: + Navigation( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace navigation +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_NAVIGATION_CAPABILITY_H_ diff --git a/src/plugins/capabilities/navigation/include/NavigationMessages.h b/src/plugins/capabilities/navigation/include/NavigationMessages.h new file mode 100644 index 0000000..00c0c65 --- /dev/null +++ b/src/plugins/capabilities/navigation/include/NavigationMessages.h @@ -0,0 +1,56 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_CAPABILITIES_NAVIGATION_ACTIONS_H_ +#define VSHL_CAPABILITIES_NAVIGATION_ACTIONS_H_ + +#include <list> +#include <string> + +using namespace std; + +namespace vshlcapabilities { +namespace capabilities { +namespace navigation { + +static string NAME = "navigation"; + +/* + ****************************************************************************************************** + * Supported actions from VA -> APPS + ****************************************************************************************************** + */ +static string NAVIGATION_SET_DESTINATION = "set_destination"; +static string NAVIGATION_CANCEL = "cancel_navigation"; + +// Supported actions from Apps -> VA + +// List of actions that are delivered from VA -> Apps +static list<string> NAVIGATION_UPSTREAM_ACTIONS = { + NAVIGATION_SET_DESTINATION, + NAVIGATION_CANCEL, +}; + +/* + ****************************************************************************************************** + * Supported actions from APPS -> VA + ****************************************************************************************************** + */ +static list<string> NAVIGATION_DOWNSTREAM_ACTIONS = {}; + +} // namespace navigation +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_NAVIGATION_ACTIONS_H_ diff --git a/src/plugins/capabilities/navigation/src/NavigationCapability.cpp b/src/plugins/capabilities/navigation/src/NavigationCapability.cpp new file mode 100644 index 0000000..e1c6cda --- /dev/null +++ b/src/plugins/capabilities/navigation/src/NavigationCapability.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "capabilities/navigation/include/NavigationCapability.h" +#include "capabilities/navigation/include/NavigationMessages.h" + +const string TAG = "vshlcapabilities::capabilities::navigation"; + +using Level = vshlcapabilities::common::interfaces::ILogger::Level; + +namespace vshlcapabilities { +namespace capabilities { +namespace navigation { + +// Create a Navigation. +shared_ptr<Navigation> Navigation::create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + auto navigation = std::shared_ptr<Navigation>(new Navigation(logger)); + return navigation; +} + +Navigation::Navigation( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + mLogger = logger; +} + +string Navigation::getName() const { + return NAME; +} + +list<string> Navigation::getUpstreamMessages() const { + return NAVIGATION_UPSTREAM_ACTIONS; +} + +list<string> Navigation::getDownstreamMessages() const { + return NAVIGATION_DOWNSTREAM_ACTIONS; +} + +} // namespace navigation +} // namespace capabilities +} // namespace vshl diff --git a/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerCapability.h b/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerCapability.h new file mode 100644 index 0000000..e80b213 --- /dev/null +++ b/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerCapability.h @@ -0,0 +1,57 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ + +#ifndef VSHL_CAPABILITIES_PLAYBACKCONTROLLER_CAPABILITY_H_ +#define VSHL_CAPABILITIES_PLAYBACKCONTROLLER_CAPABILITY_H_ + +#include <memory> + +#include "interfaces/capabilities/ICapability.h" +#include "interfaces/utilities/logging/ILogger.h" + +namespace vshlcapabilities { +namespace capabilities { +namespace playbackcontroller { + +/* + * PlaybackController capability. Calls are initiated in the endpoint. + */ +class PlaybackController : public common::interfaces::ICapability { +public: + // Create a PlaybackController. + static std::shared_ptr<PlaybackController> create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + ~PlaybackController() = default; + +protected: + string getName() const override; + + list<string> getUpstreamMessages() const override; + + list<string> getDownstreamMessages() const override; + +private: + PlaybackController( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace playbackcontroller +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_PLAYBACKCONTROLLER_CAPABILITY_H_ diff --git a/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerMessages.h b/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerMessages.h new file mode 100644 index 0000000..224b8dd --- /dev/null +++ b/src/plugins/capabilities/playbackcontroller/include/PlaybackControllerMessages.h @@ -0,0 +1,64 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_CAPABILITIES_PLAYBACKCONTROLLER_MESSAGES_H_ +#define VSHL_CAPABILITIES_PLAYBACKCONTROLLER_MESSAGES_H_ + +#include <list> +#include <string> + +using namespace std; + +namespace vshlcapabilities { +namespace capabilities { +namespace playbackcontroller { + +static string NAME = "playbackcontroller"; + +/* + ****************************************************************************************************** + * Supported actions from APPS -> VA + ****************************************************************************************************** + */ +// List of actions that are delivered from VA -> Apps +static list<string> PLAYBACKCONTROLLER_UPSTREAM_ACTIONS = { + +}; + + +/* + ****************************************************************************************************** + * Supported actions from VA -> APPS + ****************************************************************************************************** + */ +// List of actions that are delivered from Apps -> VA +/* + * payload : + * { + * "button" : "{{STRING}}" // play, pause, next, previous, skip-forward, skip-backward + * } + * @param [in] button Button pressed by the user. + * + */ +static string PLAYBACKCONTROLLER_BUTTONPRESSED = "button_pressed"; + +static list<string> PLAYBACKCONTROLLER_DOWNSTREAM_ACTIONS = { + PLAYBACKCONTROLLER_BUTTONPRESSED +}; + +} // namespace playbackcontroller +} // namespace capabilities +} // namespace vshl + +#endif // VSHL_CAPABILITIES_PLAYBACKCONTROLLER_MESSAGES_H_ diff --git a/src/plugins/capabilities/playbackcontroller/src/PlaybackControllerCapability.cpp b/src/plugins/capabilities/playbackcontroller/src/PlaybackControllerCapability.cpp new file mode 100644 index 0000000..a5abbed --- /dev/null +++ b/src/plugins/capabilities/playbackcontroller/src/PlaybackControllerCapability.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "capabilities/playbackcontroller/include/PlaybackControllerCapability.h" +#include "capabilities/playbackcontroller/include/PlaybackControllerMessages.h" + +const string TAG = "vshlcapabilities::capabilities::playbackcontroller"; + +using Level = vshlcapabilities::common::interfaces::ILogger::Level; + +namespace vshlcapabilities { +namespace capabilities { +namespace playbackcontroller { + +// Create a playbackcontroller. +shared_ptr<PlaybackController> PlaybackController::create( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + auto playbackcontroller = std::shared_ptr<PlaybackController>(new PlaybackController(logger)); + return playbackcontroller; +} + +PlaybackController::PlaybackController( + shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + mLogger = logger; +} + +string PlaybackController::getName() const { + return NAME; +} + +list<string> PlaybackController::getUpstreamMessages() const { + return PLAYBACKCONTROLLER_UPSTREAM_ACTIONS; +} + +list<string> PlaybackController::getDownstreamMessages() const { + return PLAYBACKCONTROLLER_DOWNSTREAM_ACTIONS; +} + +} // namespace playbackcontroller +} // namespace capabilities +} // namespace vshl diff --git a/src/plugins/capabilities/test/CapabilityMessagingServiceTest.cpp b/src/plugins/capabilities/test/CapabilityMessagingServiceTest.cpp new file mode 100644 index 0000000..5d3971d --- /dev/null +++ b/src/plugins/capabilities/test/CapabilityMessagingServiceTest.cpp @@ -0,0 +1,96 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include <gtest/gtest.h> + +#include "capabilities/CapabilityMessagingService.h" + +#include "test/common/ConsoleLogger.h" +#include "test/mocks/AFBApiMock.h" +#include "test/mocks/AFBEventMock.h" +#include "test/mocks/AFBRequestMock.h" +#include "test/mocks/CapabilityMock.h" + +using namespace vshlcapabilities::common::interfaces; +using namespace vshlcapabilities::capabilities; +using namespace vshlcapabilities::test::common; + +namespace vshlcapabilities { +namespace test { + +class CapabilityMessagingServiceTest : public ::testing::Test { +protected: + void SetUp() override { + mConsoleLogger = std::make_shared<ConsoleLogger>(); + mAfbApi = std::make_shared<::testing::NiceMock<AFBApiMock>>(); + } + + std::shared_ptr<::testing::NiceMock<AFBApiMock>> mAfbApi; + std::shared_ptr<ConsoleLogger> mConsoleLogger; +}; + +TEST_F(CapabilityMessagingServiceTest, failsInitializationOnInvalidParams) { + auto service = CapabilityMessagingService::create(mConsoleLogger, nullptr); + ASSERT_EQ(service, nullptr); + + service = CapabilityMessagingService::create(nullptr, mAfbApi); + ASSERT_EQ(service, nullptr); +} + +TEST_F(CapabilityMessagingServiceTest, initializesSuccessfully) { + auto service = CapabilityMessagingService::create(mConsoleLogger, mAfbApi); + ASSERT_NE(service, nullptr); +} + +TEST_F(CapabilityMessagingServiceTest, canSubscribeAndPublishCapabilityEvents) { + auto service = CapabilityMessagingService::create(mConsoleLogger, mAfbApi); + + auto capability = std::make_shared<::testing::NiceMock<CapabilityMock>>(); + std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"}); + std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"}); + std::string capabilityName = "weather"; + + ON_CALL(*capability, getName()).WillByDefault(::testing::Return(capabilityName)); + ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents)); + ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents)); + + // We don't care if and how many times subscribe method is called on event. + std::shared_ptr<AFBEventMock> mockEvent(new ::testing::NiceMock<AFBEventMock>()); + ON_CALL(*mockEvent, subscribe(::testing::_)).WillByDefault(::testing::Return(true)); + ON_CALL(*mockEvent, publishEvent(::testing::_)).WillByDefault(::testing::Return(true)); + auto eventCreator = [mockEvent](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> { + mockEvent->setName(eventName); + return mockEvent; + }; + + ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(eventCreator)); + + auto request = std::make_shared<::testing::StrictMock<AFBRequestMock>>(); + std::string payload = "The answer to life the universe and everything = 42"; + + bool result = service->publish(capability, *upstreamEvents.begin(), payload); + ASSERT_FALSE(result); // Without subscribing to the event. Publish should fail. + + result = service->subscribe(*request, capability, *upstreamEvents.begin()); + ASSERT_TRUE(result); + + result = service->subscribe(*request, capability, *downstreamEvents.begin()); + ASSERT_TRUE(result); + + result = service->publish(capability, *downstreamEvents.begin(), payload); + ASSERT_TRUE(result); +} + +} // namespace test +} // namespace vshl
\ No newline at end of file diff --git a/src/plugins/capabilities/test/PublisherForwarderTest.cpp b/src/plugins/capabilities/test/PublisherForwarderTest.cpp new file mode 100644 index 0000000..8fb499c --- /dev/null +++ b/src/plugins/capabilities/test/PublisherForwarderTest.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include <gtest/gtest.h> + +#include "capabilities/core/include/PublisherForwarder.h" +#include "capabilities/core/include/SubscriberForwarder.h" + +#include "test/common/ConsoleLogger.h" +#include "test/mocks/AFBApiMock.h" +#include "test/mocks/AFBEventMock.h" +#include "test/mocks/CapabilityMock.h" + +using namespace vshlcapabilities::common::interfaces; +using namespace vshlcapabilities::capabilities::core; +using namespace vshlcapabilities::test::common; + +namespace vshlcapabilities { +namespace test { + +class PublisherForwarderTest : public ::testing::Test { +protected: + void SetUp() override { + mConsoleLogger = std::make_shared<ConsoleLogger>(); + mAfbApi = std::make_shared<::testing::StrictMock<AFBApiMock>>(); + + mEventCreatorFn = [](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> { + std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>()); + mockEvent->setName(eventName); + return mockEvent; + }; + } + + std::shared_ptr<SubscriberForwarder> createSubscriberForwarder( + std::shared_ptr<::testing::StrictMock<CapabilityMock>> capability) { + EXPECT_CALL(*capability, getUpstreamMessages()).Times(1); + EXPECT_CALL(*capability, getDownstreamMessages()).Times(1); + + return SubscriberForwarder::create(mConsoleLogger, mAfbApi, capability); + } + + std::shared_ptr<PublisherForwarder> createPublisherForwarder( + std::shared_ptr<::testing::StrictMock<CapabilityMock>> capability) { + return PublisherForwarder::create(mConsoleLogger, capability); + } + + std::shared_ptr<::testing::StrictMock<AFBApiMock>> mAfbApi; + std::shared_ptr<ConsoleLogger> mConsoleLogger; + std::function<std::shared_ptr<IAFBApi::IAFBEvent>(const std::string&)> mEventCreatorFn; + std::shared_ptr<::testing::StrictMock<AFBEventMock>> mAfbEventMock; +}; + +TEST_F(PublisherForwarderTest, failsInitializationOnInvalidParams) { + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + + auto forwarder = PublisherForwarder::create(mConsoleLogger, nullptr); + ASSERT_EQ(forwarder, nullptr); + + forwarder = PublisherForwarder::create(nullptr, capability); + ASSERT_EQ(forwarder, nullptr); +} + +TEST_F(PublisherForwarderTest, initializesCorrectly) { + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + auto forwarder = createPublisherForwarder(capability); + + ASSERT_NE(forwarder, nullptr); +} + +TEST_F(PublisherForwarderTest, canForwardMessages) { + std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>()); + ON_CALL(*mockEvent, publishEvent(::testing::_)).WillByDefault(::testing::Return(true)); + EXPECT_CALL(*mockEvent, publishEvent(::testing::_)).Times(4); + auto eventCreator = [mockEvent](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> { + return mockEvent; + }; + + ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(eventCreator)); + EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4); + + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"}); + std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"}); + ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents)); + ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents)); + + auto publisherForwarder = createPublisherForwarder(capability); + ASSERT_NE(publisherForwarder, nullptr); + + auto subscriberForwarder = createSubscriberForwarder(capability); + ASSERT_NE(subscriberForwarder, nullptr); + + std::string payload = "The answer to life the universe and everything = 42"; + publisherForwarder->setSubscriberForwarder(subscriberForwarder); + + auto itCapability = downstreamEvents.begin(); + ASSERT_TRUE(publisherForwarder->forwardMessage(*itCapability++, payload)); + ASSERT_TRUE(publisherForwarder->forwardMessage(*itCapability++, payload)); + itCapability = upstreamEvents.begin(); + ASSERT_TRUE(publisherForwarder->forwardMessage(*itCapability++, payload)); + ASSERT_TRUE(publisherForwarder->forwardMessage(*itCapability++, payload)); +} + +} // namespace test +} // namespace vshl
\ No newline at end of file diff --git a/src/plugins/capabilities/test/SubscriberForwarderTest.cpp b/src/plugins/capabilities/test/SubscriberForwarderTest.cpp new file mode 100644 index 0000000..c3d72de --- /dev/null +++ b/src/plugins/capabilities/test/SubscriberForwarderTest.cpp @@ -0,0 +1,262 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include <gtest/gtest.h> + +#include "capabilities/core/include/SubscriberForwarder.h" + +#include "test/common/ConsoleLogger.h" +#include "test/mocks/AFBApiMock.h" +#include "test/mocks/AFBEventMock.h" +#include "test/mocks/AFBRequestMock.h" +#include "test/mocks/CapabilityMock.h" + +using namespace vshlcapabilities::common::interfaces; +using namespace vshlcapabilities::capabilities::core; +using namespace vshlcapabilities::test::common; + +namespace vshlcapabilities { +namespace test { + +class SubscriberForwarderTest : public ::testing::Test { +protected: + void SetUp() override { + mConsoleLogger = std::make_shared<ConsoleLogger>(); + mAfbApi = std::make_shared<::testing::StrictMock<AFBApiMock>>(); + + mEventCreatorFn = [](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> { + std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>()); + mockEvent->setName(eventName); + return mockEvent; + }; + } + + std::shared_ptr<SubscriberForwarder> createSubscriberForwarder( + std::shared_ptr<::testing::StrictMock<CapabilityMock>> capability) { + EXPECT_CALL(*capability, getUpstreamMessages()).Times(1); + EXPECT_CALL(*capability, getDownstreamMessages()).Times(1); + + return SubscriberForwarder::create(mConsoleLogger, mAfbApi, capability); + } + + std::shared_ptr<::testing::StrictMock<AFBApiMock>> mAfbApi; + std::shared_ptr<ConsoleLogger> mConsoleLogger; + std::function<std::shared_ptr<IAFBApi::IAFBEvent>(const std::string&)> mEventCreatorFn; + std::shared_ptr<::testing::StrictMock<AFBEventMock>> mAfbEventMock; +}; + +TEST_F(SubscriberForwarderTest, failsInitializationOnInvalidParams) { + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + + auto forwarder = SubscriberForwarder::create(mConsoleLogger, mAfbApi, nullptr); + ASSERT_EQ(forwarder, nullptr); + + forwarder = SubscriberForwarder::create(mConsoleLogger, nullptr, capability); + ASSERT_EQ(forwarder, nullptr); + + forwarder = SubscriberForwarder::create(nullptr, mAfbApi, capability); + ASSERT_EQ(forwarder, nullptr); +} + +TEST_F(SubscriberForwarderTest, initializesCorrectly) { + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + auto forwarder = createSubscriberForwarder(capability); + + ASSERT_NE(forwarder, nullptr); +} + +TEST_F(SubscriberForwarderTest, createsEventsOnInitialization) { + ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(mEventCreatorFn)); + + std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"}); + std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"}); + + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents)); + ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents)); + + auto itCapability = upstreamEvents.begin(); + EXPECT_CALL(*mAfbApi, createEvent(*itCapability)).Times(1); + itCapability++; + EXPECT_CALL(*mAfbApi, createEvent(*itCapability)).Times(1); + + itCapability = downstreamEvents.begin(); + EXPECT_CALL(*mAfbApi, createEvent(*itCapability)).Times(1); + itCapability++; + EXPECT_CALL(*mAfbApi, createEvent(*itCapability)).Times(1); + + auto forwarder = createSubscriberForwarder(capability); + ASSERT_NE(forwarder, nullptr); +} + +TEST_F(SubscriberForwarderTest, canNotSubscribeToNonExistentEvents) { + ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(mEventCreatorFn)); + EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4); + + std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"}); + std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"}); + + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents)); + ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents)); + + auto forwarder = createSubscriberForwarder(capability); + ASSERT_NE(forwarder, nullptr); + + auto nonExistentEvents = std::list<std::string>({"non", "existent", "events"}); + auto itCapability = nonExistentEvents.begin(); + auto request = std::make_shared<::testing::StrictMock<AFBRequestMock>>(); + ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++)); + ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++)); + ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++)); +} + +TEST_F(SubscriberForwarderTest, canNotSubscribeOnEventCreationFailure) { + // Fail the event creation and return null event. + ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Return(nullptr)); + EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4); + + std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"}); + std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"}); + + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents)); + ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents)); + + auto forwarder = createSubscriberForwarder(capability); + ASSERT_NE(forwarder, nullptr); + + auto itCapability = downstreamEvents.begin(); + auto request = std::make_shared<::testing::StrictMock<AFBRequestMock>>(); + std::string payload = "The answer to life the universe and everything = 42"; + ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++)); + ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++)); + itCapability = upstreamEvents.begin(); + ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++)); + ASSERT_FALSE(forwarder->subscribe(*request, *itCapability++)); +} + +TEST_F(SubscriberForwarderTest, canSubscribeToEvents) { + std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>()); + ON_CALL(*mockEvent, subscribe(::testing::_)).WillByDefault(::testing::Return(true)); + EXPECT_CALL(*mockEvent, subscribe(::testing::_)).Times(4); + auto eventCreator = [mockEvent](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> { + return mockEvent; + }; + + ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(eventCreator)); + EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4); + + std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"}); + std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"}); + + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents)); + ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents)); + + auto forwarder = createSubscriberForwarder(capability); + ASSERT_NE(forwarder, nullptr); + + auto itCapability = downstreamEvents.begin(); + auto request = std::make_shared<::testing::StrictMock<AFBRequestMock>>(); + ASSERT_TRUE(forwarder->subscribe(*request, *itCapability++)); + ASSERT_TRUE(forwarder->subscribe(*request, *itCapability)); + itCapability = upstreamEvents.begin(); + ASSERT_TRUE(forwarder->subscribe(*request, *itCapability++)); + ASSERT_TRUE(forwarder->subscribe(*request, *itCapability)); +} + +TEST_F(SubscriberForwarderTest, canNotPublishNonExistentEvents) { + std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>()); + EXPECT_CALL(*mockEvent, publishEvent(::testing::_)).Times(0); + auto eventCreator = [mockEvent](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> { + return mockEvent; + }; + + ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(eventCreator)); + EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4); + + std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"}); + std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"}); + + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents)); + ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents)); + + auto forwarder = createSubscriberForwarder(capability); + ASSERT_NE(forwarder, nullptr); + + auto nonExistentEvents = std::list<std::string>({"non", "existent", "events"}); + auto itCapability = nonExistentEvents.begin(); + ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, "My-Payload")); + ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, "My-Payload")); + ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, "My-Payload")); +} + +TEST_F(SubscriberForwarderTest, canNotPublishOnEventCreationFailure) { + // Fail the event creation and return null event. + ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Return(nullptr)); + EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4); + + std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"}); + std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"}); + + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents)); + ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents)); + + auto forwarder = createSubscriberForwarder(capability); + ASSERT_NE(forwarder, nullptr); + + auto itCapability = downstreamEvents.begin(); + std::string payload = "The answer to life the universe and everything = 42"; + ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, payload)); + ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, payload)); + itCapability = upstreamEvents.begin(); + ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, payload)); + ASSERT_FALSE(forwarder->forwardMessage(*itCapability++, payload)); +} + +TEST_F(SubscriberForwarderTest, canPublishEvents) { + std::shared_ptr<AFBEventMock> mockEvent(new ::testing::StrictMock<AFBEventMock>()); + ON_CALL(*mockEvent, publishEvent(::testing::_)).WillByDefault(::testing::Return(true)); + EXPECT_CALL(*mockEvent, publishEvent(::testing::_)).Times(4); + auto eventCreator = [mockEvent](const std::string& eventName) -> std::shared_ptr<IAFBApi::IAFBEvent> { + return mockEvent; + }; + + ON_CALL(*mAfbApi, createEvent(::testing::_)).WillByDefault(::testing::Invoke(eventCreator)); + EXPECT_CALL(*mAfbApi, createEvent(::testing::_)).Times(4); + + std::list<std::string> upstreamEvents({"up-ev1", "up-ev2"}); + std::list<std::string> downstreamEvents({"down-ev1", "down-ev2"}); + + auto capability = std::make_shared<::testing::StrictMock<CapabilityMock>>(); + ON_CALL(*capability, getUpstreamMessages()).WillByDefault(::testing::Return(upstreamEvents)); + ON_CALL(*capability, getDownstreamMessages()).WillByDefault(::testing::Return(downstreamEvents)); + + auto forwarder = createSubscriberForwarder(capability); + ASSERT_NE(forwarder, nullptr); + + auto itCapability = downstreamEvents.begin(); + std::string payload = "The answer to life the universe and everything = 42"; + ASSERT_TRUE(forwarder->forwardMessage(*itCapability++, payload)); + ASSERT_TRUE(forwarder->forwardMessage(*itCapability++, payload)); + itCapability = upstreamEvents.begin(); + ASSERT_TRUE(forwarder->forwardMessage(*itCapability++, payload)); + ASSERT_TRUE(forwarder->forwardMessage(*itCapability++, payload)); +} + +} // namespace test +} // namespace vshl
\ No newline at end of file diff --git a/src/plugins/cmake/gtest.cmake b/src/plugins/cmake/gtest.cmake new file mode 100644 index 0000000..def6559 --- /dev/null +++ b/src/plugins/cmake/gtest.cmake @@ -0,0 +1,44 @@ +# gtest + +find_package(Threads REQUIRED) + +# Enable ExternalProject CMake module +INCLUDE(ExternalProject) + +ExternalProject_Add( + gtest + URL https://github.com/google/googletest/archive/release-1.8.1.zip + SOURCE_DIR "${CMAKE_BINARY_DIR}/gtest-src" + BINARY_DIR "${CMAKE_BINARY_DIR}/gtest-build" + INSTALL_COMMAND "" + LOG_DOWNLOAD ON + LOG_CONFIGURE ON + LOG_BUILD ON +) + +# Get GTest source and binary directories from CMake project +ExternalProject_Get_Property(gtest source_dir binary_dir) + +# Create a libgtest target to be used as a dependency by test programs +ADD_LIBRARY(libgtest INTERFACE) +TARGET_INCLUDE_DIRECTORIES(libgtest + INTERFACE + ${source_dir}/googletest/include +) +TARGET_LINK_LIBRARIES(libgtest + INTERFACE + ${binary_dir}/googlemock/gtest/libgtest.a + ${CMAKE_THREAD_LIBS_INIT} +) + +# Create a libgmock target to be used as a dependency by test programs +ADD_LIBRARY(libgmock INTERFACE) +TARGET_INCLUDE_DIRECTORIES(libgmock + INTERFACE + ${source_dir}/googlemock/include +) +TARGET_LINK_LIBRARIES(libgmock + INTERFACE + ${binary_dir}/googlemock/libgmock.a + ${CMAKE_THREAD_LIBS_INIT} +)
\ No newline at end of file diff --git a/src/plugins/interfaces/afb/IAFBApi.h b/src/plugins/interfaces/afb/IAFBApi.h new file mode 100644 index 0000000..b607fd8 --- /dev/null +++ b/src/plugins/interfaces/afb/IAFBApi.h @@ -0,0 +1,98 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_COMMON_INTERFACES_AFBAPI_H_ +#define VSHL_COMMON_INTERFACES_AFBAPI_H_ + +#include <memory> +#include <string> + +#include <json-c/json_object.h> + +using namespace std; + +namespace vshlcapabilities { +namespace common { +namespace interfaces { + +/** + * Interface to represent AFB Request. + */ +class IAFBRequest { +public: + /** + * Gets the native request object. + */ + virtual void* getNativeRequest() = 0; +}; + +/** + * Interface to encapsulate all AFB (AGL Application Framework Binding) + * functions. + */ +class IAFBApi { +public: + /** + * Interface to represent AFB Event + */ + class IAFBEvent { + public: + /** + * Gets human readable name of the event. + */ + virtual std::string getName() const = 0; + + /** + * Returns true if event is valid. False otherwise. + */ + virtual bool isValid() = 0; + + /** + * Publish event to all observers. + * + * @return The number of observers that received the event. + */ + virtual int publishEvent(struct json_object* payload) = 0; + + /** + * Subscribe to the event + * + * @c request Party interested in the event. + */ + virtual bool subscribe(IAFBRequest& request) = 0; + + /** + * Unsubscribe to the event + * + * @c request Party no longer interested in the event. + */ + virtual bool unsubscribe(IAFBRequest& request) = 0; + }; + + virtual std::shared_ptr<IAFBEvent> createEvent(const std::string& eventName) = 0; + + virtual int callSync( + const std::string& api, + const std::string& verb, + struct json_object* request, + struct json_object** result, + std::string& error, + std::string& info) = 0; +}; + +} // namespace interfaces +} // namespace common +} // namespace vshl + +#endif // VSHL_COMMON_INTERFACES_AFBAPI_H_ diff --git a/src/plugins/interfaces/capabilities/ICapability.h b/src/plugins/interfaces/capabilities/ICapability.h new file mode 100644 index 0000000..ebdd4e8 --- /dev/null +++ b/src/plugins/interfaces/capabilities/ICapability.h @@ -0,0 +1,58 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ + +#ifndef VSHL_COMMON_INTERFACES_ICAPABILITY_H_ +#define VSHL_COMMON_INTERFACES_ICAPABILITY_H_ + +#include <list> +#include <string> + +using namespace std; + +namespace vshlcapabilities { +namespace common { +namespace interfaces { + +/* + * This interface defines the structure for a specific voiceagent capability. + */ +class ICapability { +public: + /* + * Returns the capability's name. + */ + virtual string getName() const = 0; + + /* + * Returns the list of upstream messages. + */ + virtual list<string> getUpstreamMessages() const = 0; + + /* + * Returns the list of downstream messages + */ + virtual list<string> getDownstreamMessages() const = 0; + + /** + * Virtual destructor to assure proper cleanup of derived types. + */ + virtual ~ICapability() = default; +}; + +} // namespace interfaces +} // namespace common +} // namespace vshl + +#endif // VSHL_COMMON_INTERFACES_ICAPABILITY_H_ diff --git a/src/plugins/interfaces/utilities/events/IEventFilter.h b/src/plugins/interfaces/utilities/events/IEventFilter.h new file mode 100644 index 0000000..a4e3c64 --- /dev/null +++ b/src/plugins/interfaces/utilities/events/IEventFilter.h @@ -0,0 +1,46 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_COMMON_INTERFACES_IEVENTFILTER_H_ +#define VSHL_COMMON_INTERFACES_IEVENTFILTER_H_ + +#include <string> + +using namespace std; + +namespace vshlcapabilities { +namespace common { +namespace interfaces { +/* + * This is an abstract class that is responsible for filtering the events + * that are delivered to the high level voice service from apps or voiceagents. + */ +class IEventFilter { +public: + // Name of the event filter. + virtual string getName() = 0; + + // Every event filter needs to implement this method and + // return true if consuming the event or false otherwise. + virtual bool onIncomingEvent(const string eventName, const string voiceAgentId, const string payload) = 0; + + // Destructor + virtual ~IEventFilter() = default; +}; + +} // namespace interfaces +} // namespace common +} // namespace vshl + +#endif // VSHL_COMMON_INTERFACES_IEVENTFILTER_H_ diff --git a/src/plugins/interfaces/utilities/logging/ILogger.h b/src/plugins/interfaces/utilities/logging/ILogger.h new file mode 100644 index 0000000..4cf25aa --- /dev/null +++ b/src/plugins/interfaces/utilities/logging/ILogger.h @@ -0,0 +1,42 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_COMMON_INTERFACES_LOGGER_H_ +#define VSHL_COMMON_INTERFACES_LOGGER_H_ + +#include <string> + +namespace vshlcapabilities { +namespace common { +namespace interfaces { + +class ILogger { +public: + enum Level { + DEBUG, + INFO, + WARNING, + ERROR, + NOTICE, + }; + + virtual void log(Level level, const std::string &tag, + const std::string &message) = 0; +}; + +} // namespace interfaces +} // namespace common +} // namespace vshl + +#endif // VSHL_COMMON_INTERFACES_LOGGER_H_ diff --git a/src/plugins/test/common/ConsoleLogger.cpp b/src/plugins/test/common/ConsoleLogger.cpp new file mode 100644 index 0000000..a2a2598 --- /dev/null +++ b/src/plugins/test/common/ConsoleLogger.cpp @@ -0,0 +1,31 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ + +#include <iostream> + +#include "test/common/ConsoleLogger.h" + +namespace vshlcapabilities { +namespace test { +namespace common { + +void ConsoleLogger::log(Level level, const std::string& tag, const std::string& message) { + string format_msg = "Tag: " + tag + ", message: " + message; + std::cout << format_msg << std::endl; +} + +} // namespace common +} // namespace test +} // namespace vshl diff --git a/src/plugins/test/common/ConsoleLogger.h b/src/plugins/test/common/ConsoleLogger.h new file mode 100644 index 0000000..2f81086 --- /dev/null +++ b/src/plugins/test/common/ConsoleLogger.h @@ -0,0 +1,37 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_TEST_COMMON_CONSOLE_LOGGER_H_ +#define VSHL_TEST_COMMON_CONSOLE_LOGGER_H_ + +#include "interfaces/utilities/logging/ILogger.h" + +using namespace std; + +namespace vshlcapabilities { +namespace test { +namespace common { + +class ConsoleLogger : public vshlcapabilities::common::interfaces::ILogger { +public: + // ILogger interface + void log(Level level, const std::string &tag, + const std::string &message) override; +}; + +} // namespace common +} // namespace test +} // namespace vshl + +#endif // VSHL_TEST_COMMON_CONSOLE_LOGGER_H_ diff --git a/src/plugins/test/mocks/AFBApiMock.h b/src/plugins/test/mocks/AFBApiMock.h new file mode 100644 index 0000000..8cefa39 --- /dev/null +++ b/src/plugins/test/mocks/AFBApiMock.h @@ -0,0 +1,41 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_TEST_MOCKS_AFBAPIMOCK_H_ +#define VSHL_TEST_MOCKS_AFBAPIMOCK_H_ + +#include <gmock/gmock.h> + +#include "interfaces/afb/IAFBApi.h" + +namespace vshlcapabilities { +namespace test { + +class AFBApiMock : public vshlcapabilities::common::interfaces::IAFBApi { +public: + MOCK_METHOD1(createEvent, std::shared_ptr<IAFBEvent>(const std::string& eventName)); + MOCK_METHOD6( + callSync, + int(const std::string& api, + const std::string& verb, + struct json_object* request, + struct json_object** result, + std::string& error, + std::string& info)); +}; + +} // namespace test +} // namespace vshl + +#endif // VSHL_TEST_MOCKS_AFBAPIMOCK_H_
\ No newline at end of file diff --git a/src/plugins/test/mocks/AFBEventMock.h b/src/plugins/test/mocks/AFBEventMock.h new file mode 100644 index 0000000..f4e2b67 --- /dev/null +++ b/src/plugins/test/mocks/AFBEventMock.h @@ -0,0 +1,47 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_TEST_MOCKS_AFBEVENTMOCK_H_ +#define VSHL_TEST_MOCKS_AFBEVENTMOCK_H_ + +#include <gmock/gmock.h> + +#include "interfaces/afb/IAFBApi.h" + +namespace vshlcapabilities { +namespace test { + +class AFBEventMock : public vshlcapabilities::common::interfaces::IAFBApi::IAFBEvent { +public: + void setName(const std::string& name) { + mName = name; + } + + std::string getName() const override { + return mName; + } + + MOCK_METHOD0(isValid, bool()); + MOCK_METHOD1(publishEvent, int(struct json_object* payload)); + MOCK_METHOD1(subscribe, bool(vshlcapabilities::common::interfaces::IAFBRequest& request)); + MOCK_METHOD1(unsubscribe, bool(vshlcapabilities::common::interfaces::IAFBRequest& request)); + +private: + std::string mName; +}; + +} // namespace test +} // namespace vshl + +#endif // VSHL_TEST_MOCKS_AFBEVENTMOCK_H_
\ No newline at end of file diff --git a/src/plugins/test/mocks/AFBRequestMock.h b/src/plugins/test/mocks/AFBRequestMock.h new file mode 100644 index 0000000..0aaeede --- /dev/null +++ b/src/plugins/test/mocks/AFBRequestMock.h @@ -0,0 +1,33 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_TEST_MOCKS_AFBREQUESTMOCK_H_ +#define VSHL_TEST_MOCKS_AFBREQUESTMOCK_H_ + +#include <gmock/gmock.h> + +#include "interfaces/afb/IAFBApi.h" + +namespace vshlcapabilities { +namespace test { + +class AFBRequestMock : public vshlcapabilities::common::interfaces::IAFBRequest { +public: + MOCK_METHOD0(getNativeRequest, void*()); +}; + +} // namespace test +} // namespace vshl + +#endif // VSHL_TEST_MOCKS_AFBREQUESTMOCK_H_
\ No newline at end of file diff --git a/src/plugins/test/mocks/CapabilityMock.h b/src/plugins/test/mocks/CapabilityMock.h new file mode 100644 index 0000000..aaa0bd5 --- /dev/null +++ b/src/plugins/test/mocks/CapabilityMock.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_TEST_MOCKS_CAPABILITYMOCK_H_ +#define VSHL_TEST_MOCKS_CAPABILITYMOCK_H_ + +#include <gmock/gmock.h> + +#include "interfaces/capabilities/ICapability.h" + +namespace vshlcapabilities { +namespace test { + +class CapabilityMock : public vshlcapabilities::common::interfaces::ICapability { +public: + MOCK_CONST_METHOD0(getName, std::string()); + MOCK_CONST_METHOD0(getUpstreamMessages, std::list<std::string>()); + MOCK_CONST_METHOD0(getDownstreamMessages, std::list<std::string>()); +}; + +} // namespace test +} // namespace vshl + +#endif // VSHL_TEST_MOCKS_CAPABILITYMOCK_H_
\ No newline at end of file diff --git a/src/plugins/utilities/events/EventRouter.cpp b/src/plugins/utilities/events/EventRouter.cpp new file mode 100644 index 0000000..e715ca8 --- /dev/null +++ b/src/plugins/utilities/events/EventRouter.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "utilities/events/EventRouter.h" + +static string TAG = "vshlcapabilities::utilities::events::EventRouter"; + +using Level = vshlcapabilities::common::interfaces::ILogger::Level; + +namespace vshlcapabilities { +namespace utilities { +namespace events { + +unique_ptr<EventRouter> EventRouter::create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) { + return std::unique_ptr<EventRouter>(new EventRouter(logger)); +} + +EventRouter::EventRouter(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger) : mLogger(logger) { +} + +EventRouter::~EventRouter() { + mEventFilters.clear(); +} + +bool EventRouter::handleIncomingEvent(const string eventName, const string voiceAgentId, const string payload) { + for (auto eventFilter : mEventFilters) { + if (eventFilter->onIncomingEvent(eventName, voiceAgentId, payload)) { + return true; + } + } + + return false; +} + +bool EventRouter::addEventFilter(shared_ptr<vshlcapabilities::common::interfaces::IEventFilter> filter) { + if (!filter) { + mLogger->log(Level::ERROR, TAG, "Failed to add event filter. Invalid arguments."); + return false; + } + + mEventFilters.insert(filter); + return true; +} + +bool EventRouter::removeEventFilter(shared_ptr<vshlcapabilities::common::interfaces::IEventFilter> filter) { + if (!filter) { + mLogger->log(Level::ERROR, TAG, "Failed to add remove filter. Invalid arguments."); + return false; + } + + mEventFilters.erase(filter); + return true; +} + +} // namespace events +} // namespace utilities +} // namespace vshl diff --git a/src/plugins/utilities/events/EventRouter.h b/src/plugins/utilities/events/EventRouter.h new file mode 100644 index 0000000..1286128 --- /dev/null +++ b/src/plugins/utilities/events/EventRouter.h @@ -0,0 +1,66 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_UTILITIES_EVENTS_EVENTMANAGER_H_ +#define VSHL_UTILITIES_EVENTS_EVENTMANAGER_H_ + +#include <memory> +#include <string> +#include <unordered_set> + +#include "interfaces/utilities/events/IEventFilter.h" +#include "interfaces/utilities/logging/ILogger.h" + +using namespace std; + +namespace vshlcapabilities { +namespace utilities { +namespace events { +/* + * This class is responsible for routing incoming events to + * the appropriate event listener for consumption. + * Note: The listeners should implement the IEventFilter class. + */ +class EventRouter { +public: + static unique_ptr<EventRouter> create(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + // Destructor + ~EventRouter(); + + // Add event filter as listerner. + bool addEventFilter(shared_ptr<vshlcapabilities::common::interfaces::IEventFilter> filter); + + // Remove event filter as listerner. + bool removeEventFilter(shared_ptr<vshlcapabilities::common::interfaces::IEventFilter> filter); + + // This method is called by the controller for routing + // the event to appropriate listener. + bool handleIncomingEvent(const string eventName, const string voiceAgentId, const string payload); + +private: + EventRouter(shared_ptr<vshlcapabilities::common::interfaces::ILogger> logger); + + // set of event filters. + unordered_set<shared_ptr<vshlcapabilities::common::interfaces::IEventFilter>> mEventFilters; + + // Logger + shared_ptr<vshlcapabilities::common::interfaces::ILogger> mLogger; +}; + +} // namespace events +} // namespace utilities +} // namespace vshl + +#endif // VSHL_UTILITIES_EVENTS_EVENTROUTER_H_ diff --git a/src/plugins/utilities/logging/Logger.cpp b/src/plugins/utilities/logging/Logger.cpp new file mode 100644 index 0000000..c121556 --- /dev/null +++ b/src/plugins/utilities/logging/Logger.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#include "utilities/logging/Logger.h" + +namespace vshlcapabilities { +namespace utilities { +namespace logging { + +// Constructor +Logger::Logger(AFB_ApiT api) { + mApi = api; +} + +unique_ptr<Logger> Logger::create(AFB_ApiT api) { + auto logger = std::unique_ptr<Logger>(new Logger(api)); + return logger; +} + +void Logger::log(Level level, const std::string& tag, const std::string& message) { + string format_msg = "Tag: " + tag + ", message: " + message; + switch (level) { + case Level::NOTICE: + AFB_ApiNotice(mApi, format_msg.c_str()); + break; + case Level::WARNING: + AFB_ApiWarning(mApi, format_msg.c_str()); + break; + case Level::DEBUG: + AFB_ApiDebug(mApi, format_msg.c_str()); + break; + case Level::ERROR: + AFB_ApiError(mApi, format_msg.c_str()); + break; + case Level::INFO: + AFB_ApiInfo(mApi, format_msg.c_str()); + break; + default: + break; + } +} + +} // namespace logging +} // namespace utilities +} // namespace vshl diff --git a/src/plugins/utilities/logging/Logger.h b/src/plugins/utilities/logging/Logger.h new file mode 100644 index 0000000..56f810d --- /dev/null +++ b/src/plugins/utilities/logging/Logger.h @@ -0,0 +1,53 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef VSHL_UTILITIES_LOGGING_LOGGER_H_ +#define VSHL_UTILITIES_LOGGING_LOGGER_H_ + +#include <memory> + +extern "C" { +#define AFB_BINDING_VERSION 3 +#include "afb-definitions.h" +#include "ctl-plugin.h" +}; + +#include "interfaces/utilities/logging/ILogger.h" + +using namespace std; + +namespace vshlcapabilities { +namespace utilities { +namespace logging { + +class Logger : public vshlcapabilities::common::interfaces::ILogger { +public: + static std::unique_ptr<Logger> create(AFB_ApiT api); + + // ILogger interface + void log(Level level, const std::string &tag, + const std::string &message) override; + +private: + Logger(AFB_ApiT api); + + // Binding API reference + AFB_ApiT mApi; +}; + +} // namespace logging +} // namespace utilities +} // namespace vshl + +#endif // VSHL_UTILITIES_LOGGING_LOGGER_H_ diff --git a/src/vshl-capabilities-apidef.h b/src/vshl-capabilities-apidef.h new file mode 100644 index 0000000..6ce4cb3 --- /dev/null +++ b/src/vshl-capabilities-apidef.h @@ -0,0 +1,53 @@ + +static const char _afb_description_vshl_capabilities[] = + "{\"openapi\":\"3.0.0\",\"$schema\":\"http://iot.bzh/download/openapi/sch" + "ema-3.0/default-schema.json\",\"info\":{\"description\":\"\",\"title\":\"" + "High Level Voice Service Capabilities APIs\",\"version\":\"0.1\",\"x-bin" + "ding-c-generator\":{\"api\":\"vshl-capabilities\",\"version\":3,\"prefix" + "\":\"afv_\",\"postfix\":\"\",\"start\":null,\"onevent\":null,\"init\":\"" + "init\",\"scope\":\"\",\"private\":false,\"noconcurrency\":true}},\"serve" + "rs\":[{\"url\":\"ws://{host}:{port}/api/monitor\",\"description\":\"TS c" + "aching binding\",\"variables\":{\"host\":{\"default\":\"localhost\"},\"p" + "ort\":{\"default\":\"1234\"}},\"x-afb-events\":[{\"$ref\":\"#/components" + "/schemas/afb-event\"}]}],\"components\":{\"schemas\":{\"afb-reply\":{\"$" + "ref\":\"#/components/schemas/afb-reply-v3\"},\"afb-event\":{\"$ref\":\"#" + "/components/schemas/afb-event-v3\"},\"afb-reply-v3\":{\"title\":\"Generi" + "c response.\",\"type\":\"object\",\"required\":[\"jtype\",\"request\"],\"" + "properties\":{\"jtype\":{\"type\":\"string\",\"const\":\"afb-reply\"},\"" + "request\":{\"type\":\"object\",\"required\":[\"status\"],\"properties\":" + "{\"status\":{\"type\":\"string\"},\"info\":{\"type\":\"string\"},\"token" + "\":{\"type\":\"string\"},\"uuid\":{\"type\":\"string\"},\"reqid\":{\"typ" + "e\":\"string\"}}},\"response\":{\"type\":\"object\"}}},\"afb-event-v3\":" + "{\"type\":\"object\",\"required\":[\"jtype\",\"event\"],\"properties\":{" + "\"jtype\":{\"type\":\"string\",\"const\":\"afb-event\"},\"event\":{\"typ" + "e\":\"string\"},\"data\":{\"type\":\"object\"}}}},\"responses\":{\"200\"" + ":{\"description\":\"A complex object array response\",\"content\":{\"app" + "lication/json\":{\"schema\":{\"$ref\":\"#/components/schemas/afb-reply\"" + "}}}}}}}" +; + + +static const struct afb_verb_v3 _afb_verbs_vshl_capabilities[] = { + { + .verb = NULL, + .callback = NULL, + .auth = NULL, + .info = NULL, + .session = 0, + .vcbdata = NULL, + .glob = 0 + } +}; + +const struct afb_binding_v3 afbBindingV3 = { + .api = "vshl-capabilities", + .specification = _afb_description_vshl_capabilities, + .info = "", + .verbs = _afb_verbs_vshl_capabilities, + .preinit = NULL, + .init = init, + .onevent = NULL, + .userdata = NULL, + .noconcurrency = 1 +}; + diff --git a/src/vshl-capabilities-apidef.json b/src/vshl-capabilities-apidef.json new file mode 100644 index 0000000..158bf5a --- /dev/null +++ b/src/vshl-capabilities-apidef.json @@ -0,0 +1,109 @@ +{ + "openapi": "3.0.0", + "$schema": "http://iot.bzh/download/openapi/schema-3.0/default-schema.json", + "info": { + "description": "", + "title": "High Level Voice Service Capabilities APIs", + "version": "0.1", + "x-binding-c-generator": { + "api": "vshl-capabilities", + "version": 3, + "prefix": "afv_", + "postfix": "", + "start": null, + "onevent": null, + "init": "init", + "scope": "", + "private": false, + "noconcurrency": true + } + }, + "servers": [{ + "url": "ws://{host}:{port}/api/monitor", + "description": "TS caching binding", + "variables": { + "host": { + "default": "localhost" + }, + "port": { + "default": "1234" + } + }, + "x-afb-events": [{ + "$ref": "#/components/schemas/afb-event" + }] + }], + "components": { + "schemas": { + "afb-reply": { + "$ref": "#/components/schemas/afb-reply-v3" + }, + "afb-event": { + "$ref": "#/components/schemas/afb-event-v3" + }, + "afb-reply-v3": { + "title": "Generic response.", + "type": "object", + "required": ["jtype", "request"], + "properties": { + "jtype": { + "type": "string", + "const": "afb-reply" + }, + "request": { + "type": "object", + "required": ["status"], + "properties": { + "status": { + "type": "string" + }, + "info": { + "type": "string" + }, + "token": { + "type": "string" + }, + "uuid": { + "type": "string" + }, + "reqid": { + "type": "string" + } + } + }, + "response": { + "type": "object" + } + } + }, + "afb-event-v3": { + "type": "object", + "required": ["jtype", "event"], + "properties": { + "jtype": { + "type": "string", + "const": "afb-event" + }, + "event": { + "type": "string" + }, + "data": { + "type": "object" + } + } + } + }, + "responses": { + "200": { + "description": "A complex object array response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/afb-reply" + } + } + } + } + } + } +}
\ No newline at end of file diff --git a/src/vshl-capabilities-binding.c b/src/vshl-capabilities-binding.c new file mode 100644 index 0000000..b38210a --- /dev/null +++ b/src/vshl-capabilities-binding.c @@ -0,0 +1,126 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#define _GNU_SOURCE +#include "vshl-capabilities-binding.h" + +afb_dynapi* AFB_default; + +// Config Section definition (note: controls section index should match handle +// retrieval in HalConfigExec) +static CtlSectionT ctrlSections[] = {{.key = "plugins", .loadCB = PluginConfig}, + {.key = "controls", .loadCB = ControlConfig}, + {.key = NULL}}; + +static AFB_ApiVerbs ctrlApiVerbs[] = { + {.verb = NULL} /* marker for end of the array */ +}; + +static int ctrlLoadStaticVerbs(afb_dynapi* apiHandle, AFB_ApiVerbs* verbs) { + int errcount = 0; + + for (int idx = 0; verbs[idx].verb; idx++) { + errcount += afb_dynapi_add_verb( + apiHandle, + ctrlApiVerbs[idx].verb, + NULL, + ctrlApiVerbs[idx].callback, + (void*)&ctrlApiVerbs[idx], + ctrlApiVerbs[idx].auth, + 0); + } + + return errcount; +}; + +// next generation dynamic API-V3 mode +#include <signal.h> + +static int CtrlInitOneApi(AFB_ApiT apiHandle) +{ + CtlConfigT *ctrlConfig; + + if(!apiHandle) + return -1; + + // Retrieve section config from api handle + ctrlConfig = (CtlConfigT *) AFB_ApiGetUserData(apiHandle); + if(!ctrlConfig) + return -2; + + return CtlConfigExec(apiHandle, ctrlConfig); +} + +static int ctrlLoadOneApi(void* cbdata, AFB_ApiT apiHandle) { + CtlConfigT* ctrlConfig = (CtlConfigT*)cbdata; + + // save closure as api's data context + afb_dynapi_set_userdata(apiHandle, ctrlConfig); + + // add static controls verbs + int err = ctrlLoadStaticVerbs(apiHandle, ctrlApiVerbs); + if (err) { + AFB_ApiError(apiHandle, "ctrlLoadStaticVerbs fail to register static V2 verbs"); + return ERROR; + } + + // load section for corresponding API + err = CtlLoadSections(apiHandle, ctrlConfig, ctrlSections); + if (err) { + AFB_ApiError(apiHandle, "CtlLoadSections fail to load the sections"); + return ERROR; + } + + // declare an event event manager for this API; + afb_dynapi_on_event(apiHandle, CtrlDispatchApiEvent); + + // init API function (does not receive user closure ??? + afb_dynapi_on_init(apiHandle, CtrlInitOneApi); + + afb_dynapi_seal(apiHandle); + return err; +} + +int afbBindingEntry(afb_dynapi* apiHandle) { + AFB_default = apiHandle; + AFB_ApiNotice(apiHandle, "Controller in afbBindingEntry"); + + const char* dirList = getenv("CONTROL_CONFIG_PATH"); + if (!dirList) dirList = CONTROL_CONFIG_PATH; + + const char* configPath = CtlConfigSearch(apiHandle, dirList, ""); + if (!configPath) { + AFB_ApiError(apiHandle, "CtlPreInit: No %s* config found in %s ", GetBinderName(), dirList); + return ERROR; + } + + // load config file and create API + CtlConfigT* ctrlConfig = CtlLoadMetaData(apiHandle, configPath); + if (!ctrlConfig) { + AFB_ApiError(apiHandle, "CtrlBindingDyn No valid control config file in:\n-- %s", configPath); + return ERROR; + } + + if (!ctrlConfig->api) { + AFB_ApiError(apiHandle, "CtrlBindingDyn API Missing from metadata in:\n-- %s", configPath); + return ERROR; + } + + AFB_ApiNotice(apiHandle, "Controller API='%s' info='%s'", ctrlConfig->api, ctrlConfig->info); + + // create one API per config file (Pre-V3 return code ToBeChanged) + int status = afb_dynapi_new_api(apiHandle, ctrlConfig->api, ctrlConfig->info, 1, ctrlLoadOneApi, ctrlConfig); + + return status; +} diff --git a/src/vshl-capabilities-binding.h b/src/vshl-capabilities-binding.h new file mode 100644 index 0000000..75e7c91 --- /dev/null +++ b/src/vshl-capabilities-binding.h @@ -0,0 +1,25 @@ +/* + * Copyright 2018-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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. + */ +#ifndef _CTL_BINDING_INCLUDE_ +#define _CTL_BINDING_INCLUDE_ + +#define AFB_BINDING_VERSION 3 +#include <ctl-config.h> + +#ifndef ERROR +#define ERROR -1 +#endif + +#endif /* _CTL_BINDING_INCLUDE_ */
\ No newline at end of file |