From: Lukasz Bardeli Date: Tue, 16 Feb 2016 08:52:30 +0000 (+0100) Subject: [Iotcon] implemented addPresenceEventListener and removePresenceEventListener. X-Git-Tag: submit/tizen/20160222.104327^2~15 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f745c762615a9667df7e48eaf3189eb946bb1837;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Iotcon] implemented addPresenceEventListener and removePresenceEventListener. Change-Id: Ibe579a8c20674a275685a40e5e25b8d943b47a12 Signed-off-by: Lukasz Bardeli --- diff --git a/src/iotcon/iotcon.gyp b/src/iotcon/iotcon.gyp index b5fd720f..c45581fa 100644 --- a/src/iotcon/iotcon.gyp +++ b/src/iotcon/iotcon.gyp @@ -17,6 +17,8 @@ 'iotcon_instance.h', 'iotcon_server_manager.cc', 'iotcon_server_manager.h', + 'iotcon_client_manager.cc', + 'iotcon_client_manager.h', 'iotcon_utils.cc', 'iotcon_utils.h', ], diff --git a/src/iotcon/iotcon_api.js b/src/iotcon/iotcon_api.js index 1275ffb7..cee73089 100644 --- a/src/iotcon/iotcon_api.js +++ b/src/iotcon/iotcon_api.js @@ -899,7 +899,7 @@ Client.prototype.findResource = function() { }; var presenceEventListener = createListener('PresenceEventListener', function(response) { - return new PresenceResponse(native.getResultObject(response)); + return new PresenceResponse(response.data); }); Client.prototype.addPresenceEventListener = function() { @@ -909,7 +909,8 @@ Client.prototype.addPresenceEventListener = function() { nullable: true }, { name: 'resourceType', - type: types.STRING + type: types.STRING, + nullable: true }, { name: 'connectivityType', type: types.ENUM, diff --git a/src/iotcon/iotcon_client_manager.cc b/src/iotcon/iotcon_client_manager.cc new file mode 100644 index 00000000..fb840c3d --- /dev/null +++ b/src/iotcon/iotcon_client_manager.cc @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2015 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 "iotcon/iotcon_client_manager.h" + +#include "common/logger.h" + +namespace extension { +namespace iotcon { + +using common::TizenResult; +using common::TizenSuccess; + +namespace { + +long long GetPresenceNextId() { + static long long id = 0; + return ++id; +} + +} // namespace + +IotconClientManager& IotconClientManager::GetInstance() { + static IotconClientManager instance; + return instance; +} + +TizenResult IotconClientManager::RestoreHandles() { + ScopeLogger(); + + for (const auto& it : presence_map_) { + LoggerD("Restoring handle for presence event with id: %lld", it.first); + + PresenceEventPtr presence = it.second; + char* host = nullptr; + char* resource_type = nullptr; + iotcon_connectivity_type_e con_type = IOTCON_CONNECTIVITY_IPV4; + + auto res = IotconUtils::ExtractFromPresenceEvent(presence, &host, + &con_type, &resource_type); + if (!res){ + return res; + } + + const iotcon_presence_h old_handle = presence->handle; + int ret = iotcon_add_presence_cb(host, con_type, resource_type, + PresenceHandler, this,&(presence->handle)); + if (IOTCON_ERROR_NONE != ret || nullptr == presence->handle) { + LogAndReturnTizenError(IotconUtils::ConvertIotconError(ret), + ("iotcon_add_presence_cb() failed: %d (%s)", + ret, get_error_message(ret))); + } + if (old_handle) { + LoggerD("destroy handle which is currently invalid: %p", old_handle); + iotcon_remove_presence_cb(old_handle); + } + LoggerD("new handle: %p", (presence->handle)); + } + + return TizenSuccess(); +} + +void IotconClientManager::PresenceHandler(iotcon_presence_h presence, + iotcon_error_e err, + iotcon_presence_response_h response, + void *user_data) { + ScopeLogger(); + + if(IOTCON_ERROR_NONE != err) { + LoggerE("Error in presence event callback!"); + return; + } + auto that = static_cast(user_data); + + for (const auto& p : that->presence_map_) { + if (p.second->presence_listener && p.second->handle == presence) { + picojson::value value{picojson::object{}}; + auto& obj = value.get(); + auto ret = IotconUtils::PresenceResponseToJson(response, + &obj); + if (!ret) { + LoggerE("PresenceResponseToJson() failed"); + return; + } + // call listener + p.second->presence_listener(TizenSuccess(), value); + } + } +}; + +common::TizenResult IotconClientManager::AddPresenceEventListener( + const char* host, const iotcon_connectivity_type_e con_type_e, + const char* resource_type, PresenceEventPtr presence) { + ScopeLogger(); + + auto result = IotconUtils::ConvertIotconError(iotcon_add_presence_cb( + host, con_type_e, resource_type, PresenceHandler, this, + &(presence->handle))); + + // storing PresenceEvent into map + presence->id = GetPresenceNextId(); + presence_map_.insert(std::make_pair(presence->id, presence)); + + return TizenSuccess(); +} + +common::TizenResult IotconClientManager::RemovePresenceEventListener(long long id) { + auto it = presence_map_.find(id); + if (it == presence_map_.end()) { + return LogAndCreateTizenError(AbortError, "Presence callback with specified ID does not exist"); + } + + auto result = IotconUtils::ConvertIotconError(iotcon_remove_presence_cb(it->second->handle)); + + if (!result) { + LogAndReturnTizenError(result, ("iotcon_remove_presence_cb failed")); + } + + presence_map_.erase(id); + + return TizenSuccess(); +} + +} // namespace iotcon +} // namespace extension diff --git a/src/iotcon/iotcon_client_manager.h b/src/iotcon/iotcon_client_manager.h new file mode 100644 index 00000000..7473a43f --- /dev/null +++ b/src/iotcon/iotcon_client_manager.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 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 WEBAPI_PLUGINS_IOTCON_CLIENT_MANAGER_H__ +#define WEBAPI_PLUGINS_IOTCON_CLIENT_MANAGER_H__ + +#include +#include +#include +#include + +#include "iotcon/iotcon_utils.h" + +#include "common/tizen_result.h" + +namespace extension { +namespace iotcon { + +class IotconClientManager { + public: + static IotconClientManager& GetInstance(); + + common::TizenResult RestoreHandles(); + common::TizenResult AddPresenceEventListener(const char* host, + const iotcon_connectivity_type_e con_type_e, + const char* resource_type, + PresenceEventPtr presence); + common::TizenResult RemovePresenceEventListener(long long id); + + private: + IotconClientManager() = default; + IotconClientManager(const IotconClientManager&) = delete; + IotconClientManager(IotconClientManager&&) = delete; + IotconClientManager& operator=(const IotconClientManager&) = delete; + IotconClientManager& operator=(IotconClientManager&&) = delete; + + static void PresenceHandler(iotcon_presence_h resource, + iotcon_error_e err, + iotcon_presence_response_h response, + void *user_data); + + PresenceMap presence_map_; +}; + +} // namespace iotcon +} // namespace extension + +#endif // WEBAPI_PLUGINS_IOTCON_CLIENT_MANAGER_H__ diff --git a/src/iotcon/iotcon_instance.cc b/src/iotcon/iotcon_instance.cc index 6f2e9d15..ae913dff 100644 --- a/src/iotcon/iotcon_instance.cc +++ b/src/iotcon/iotcon_instance.cc @@ -17,12 +17,15 @@ #include "iotcon/iotcon_instance.h" #include +#include #include "common/logger.h" #include "common/scope_exit.h" #include "common/tools.h" #include "iotcon/iotcon_utils.h" +#include "iotcon/iotcon_server_manager.h" +#include "iotcon/iotcon_client_manager.h" namespace extension { namespace iotcon { @@ -33,8 +36,6 @@ typedef struct { common::PostCallback fun; } CallbackData; -const std::string kTimeout = "timeout"; - #define CHECK_EXIST(args, name) \ if (args.end() == args.find(name)) { \ return common::TypeMismatchError(std::string(name) + " is required argument"); \ @@ -57,6 +58,7 @@ const picojson::value& GetArg(const picojson::object& args, const std::string& n const common::ListenerToken kResourceRequestListenerToken{"ResourceRequestListener"}; const common::ListenerToken kFindResourceListenerToken{"FindResourceListener"}; +const common::ListenerToken kPresenceEventListenerToken{"PresenceEventListener"}; const std::string kObserverIds = "observerIds"; const std::string kQos = "qos"; @@ -64,6 +66,7 @@ const std::string kChildId = "childId"; const std::string kType = "type"; const std::string kInterface = "iface"; +const std::string kTimeout = "timeout"; } // namespace IotconInstance::IotconInstance() { @@ -126,6 +129,14 @@ IotconInstance::IotconInstance() { } else { LoggerD("Iotcon connection changed callback is registered"); } + + ret = iotcon_start_presence(0); + if (IOTCON_ERROR_NONE != ret) { + LoggerE("Could not start presence: %s", + get_error_message(ret)); + } else { + LoggerD("Iotcon iotcon_start_presence"); + } } } @@ -146,12 +157,18 @@ void IotconInstance::ConnectionChangedCallback(bool is_connected, void* user_dat if (!ret) { LoggerD("Connection recovered, but restoring handles failed"); } + + ret = IotconClientManager::GetInstance().RestoreHandles(); + if (!ret) { + LoggerD("Connection recovered, but restoring presence failed"); + } } } IotconInstance::~IotconInstance() { ScopeLogger(); + iotcon_stop_presence(); iotcon_remove_connection_changed_cb(ConnectionChangedCallback, this); iotcon_disconnect(); } @@ -553,15 +570,65 @@ common::TizenResult IotconInstance::ClientFindResource(const picojson::object& a common::TizenResult IotconInstance::ClientAddPresenceEventListener(const picojson::object& args) { ScopeLogger(); - return common::UnknownError("Not implemented"); + + CHECK_EXIST(args, kHostAddress); + CHECK_EXIST(args, kResourceType); + CHECK_EXIST(args, kConnectivityType); + + char* host = nullptr; + if (args.find(kHostAddress)->second.is()) { + host = const_cast(args.find(kHostAddress)->second.get().c_str()); + } + + char* resource_type = nullptr; + if (args.find(kResourceType)->second.is()) { + resource_type = const_cast(args.find(kResourceType)->second.get().c_str()); + } + + auto& con_type = GetArg(args, kConnectivityType); + if (!con_type.is()) { + return common::TypeMismatchError("connectivityType needs to be a string"); + } + iotcon_connectivity_type_e con_type_e = IotconUtils::ToConnectivityType( + con_type.get()); + + PresenceEventPtr presence{new PresenceEvent()}; + auto ret = IotconClientManager::GetInstance().AddPresenceEventListener( + host, con_type_e, resource_type, presence); + if (!ret) { + return ret; + } + + long long id = presence->id; + + presence->presence_listener = [this, id](const common::TizenResult&, const picojson::value& v) { + picojson::value response{picojson::object{}}; + auto& obj = response.get(); + + obj.insert(std::make_pair(kId, picojson::value{static_cast(id)})); + obj.insert(std::make_pair("data", v)); + + Post(kPresenceEventListenerToken, common::TizenSuccess{response}); + }; + + return common::TizenSuccess(picojson::value{static_cast(id)}); } common::TizenResult IotconInstance::ClientRemovePresenceEventListener(const picojson::object& args) { ScopeLogger(); - return common::UnknownError("Not implemented"); + + CHECK_EXIST(args, kId); + + auto ret = IotconClientManager::GetInstance().RemovePresenceEventListener(GetId(args)); + + if (!ret) { + return ret; + } + + return common::TizenSuccess(); } -void IotconPDeviceInfoCb(iotcon_device_info_h device_info, +void IotconDeviceInfoCb(iotcon_device_info_h device_info, iotcon_error_e result, void *user_data) { ScopeLogger(); @@ -572,7 +639,7 @@ void IotconPDeviceInfoCb(iotcon_device_info_h device_info, if (IOTCON_ERROR_NONE != result) { ret = IotconUtils::ConvertIotconError(result); } else { - auto ret = IotconUtils::DeviceInfoToJson(device_info,&v.get()); + ret = IotconUtils::DeviceInfoToJson(device_info,&v.get()); } data->fun(ret, v); @@ -593,7 +660,7 @@ common::TizenResult IotconInstance::ClientGetDeviceInfo(const picojson::object& CallbackData* data = new CallbackData{SimplePost(token)}; auto result = IotconUtils::ConvertIotconError( - iotcon_get_device_info(host.c_str(), con_type_e, IotconPDeviceInfoCb, + iotcon_get_device_info(host.c_str(), con_type_e, IotconDeviceInfoCb, data)); if (!result) { diff --git a/src/iotcon/iotcon_instance.h b/src/iotcon/iotcon_instance.h index 0793370a..af3c184d 100644 --- a/src/iotcon/iotcon_instance.h +++ b/src/iotcon/iotcon_instance.h @@ -19,7 +19,7 @@ #include "common/tizen_instance.h" -#include "iotcon/iotcon_server_manager.h" +#include namespace extension { namespace iotcon { diff --git a/src/iotcon/iotcon_utils.cc b/src/iotcon/iotcon_utils.cc index 2d6c192f..88c8a711 100644 --- a/src/iotcon/iotcon_utils.cc +++ b/src/iotcon/iotcon_utils.cc @@ -66,6 +66,16 @@ namespace { X(IOTCON_QOS_HIGH, "HIGH") \ XD(IOTCON_QOS_LOW, "unknown") +#define IOTCON_PRESENCE_RESULT_E \ + X(IOTCON_PRESENCE_OK, "OK") \ + X(IOTCON_PRESENCE_STOPPED, "STOPPED") \ + XD(IOTCON_PRESENCE_TIMEOUT, "TIMEOUT") + +#define IOTCON_PRESENCE_TRIGGER_E \ + X(IOTCON_PRESENCE_RESOURCE_CREATED, "CREATED") \ + X(IOTCON_PRESENCE_RESOURCE_UPDATED, "UPDATED") \ + XD(IOTCON_PRESENCE_RESOURCE_DESTROYED, "DESTROYED") + } // namespace const std::string kIsDiscoverable = "isDiscoverable"; @@ -118,6 +128,9 @@ const std::string kSpecVersion = "specVersion"; const std::string kOicDeviceId = "oicDeviceId"; const std::string kDataModelVersion = "dataModelVersion"; +const std::string kResultType = "resultType"; +const std::string kTriggerType = "triggerType"; + using common::TizenResult; using common::TizenSuccess; @@ -1223,6 +1236,108 @@ common::TizenResult IotconUtils::StateListFromJson(const picojson::array& l, return TizenSuccess(); } +common::TizenResult IotconUtils::PresenceResponseToJson( + iotcon_presence_response_h presence, picojson::object* out) { + ScopeLogger(); + + { + // hostAddress + char* host = nullptr; + auto result = ConvertIotconError(iotcon_presence_response_get_host_address(presence, + &host)); + if (!result || !host) { + LogAndReturnTizenError(result, ("iotcon_presence_response_get_host_address() failed")); + } + out->insert(std::make_pair(kHostAddress, picojson::value{std::string(host)})); + } + + { + // connectivityType + iotcon_connectivity_type_e con_type = IOTCON_CONNECTIVITY_IPV4; + auto result = ConvertIotconError(iotcon_presence_response_get_connectivity_type(presence, + &con_type)); + if (!result) { + LogAndReturnTizenError(result, ("iotcon_presence_response_get_connectivity_type() failed")); + } + out->insert(std::make_pair(kConnectivityType, picojson::value{ + FromConnectivityType(con_type)})); + } + + { + // resourceType + char* resource_type = nullptr; + auto result = ConvertIotconError(iotcon_presence_response_get_resource_type(presence, + &resource_type)); + if (!result || !resource_type) { + LoggerE("iotcon_presence_response_get_resource_type() failed"); + out->insert(std::make_pair(kResourceType, picojson::value())); + } else { + out->insert(std::make_pair(kResourceType, picojson::value{std::string(resource_type)})); + } + } + + // resultType + iotcon_presence_result_e result_type = IOTCON_PRESENCE_OK; + { + auto result = ConvertIotconError(iotcon_presence_response_get_result(presence, + &result_type)); + if (!result) { + LogAndReturnTizenError(result, ("iotcon_presence_response_get_result() failed")); + } + + out->insert(std::make_pair(kResultType, picojson::value{ + FromPresenceResponseResultType(result_type)})); + } + + { + // triggerType + iotcon_presence_trigger_e trigger_type = IOTCON_PRESENCE_RESOURCE_CREATED; + if (IOTCON_PRESENCE_OK == result_type) { + auto result = ConvertIotconError(iotcon_presence_response_get_trigger(presence, + &trigger_type)); + if (!result) { + LoggerE("iotcon_presence_response_get_trigger() failed"); + out->insert(std::make_pair(kTriggerType, picojson::value())); + } else { + out->insert(std::make_pair(kTriggerType, picojson::value{FromPresenceTriggerType( + trigger_type)})); + } + } else { + out->insert(std::make_pair(kTriggerType, picojson::value())); + } + + } + + return TizenSuccess(); +} + +common::TizenResult IotconUtils::ExtractFromPresenceEvent(const PresenceEventPtr& pointer, + char** host, + iotcon_connectivity_type_e* con_type, + char** resource_type) { + ScopeLogger(); + + auto result = ConvertIotconError(iotcon_presence_get_host_address(pointer->handle, + host)); + if (!result) { + LogAndReturnTizenError(result, ("Gathering presence host address failed")); + } + + result = ConvertIotconError(iotcon_presence_get_connectivity_type(pointer->handle, + con_type)); + if (!result) { + LogAndReturnTizenError(result, ("Gathering presence connectivity type failed")); + } + + result = ConvertIotconError(iotcon_presence_get_resource_type(pointer->handle, + resource_type)); + if (!result) { + LogAndReturnTizenError(result, ("Gathering presence resource type failed")); + } + + return TizenSuccess(); +} + common::TizenResult IotconUtils::PlatformInfoGetProperty(iotcon_platform_info_h platform, iotcon_platform_info_e property_e, const std::string& name, @@ -1484,6 +1599,22 @@ std::string IotconUtils::FromInterface(iotcon_interface_e e) { } } +std::string IotconUtils::FromPresenceResponseResultType(iotcon_presence_result_e e) { + ScopeLogger(); + + switch (e) { + IOTCON_PRESENCE_RESULT_E + } +} + +std::string IotconUtils::FromPresenceTriggerType(iotcon_presence_trigger_e e) { + ScopeLogger(); + + switch (e) { + IOTCON_PRESENCE_TRIGGER_E + } +} + #undef X #undef XD diff --git a/src/iotcon/iotcon_utils.h b/src/iotcon/iotcon_utils.h index fdbfc313..b8fb9345 100644 --- a/src/iotcon/iotcon_utils.h +++ b/src/iotcon/iotcon_utils.h @@ -40,6 +40,7 @@ extern const std::string kIsSlow; extern const std::string kIsSecure; extern const std::string kIsExplicitDiscoverable; extern const std::string kResourceTypes; +extern const std::string kResourceType; extern const std::string kResourceInterfaces; extern const std::string kResourceChildren; extern const std::string kUriPath; @@ -51,8 +52,12 @@ extern const std::string kConnectivityType; extern const std::string kResourceType; class ResourceInfo; +class PresenceEvent; + typedef std::shared_ptr ResourceInfoPtr; typedef std::map ResourceInfoMap; +typedef std::shared_ptr PresenceEventPtr; +typedef std::map PresenceMap; struct ResourceInfo { long long id; @@ -94,6 +99,12 @@ struct RemoteResourceInfo { } }; +struct PresenceEvent { + long long id; + iotcon_presence_h handle; + common::PostCallback presence_listener; +}; + class IotconUtils { public: static void PropertiesToJson(int properties, picojson::object* res); @@ -123,6 +134,12 @@ class IotconUtils { picojson::array* out); static common::TizenResult QueryToJson(iotcon_query_h query, picojson::object* out); + static common::TizenResult PresenceResponseToJson(iotcon_presence_response_h presence, + picojson::object* out); + static common::TizenResult ExtractFromPresenceEvent(const PresenceEventPtr& pointer, + char** host, + iotcon_connectivity_type_e* con_type, + char** resource_type); static common::TizenResult PlatformInfoToJson(iotcon_platform_info_h platform, picojson::object* out); static common::TizenResult PlatformInfoGetProperty(iotcon_platform_info_h platform, @@ -150,6 +167,8 @@ class IotconUtils { static std::string FromRequestType(iotcon_request_type_e e); static std::string FromObserveType(iotcon_observe_type_e e); static std::string FromInterface(iotcon_interface_e e); + static std::string FromPresenceResponseResultType(iotcon_presence_result_e e); + static std::string FromPresenceTriggerType(iotcon_presence_trigger_e e); static iotcon_interface_e ToInterface(const std::string& e); static iotcon_connectivity_type_e ToConnectivityType(const std::string& e);