diff options
Diffstat (limited to 'src/cloudproxy-bindings.cpp')
-rwxr-xr-x | src/cloudproxy-bindings.cpp | 329 |
1 files changed, 80 insertions, 249 deletions
diff --git a/src/cloudproxy-bindings.cpp b/src/cloudproxy-bindings.cpp index 1a40730..c69e9c7 100755 --- a/src/cloudproxy-bindings.cpp +++ b/src/cloudproxy-bindings.cpp @@ -20,37 +20,20 @@ #include <memory> #include <algorithm> -#include <iothub.h> -#include <iothub_device_client.h> -#include <iothub_client_options.h> -#include <iothub_message.h> -#include <iothubtransportmqtt.h> -#include <azure_c_shared_utility/threadapi.h> // ThreadAPI_Sleep() -#include <azure_c_shared_utility/tickcounter.h> // tickcounter_ms_t - -#include "hmi-debug.h" #include "utils.h" #include "ClientManager.h" +#include "CloudType.h" +#include "AwsClient.h" +#include "AzureClient.h" #include <glib.h> -static const char* API_name{"cloudproxy"}; - -static std::string g_connectionString; -static IOTHUB_DEVICE_CLIENT_HANDLE g_device_handle{nullptr}; -static bool g_iot_inited{false}; - - +namespace +{ -static utils::scope_exit g_destroy([]{ - if (g_iot_inited) - { - if (g_device_handle) - IoTHubDeviceClient_Destroy(g_device_handle); +std::map<std::string, std::unique_ptr<CloudClient>> g_clouds; - IoTHub_Deinit(); - } -}); +} static bool loadConf() @@ -60,7 +43,7 @@ static bool loadConf() const char *p = getenv("AFM_APP_INSTALL_DIR"); if(!p) { - HMI_ERROR("cloudproxy-service", "AFM_APP_INSTALL_DIR is not set, try to find conf in %s", DEFAULT_ETC_PATH); + AFB_ERROR("AFM_APP_INSTALL_DIR is not set, try to find conf in %s", DEFAULT_ETC_PATH); p = DEFAULT_ETC_PATH; } @@ -70,273 +53,127 @@ static bool loadConf() g_autoptr(GKeyFile) conf_file = g_key_file_new(); g_autoptr(GError) error = nullptr; + AFB_DEBUG("Load config file: %s", conf_path.c_str()); if (!conf_file || !g_key_file_load_from_file(conf_file, conf_path.c_str(), G_KEY_FILE_NONE, &error)) { - HMI_ERROR("cloudproxy-service", "can't load file %s", conf_path.c_str()); - return false; - } - - g_autofree gchar *value = g_key_file_get_string(conf_file, "AzureCloudConnection", "DeviceConnectionString", &error); - if (value == nullptr) - { - HMI_ERROR("cloudproxy-service", "can't read DeviceConnectionString from config %d", conf_path.c_str()); - return false; - } - - g_connectionString = value; - if (g_connectionString.empty()) - { - HMI_ERROR("cloudproxy-service", "DeviceConnectionString is empty"); + AFB_ERROR("Can't load file %s", conf_path.c_str()); return false; } - return true; -} - - -//-------------- Iot callbacks -static void connection_status_callback(IOTHUB_CLIENT_CONNECTION_STATUS result, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void* user_context) -{ - HMI_NOTICE("cloudproxy-service", "%s called: result %d, reason %d", __FUNCTION__, result, reason); - - (void)reason; - (void)user_context; - // This sample DOES NOT take into consideration network outages. - if (result == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED && reason == IOTHUB_CLIENT_CONNECTION_OK) - { - HMI_NOTICE("cloudproxy-service", "The device client is connected to iothub"); - } - else - { - HMI_NOTICE("cloudproxy-service", "The device client has been disconnected"); - } -} - -static IOTHUBMESSAGE_DISPOSITION_RESULT receive_msg_callback(IOTHUB_MESSAGE_HANDLE message, void* user_context) -{ - HMI_NOTICE("cloudproxy-service", "%s called", __FUNCTION__); - (void)user_context; - const char* messageId; - const char* correlationId; - - IOTHUBMESSAGE_CONTENT_TYPE content_type = IoTHubMessage_GetContentType(message); - - if (content_type == IOTHUBMESSAGE_BYTEARRAY) + //-- Azure parameters: { - const unsigned char* buff_msg; - size_t buff_len; + std::unique_ptr<CloudClient> azure{new AzureClient}; + if (!azure->loadConf(conf_file)) + return false; - if (IoTHubMessage_GetByteArray(message, &buff_msg, &buff_len) != IOTHUB_MESSAGE_OK) - { - HMI_ERROR("cloudproxy-service", "Failure retrieving byte array message"); - } - else - { - HMI_NOTICE("cloudproxy-service", "Received Binary message, size %d, data '%.*s'", (int)buff_len, (int)buff_len, buff_msg); - } - - const char* app_id = IoTHubMessage_GetProperty(message, "application_id"); - HMI_NOTICE("cloudproxy-service", "Received property 'application_id': %s", (app_id ? app_id : "<unavailable>")); - - if (app_id && app_id[0]) - ClientManager::instance().emitReceivedMessage(app_id, std::string((const char*)buff_msg, buff_len)); - else - HMI_ERROR("cloudproxy-service", "Can't emit SendMessageConfirmation: appid is not valid"); - } - else if (content_type == IOTHUBMESSAGE_STRING) - { - const char* string_msg = IoTHubMessage_GetString(message); - if (string_msg == nullptr) - { - HMI_NOTICE("cloudproxy-service", "Failure retrieving String message"); - } - else - { - HMI_NOTICE("cloudproxy-service", "Received String message, size %d, data '%s'", strlen(string_msg), string_msg); - } - - const char* app_id = IoTHubMessage_GetProperty(message, "application_id"); - HMI_NOTICE("cloudproxy-service", "Received property 'application_id': %s", (app_id ? app_id : "<unavailable>")); - - if (app_id && app_id[0]) - ClientManager::instance().emitReceivedMessage(app_id, string_msg); + if (azure->enabled()) + g_clouds[CloudType::Azure] = std::move(azure); else - HMI_ERROR("cloudproxy-service", "Can't emit SendMessageConfirmation: appid is not valid"); - } - else - { - HMI_ERROR("cloudproxy-service", "Unsupported message content type"); - } - - return IOTHUBMESSAGE_ACCEPTED; -} - - -static int device_method_callback(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* resp_size, void* userContextCallback) -{ - HMI_NOTICE("cloudproxy-service", "%s called, method_name %s", __FUNCTION__, method_name); - - const char* device_id = (const char*)userContextCallback; - char* end = nullptr; - int newInterval; - - int status = 501; - const char* RESPONSE_STRING = "{ \"Response\": \"Unknown method requested.\" }"; - - HMI_NOTICE("cloudproxy-service", "Device Method called for device %s", device_id); - HMI_NOTICE("cloudproxy-service", "Device Method name: %s", method_name); - HMI_NOTICE("cloudproxy-service", "Device Method payload: %.*s", (int)size, (const char*)payload); - - HMI_NOTICE("cloudproxy-service", "Response status: %d", status); - HMI_NOTICE("cloudproxy-service", "Response payload: %s", RESPONSE_STRING); - - *resp_size = strlen(RESPONSE_STRING); - if ((*response = (unsigned char*)malloc(*resp_size)) == NULL) - { - status = -1; - } - else - { - memcpy(*response, RESPONSE_STRING, *resp_size); + g_clouds[CloudType::Azure].reset(); } - return status; -} - - -static void send_confirm_callback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback) -{ - HMI_NOTICE("cloudproxy-service", "%s called, result %d", __FUNCTION__, result); - (void)userContextCallback; - // When a message is sent this callback will get invoked - - HMI_NOTICE("cloudproxy-service", "Confirmation callback result %s", MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result)); - - const char* appid = (const char*)userContextCallback; - if (!appid || !appid[0]) + //-- AWS parameters: { - HMI_ERROR("cloudproxy-service", "Confirmation callback: appid is not set"); - - if (userContextCallback) - free(userContextCallback); + std::unique_ptr<CloudClient> aws{new AwsClient}; + if (!aws->loadConf(conf_file)) + return false; - return; - } - - ClientManager::instance().emitSendMessageConfirmation(appid, result == IOTHUB_CLIENT_CONFIRMATION_OK); - free(userContextCallback); -} -//-------------- - -//-------------- help functions -static bool createConnection() -{ - HMI_NOTICE("cloudproxy-service", "%s called", __FUNCTION__); - - if (g_device_handle) - { - HMI_WARNING("cloudproxy-service", "connection already created"); - return true; + if (aws->enabled()) + g_clouds[CloudType::Aws] = std::move(aws); + else + g_clouds[CloudType::Aws].reset(); } - g_device_handle = IoTHubDeviceClient_CreateFromConnectionString(g_connectionString.c_str(), MQTT_Protocol); - if (!g_device_handle) + if (!std::any_of(g_clouds.begin(), g_clouds.end(), [](const auto& c){ return !!c.second; })) { - HMI_ERROR("cloudproxy-service", "Failure creating IoTHubDeviceClient device"); + AFB_ERROR("All cloud connection types are disabled by configuration"); return false; } - bool traceOn = false; - IoTHubDeviceClient_SetOption(g_device_handle, OPTION_LOG_TRACE, &traceOn); - IoTHubDeviceClient_SetConnectionStatusCallback(g_device_handle, connection_status_callback, nullptr); - IoTHubDeviceClient_SetMessageCallback(g_device_handle, receive_msg_callback, nullptr); - IoTHubDeviceClient_SetDeviceMethodCallback(g_device_handle, device_method_callback, nullptr); - - tickcounter_ms_t ms_delay = 10; - IoTHubDeviceClient_SetOption(g_device_handle, OPTION_DO_WORK_FREQUENCY_IN_MS, &ms_delay); // DoWork multithread - return true; } -//-------------- - static void pingSample(afb_req_t request) { static int pingcount = 0; afb_req_success_f(request, json_object_new_int(pingcount), "Ping count = %d", pingcount); - HMI_NOTICE("cloudproxy-service", "Verbosity macro at level notice invoked at ping invocation count = %d", pingcount); + AFB_NOTICE("Verbosity macro at level notice invoked at ping invocation count = %d", pingcount); pingcount++; } -static bool initAzureSdk() -{ - //Allow program to try to establish connection several times - if (!g_iot_inited) - { - if(IoTHub_Init()) - { - HMI_ERROR("cloudproxy-service","Azure IoTHub_Init() failed"); - } - else - { - g_iot_inited = true; - } - } - - return g_iot_inited; -} - static void sendMessage(afb_req_t request) { - HMI_NOTICE("cloudproxy-service", "%s called", __FUNCTION__); + AFB_NOTICE("%s called", __FUNCTION__); json_object* object = afb_req_json(request); if (!object) { - HMI_ERROR("cloudproxy-service", "Can't parse request"); + AFB_ERROR("Can't parse request"); afb_req_fail_f(request, "failed", "called %s", __FUNCTION__); return; } const std::string appid{utils::get_application_id(request)}; - std::string data; - json_object *obj_data; - if(!json_object_object_get_ex(object, "data", &obj_data)) + if (appid.empty()) { - HMI_ERROR("cloudproxy-service", "can't obtain application_id or data from request"); + AFB_ERROR("can't obtain application_id from request"); + afb_req_fail_f(request, "failed", "called %s", __FUNCTION__); return; } - data = json_object_get_string(obj_data); - if (!g_device_handle && !createConnection()) + auto read_string = [object](const char* tag, std::string& read_to) + { + json_object* jobj{nullptr}; + if (!json_object_object_get_ex(object, tag, &jobj)) + { + AFB_ERROR("can't obtain %s from request", tag); + return false; + } + read_to = json_object_get_string(jobj); + return true; + }; + + std::string cloud_type; + if (!read_string("cloud_type", cloud_type)) { - HMI_ERROR("cloudproxy-service", "Can't create connection to cloud"); afb_req_fail_f(request, "failed", "called %s", __FUNCTION__); return; } - IOTHUB_MESSAGE_HANDLE message_handle = IoTHubMessage_CreateFromString(data.c_str()); + std::string data; + if (!read_string("data", data)) + { + afb_req_fail_f(request, "failed", "called %s", __FUNCTION__); + return; + } - utils::scope_exit message_handle_destroy([&message_handle](){ - // The message is copied to the sdk, so the we can destroy it - if (message_handle) - IoTHubMessage_Destroy(message_handle); - }); + if (!CloudType::isSupported(cloud_type)) + { + AFB_ERROR("Unsupported cloud type is requested: '%s'", cloud_type.c_str()); + afb_req_fail_f(request, "failed", "called %s", __FUNCTION__); + return; + } - if (!message_handle) + if (!g_clouds[cloud_type]) { - HMI_ERROR("cloudproxy-service", "Can't create IoTHubMessage message"); + AFB_ERROR("%s cloud connection is disabled by config", cloud_type.c_str()); afb_req_fail_f(request, "failed", "called %s", __FUNCTION__); return; } - IoTHubMessage_SetProperty(message_handle, "application_id", appid.c_str()); + CloudClient* client{g_clouds[cloud_type.c_str()].get()}; + if (!client->connected() && !client->createConnection()) + { + AFB_ERROR("Can't create connection to %s cloud", cloud_type.c_str()); + afb_req_fail_f(request, "failed", "called %s", __FUNCTION__); + return; + } - if (IoTHubDeviceClient_SendEventAsync(g_device_handle, message_handle, send_confirm_callback, strdup(appid.c_str()))) + if (!client->sendMessage(appid, data)) { - HMI_ERROR("cloudproxy-service", "Can't send IoTHubMessage message"); + AFB_ERROR("Can't send message to %s cloud", cloud_type.c_str()); afb_req_fail_f(request, "failed", "called %s", __FUNCTION__); return; } @@ -347,19 +184,19 @@ static void sendMessage(afb_req_t request) static void subscribe(afb_req_t request) { - HMI_NOTICE("cloudproxy-service", "%s called", __FUNCTION__); + AFB_NOTICE("%s called", __FUNCTION__); std::string req_appid{utils::get_application_id(request)}; if(req_appid.empty()) { - HMI_ERROR("cloudproxy-service", "Can't subscribe: empty appid"); + AFB_ERROR("Can't subscribe: empty appid"); afb_req_fail_f(request, "%s failed: application_id is not defined in request", __FUNCTION__); return; } if (!ClientManager::instance().handleRequest(request, __FUNCTION__, req_appid)) { - HMI_ERROR("cloudproxy-service", "%s failed in handleRequest", __FUNCTION__); + AFB_ERROR("%s failed in handleRequest", __FUNCTION__); afb_req_fail_f(request, "%s failed", __FUNCTION__); } else @@ -370,19 +207,19 @@ static void subscribe(afb_req_t request) static void unsubscribe(afb_req_t request) { - HMI_NOTICE("cloudproxy-service", "%s called", __FUNCTION__); + AFB_NOTICE("%s called", __FUNCTION__); std::string req_appid{utils::get_application_id(request)}; if(req_appid.empty()) { - HMI_ERROR("cloudproxy-service", "Can't unsubscribe: empty appid"); + AFB_ERROR("Can't unsubscribe: empty appid"); afb_req_fail_f(request, "%s failed: application_id is not defined in request", __FUNCTION__); return; } if (!ClientManager::instance().handleRequest(request, __FUNCTION__, req_appid)) { - HMI_ERROR("cloudproxy-service", "%s failedin handleRequest", __FUNCTION__); + AFB_ERROR("%s failedin handleRequest", __FUNCTION__); afb_req_fail_f(request, "%s failed", __FUNCTION__); } else @@ -406,17 +243,11 @@ static const afb_verb_t verbs[]= { static int preinit(afb_api_t api) { - HMI_NOTICE("cloudproxy-service", "binding preinit (was register)"); + AFB_NOTICE("binding preinit (was register)"); if (!loadConf()) { - HMI_ERROR("cloudproxy-service", "Can't load configuration file or configuration is wrong"); - return -1; - } - - if (!initAzureSdk()) - { - HMI_ERROR("cloudproxy-service", "Can't initialize Azure SDK"); + AFB_ERROR("Can't load configuration file or configuration is wrong"); return -1; } @@ -426,8 +257,8 @@ static int preinit(afb_api_t api) static int init(afb_api_t api) { - HMI_NOTICE("cloudproxy-service","binding init"); - return (g_iot_inited ? 0 : -1); + AFB_NOTICE("binding init"); + return 0; } const afb_binding_t afbBindingExport = { |