From: Jihoon Kim Date: Mon, 2 May 2022 01:34:45 +0000 (+0900) Subject: Support NLP CAPI X-Git-Tag: submit/tizen/20220524.051852~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F75%2F274575%2F10;p=platform%2Fcore%2Fuifw%2Fnlp.git Support NLP CAPI [==========] Running 7 tests from 2 test suites. [----------] Global test environment set-up. [----------] 3 tests from NlpCAPITest [ RUN ] NlpCAPITest.utc_nlp_connect_n [ OK ] NlpCAPITest.utc_nlp_connect_n (2 ms) [ RUN ] NlpCAPITest.utc_nlp_connect_p status : 0 request id : 1 tag: NNP, token : Hello tag: NNP, token : World request id: 1 token : Hello, tag : NNPtoken: Hello, tag: NNP token : World, tag : NNPtoken: World, tag: NNP [ OK ] NlpCAPITest.utc_nlp_connect_p (12982 ms) [ RUN ] NlpCAPITest.utc_nlp_foreach_pos_tag_n [ OK ] NlpCAPITest.utc_nlp_foreach_pos_tag_n (0 ms) [----------] 3 tests from NlpCAPITest (12984 ms total) Change-Id: I3d479cbaa48c76d4ce1d4725c0469c3abe4af473 Signed-off-by: Jihoon Kim --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 7f49e8d..3edb70a 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +ADD_SUBDIRECTORY(client) ADD_SUBDIRECTORY(service) ADD_SUBDIRECTORY(nlp_resource_data) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt new file mode 100644 index 0000000..9899bc3 --- /dev/null +++ b/client/CMakeLists.txt @@ -0,0 +1,132 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SET(project_prefix "capi") +SET(prefix "/usr") +SET(version "0.0.1") +SET(maintainer "Jihoon Kim ") +SET(description "NLP APIs") +SET(service "ui") +SET(submodule "nlp") +SET(dependents "dlog glib-2.0 rpc-port capi-appfw-app-common") +SET(LIBDIR ${LIB_INSTALL_DIR}) + +SET(Services + "application" + "base" + "content" + "location" + "media" + "messaging" + "network" + "social" + "telephony" + "system" + "ui" + ) + +FOREACH(lines ${configs}) + IF(${lines} MATCHES "([^=]*)=['\"](.*)['\"]") + SET(key ${CMAKE_MATCH_1}) + SET(value ${CMAKE_MATCH_2}) + SET(${key} "${value}") + ENDIF() +ENDFOREACH(lines ${configs}) + +LIST(FIND Services ${service} sfind) + +IF( ${sfind} EQUAL -1 ) + MESSAGE(FATAL_ERROR "Service must be one of ") + FOREACH( s IN ${Services} ) + MESSAGE(FATAL_ERROR "[${s}]") + ENDFOREACH( s IN ${Services} ) +ENDIF( ${sfind} EQUAL -1 ) + +SET(fw_name "${project_prefix}-${service}-${submodule}") + +PROJECT(${fw_name} C) + +SET(CMAKE_INSTALL_PREFIX ${prefix}) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(VERSION ${version}) + +SET(INC_DIR ../include) +INCLUDE_DIRECTORIES(${INC_DIR}) + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_name} REQUIRED ${dependents}) +FOREACH(flag ${${fw_name}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -fpermissive") +SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") + +IF("${ARCH}" STREQUAL "arm") + ADD_DEFINITIONS("-DTARGET") +ENDIF("${ARCH}" STREQUAL "arm") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DTIZEN_DEBUG") + +SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib") + +AUX_SOURCE_DIRECTORY(. SOURCES) +ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) + +SET_TARGET_PROPERTIES(${fw_name} + PROPERTIES + VERSION ${FULLVER} + SOVERSION ${MAJORVER} + CLEAN_DIRECT_OUTPUT 1 +) + +INSTALL(TARGETS ${fw_name} DESTINATION ${LIBDIR}) +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include + FILES_MATCHING + PATTERN "*_private.h" EXCLUDE + PATTERN "${INC_DIR}/*.h" + ) + +SET(PC_NAME ${fw_name}) +SET(PC_REQUIRED ${dependents}) +SET(PC_LDFLAGS -l${fw_name}) + +CONFIGURE_FILE( + capi-ui-nlp.pc.in + ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc + @ONLY +) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIBDIR}/pkgconfig) + +IF(UNIX) + +ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution) +ADD_CUSTOM_COMMAND( + DEPENDS clean + COMMENT "distribution clean" + COMMAND find + ARGS . + -not -name config.cmake -and \( + -name tester.c -or + -name Testing -or + -name CMakeFiles -or + -name cmake.depends -or + -name cmake.check_depends -or + -name CMakeCache.txt -or + -name cmake.check_cache -or + -name *.cmake -or + -name Makefile -or + -name core -or + -name core.* -or + -name gmon.out -or + -name install_manifest.txt -or + -name *.pc -or + -name *~ \) + | grep -v TC | xargs rm -rf + TARGET distclean + VERBATIM +) + +ENDIF(UNIX) diff --git a/client/capi-ui-nlp.manifest b/client/capi-ui-nlp.manifest new file mode 100644 index 0000000..dfdc35c --- /dev/null +++ b/client/capi-ui-nlp.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/client/capi-ui-nlp.pc.in b/client/capi-ui-nlp.pc.in new file mode 100644 index 0000000..3bcc226 --- /dev/null +++ b/client/capi-ui-nlp.pc.in @@ -0,0 +1,13 @@ +# Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=/usr +libdir=@LIBDIR@ +includedir=/usr/include + +Name: @PC_NAME@ +Description: @PACKAGE_DESCRIPTION@ +Version: @VERSION@ +Requires: @PC_REQUIRED@ +Libs: -L${libdir} @PC_LDFLAGS@ +Cflags: -I${includedir} diff --git a/client/nlp_client.c b/client/nlp_client.c new file mode 100644 index 0000000..9043ec6 --- /dev/null +++ b/client/nlp_client.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nlp_private.h" +#include "message_proxy.h" + +#define NLP_SERVICE_APP_ID "org.tizen.nlp.service" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "NLP_CLIENT" + +static int _nlp_context_count = 0; +static unsigned int _request_id = 0; + +typedef struct { + const char *token; + const char *tag; +} pos_tag_s; + +//LCOV_EXCL_START +static void _notify_cb(void *user_data, const char *sender, bundle *msg) +{ + nlp_h nh = user_data; + LOGD("sender: %s", sender); + char *request_id = NULL; + char *command = NULL; + + bundle_get_str(msg, "request_id", &request_id); + bundle_get_str(msg, "command", &command); + + LOGD("id : %s, command : %s", request_id, command); + + if (!command) return; + + if (strcmp(command, "pos_tag") == 0) { + const char **tag_array = NULL; + const char **token_array = NULL; + int len_tag_array = 0; + int len_token_array = 0; + pos_tag_s* pos_tag_pair = NULL; + GList *glist = NULL; + nlp_pos_tag_result_h pos_tag_result_h = NULL; + + tag_array = bundle_get_str_array(msg, "return_tag", &len_tag_array); + token_array = bundle_get_str_array(msg, "return_token", &len_token_array); + + for (int i=0; i < len_tag_array; i++) { + pos_tag_pair = (pos_tag_s* )calloc(1, sizeof(pos_tag_s)); + if (pos_tag_pair) { + pos_tag_pair->token = token_array[i]; + pos_tag_pair->tag = tag_array[i]; + } + + LOGD("tag: %s, token : %s", tag_array[i], token_array[i]); + + glist = g_list_append(glist, pos_tag_pair); + } + + pos_tag_result_h = glist; + + if (nh->pos_tag_result_cb) + nh->pos_tag_result_cb((unsigned int)atoi(request_id), pos_tag_result_h, nh->pos_tag_result_data); + } +} + +static void __on_connected(rpc_port_proxy_message_h h, void *user_data) +{ + nlp_h nh = user_data; + if (!nh) { + LOGW("no user data"); + return; + } + + nh->connected = true; + + LOGI("connected"); + + rpc_port_proxy_message_notify_cb_h notify_cb_h; + rpc_port_proxy_message_notify_cb_create(¬ify_cb_h); + rpc_port_proxy_message_notify_cb_set_callback(notify_cb_h, _notify_cb, nh); + rpc_port_proxy_message_notify_cb_set_once(notify_cb_h, false); + + char *app_id = NULL; + app_get_id(&app_id); + if (!app_id) { + char pid[256]; + snprintf(pid, sizeof(pid), "%u", getpid()); + app_id = strdup(pid); + } + + int r = rpc_port_proxy_message_invoke_coregister(h, app_id, notify_cb_h); + if (r != 0) + LOGW("[ERROR] Failed to invoke Register"); + + free(app_id); + + if (nh->connection_callback) + nh->connection_callback(nh, NLP_CONNECTION_STATUS_CONNECTED, nh->connection_userdata); +} + +//LCOV_EXCL_START +static void __on_disconnected(rpc_port_proxy_message_h h, void *user_data) +{ + LOGI("disconnected"); + + nlp_h nh = user_data; + if (nh) { + nh->connected = false; + + if (nh && nh->connection_callback) + nh->connection_callback(nh, NLP_CONNECTION_STATUS_DISCONNECTED, nh->connection_userdata); + + nh->rpc_h = NULL; + } +} + +static void __on_rejected(rpc_port_proxy_message_h h, void *user_data) +{ + LOGW("Connection rejected"); + + nlp_h nh = user_data; + + if (nh && nh->connection_callback) + nh->connection_callback(nh, NLP_CONNECTION_STATUS_REJECTED, nh->connection_userdata); +} +//LCOV_EXCL_STOP + +EXPORT_API int nlp_create(nlp_h *nh) +{ + int ret; + + if (!nh) + return NLP_ERROR_INVALID_PARAMETER; + + rpc_port_proxy_message_callback_s rpc_callback = { + .connected = __on_connected, + .disconnected = __on_disconnected, + .rejected = __on_rejected + }; + + struct nlp_s *ns = (nlp_h)calloc(1, sizeof(struct nlp_s)); + if (!ns) + return NLP_ERROR_OUT_OF_MEMORY; + + ret = rpc_port_proxy_message_create(NLP_SERVICE_APP_ID, &rpc_callback, ns, &ns->rpc_h); + if (ret != RPC_PORT_ERROR_NONE) { + LOGW("[ERROR] Failed to create rpc port. err = %d", ret); + free(ns); + return NLP_ERROR_OUT_OF_MEMORY; + } + + ns->context_id = _nlp_context_count++; + *nh = ns; + + return NLP_ERROR_NONE; +} + +EXPORT_API int nlp_destroy(nlp_h nh) +{ + if (!nh) + return NLP_ERROR_INVALID_PARAMETER; + + nh->connection_callback = NULL; + + if (nh->rpc_h) { + rpc_port_proxy_message_destroy(nh->rpc_h); + nh->rpc_h = NULL; + } + + free(nh); + + return NLP_ERROR_NONE; +} + +EXPORT_API int nlp_connect(nlp_h nh, nlp_connection_status_changed_cb callback, void *user_data) +{ + LOGI("nlp client connect. handle : %p", nh); + + int ret; + + if (!nh || !callback) { + LOGW("[ERROR] Invalid parameter"); + return NLP_ERROR_INVALID_PARAMETER; + } + + if (!nh->rpc_h) { + return NLP_ERROR_OPERATION_FAILED; + } + + nh->connection_callback = callback; + nh->connection_userdata = user_data; + + ret = rpc_port_proxy_message_connect(nh->rpc_h); + if (ret != RPC_PORT_ERROR_NONE) { + //LCOV_EXCL_START + switch(ret) { + case RPC_PORT_ERROR_IO_ERROR: + LOGW("[ERROR] Failed to connect rpc port. I/O Error"); + break; + case RPC_PORT_ERROR_OUT_OF_MEMORY: + LOGW("[ERROR] Failed to connect rpc port. Out of memory"); + return NLP_ERROR_OUT_OF_MEMORY; + break; + case RPC_PORT_ERROR_INVALID_PARAMETER: + LOGW("[ERROR] Failed to connect rpc port. Invalid parameter"); + break; + case RPC_PORT_ERROR_PERMISSION_DENIED: + LOGW("[ERROR] Failed to connect rpc port. Permission denied"); + return NLP_ERROR_PERMISSION_DENIED; + break; + default: + LOGW("[ERROR] Failed to connect rpc port. errcode = %d", ret); + break; + } + return NLP_ERROR_OPERATION_FAILED; + //LCOV_EXCL_STOP + } + else { + return NLP_ERROR_NONE; + } +} + +EXPORT_API int nlp_request_pos_tag(nlp_h nh, const char *str, unsigned int *request_id) +{ + if (!nh || !str) { + LOGW("[ERROR] Invalid parameter"); + return NLP_ERROR_INVALID_PARAMETER; + } + + if (!nh->rpc_h) { + return NLP_ERROR_OPERATION_FAILED; + } + + _request_id++; + char id[16]; + snprintf(id, sizeof(id), "%u", _request_id); + + bundle *msg = bundle_create(); + bundle_add_str(msg, "command", "pos_tag"); + bundle_add_str(msg, "info", str); + bundle_add_str(msg, "request_id", id); + + rpc_port_proxy_message_invoke_send(nh->rpc_h, msg); + bundle_free(msg); + + if (request_id) + *request_id = _request_id; + + return NLP_ERROR_NONE; +} + +EXPORT_API int nlp_set_pos_tag_result_cb(nlp_h nh, nlp_pos_tag_result_cb callback, void *user_data) +{ + if (!nh || !callback) { + LOGW("[ERROR] Invalid parameter"); + return NLP_ERROR_INVALID_PARAMETER; + } + + nh->pos_tag_result_cb = callback; + nh->pos_tag_result_data = user_data; + + return NLP_ERROR_NONE; +} + +EXPORT_API int nlp_unset_pos_tag_result_cb(nlp_h nh) +{ + if (!nh) { + LOGW("[ERROR] Invalid parameter"); + return NLP_ERROR_INVALID_PARAMETER; + } + + nh->pos_tag_result_cb = NULL; + nh->pos_tag_result_data = NULL; + + return NLP_ERROR_NONE; +} + +int nlp_foreach_pos_tag(nlp_pos_tag_result_h pos_tag_result_h, nlp_pos_tag_foreach_cb callback, void* user_data) +{ + if (!pos_tag_result_h || !callback) { + LOGW("[ERROR] Invalid parameter"); + return NLP_ERROR_INVALID_PARAMETER; + } + + GList *glist = pos_tag_result_h; + + GList* iter = NULL; + pos_tag_s* pos_tag_pair = NULL; + + if (g_list_length(glist) > 0) { + iter = g_list_first(glist); + + while (NULL != iter) { + pos_tag_pair = iter->data; + if (NULL != pos_tag_pair) { + LOGD("token : %s, tag : %s", pos_tag_pair->token, pos_tag_pair->tag); + callback(pos_tag_pair->token, pos_tag_pair->tag, user_data); + } + + /* next item */ + iter = g_list_next(iter); + + free(pos_tag_pair); + } + + g_list_free(glist); + glist = NULL; + } + + return NLP_ERROR_NONE; +} diff --git a/client/nlp_private.h b/client/nlp_private.h new file mode 100644 index 0000000..f51fcfc --- /dev/null +++ b/client/nlp_private.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd 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. + */ + +#ifndef __TIZEN_UIX_NLP_PRIVATE_H__ +#define __TIZEN_UIX_NLP_PRIVATE_H__ + +#include "../client/message_proxy.h" + +struct nlp_s { + rpc_port_proxy_message_h rpc_h; + + unsigned int context_id; + + bool connected; + + nlp_connection_status_changed_cb connection_callback; + void *connection_userdata; + + nlp_pos_tag_result_cb pos_tag_result_cb; + void *pos_tag_result_data; +}; + +#endif /* __TIZEN_UIX_NLP_PRIVATE_H__ */ diff --git a/include/nlp.h b/include/nlp.h new file mode 100644 index 0000000..a938b1b --- /dev/null +++ b/include/nlp.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd 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. + */ + +#ifndef __TIZEN_UIX_NLP_H__ +#define __TIZEN_UIX_NLP_H__ + +#include +#include + +/** + * @file nlp.h + * @brief This file contains NLP APIs and related enumeration. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup CAPI_UIX_NLP_CLIENT_MODULE + * @{ + */ + +#define TIZEN_ERROR_NLP -0x030E0000 + +/** + * @brief Enumeration for NLP function error. + * + * @since_tizen 7.0 + */ +typedef enum { + NLP_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ + NLP_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + NLP_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ + NLP_ERROR_OPERATION_FAILED = TIZEN_ERROR_NLP | 0x0001, /**< Operation failed */ + NLP_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */ + NLP_ERROR_SERVICE_NOT_CONNECTED = TIZEN_ERROR_NLP | 0x0002, /**< Unable to connect to NLP Service */ +} nlp_error_e; + +/** + * @brief Enumeration of connection status. + * @since_tizen 7.0 + */ +typedef enum { + NLP_CONNECTION_STATUS_CONNECTED = 0, /**< Connected */ + NLP_CONNECTION_STATUS_DISCONNECTED, /**< Disconnected */ + NLP_CONNECTION_STATUS_REJECTED, /**< Rejected */ +} nlp_connection_status_e; + +/** + * @brief The nlp handle. + * @since_tizen 7.0 + */ +typedef struct nlp_s *nlp_h; + +typedef GList *nlp_pos_tag_result_h; + +/** + * @brief Called when the connection status is changed. + * @since_tizen 7.0 + * @remarks @a nh should not be freed and can be used only in the callback. + * @param[in] nh The nlp handle + * @param[in] status The connection status + * @param[in] user_data The user data passed from the callback function + * @see nlp_connect() + */ +typedef void (*nlp_connection_status_changed_cb)(nlp_h nh, nlp_connection_status_e status, void* user_data); + +typedef void (*nlp_pos_tag_result_cb)(unsigned int request_id, nlp_pos_tag_result_h pos_tag_result_h, void *user_data); + +typedef bool (*nlp_pos_tag_foreach_cb)(const char* token, const char *tag, void* user_data); + +/** + * @brief Creates a handle for nlp. + * @since_tizen 7.0 + * @remarks If the function succeeds, @a nh handle must be released with nlp_destroy(). + * @param[out] nh The nlp handle + * @return 0 on success, otherwise a negative error value + * @retval #NLP_ERROR_NONE No error + * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #NLP_ERROR_OUT_OF_MEMORY Out of memory + * @see nlp_destroy() + */ +int nlp_create(nlp_h *nh); + +/** + * @brief Destroys an nlp. + * @since_tizen 7.0 + * @param[in] nh The nlp handle + * @return 0 on success, otherwise a negative error value + * @retval #NLP_ERROR_NONE No error + * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter + * @see nlp_create() + */ +int nlp_destroy(nlp_h nh); + +/** + * @brief Connects to nlp service application. + * @since_tizen 7.0 + * @param[in] nh The nlp handle + * @param[in] callback The callback function to register + * @param[in] user_data The user data to be passed to the callback function + * @return 0 on success, otherwise a negative error value + * @retval #NLP_ERROR_NONE No error + * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #NLP_ERROR_PERMISSION_DENIED Permission denied + * @retval #NLP_ERROR_OPERATION_FAILED Operation failure + */ +int nlp_connect(nlp_h nh, nlp_connection_status_changed_cb callback, void *user_data); + +/** + * @brief Requests to get the part of speech tagging given the string @str. + * @since_tizen 7.0 + * @remarks The result can be received by the callback function registered by nlp_set_pos_tag_result_cb(). + * @param[in] nh The nlp handle + * @param[in] str The string to be requested to get the part of speech tagging + * @param[out] request_id The request ID to be distingushed + * @return 0 on success, otherwise a negative error value + * @retval #NLP_ERROR_NONE No error + * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #NLP_ERROR_OPERATION_FAILED Operation failure + */ +int nlp_request_pos_tag(nlp_h ah, const char *str, unsigned int *request_id); + +/** + * @brief Sets the callback to receive the part of speech tagging. + * @since_tizen 7.0 + * @param[in] nh The NLP handle + * @param[in] callback The callback function to register + * @param[in] user_data The user data to be passed to the callback function + * @return 0 on success, otherwise a negative error value + * @retval #NLP_ERROR_NONE No error + * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter + * @see nlp_unset_pos_tag_result_cb() + */ +int nlp_set_pos_tag_result_cb(nlp_h nh, nlp_pos_tag_result_cb callback, void *user_data); + +/** + * @brief Unsets the callback to receive the part of speech tagging. + * @since_tizen 7.0 + * @param[in] nh The NLP handle + * @return 0 on success, otherwise a negative error value + * @retval #NLP_ERROR_NONE No error + * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter + * @see nlp_set_pos_tag_result_cb() + */ +int nlp_unset_pos_tag_result_cb(nlp_h nh); + +/** + * @brief Retrieves the part of speech tagging using callback function. + * @since_tizen 7.0 + * @param[in] pos_tag_result_h The part of speech tagging result handle + * @param[in] callback The callback function to register + * @param[in] user_data The user data to be passed to the callback function + * @return 0 on success, otherwise a negative error value + * @retval #NLP_ERROR_NONE No error + * @retval #NLP_ERROR_INVALID_PARAMETER Invalid parameter + */ +int nlp_foreach_pos_tag(nlp_pos_tag_result_h pos_tag_result_h, nlp_pos_tag_foreach_cb callback, void* user_data); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_UIX_NLP_H__ */ diff --git a/packaging/nlp.spec b/packaging/nlp.spec index 2c6f3ff..9b0cba7 100755 --- a/packaging/nlp.spec +++ b/packaging/nlp.spec @@ -7,6 +7,7 @@ Group: Graphics & UI Framework/Input License: Apache-2.0 Source0: %{name}-%{version}.tar.gz BuildRequires: cmake +BuildRequires: tidl BuildRequires: pkgconfig(capi-appfw-service-application) BuildRequires: pkgconfig(libtzplatform-config) BuildRequires: pkgconfig(bundle) @@ -22,10 +23,33 @@ Requires: %{name}-data-en # runtime requires Requires(post): coreutils +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%if 0%{?gcov:1} +BuildRequires: lcov +BuildRequires: zip +%endif %description Natural Language Processing service. +%package devel +Summary: NLP Client Library (Development) +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +NLP Library (Development) + +%if 0%{?gcov:1} +%package gcov +Summary: NLP Library (gcov) +Group: Graphics & UI Framework/Input +%description gcov +NLP gcov objects +%endif + %package data-en Summary: Data files for English Group: Graphics & UI Framework/Input @@ -44,19 +68,59 @@ GTest for NLP %prep %setup -q +tidlc -p -l C -i tidl/message.tidl -o message_proxy +mv message_proxy.h ./client/ +mv message_proxy.c ./client/ + +tidlc -s -l C -i tidl/message.tidl -o message_stub +mv message_stub.h ./service/src +mv message_stub.c ./service/src + %build +%if 0%{?gcov:1} +export CFLAGS+=" -fprofile-arcs -ftest-coverage" +export CXXFLAGS+=" -fprofile-arcs -ftest-coverage" +export FFLAGS+=" -fprofile-arcs -ftest-coverage" +export LDFLAGS+=" -lgcov" +%endif + %define _app_home_dir %{TZ_SYS_RO_APP}/%{name} %define _app_bin_dir %{_app_home_dir}/bin +export CFLAGS+=" -DTIZEN_DEBUG_ENABLE -fvisibility=hidden -Werror" +export CXXFLAGS+=" -DTIZEN_DEBUG_ENABLE -fvisibility=hidden -Werror" +export FFLAGS+=" -DTIZEN_DEBUG_ENABLE -fvisibility=hidden" + +rm -rf CMakeFiles +rm -rf CMakeCache.txt MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DLIB_INSTALL_DIR:PATH=%{_libdir} -DPYTHON3_SITELIB_PATH=%{python3_sitelib} make %{?jobs:-j%jobs} + %install rm -rf %{buildroot} %make_install +%if 0%{?gcov:1} +find . -name '*_proxy.c.gcno' -exec rm {} \; +find . -name '*_stub.c.gcno' -exec rm {} \; + +find . -name '*.gcno' | tar cf %{name}-gcov.tar -T - +install -d -m 755 %{buildroot}%{_datadir}/gcov/obj +tar xf %{name}-gcov.tar -C %{buildroot}%{_datadir}/gcov/obj +%endif + +%check +%if 0%{?gcov:1} +ctest --output-on-failure %{?_smp_mflags} +lcov -c --ignore-errors graph --no-external -q -d . -o %{name}.info +genhtml %{name}.info -o %{name}.out +zip -r %{name}.zip %{name}.out %{name}.info +install -m 0644 %{name}.zip %{buildroot}%{_datadir}/gcov/ +%endif + %define tizen_sign 1 %define tizen_sign_base %{TZ_SYS_RO_APP}/%{name} %define tizen_sign_level public @@ -64,19 +128,26 @@ rm -rf %{buildroot} %define tizen_dist_sign 1 %post +/sbin/ldconfig -%postun +%postun -p /sbin/ldconfig %files %manifest service/%{name}.manifest %defattr(-,root,root,-) %attr(755,root,root) %{_app_bin_dir}/%{name} +%{_libdir}/libcapi-ui-nlp.so.* +%{_libdir}/libcapi-ui-nlp.so %{_app_bin_dir}/* %{TZ_SYS_RO_PACKAGES}/%{name}.xml %{python3_sitelib}/langdetect/* %{python3_sitelib}/nltk/* %license LICENSE +%files devel +%{_includedir}/nlp.h +%{_libdir}/pkgconfig/capi-ui-nlp.pc + %files data-en %manifest service/%{name}.manifest %defattr(-,root,root,-) @@ -85,3 +156,8 @@ rm -rf %{buildroot} %files unittests %{_bindir}/* + +%if 0%{?gcov:1} +%files gcov +%{_datadir}/gcov/* +%endif diff --git a/service/CMakeLists.txt b/service/CMakeLists.txt index ef5a8bd..86bfed6 100755 --- a/service/CMakeLists.txt +++ b/service/CMakeLists.txt @@ -6,7 +6,7 @@ INCLUDE(FindPkgConfig) SET(SERVICE_SRC src/service.c - src/message.c + src/message_stub.c src/main.c src/nltk.c ) diff --git a/service/inc/message.h b/service/inc/message.h deleted file mode 100644 index a699078..0000000 --- a/service/inc/message.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Generated by tidlc 1.2.4. - * - * Copyright (c) 2018 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct message_context_s* rpc_port_stub_message_context_h; - -int rpc_port_stub_message_context_set_tag(rpc_port_stub_message_context_h ctx, void *tag); - -int rpc_port_stub_message_context_get_tag(rpc_port_stub_message_context_h ctx, void **tag); - -int rpc_port_stub_message_context_get_sender(rpc_port_stub_message_context_h ctx, char **sender); - -typedef struct message_notify_cb_s *rpc_port_message_notify_cb_h; - -int rpc_port_message_notify_cb_destroy(rpc_port_message_notify_cb_h h); - -int rpc_port_message_notify_cb_clone(rpc_port_message_notify_cb_h h, rpc_port_message_notify_cb_h *clone); - -int rpc_port_message_notify_cb_invoke(rpc_port_message_notify_cb_h h, const char *sender, bundle *msg); - -typedef struct { - void (*create)(rpc_port_stub_message_context_h context, void *user_data); - void (*terminate)(rpc_port_stub_message_context_h context, void *user_data); - - int (*coregister)(rpc_port_stub_message_context_h context, const char *name, rpc_port_message_notify_cb_h cb, void *user_data); - void (*unregister)(rpc_port_stub_message_context_h context, void *user_data); - int (*send)(rpc_port_stub_message_context_h context, bundle *msg, void *user_data); -} rpc_port_stub_message_callback_s; - -int rpc_port_stub_message_register(rpc_port_stub_message_callback_s *callback, void *user_data); - -int rpc_port_stub_message_unregister(void); - -#ifdef __cplusplus -} -#endif diff --git a/service/message.tidl b/service/message.tidl deleted file mode 100644 index 76ea688..0000000 --- a/service/message.tidl +++ /dev/null @@ -1,7 +0,0 @@ -interface message { - void notify_cb(string sender, bundle *msg) delegate; - - int coregister(string name, notify_cb cb); - void unregister() async; - int send(bundle *msg); -} diff --git a/service/prebuild.sh b/service/prebuild.sh index 979a7d2..dc112bc 100755 --- a/service/prebuild.sh +++ b/service/prebuild.sh @@ -1,4 +1,5 @@ #!/bin/bash -tidlc -s -l C -i message.tidl -o message -mv message.h ./inc/ -mv message.c ./src/ \ No newline at end of file +tidlc -s -l C -i message.tidl -o messageStub +tidlc -p -l C -i message.tidl -o messageProxy +mv messageStub.h ./inc/ +mv messageStub.c ./src/ diff --git a/service/src/message.c b/service/src/message.c deleted file mode 100644 index 6eff7e8..0000000 --- a/service/src/message.c +++ /dev/null @@ -1,571 +0,0 @@ -/* - * Generated by tidlc 1.2.4. - * - * Copyright (c) 2018 Samsung Electronics Co., Ltd. - * - * 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. - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "message.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif - -#define LOG_TAG "RPC_PORT_STUB" - -#ifdef _E -#undef _E -#endif - -#ifdef _W -#undef _W -#endif - -#ifdef _I -#undef _I -#endif - -#ifdef _D -#undef _D -#endif - -#define _E(fmt, ...) dlog_print(DLOG_ERROR, LOG_TAG, "%s: %s(%d) > "fmt, basename(__FILE__), __FUNCTION__, __LINE__, ##__VA_ARGS__) -#define _W(fmt, ...) dlog_print(DLOG_WARN, LOG_TAG, "%s: %s(%d) > "fmt, basename(__FILE__), __FUNCTION__, __LINE__, ##__VA_ARGS__) -#define _I(fmt, ...) dlog_print(DLOG_INFO, LOG_TAG, "%s: %s(%d) > "fmt, basename(__FILE__), __FUNCTION__, __LINE__, ##__VA_ARGS__) -#define _D(fmt, ...) dlog_print(DLOG_DEBUG, LOG_TAG, "%s: %s(%d) > "fmt, basename(__FILE__), __FUNCTION__, __LINE__, ##__VA_ARGS__) - -typedef int (*stub_method)(rpc_port_h, rpc_port_parcel_h, void *data); - -enum message_method_e { - message_METHOD_Result, - message_METHOD_Callback, - message_METHOD_coregister, - message_METHOD_unregister, - message_METHOD_send, -}; - -enum message_delegate_e { - message_DELEGATE_notify_cb = 1, -}; - -static rpc_port_stub_h __message_stub; -static rpc_port_stub_message_callback_s __message_callback; -static void *__message_user_data; -static GList *__message_contexts; - -struct message_context_s { - char *sender; - char *instance; - rpc_port_h port; - void *tag; - rpc_port_stub_message_callback_s callback; - void *user_data; -}; - -static struct message_context_s *__create_message_context(const char *sender, const char *instance) -{ - struct message_context_s *handle; - - handle = calloc(1, sizeof(struct message_context_s)); - if (!handle) { - _E("Out of memory"); - return NULL; - } - - handle->sender = strdup(sender); - if (!handle->sender) { - _E("Out of memory"); - free(handle); - return NULL; - } - - handle->instance = strdup(instance); - if (!handle->instance) { - _E("Out of memory"); - free(handle->sender); - free(handle); - return NULL; - } - - handle->callback = __message_callback; - handle->user_data = __message_user_data; - - return handle; -} - -static void __destroy_message_context(gpointer data) -{ - struct message_context_s *handle = data; - - if (!handle) { - _E("Critical error!"); - return; - } - - free(handle->instance); - free(handle->sender); - free(handle); -} - -static struct message_context_s *__find_message_context(const char *instance) -{ - struct message_context_s *handle; - GList *iter; - - iter = __message_contexts; - while (iter) { - handle = (struct message_context_s *)iter->data; - if (!strcmp(handle->instance, instance)) - return handle; - iter = g_list_next(iter); - } - - return NULL; -} - -int rpc_port_stub_message_context_set_tag(rpc_port_stub_message_context_h ctx, void *tag) -{ - if (!ctx) { - _E("Invalid parameter"); - return -1; - } - - ctx->tag = tag; - - return 0; -} - -int rpc_port_stub_message_context_get_tag(rpc_port_stub_message_context_h ctx, void **tag) -{ - if (!ctx || !tag) { - _E("Invalid parameter"); - return -1; - } - - *tag = ctx->tag; - - return 0; -} - -int rpc_port_stub_message_context_get_sender(rpc_port_stub_message_context_h ctx, char **sender) -{ - if (!ctx || !sender) { - _E("Invalid parameter"); - return -1; - } - - *sender = strdup(ctx->sender); - if (*sender == NULL) { - _E("Out of memory"); - return -1; - } - - return 0; -} - -struct message_notify_cb_s { - rpc_port_parcelable_t parcelable; - rpc_port_h port; - int id; - int seq_id; - bool once; - bool valid; -}; - -static void __message_notify_cb_to(rpc_port_parcel_h parcel, void *data) -{ - rpc_port_message_notify_cb_h handle = data; - - if (!handle) { - _E("Invalid parameter"); - return; - } - - rpc_port_parcel_write_int32(parcel, handle->id); - rpc_port_parcel_write_int32(parcel, handle->seq_id); - rpc_port_parcel_write_bool(parcel, handle->once); -} - -static void __message_notify_cb_from(rpc_port_parcel_h parcel, void *data) -{ - rpc_port_message_notify_cb_h handle = data; - - if (!handle) { - _E("Invalid parameter"); - return; - } - - rpc_port_parcel_read_int32(parcel, &handle->id); - rpc_port_parcel_read_int32(parcel, &handle->seq_id); - rpc_port_parcel_read_bool(parcel, &handle->once); -} - -int rpc_port_message_notify_cb_create(rpc_port_message_notify_cb_h *h) -{ - struct message_notify_cb_s *handle; - static int seq_num; - - if (!h) { - _E("Invalid parameter"); - return -1; - } - - handle = calloc(1, sizeof(struct message_notify_cb_s)); - if (!handle) { - _E("Out of memory"); - return -1; - } - - handle->parcelable.to = __message_notify_cb_to; - handle->parcelable.from = __message_notify_cb_from; - handle->id = message_DELEGATE_notify_cb; - handle->seq_id = g_atomic_int_add(&seq_num, 1) + 1; - handle->once = false; - handle->valid = true; - - *h = handle; - - return 0; -} - -int rpc_port_message_notify_cb_destroy(rpc_port_message_notify_cb_h h) -{ - if (!h) { - _E("Invalid parameter"); - return -1; - } - - free(h); - - return 0; -} - -int rpc_port_message_notify_cb_clone(rpc_port_message_notify_cb_h h, rpc_port_message_notify_cb_h *clone) -{ - rpc_port_message_notify_cb_h handle; - - if (!h || !clone) { - _E("Invalid parameter"); - return -1; - } - - handle = calloc(1, sizeof(struct message_notify_cb_s)); - if (!handle) { - _E("Out of memory"); - return -1; - } - - handle->parcelable = h->parcelable; - handle->port = h->port; - handle->id = h->id; - handle->seq_id = h->seq_id; - handle->once = h->once; - handle->valid = h->valid; - - *clone = handle; - - return 0; -} - -int rpc_port_message_notify_cb_invoke(rpc_port_message_notify_cb_h h, const char *sender, bundle *msg) -{ - rpc_port_parcel_h parcel = NULL; - - if (!h || !h->port) { - _E("Invalid parameter"); - return -1; - } - - if (h->once && !h->valid) { - _E("Invalid callback"); - return -1; - } - - rpc_port_parcel_create(&parcel); - if (!parcel) { - _E("Failed to create parcel"); - return -1; - } - - rpc_port_parcel_write_int32(parcel, message_METHOD_Callback); - rpc_port_parcel_write(parcel, &h->parcelable, h); - rpc_port_parcel_write_string(parcel, sender ? sender : ""); - rpc_port_parcel_write_bundle(parcel, msg); - - rpc_port_parcel_send(parcel, h->port); - rpc_port_parcel_destroy(parcel); - h->valid = false; - - return 0; -} - -int rpc_port_message_notify_cb_set_port(rpc_port_message_notify_cb_h h, rpc_port_h port) -{ - if (!h || !port) { - _E("Invalid parameter"); - return -1; - } - - h->port = port; - - return 0; -} - -static int __message_method_coregister(rpc_port_h port, rpc_port_parcel_h parcel, void *data) -{ - rpc_port_stub_message_context_h context = data; - rpc_port_h callback_port; - int r; - - r = rpc_port_stub_get_port(__message_stub, RPC_PORT_PORT_CALLBACK, context->instance, &callback_port); - if (r != 0) - _E("Failed to get callback port"); - - char *name; - rpc_port_message_notify_cb_h cb; - - rpc_port_parcel_read_string(parcel, &name); - rpc_port_message_notify_cb_create(&cb); - rpc_port_message_notify_cb_set_port(cb, callback_port); - rpc_port_parcel_read(parcel, &cb->parcelable, cb); - - int ret = context->callback.coregister(context, name, cb, context->user_data); - do { - rpc_port_parcel_h result; - - rpc_port_parcel_create(&result); - rpc_port_parcel_write_int32(result, message_METHOD_Result); - rpc_port_parcel_write_int32(result, ret); - rpc_port_parcel_send(result, port); - rpc_port_parcel_destroy(result); - } while (0); - - free(name); - rpc_port_message_notify_cb_destroy(cb); - return 0; -} - -static int __message_method_unregister(rpc_port_h port, rpc_port_parcel_h parcel, void *data) -{ - rpc_port_stub_message_context_h context = data; - rpc_port_h callback_port; - int r; - - r = rpc_port_stub_get_port(__message_stub, RPC_PORT_PORT_CALLBACK, context->instance, &callback_port); - if (r != 0) - _E("Failed to get callback port"); - - context->callback.unregister(context, context->user_data); - - return 0; -} - -static int __message_method_send(rpc_port_h port, rpc_port_parcel_h parcel, void *data) -{ - rpc_port_stub_message_context_h context = data; - rpc_port_h callback_port; - int r; - - r = rpc_port_stub_get_port(__message_stub, RPC_PORT_PORT_CALLBACK, context->instance, &callback_port); - if (r != 0) - _E("Failed to get callback port"); - - bundle *msg; - - rpc_port_parcel_read_bundle(parcel, &msg); - - int ret = context->callback.send(context, msg, context->user_data); - do { - rpc_port_parcel_h result; - - rpc_port_parcel_create(&result); - rpc_port_parcel_write_int32(result, message_METHOD_Result); - rpc_port_parcel_write_int32(result, ret); - rpc_port_parcel_send(result, port); - rpc_port_parcel_destroy(result); - } while (0); - - bundle_free(msg); - return 0; -} - -static stub_method __message_method_table[] = { - [message_METHOD_coregister] = __message_method_coregister, - [message_METHOD_unregister] = __message_method_unregister, - [message_METHOD_send] = __message_method_send, -}; - -static void __message_on_connected(const char *sender, const char *instance, void *data) -{ - rpc_port_stub_message_context_h context; - - _I("[__RPC_PORT__] sender(%s), instance(%s)", sender, instance); - context = __create_message_context(sender, instance); - if (!context) - return; - - if (context->callback.create) - context->callback.create(context, context->user_data); - __message_contexts = g_list_append(__message_contexts, context); -} - -static void __message_on_disconnected(const char *sender, const char *instance, void *data) -{ - rpc_port_stub_message_context_h context; - - _I("[__RPC_PORT__] sender(%s), instance(%s)", sender, instance); - context = __find_message_context(instance); - if (!context) - return; - - if (context->callback.terminate) - context->callback.terminate(context, context->user_data); - __message_contexts = g_list_remove(__message_contexts, context); - __destroy_message_context(context); -} - -static int __message_on_received(const char *sender, const char *instance, rpc_port_h port, void *data) -{ - rpc_port_stub_message_context_h context; - rpc_port_parcel_h parcel; - int cmd = -1; - int r; - - _I("[__RPC_PORT__] sender(%s), instance(%s)", sender, instance); - context = __find_message_context(instance); - if (!context) { - _E("Failed to find message context(%s)", instance); - return -1; - } - - context->port = port; - r = rpc_port_parcel_create_from_port(&parcel, port); - if (r != 0) { - _E("Failed to create parcel from port"); - return r; - } - - rpc_port_parcel_read_int32(parcel, &cmd); - if (cmd > 1 && cmd < (sizeof(__message_method_table) / sizeof(__message_method_table[0]))) { - if (__message_method_table[cmd]) - r = __message_method_table[cmd](port, parcel, context); - } else { - _E("Unknown Command(%d)", cmd); - r = -1; - } - - rpc_port_parcel_destroy(parcel); - - return r; -} - -static int __message_add_privileges(void) -{ - - return 0; -} - -int rpc_port_stub_message_register(rpc_port_stub_message_callback_s *callback, void *user_data) -{ - int r; - - if (__message_stub) { - _W("Already exists"); - return -1; - } - - if (!callback) { - _E("Invalid parameter"); - return -1; - } - - __message_callback = *callback; - __message_user_data = user_data; - r = rpc_port_stub_create(&__message_stub, "message"); - if (r != 0) { - _E("Failed to create stub handle"); - return r; - } - - r = rpc_port_stub_add_received_event_cb(__message_stub, __message_on_received, NULL); - if (r != 0) { - _E("Failed to add received event callback"); - rpc_port_stub_destroy(__message_stub); - __message_stub = NULL; - return r; - } - - r = rpc_port_stub_add_connected_event_cb(__message_stub, __message_on_connected, NULL); - if (r != 0) { - _E("Failed to add connected event callback"); - rpc_port_stub_destroy(__message_stub); - __message_stub = NULL; - return r; - } - - r = rpc_port_stub_add_disconnected_event_cb(__message_stub, __message_on_disconnected, NULL); - if (r != 0) { - _E("Failed to add disconnected event callback"); - rpc_port_stub_destroy(__message_stub); - __message_stub = NULL; - return r; - } - - r = __message_add_privileges(); - if (r != 0) { - _E("Failed to add privileges"); - rpc_port_stub_destroy(__message_stub); - __message_stub = NULL; - return r; - } - - r = rpc_port_stub_listen(__message_stub); - if (r != 0) { - _E("Failed to listen stub"); - rpc_port_stub_destroy(__message_stub); - __message_stub = NULL; - return r; - } - - return 0; -} - -int rpc_port_stub_message_unregister(void) -{ - int r; - - if (!__message_stub) - return -1; - - if (__message_contexts) { - g_list_free_full(__message_contexts, __destroy_message_context); - __message_contexts = NULL; - } - - r = rpc_port_stub_destroy(__message_stub); - __message_stub = NULL; - - return r; -} diff --git a/service/src/service.c b/service/src/service.c index 4a11dfa..1c97f9b 100755 --- a/service/src/service.c +++ b/service/src/service.c @@ -6,7 +6,7 @@ #undef _POSIX_C_SOURCE #include "service.h" #include "nlp_log.h" -#include "message.h" +#include "message_stub.h" #include "nltk.h" typedef enum { @@ -23,11 +23,11 @@ static gint service_close_timer = 0; struct client_s { char *id; - rpc_port_message_notify_cb_h cb; + rpc_port_stub_message_notify_cb_h cb; }; static struct client_s *__create_client(const char *id, - rpc_port_message_notify_cb_h cb) + rpc_port_stub_message_notify_cb_h cb) { PENTER(); struct client_s *handle; @@ -45,7 +45,7 @@ static struct client_s *__create_client(const char *id, return NULL; } - rpc_port_message_notify_cb_clone(cb, &handle->cb); + rpc_port_stub_message_notify_cb_clone(cb, &handle->cb); if (!handle->cb) { PERR("Out of memory"); free(handle->id); @@ -88,7 +88,7 @@ static void __destroy_client(gpointer data) return; if (handle->cb) - rpc_port_message_notify_cb_destroy(handle->cb); + rpc_port_stub_message_notify_cb_destroy(handle->cb); if (handle->id) free(handle->id); free(handle); @@ -124,7 +124,7 @@ static void __message_terminate(rpc_port_stub_message_context_h context, } static int __message_register(rpc_port_stub_message_context_h context, - const char *name, rpc_port_message_notify_cb_h cb, + const char *name, rpc_port_stub_message_notify_cb_h cb, void *user_data) { struct client_s *client; @@ -146,7 +146,10 @@ static int __message_send(rpc_port_stub_message_context_h context, char *message = NULL; bundle_get_str(msg, "command", &message); rpc_port_stub_message_context_get_tag(context, (void *)&sender_client); - PLOG("[__RPC_PORT__] name(%s), msg(%s)", sender_client->id, message); + if (sender_client) + PLOG("[__RPC_PORT__] name(%s), msg(%s)", sender_client->id, message); + else + PERR("[__RPC_PORT__] no sender info. msg(%s)", message); bundle *reply = bundle_create(); char *info = NULL; @@ -357,8 +360,12 @@ static int __message_send(rpc_port_stub_message_context_h context, bundle_add_str(reply, "command", "Exception happens"); break; } - bundle_add_str(reply, "request_id", request_id); - rpc_port_message_notify_cb_invoke(sender_client->cb, sender_client->id, reply); + bundle_add_str(reply, "request_id", request_id ? request_id : ""); + if (sender_client) + rpc_port_stub_message_notify_cb_invoke(sender_client->cb, sender_client->id, reply); + else + PERR("No sender info"); + bundle_free(reply); start_timer(); return 0; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d6b58b0..a851d5d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,12 +34,16 @@ AUX_SOURCE_DIRECTORY(src SOURCES) AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../service/src NLP_SERVICE_SOURCES) list(REMOVE_ITEM NLP_SERVICE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../service/src/main.c") +AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../client NLP_CLIENT_SOURCES) + ADD_DEFINITIONS("-DFULLVER=\"${FULLVER}\"") ADD_EXECUTABLE(${UTC_NLP} ${NLP_SERVICE_SOURCES} + ${NLP_CLIENT_SOURCES} ${SOURCES} ) + TARGET_LINK_LIBRARIES(${UTC_NLP} ${GTEST_LIBRARIES} ${pkgs_LDFLAGS} ${EXTRA_LDFLAGS}) INSTALL(TARGETS ${UTC_NLP} DESTINATION /usr/bin) diff --git a/tests/src/nlp_capi_unittests.cpp b/tests/src/nlp_capi_unittests.cpp new file mode 100644 index 0000000..aa9b54e --- /dev/null +++ b/tests/src/nlp_capi_unittests.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * + * 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. + */ + +#include + +#include +#include +#include +#include +#include + +#define GMAINLOOP 1 +#define WAIT_RESULT_DELAY 10 + +static int g_init = false; +static GMainLoop *loop = NULL; + +static gint service_close_timer = 0; + +using namespace std; + +namespace { + +static void STOP_LOOP(); +static void WAIT_FOR_CALLBACK(); + +gboolean timer_cb(gpointer data) +{ + printf("time runs out\n"); + service_close_timer = 0; + STOP_LOOP(); + + return FALSE; +} + +void stop_timer() +{ + if (service_close_timer > 0) + g_source_remove(service_close_timer); + + service_close_timer = 0; +} + +bool pos_tag_foreach_cb(const char* token, const char *tag, void* user_data) +{ + printf("token: %s, tag: %s\n", token, tag); + + return true; +} + +void pos_tag_result_cb(unsigned int request_id, nlp_pos_tag_result_h pos_tag_result_h, void *user_data) +{ + printf("request id: %d\n", request_id); + + nlp_foreach_pos_tag(pos_tag_result_h, pos_tag_foreach_cb, NULL); + + STOP_LOOP(); +} + +static void _connection_cb(nlp_h nh, nlp_connection_status_e status, void* user_data) +{ + printf("status : %d\n", status); + + unsigned int request_id = 0; + + nlp_set_pos_tag_result_cb(nh, pos_tag_result_cb, NULL); + + nlp_request_pos_tag(nh, "Hello World", &request_id); + printf("request id : %d\n", request_id); + + WAIT_FOR_CALLBACK(); +} + +static void STOP_LOOP() +{ + printf("quit loop\n"); + if (loop) + g_main_loop_quit(loop); +} + +static void WAIT_FOR_CALLBACK() +{ + stop_timer(); + + service_close_timer = g_timeout_add(WAIT_RESULT_DELAY*1000, timer_cb, NULL); + if (service_close_timer == 0) + printf("failed to create timer\n"); + + printf("start loop\n"); + + if (loop) { + g_main_loop_quit(loop); + g_main_loop_run(loop); + } + else { + printf("Can't run loop. loop NULL\n"); + } +} + +class NlpCAPITest : public testing::Test { + public: + nlp_h nh = NULL; + + virtual void SetUp() { + if (!g_init) { + g_init = true; + } + + loop = g_main_loop_new(NULL, FALSE); + + int ret = nlp_create(&nh); + EXPECT_EQ(ret, NLP_ERROR_NONE); + EXPECT_NE(nh, nullptr); + } + virtual void TearDown() { + if (nh) + nlp_destroy(nh); + + if (loop) + g_main_loop_unref(loop); + + loop = NULL; + } +}; + +TEST_F(NlpCAPITest, utc_nlp_connect_invalid_parameter) +{ + int ret = nlp_connect(nh, NULL, NULL); + EXPECT_EQ(ret, NLP_ERROR_INVALID_PARAMETER); +} + +TEST_F(NlpCAPITest, utc_nlp_connect_p) +{ + int ret = nlp_connect(nh, _connection_cb, NULL); + EXPECT_EQ(ret, NLP_ERROR_NONE); + + WAIT_FOR_CALLBACK(); +} + +TEST_F(NlpCAPITest, utc_nlp_foreach_pos_tag_invalid_parameter) +{ + int ret = nlp_foreach_pos_tag(NULL, NULL, NULL); + EXPECT_EQ(ret, NLP_ERROR_INVALID_PARAMETER); +} + +} // namespace diff --git a/tidl/message.tidl b/tidl/message.tidl new file mode 100644 index 0000000..bd52a79 --- /dev/null +++ b/tidl/message.tidl @@ -0,0 +1,7 @@ +interface message { + void notify_cb(string sender, bundle msg) delegate; + + int coregister(string name, notify_cb cb); + void unregister() async; + int send(bundle msg); +}