diff --git a/AutoAnswer/.gitignore b/AutoAnswer/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0924e880c95cac5f0781754b2690ed5aab015034 --- /dev/null +++ b/AutoAnswer/.gitignore @@ -0,0 +1,2 @@ +/AutoAnswer +AutoAnswer* diff --git a/AutoAnswer/BotChatHandler.cpp b/AutoAnswer/BotChatHandler.cpp index 6a031792a737d70bdf1fe64c116a4ac3d42aa345..c877e376900ac01e5a69480b750b21187dc7a87c 100644 --- a/AutoAnswer/BotChatHandler.cpp +++ b/AutoAnswer/BotChatHandler.cpp @@ -72,7 +72,8 @@ BotChatHandler::detach(chatSubjectPtr subject) BotChatHandler::~BotChatHandler() { - for (const auto& subject : subjects) { + const auto copy = subjects; + for (const auto& subject : copy) { detach(subject); } } diff --git a/AutoAnswer/BotPeerChatSubscriber.cpp b/AutoAnswer/BotPeerChatSubscriber.cpp index 19760f5a7dfc0ee2a1c6fd6767251b4c1a135d50..8f2475a7b59a9a1c893c5f7cfbbc6f7a8e6051ea 100644 --- a/AutoAnswer/BotPeerChatSubscriber.cpp +++ b/AutoAnswer/BotPeerChatSubscriber.cpp @@ -60,6 +60,10 @@ BotPeerChatSubscriber::update(Observable<pluginMessagePtr>*, const pluginMessage else if (message->data.at("type") == "text/plain" && message->data.at("body") == input) { sendMsg["type"] = "text/plain"; sendMsg["body"] = answer; +#ifdef __DEBUG__ + Plog::log(Plog::LogPriority::INFO, TAG, "input " + message->data.at("body")); + Plog::log(Plog::LogPriority::INFO, TAG, "ouput " + answer); +#endif } if (!sendMsg.empty()) { sendText(message->accountId, message->peerId, sendMsg, message->isSwarm); @@ -106,6 +110,8 @@ BotPeerChatSubscriber::sendText(std::string& accountId, sendMsg, true); botAnswer->isSwarm = swarm; +#ifndef __DEBUG__ api_->invokeService(api_, "sendTextMessage", botAnswer.get()); +#endif } } // namespace jami diff --git a/AutoAnswer/CMakeLists.txt b/AutoAnswer/CMakeLists.txt index a0db3f1712959b108665c0d8aa978273334c5236..eb063996db3996ac48ea8ebc0d13b5f57aeb7664 100644 --- a/AutoAnswer/CMakeLists.txt +++ b/AutoAnswer/CMakeLists.txt @@ -33,24 +33,39 @@ message(JPL\ path:\ ${JPL_DIRECTORY}/../../../build/${ProjectName}/${JPL_FILE_NA set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") + +if(TESTPROCESS) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D__DEBUG__ /MD") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /D__DEBUG__ /MD") +else() + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MD") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") +endif() set(plugin_SRC BotChatHandler.cpp BotPeerChatSubscriber.cpp PluginPreferenceHandler.cpp main.cpp + ./../lib/common.cpp ) set(plugin_HDR BotChatHandler.h BotPeerChatSubscriber.h PluginPreferenceHandler.h ./../lib/pluglog.h + ./../lib/common.h ) -add_library(${ProjectName} SHARED ${plugin_SRC} +if(TESTPROCESS) + add_executable(${ProjectName} ${plugin_SRC} ${plugin_HDR} ) +else() + add_library(${ProjectName} SHARED ${plugin_SRC} + ${plugin_HDR} + ) +endif() + target_include_directories(${ProjectName} PUBLIC ${PROJECT_BINARY_DIR} ${PROJECT_SOURCE_DIR} @@ -58,23 +73,35 @@ target_include_directories(${ProjectName} PUBLIC ${PROJECT_BINARY_DIR} ${DAEMON_SRC} ${CONTRIB_PATH} ${CONTRIB_PATH}/build/fmt/include + ${CONTRIB_PATH}/build/yaml-cpp/include ) target_link_directories(${ProjectName} PUBLIC ${CONTRIB_PATH} ${CONTRIB_PATH}/build/fmt/msvc/Release + ${CONTRIB_PATH}/build/yaml-cpp/msvc/Release ) -add_custom_command( - TARGET ${ProjectName} - PRE_BUILD - COMMAND python ${PROJECT_SOURCE_DIR}/../SDK/jplManipulation.py --preassemble --plugin=${ProjectName} - COMMENT "Assembling Plugin files" -) +target_link_libraries(${ProjectName} PUBLIC libyaml-cppmd) + +if(TESTPROCESS) + add_custom_command( + TARGET ${ProjectName} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/testPreferences.yml ${PROJECT_BINARY_DIR}/ + ) +else() + add_custom_command( + TARGET ${ProjectName} + PRE_BUILD + COMMAND python ${PROJECT_SOURCE_DIR}/../SDK/jplManipulation.py --preassemble --plugin=${ProjectName} + COMMENT "Assembling Plugin files" + ) -add_custom_command( - TARGET ${ProjectName} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/Release/${ProjectName}.lib ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM} - COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/Release/${LIBRARY_FILE_NAME} ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM} - COMMAND python ${PROJECT_SOURCE_DIR}/../SDK/jplManipulation.py --assemble --plugin=${ProjectName} - COMMENT "Generating JPL archive" -) + add_custom_command( + TARGET ${ProjectName} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/Release/${ProjectName}.lib ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM} + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/Release/${LIBRARY_FILE_NAME} ${JPL_DIRECTORY}/lib/${CONTRIB_PLATFORM} + COMMAND python ${PROJECT_SOURCE_DIR}/../SDK/jplManipulation.py --assemble --plugin=${ProjectName} + COMMENT "Generating JPL archive" + ) +endif() diff --git a/AutoAnswer/build.sh b/AutoAnswer/build.sh index 5af8d2143e91134e9a077de5439113a5735e979e..8b136ecebff0a086fe44959185ef5c0c7b4230e0 100755 --- a/AutoAnswer/build.sh +++ b/AutoAnswer/build.sh @@ -6,10 +6,10 @@ ARCH=$(uname -m) EXTRAPATH='' # Flags: -# -p: number of processors to use +# -p: number of processors to use. # -c: Runtime plugin cpu/gpu setting. # -t: target platform. - +# -d: debug program. if [ -z "${DAEMON}" ]; then DAEMON="./../../daemon" @@ -36,8 +36,11 @@ elif [ "${PLATFORM}" = "Darwin" ]; then echo "Building with ${PLATFORM}" fi -while getopts t:c:p OPT; do +while getopts t:c:p:d OPT; do case "$OPT" in + d) + DEBUG=true + ;; t) PLATFORM="${OPTARG}" ;; @@ -54,34 +57,48 @@ done if [ "${PLATFORM}" = "linux-gnu" ] || [ "${PLATFORM}" = "redhat-linux" ] || [ "${PLATFORM}" = "Darwin" ] then - python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME} - CONTRIB_PLATFORM=${CONTRIB_PLATFORM_CURT}-${PLATFORM} OUTPUTFOLDER=${CONTRIB_PLATFORM} if [ "${PLATFORM}" = "Darwin" ]; then CONTRIB_PLATFORM=${CONTRIB_PLATFORM}${CONTRIB_PLATFORM_EXTRA} fi + if [ ${DEBUG} ]; then + OUTPUT="${PLUGIN_NAME}" + CLANG_OPTS="-g -fsanitize=address" + EXTRA_DEBUG_LIBRARIES="-lyaml-cpp" + EXTRA_DEFINES="-D__DEBUG__" + else + python3 ./../SDK/jplManipulation.py --preassemble --plugin=${PLUGIN_NAME} + CLANG_OPTS="-O3 -shared" + OUTPUT="build-local/jpl/lib/${OUTPUTFOLDER}/${SO_FILE_NAME}" + fi + # Compile - clang++ -std=c++17 -shared -fPIC \ + clang++ -std=c++17 -fPIC ${CLANG_OPTS} \ -Wl,-rpath,"\${ORIGIN}" \ -Wall -Wextra \ - -Wno-unused-variable \ - -Wno-unused-function \ -Wno-unused-parameter \ + ${EXTRA_DEFINES} \ -I"." \ -I"${DAEMON_SRC}" \ -I"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/include" \ -I"${PLUGINS_LIB}" \ + ./../lib/common.cpp \ PluginPreferenceHandler.cpp \ BotChatHandler.cpp \ BotPeerChatSubscriber.cpp \ main.cpp \ -L"${CONTRIB_PATH}/${CONTRIB_PLATFORM}/lib/" \ - -o "build-local/jpl/lib/${OUTPUTFOLDER}/${SO_FILE_NAME}" + ${EXTRA_DEBUG_LIBRARIES} \ + -o "${OUTPUT}" if [ "${PLATFORM}" = "Darwin" ]; then - install_name_tool -id "@loader_path/${SO_FILE_NAME}" "build-local/jpl/lib/${OUTPUTFOLDER}/${SO_FILE_NAME}" + if [ ! ${DEBUG} ]; then + install_name_tool -id "@loader_path/${PLUGIN_NAME}" "${OUTPUT}" + else + install_name_tool -id "@loader_path/${SO_FILE_NAME}" "${OUTPUT}" + fi fi if [ -n "${APPLE_SIGN_CERTIFICATE}" ]; then @@ -199,8 +216,6 @@ then -Wl,-Bsymbolic,-rpath,"\${ORIGIN}" \ -shared \ -Wall -Wextra \ - -Wno-unused-variable \ - -Wno-unused-function \ -Wno-unused-parameter \ -I"." \ -I"${DAEMON_SRC}" \ @@ -223,4 +238,6 @@ then done fi -python3 ./../SDK/jplManipulation.py --assemble --plugin=${PLUGIN_NAME} --distribution=${PLATFORM} --extraPath=${EXTRAPATH} +if [ ! ${DEBUG} ]; then + python3 ./../SDK/jplManipulation.py --assemble --plugin=${PLUGIN_NAME} --distribution=${PLATFORM} --extraPath=${EXTRAPATH} +fi diff --git a/AutoAnswer/main.cpp b/AutoAnswer/main.cpp index ff4d180d035c3ca602cf297abb64fe6d82f9a30e..dfed25f59ebbd466441b72c97628f6c6f12147c0 100644 --- a/AutoAnswer/main.cpp +++ b/AutoAnswer/main.cpp @@ -26,6 +26,13 @@ #include "plugin/jamiplugin.h" #include "BotChatHandler.h" +#ifdef __DEBUG__ +#include <common.h> +#include <assert.h> +#include <yaml-cpp/yaml.h> +#include <fstream> +#endif + #ifdef WIN32 #define EXPORT_PLUGIN __declspec(dllexport) #else @@ -80,3 +87,85 @@ JAMI_dynPluginInit(const JAMI_PluginAPI* api) return pluginExit; } } + +#ifdef __DEBUG__ + +int +main () +{ + std::cout << "********************************" << std::endl; + std::cout << "** AutoAnswer Debug Version **" << std::endl; + std::cout << "********************************" << std::endl; + std::cout << "Version " << AutoAnswer_VERSION_MAJOR << "." << AutoAnswer_VERSION_MINOR << "." + << AutoAnswer_VERSION_PATCH << std::endl << std::endl; + + +#ifdef _WIN32 + std::ifstream file = std::ifstream(string_utils::to_wstring("testPreferences.yml")); +#else + std::ifstream file = std::ifstream("testPreferences.yml", std::ios_base::in); +#endif + + assert(file.is_open()); + YAML::Node node = YAML::Load(file); + + assert(node.IsMap()); + std::map<std::string, std::map<std::string, std::string>> preferences; + preferences["default"] = {}; + for (const auto& kv : node) { + preferences["default"][kv.first.as<std::string>()] = kv.second.as<std::string>(); + std::cout << "Key: " << kv.first.as<std::string>() << "; Value: " << kv.second.as<std::string>() << std::endl; + } + + std::string dataPath = "tester"; + + auto fmpPluginPreferenceHandler + = std::make_unique<jami::PluginPreferenceHandler>(nullptr, std::move(preferences), dataPath); + + auto fmpBotChatHandler + = std::make_unique<jami::BotChatHandler>(nullptr, + std::move(dataPath), + fmpPluginPreferenceHandler.get()); + + auto subject = std::make_shared<jami::PublishObservable<jami::pluginMessagePtr>>(); + std::pair<std::string, std::string> subjectConnection("origin", "destiny"); + fmpBotChatHandler->notifyChatSubject(subjectConnection, subject); + + // Only test for swarm + + // Valid Sender, Receiver, direction and message + std::cout << "Test 1" << std::endl << "Should print input/output" << std::endl; + std::map<std::string, std::string> sendMsg = {{"type", "text/plain"}, {"body", preferences["default"]["inText"]}}; + jami::pluginMessagePtr jamiMsg = std::make_shared<JamiMessage>("origin", + "destiny", + true, + sendMsg, + false); + jamiMsg->isSwarm = true; + subject->publish(jamiMsg); + + + // Valid Sender, Receiver and message but not direction + std::cout << "Test 2" << std::endl << "Should NOT print input/output" << std::endl; + jamiMsg.reset(new JamiMessage("origin", + "destiny", + false, + sendMsg, + false)); + jamiMsg->isSwarm = true; + subject->publish(jamiMsg); + + // Invalid Sender, Receiver, direction and message + std::cout << "Test 3" << std::endl << "Should NOT print input/output" << std::endl; + sendMsg["body"] = preferences["default"]["invalid"]; + jamiMsg.reset(new JamiMessage("destiny", + "origin", + true, + sendMsg, + false)); + jamiMsg->isSwarm = true; + subject->publish(jamiMsg); + + return 0; +} +#endif diff --git a/AutoAnswer/package.json b/AutoAnswer/package.json index 3161df36e7612547f2a15d56d7fec6ef601e2932..a1dee2f411719e78899f756db695f90d7d26650f 100644 --- a/AutoAnswer/package.json +++ b/AutoAnswer/package.json @@ -3,9 +3,12 @@ "version": "2.0.0", "extractLibs": false, "deps": [ - "fmt" + "fmt", + "yaml-cpp" + ], + "defines": [ + "TESTPROCESS=False" ], - "defines": [], "custom_scripts": { "pre_build": [ "mkdir msvc" diff --git a/AutoAnswer/testPreferences.yml b/AutoAnswer/testPreferences.yml new file mode 100644 index 0000000000000000000000000000000000000000..5b0283df2d0566f2f12c8bbafb776887d5cd9db9 --- /dev/null +++ b/AutoAnswer/testPreferences.yml @@ -0,0 +1,3 @@ +answer: "Occupied" +inText: "Trigger" +invalid: "invalid message" diff --git a/GreenScreen/pluginProcessor.cpp b/GreenScreen/pluginProcessor.cpp index 737ebfeeedcf167877ef5eac257acb69974db6fd..52b7d17e9306c1931471f72dbd8b1075d6a20998 100644 --- a/GreenScreen/pluginProcessor.cpp +++ b/GreenScreen/pluginProcessor.cpp @@ -29,24 +29,7 @@ extern "C" { #include <pluglog.h> #ifdef WIN32 -#include <WTypes.h> - -namespace string_utils { -std::wstring -to_wstring(const std::string& str) { - int codePage = CP_UTF8; - int srcLength = (int) str.length(); - int requiredSize = MultiByteToWideChar(codePage, 0, str.c_str(), srcLength, nullptr, 0); - if (!requiredSize) { - throw std::runtime_error("Can't convert string to wstring"); - } - std::wstring result((size_t) requiredSize, 0); - if (!MultiByteToWideChar(codePage, 0, str.c_str(), srcLength, &(*result.begin()), requiredSize)) { - throw std::runtime_error("Can't convert string to wstring"); - } - return result; -} -} // namespace string_utils +#include <common.h> #endif const char sep = separator(); diff --git a/lib/common.cpp b/lib/common.cpp new file mode 100644 index 0000000000000000000000000000000000000000..20472780ea4a62b3ee8b1ef179fee6ffdd023bf9 --- /dev/null +++ b/lib/common.cpp @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2022 Savoir-faire Linux Inc. + * + * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "common.h" + +#ifdef WIN32 +#include <WTypes.h> +#include <stdexcept> + +namespace string_utils { +std::wstring +to_wstring(const std::string& str) { + int codePage = CP_UTF8; + int srcLength = (int) str.length(); + int requiredSize = MultiByteToWideChar(codePage, 0, str.c_str(), srcLength, nullptr, 0); + if (!requiredSize) { + throw std::runtime_error("Can't convert string to wstring"); + } + std::wstring result((size_t) requiredSize, 0); + if (!MultiByteToWideChar(codePage, 0, str.c_str(), srcLength, &(*result.begin()), requiredSize)) { + throw std::runtime_error("Can't convert string to wstring"); + } + return result; +} +} // namespace string_utils +#endif // WIN32 diff --git a/lib/common.h b/lib/common.h new file mode 100644 index 0000000000000000000000000000000000000000..f0543d0aec43b8660959137abfe922e340dad0f2 --- /dev/null +++ b/lib/common.h @@ -0,0 +1,32 @@ +/** + * Copyright (C) 2022 Savoir-faire Linux Inc. + * + * Author: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef COMMON_H +#define COMMON_H + +#ifdef WIN32 + +#include <string> + +namespace string_utils { +std::wstring to_wstring(const std::string& str); +} // namespace string_utils +#endif // WIN32 +#endif // COMMON_H