namespace iotcon {
namespace {
-const std::string kCallbackId = "callbackId";
-const std::string kIsDiscoverable = "isDiscoverable";
-const std::string kIsObservable = "isObservable";
-const std::string kResourceTypes = "resourceTypes";
-const std::string kUriPath = "uriPath";
-
#define CHECK_EXIST(args, name, out) \
if (!args.contains(name)) {\
std::string message = std::string(name) + " is required argument";\
if (IOTCON_ERROR_NONE != ret) {
LoggerE("Could not connnect to iotcon service: %s", get_error_message(ret));
} else {
- ret = iotcon_add_connection_changed_cb(ConnectionChangedCallback, nullptr);
+ LoggerD("Iotcon service connected");
+ ret = iotcon_add_connection_changed_cb(ConnectionChangedCallback, this);
if (IOTCON_ERROR_NONE != ret) {
LoggerE("Could not add connection changed callback for iotcon service: %s",
get_error_message(ret));
+ } else {
+ LoggerD("Iotcon connection changed callback is registered");
}
}
}
void IotconInstance::ConnectionChangedCallback(bool is_connected, void* user_data) {
LoggerD("Enter");
-
- // try to recover connection to iotcon service
if (!is_connected) {
- int ret = iotcon_connect();
- if (IOTCON_ERROR_NONE != ret) {
- LoggerE("Could not connnect to iotcon service: %s", get_error_message(ret));
+ LoggerD("Connection lost, need to wait for connection recovery");
+ } else {
+ IotconInstance* instance = static_cast<IotconInstance*>(user_data);
+ if (!instance) {
+ LoggerE("instance is NULL");
+ return;
+ }
+
+ LoggerD("Connection recovered, restoring handles");
+ PlatformResult ret = instance->manager_.RestoreHandles();
+ if (ret.IsError()) {
+ LoggerD("Connection recovered, but restoring handles failed");
}
- // TODO consider re-adding connection changed listener with iotcon_add_connection_changed_cb()
}
}
IotconInstance::~IotconInstance() {
LoggerD("Enter");
- iotcon_remove_connection_changed_cb(ConnectionChangedCallback, nullptr);
+ iotcon_remove_connection_changed_cb(ConnectionChangedCallback, this);
iotcon_disconnect();
}
picojson::object& out) {
LoggerD("Enter");
LoggerD("args: %s", args.serialize().c_str());
- //args: {"callbackId":2,"isDiscoverable":true,
- //"isObservable":true,"resourceTypes":["t1","t2"],"uriPath":"uriPath"}
-
CHECK_EXIST(args, kCallbackId, out)
CHECK_EXIST(args, kIsDiscoverable, out)
CHECK_EXIST(args, kIsObservable, out)
CHECK_EXIST(args, kResourceTypes, out)
+ CHECK_EXIST(args, kResourceInterfaces, out)
CHECK_EXIST(args, kUriPath, out)
const double callback_id = args.get(kCallbackId).get<double>();
+ // TODO consider support other properties
const bool is_discoverable = args.get(kIsDiscoverable).get<bool>();
const bool is_observable = args.get(kIsObservable).get<bool>();
- const auto& resource_type = args.get(kResourceTypes).get<picojson::array>();
+ const auto& resource_types = args.get(kResourceTypes).get<picojson::array>();
+ const auto& resource_interfaces = args.get(kResourceInterfaces).get<picojson::array>();
const std::string& uri_path = args.get(kUriPath).get<std::string>();
- auto create = [this, callback_id, is_discoverable, is_observable, resource_type, uri_path]
+ auto create = [this, callback_id, is_discoverable, is_observable,
+ resource_types, uri_path, resource_interfaces]
(const std::shared_ptr<picojson::value>& response) -> void {
LoggerD("Create resource");
+
picojson::value result = picojson::value(picojson::object());
- // TODO implement CreateResource
- PlatformResult ret = manager_.CreateResource();
+ ResourceInfoPtr resource{new ResourceInfo()};
+ PlatformResult ret = manager_.CreateResource(uri_path, resource_interfaces, resource_types,
+ is_discoverable, is_observable, resource);
+ if (ret.IsError()) {
+ LogAndReportError(ret,&(response->get<picojson::object>()));
+ return;
+ }
+ LoggerD("RESOURCE\nid: %lld\nhandle: %p", resource->id, resource->handle);
+
+ ret = IotconUtils::ResourceToJson(resource, manager_, &(result.get<picojson::object>()));
if (ret.IsError()) {
LogAndReportError(ret,&(response->get<picojson::object>()));
return;
void IotconInstance::IotconServerRemoveResource(const picojson::value& args,
picojson::object& out) {
LoggerD("Enter");
-
}
void IotconInstance::IotconServerUpdateResource(const picojson::value& args,
picojson::object& out) {
LoggerD("Enter");
-
}
void IotconInstance::IotconGetTimeout(const picojson::value& args,
picojson::object& out) {
LoggerD("Enter");
-
}
void IotconInstance::IotconSetTimeout(const picojson::value& args,
picojson::object& out) {
LoggerD("Enter");
-
}
} // namespace iotcon
using common::ErrorCode;
IotconServerManager::IotconServerManager(IotconInstance* instance)
- : instance_(instance) {
+ : instance_(instance),
+ global_id_(0) {
LoggerD("Entered");
}
PlatformResult IotconServerManager::RestoreHandles() {
LoggerD("Entered");
+
+ for (auto it = resource_map_.begin(); it != resource_map_.end(); ++it) {
+ LoggerD ("Restoring handle for resource with id: %lld", it->first);
+ ResourceInfoPtr resource = it->second;
+
+ char* uri_path = nullptr;
+ iotcon_resource_types_h res_types = nullptr;
+ int ifaces = 0;
+ int properties = 0;
+ PlatformResult res = IotconUtils::ExtractFromResource(resource, &uri_path,
+ &res_types, &ifaces, &properties);
+ if (res.IsError()){
+ return res;
+ }
+
+ const iotcon_resource_h old_handle = resource->handle;
+ LoggerD("Create resource from backup data, uri: %s, res_types: %p, ifaces: %d, properties: %d",
+ uri_path, res_types, ifaces, properties);
+
+ int ret = iotcon_resource_create(uri_path, res_types, ifaces, properties,
+ RequestHandler, // request_callback
+ nullptr, // user_data
+ &(resource->handle));
+ if (IOTCON_ERROR_NONE != ret || nullptr == resource->handle) {
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.",
+ ("iotcon_resource_create failed: %d (%s)",
+ ret, get_error_message(ret)));
+ }
+ LoggerD("new handle: %p", (resource->handle));
+ if (old_handle) {
+ LoggerD("destroy handle which is currently invalid: %p", old_handle);
+ iotcon_resource_destroy(old_handle);
+ }
+ }
+ // TODO
+ // bind children (consider if it is necessary?
+ // Maybe holding children in resource_map is enough)
+
+ return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+void IotconServerManager::RequestHandler(iotcon_resource_h resource,
+ iotcon_request_h request, void *user_data) {
+ LoggerD("Entered");
+ // TODO probably should be handled somehow later
+}
+
+PlatformResult IotconServerManager::CreateResource(const std::string& uri_path,
+ const picojson::array& interfaces_array,
+ const picojson::array& types_array,
+ bool is_discoverable,
+ bool is_observable,
+ ResourceInfoPtr res_pointer) {
+ LoggerD("Entered");
+
+ int ret;
+ int interfaces = IOTCON_INTERFACE_NONE;
+ PlatformResult res = IotconUtils::ArrayToInterfaces(interfaces_array, &interfaces);
+ if (res.IsError()) {
+ return res;
+ }
+
+ iotcon_resource_types_h resource_types = nullptr;
+ res = IotconUtils::ArrayToTypes(types_array, &resource_types);
+ if (res.IsError()) {
+ return res;
+ }
+
+ // TODO consider support other properties
+ int properties = ((is_discoverable ? IOTCON_RESOURCE_DISCOVERABLE : IOTCON_RESOURCE_NO_PROPERTY) |
+ (is_observable ? IOTCON_RESOURCE_OBSERVABLE : IOTCON_RESOURCE_NO_PROPERTY) |
+ IOTCON_RESOURCE_ACTIVE);
+
+ // Create resource
+ ret = iotcon_resource_create(uri_path.c_str(),
+ resource_types,
+ interfaces,
+ properties,
+ RequestHandler, // request_callback
+ nullptr, // user_data
+ &(res_pointer->handle));
+ if (IOTCON_ERROR_NONE != ret || nullptr == res_pointer->handle) {
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.",
+ ("iotcon_resource_create failed: %d (%s)",
+ ret, get_error_message(ret)));
+ }
+
+ // storing ResourceInfo into map
+ res_pointer->id = ++global_id_;
+ resource_map_.insert(std::make_pair(res_pointer->id, res_pointer));
return PlatformResult(ErrorCode::NO_ERROR);
}
-PlatformResult IotconServerManager::CreateResource() {
+common::PlatformResult IotconServerManager::GetResourceById(long long id,
+ ResourceInfoPtr* res_pointer) const {
LoggerD("Entered");
- // TODO implement
- return PlatformResult(ErrorCode::NOT_SUPPORTED_ERR, "Not implemented yet");
+ auto it = resource_map_.find(id);
+ if (it == resource_map_.end()) {
+ LoggerE("Not found such resource");
+ return PlatformResult(ErrorCode::NOT_FOUND_ERR, "Not found such resource");
+ }
+ LoggerE("Resource found");
+ *res_pointer = it->second;
+ return PlatformResult(ErrorCode::NO_ERROR);
}
} // namespace iotcon
#include <string>
#include <iotcon.h>
+#include "iotcon/iotcon_utils.h"
+
#include "common/picojson.h"
#include "common/platform_result.h"
namespace extension {
namespace iotcon {
-struct ResourceInfo {
- const char *uri_path;
- iotcon_resource_types_h res_types;
- int ifaces;
- int properties;
- iotcon_resource_h handle;
- ResourceInfo() :
- uri_path(nullptr), res_types(nullptr), ifaces(0),
- properties(0), handle(nullptr) {}
- ~ResourceInfo() {
- delete uri_path;
- iotcon_resource_types_destroy(res_types);
- iotcon_resource_destroy (handle);
- }
-};
-
-typedef std::shared_ptr<ResourceInfo> ResourceInfoPtr;
-typedef std::map<long long, ResourceInfoPtr> ResourceInfoMap;
-
class IotconInstance;
class IotconServerManager {
IotconServerManager(IotconInstance* instance);
~IotconServerManager();
+ static void RequestHandler(iotcon_resource_h resource,
+ iotcon_request_h request, void *user_data);
common::PlatformResult RestoreHandles();
-
- common::PlatformResult CreateResource(/*std::string uri_path, bool is_discoverable,
- bool is_observable, picojson::array array,
- iotcon_resource_h* res_handle*/);
-
+ common::PlatformResult CreateResource(const std::string& uri_path,
+ const picojson::array& interfaces_array,
+ const picojson::array& types_array, bool is_discoverable,
+ bool is_observable,
+ ResourceInfoPtr res_pointer);
+ common::PlatformResult GetResourceById(long long id, ResourceInfoPtr* res_pointer) const;
private:
IotconInstance* instance_;
ResourceInfoMap resource_map_;
+ long long global_id_;
};
} // namespace iotcon
} // namespace extension
#include "common/platform_exception.h"
#include "common/scope_exit.h"
+#include "iotcon/iotcon_server_manager.h"
+
namespace extension {
namespace iotcon {
+const std::string kCallbackId = "callbackId";
+const std::string kIsDiscoverable = "isDiscoverable";
+const std::string kIsObservable = "isObservable";
+const std::string kResourceTypes = "resourceTypes";
+const std::string kResourceInterfaces = "resourceInterfaces";
+const std::string kResourceChildren = "resources";
+const std::string kUriPath = "uriPath";
+const std::string kResourceId = "id";
+
+const std::string kInterfaceDefault = "DEFAULT";
+const std::string kInterfaceLink = "LINK";
+const std::string kInterfaceBatch = "BATCH";
+const std::string kInterfaceGroup = "GROUP";
+
using common::PlatformResult;
using common::ErrorCode;
-PlatformResult IotconUtils::ResourceToJson(iotcon_resource_h handle, picojson::value* res) {
+PlatformResult IotconUtils::StringToInterface(const std::string& interface, iotcon_interface_e* res) {
LoggerD("Entered");
+ if (kInterfaceDefault == interface) {
+ *res = IOTCON_INTERFACE_DEFAULT;
+ } else if (kInterfaceLink == interface) {
+ *res = IOTCON_INTERFACE_LINK;
+ } else if (kInterfaceBatch == interface) {
+ *res = IOTCON_INTERFACE_BATCH;
+ } else if (kInterfaceGroup == interface) {
+ *res = IOTCON_INTERFACE_GROUP;
+ } else {
+ return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Not supported interface name");
+ }
+ return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult IotconUtils::ArrayToInterfaces(const picojson::array& interfaces, int* res) {
+ LoggerD("Entered");
+ int result_value = IOTCON_INTERFACE_NONE;
+
+ for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
+ if (!iter->is<std::string>()) {
+ LoggerE("Array holds incorrect interface names");
+ return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Array holds incorrect interface names");
+ } else {
+ iotcon_interface_e interface = IOTCON_INTERFACE_NONE;
+ PlatformResult ret = StringToInterface(iter->get<std::string>(), &interface);
+ if (ret.IsError()) {
+ return ret;
+ }
+ result_value |= interface;
+ }
+ }
+ *res = result_value;
+ return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+picojson::array IotconUtils::InterfacesToArray(int interfaces) {
+ LoggerD("Entered");
+ picojson::array res;
+ if (interfaces & IOTCON_INTERFACE_DEFAULT) {
+ res.push_back(picojson::value(kInterfaceDefault));
+ }
+ if (interfaces & IOTCON_INTERFACE_LINK) {
+ res.push_back(picojson::value(kInterfaceLink));
+ }
+ if (interfaces & IOTCON_INTERFACE_BATCH) {
+ res.push_back(picojson::value(kInterfaceBatch));
+ }
+ if (interfaces & IOTCON_INTERFACE_GROUP) {
+ res.push_back(picojson::value(kInterfaceGroup));
+ }
+ return res;
+}
+
+PlatformResult IotconUtils::ArrayToTypes(const picojson::array& types, iotcon_resource_types_h* res) {
+ LoggerD("Entered");
+
+ iotcon_resource_types_h resource_types = nullptr;
+ int ret = iotcon_resource_types_create(&resource_types);
+ if (IOTCON_ERROR_NONE != ret) {
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.",
+ ("iotcon_resource_types_create failed: %d (%s)",
+ ret, get_error_message(ret)));
+ }
+
+ for (auto iter = types.begin(); iter != types.end(); ++iter) {
+ if (!iter->is<std::string>()) {
+ LoggerE("Array holds incorrect types");
+ return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Array holds incorrect types");
+ } else {
+ ret = iotcon_resource_types_add(resource_types, iter->get<std::string>().c_str());
+ if (IOTCON_ERROR_NONE != ret) {
+ iotcon_resource_types_destroy(resource_types);
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unknown error occurred.",
+ ("iotcon_resource_types_add failed: %d (%s)",
+ ret, get_error_message(ret)));
+ }
+ }
+ }
+ *res = resource_types;
+ return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+static bool ResourceTypeIterator(const char *type, void *user_data) {
+ LoggerD("Enter");
+
+ picojson::array* array_data = static_cast<picojson::array*>(user_data);
+ if (!array_data) {
+ LoggerE("user_data is NULL");
+ return false;
+ }
+
+ array_data->push_back(picojson::value(type));
+ return true;
+}
+
+PlatformResult IotconUtils::ExtractFromResource(const ResourceInfoPtr& pointer,
+ char** uri_path,
+ iotcon_resource_types_h* res_types,
+ int* ifaces,
+ int* properties) {
+ LoggerD("Entered");
+ int ret = iotcon_resource_get_uri_path (pointer->handle, uri_path);
+ if (IOTCON_ERROR_NONE != ret) {
+ LoggerD("Error %s", get_error_message(ret));
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Gathering resource uri path failed");
+ }
+
+ ret = iotcon_resource_get_types (pointer->handle, res_types);
+ if (IOTCON_ERROR_NONE != ret) {
+ LoggerD("Error %s", get_error_message(ret));
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Gathering resource types failed");
+ }
+
+ ret = iotcon_resource_get_interfaces (pointer->handle, ifaces);
+ if (IOTCON_ERROR_NONE != ret) {
+ LoggerD("Error %s", get_error_message(ret));
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Gathering resource interfaces failed");
+ }
+
+ ret = iotcon_resource_get_properties (pointer->handle, properties);
+ if (IOTCON_ERROR_NONE != ret) {
+ LoggerD("Error %s", get_error_message(ret));
+ return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Gathering resource properties failed");
+ }
+ return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult IotconUtils::ResourceToJson(ResourceInfoPtr pointer,
+ const IotconServerManager& manager,
+ picojson::object* res) {
+ LoggerD("Entered");
+
+ char* uri_path = nullptr;
+ iotcon_resource_types_h res_types = nullptr;
+ int ifaces = 0;
+ int properties = 0;
+ PlatformResult ret = ExtractFromResource(pointer, &uri_path, &res_types, &ifaces, &properties);
+ if (ret.IsError()){
+ return ret;
+ }
+ res->insert(std::make_pair(kResourceId, picojson::value(static_cast<double>(pointer->id))));
+ res->insert(std::make_pair(kUriPath, picojson::value(uri_path)));
+
+ picojson::array types;
+ iotcon_resource_types_foreach(res_types, ResourceTypeIterator, &types);
+ res->insert(std::make_pair(kResourceTypes, picojson::value(types)));
+
+ res->insert(std::make_pair(kResourceInterfaces,
+ picojson::value(InterfacesToArray(ifaces))));
+ bool observable = properties & IOTCON_RESOURCE_OBSERVABLE;
+ res->insert(std::make_pair(kIsObservable, picojson::value(observable)));
+ bool discoverable = properties & IOTCON_RESOURCE_DISCOVERABLE;
+ res->insert(std::make_pair(kIsDiscoverable, picojson::value(discoverable)));
+
+ picojson::array children;
+ for (auto iter = pointer->children_ids.begin(); iter != pointer->children_ids.end(); ++iter) {
+ if (pointer->id == (*iter)) {
+ // prevent infinite recurrence
+ continue;
+ }
+ ResourceInfoPtr resource;
+ ret = manager.GetResourceById((*iter), &resource);
+ if (ret.IsSuccess()) {
+ LoggerD("Found children RESOURCE\nid: %lld\nhandle: %p", resource->id, resource->handle);
+
+ picojson::value child = picojson::value(picojson::object());
+ ret = IotconUtils::ResourceToJson(resource, manager, &(child.get<picojson::object>()));
+ if (ret.IsSuccess()) {
+ children.push_back(child);
+ }
+ } else {
+ LoggerD("Not found such resource");
+ }
+ }
+ res->insert(std::make_pair(kResourceChildren, picojson::value(children)));
+ // observerIds would be done on demand from JS
- // TODO implement conversion
- return LogAndCreateResult(ErrorCode::NOT_SUPPORTED_ERR, "Not implemented yet");
+ return PlatformResult(ErrorCode::NO_ERROR);
}
} // namespace iotcon
#define WEBAPI_PLUGINS_IOTCON_IOTCON_UTILS_H__
#include <string>
+#include <memory>
+#include <vector>
+#include <map>
+#include <stdlib.h>
#include <iotcon.h>
namespace extension {
namespace iotcon {
+extern const std::string kCallbackId;
+extern const std::string kIsDiscoverable;
+extern const std::string kIsObservable;
+extern const std::string kResourceTypes;
+extern const std::string kResourceInterfaces;
+extern const std::string kResourceChildren;
+extern const std::string kUriPath;
+extern const std::string kResourceId;
+
+struct ResourceInfo {
+ long long id;
+ std::vector<long long> children_ids;
+ iotcon_resource_h handle;
+ ResourceInfo() :
+ id(0), handle(nullptr) {}
+ ~ResourceInfo() {
+ iotcon_resource_destroy (handle);
+ }
+};
+
+typedef std::shared_ptr<ResourceInfo> ResourceInfoPtr;
+typedef std::map<long long, ResourceInfoPtr> ResourceInfoMap;
+
+class IotconServerManager;
class IotconUtils {
public:
- static common::PlatformResult ResourceToJson(iotcon_resource_h handle, picojson::value* res);
+ static common::PlatformResult StringToInterface(const std::string& interface, iotcon_interface_e* res);
+ static common::PlatformResult ArrayToInterfaces(const picojson::array& interfaces, int* res);
+ static picojson::array InterfacesToArray(int interfaces);
+ static common::PlatformResult ArrayToTypes(const picojson::array& types, iotcon_resource_types_h* res);
+ static common::PlatformResult ExtractFromResource(const ResourceInfoPtr& pointer,
+ char** uri_path,
+ iotcon_resource_types_h* res_types,
+ int* ifaces,
+ int* properties);
+ static common::PlatformResult ResourceToJson(ResourceInfoPtr pointer,
+ const IotconServerManager& manager,
+ picojson::object* res);
};
} // namespace iotcon