LCOV - code coverage report
Current view: top level - capi-machine-learning-inference-1.8.5/c/src - ml-api-service-offloading.c (source / functions) Coverage Total Hit
Test: ML API 1.8.5-0 platform/core/api/machine-learning#631dc84d7897cf891d276061d07fd0136e5e4915 Lines: 0.0 % 518 0
Test Date: 2024-05-23 14:26:16 Functions: 0.0 % 26 0

            Line data    Source code
       1              : /* SPDX-License-Identifier: Apache-2.0 */
       2              : /**
       3              :  * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved.
       4              :  *
       5              :  * @file ml-api-service-offloading.c
       6              :  * @date 26 Jun 2023
       7              :  * @brief ML offloading service of NNStreamer/Service C-API
       8              :  * @see https://github.com/nnstreamer/nnstreamer
       9              :  * @author Gichan Jang <gichan2.jang@samsung.com>
      10              :  * @bug No known bugs except for NYI items
      11              :  */
      12              : 
      13              : #include <glib.h>
      14              : #include <glib/gstdio.h>
      15              : #include <gio/gio.h>
      16              : #include <gst/gst.h>
      17              : #include <gst/gstbuffer.h>
      18              : #include <gst/app/app.h>
      19              : #include <string.h>
      20              : #include <curl/curl.h>
      21              : #include <json-glib/json-glib.h>
      22              : #include <nnstreamer-edge.h>
      23              : 
      24              : #include "ml-api-internal.h"
      25              : #include "ml-api-service.h"
      26              : #include "ml-api-service-private.h"
      27              : #include "ml-api-service-offloading.h"
      28              : #include "ml-api-service-training-offloading.h"
      29              : 
      30              : #define MAX_PORT_NUM_LEN 6U
      31              : 
      32              : /**
      33              :  * @brief Data struct for options.
      34              :  */
      35              : typedef struct
      36              : {
      37              :   gchar *host;
      38              :   guint port;
      39              :   gchar *topic;
      40              :   gchar *dest_host;
      41              :   guint dest_port;
      42              :   nns_edge_connect_type_e conn_type;
      43              :   nns_edge_node_type_e node_type;
      44              :   gchar *id;
      45              : } edge_info_s;
      46              : 
      47              : /**
      48              :  * @brief Structure for ml_service_offloading.
      49              :  */
      50              : typedef struct
      51              : {
      52              :   nns_edge_h edge_h;
      53              :   nns_edge_node_type_e node_type;
      54              : 
      55              :   gchar *path; /**< A path to save the received model file */
      56              :   GHashTable *table;
      57              : 
      58              :   ml_service_offloading_mode_e offloading_mode;
      59              :   void *priv;
      60              : } _ml_service_offloading_s;
      61              : 
      62              : /**
      63              :  * @brief Get ml-service node type from ml_option.
      64              :  */
      65              : static nns_edge_node_type_e
      66            0 : _mlrs_get_node_type (const gchar * value)
      67              : {
      68            0 :   nns_edge_node_type_e node_type = NNS_EDGE_NODE_TYPE_UNKNOWN;
      69              : 
      70            0 :   if (!value)
      71            0 :     return node_type;
      72              : 
      73            0 :   if (g_ascii_strcasecmp (value, "sender") == 0) {
      74            0 :     node_type = NNS_EDGE_NODE_TYPE_QUERY_CLIENT;
      75            0 :   } else if (g_ascii_strcasecmp (value, "receiver") == 0) {
      76            0 :     node_type = NNS_EDGE_NODE_TYPE_QUERY_SERVER;
      77              :   } else {
      78            0 :     _ml_error_report ("Invalid node type '%s', please check node type.", value);
      79              :   }
      80              : 
      81            0 :   return node_type;
      82              : }
      83              : 
      84              : /**
      85              :  * @brief Get nnstreamer-edge connection type
      86              :  */
      87              : static nns_edge_connect_type_e
      88            0 : _mlrs_get_conn_type (const gchar * value)
      89              : {
      90            0 :   nns_edge_connect_type_e conn_type = NNS_EDGE_CONNECT_TYPE_UNKNOWN;
      91              : 
      92            0 :   if (!value)
      93            0 :     return conn_type;
      94              : 
      95            0 :   if (0 == g_ascii_strcasecmp (value, "TCP"))
      96            0 :     conn_type = NNS_EDGE_CONNECT_TYPE_TCP;
      97            0 :   else if (0 == g_ascii_strcasecmp (value, "HYBRID"))
      98            0 :     conn_type = NNS_EDGE_CONNECT_TYPE_HYBRID;
      99            0 :   else if (0 == g_ascii_strcasecmp (value, "MQTT"))
     100            0 :     conn_type = NNS_EDGE_CONNECT_TYPE_MQTT;
     101            0 :   else if (0 == g_ascii_strcasecmp (value, "AITT"))
     102            0 :     conn_type = NNS_EDGE_CONNECT_TYPE_AITT;
     103              :   else
     104            0 :     conn_type = NNS_EDGE_CONNECT_TYPE_UNKNOWN;
     105              : 
     106            0 :   return conn_type;
     107              : }
     108              : 
     109              : /**
     110              :  * @brief Get edge info from ml_option.
     111              :  */
     112              : static void
     113            0 : _mlrs_get_edge_info (ml_option_h option, edge_info_s ** edge_info)
     114              : {
     115              :   edge_info_s *_info;
     116              :   void *value;
     117              : 
     118            0 :   *edge_info = _info = g_new0 (edge_info_s, 1);
     119              : 
     120            0 :   if (ML_ERROR_NONE == ml_option_get (option, "host", &value))
     121            0 :     _info->host = g_strdup (value);
     122              :   else
     123            0 :     _info->host = g_strdup ("localhost");
     124            0 :   if (ML_ERROR_NONE == ml_option_get (option, "port", &value))
     125            0 :     _info->port = (guint) g_ascii_strtoull (value, NULL, 10);
     126            0 :   if (ML_ERROR_NONE == ml_option_get (option, "dest-host", &value))
     127            0 :     _info->dest_host = g_strdup (value);
     128              :   else
     129            0 :     _info->dest_host = g_strdup ("localhost");
     130            0 :   if (ML_ERROR_NONE == ml_option_get (option, "dest-port", &value))
     131            0 :     _info->dest_port = (guint) g_ascii_strtoull (value, NULL, 10);
     132            0 :   if (ML_ERROR_NONE == ml_option_get (option, "connect-type", &value))
     133            0 :     _info->conn_type = _mlrs_get_conn_type (value);
     134              :   else
     135            0 :     _info->conn_type = NNS_EDGE_CONNECT_TYPE_UNKNOWN;
     136            0 :   if (ML_ERROR_NONE == ml_option_get (option, "topic", &value))
     137            0 :     _info->topic = g_strdup (value);
     138            0 :   if (ML_ERROR_NONE == ml_option_get (option, "node-type", &value))
     139            0 :     _info->node_type = _mlrs_get_node_type (value);
     140            0 :   if (ML_ERROR_NONE == ml_option_get (option, "id", &value))
     141            0 :     _info->id = g_strdup (value);
     142            0 : }
     143              : 
     144              : /**
     145              :  * @brief Set nns-edge info.
     146              :  */
     147              : static void
     148            0 : _mlrs_set_edge_info (edge_info_s * edge_info, nns_edge_h edge_h)
     149              : {
     150            0 :   char port[MAX_PORT_NUM_LEN] = { 0, };
     151              : 
     152            0 :   nns_edge_set_info (edge_h, "HOST", edge_info->host);
     153            0 :   g_snprintf (port, MAX_PORT_NUM_LEN, "%u", edge_info->port);
     154            0 :   nns_edge_set_info (edge_h, "PORT", port);
     155              : 
     156            0 :   if (edge_info->topic)
     157            0 :     nns_edge_set_info (edge_h, "TOPIC", edge_info->topic);
     158              : 
     159            0 :   nns_edge_set_info (edge_h, "DEST_HOST", edge_info->dest_host);
     160            0 :   g_snprintf (port, MAX_PORT_NUM_LEN, "%u", edge_info->dest_port);
     161            0 :   nns_edge_set_info (edge_h, "DEST_PORT", port);
     162            0 : }
     163              : 
     164              : /**
     165              :  * @brief Release edge info.
     166              :  */
     167              : static void
     168            0 : _mlrs_release_edge_info (edge_info_s * edge_info)
     169              : {
     170            0 :   g_free (edge_info->dest_host);
     171            0 :   g_free (edge_info->host);
     172            0 :   g_free (edge_info->topic);
     173            0 :   g_free (edge_info->id);
     174            0 :   g_free (edge_info);
     175            0 : }
     176              : 
     177              : /**
     178              :  * @brief Get ml offloading service type from ml_option.
     179              :  */
     180              : static ml_service_offloading_type_e
     181            0 : _mlrs_get_service_type (gchar * service_str)
     182              : {
     183            0 :   ml_service_offloading_type_e service_type =
     184              :       ML_SERVICE_OFFLOADING_TYPE_UNKNOWN;
     185              : 
     186            0 :   if (!service_str)
     187            0 :     return service_type;
     188              : 
     189            0 :   if (g_ascii_strcasecmp (service_str, "model_raw") == 0) {
     190            0 :     service_type = ML_SERVICE_OFFLOADING_TYPE_MODEL_RAW;
     191            0 :   } else if (g_ascii_strcasecmp (service_str, "model_uri") == 0) {
     192            0 :     service_type = ML_SERVICE_OFFLOADING_TYPE_MODEL_URI;
     193            0 :   } else if (g_ascii_strcasecmp (service_str, "pipeline_raw") == 0) {
     194            0 :     service_type = ML_SERVICE_OFFLOADING_TYPE_PIPELINE_RAW;
     195            0 :   } else if (g_ascii_strcasecmp (service_str, "pipeline_uri") == 0) {
     196            0 :     service_type = ML_SERVICE_OFFLOADING_TYPE_PIPELINE_URI;
     197            0 :   } else if (g_ascii_strcasecmp (service_str, "reply") == 0) {
     198            0 :     service_type = ML_SERVICE_OFFLOADING_TYPE_REPLY;
     199              :   } else {
     200            0 :     _ml_error_report ("Invalid service type '%s', please check service type.",
     201              :         service_str);
     202              :   }
     203              : 
     204            0 :   return service_type;
     205              : }
     206              : 
     207              : /**
     208              :  * @brief Get ml offloading service activation type.
     209              :  */
     210              : static gboolean
     211            0 : _mlrs_parse_activate (const gchar * activate)
     212              : {
     213            0 :   return (activate && g_ascii_strcasecmp (activate, "true") == 0);
     214              : }
     215              : 
     216              : /**
     217              :  * @brief Callback function for receving data using curl.
     218              :  */
     219              : static size_t
     220            0 : curl_mem_write_cb (void *data, size_t size, size_t nmemb, void *clientp)
     221              : {
     222            0 :   size_t recv_size = size * nmemb;
     223            0 :   GByteArray *array = (GByteArray *) clientp;
     224              : 
     225            0 :   if (!array || !data || recv_size == 0)
     226            0 :     return 0;
     227              : 
     228            0 :   g_byte_array_append (array, data, recv_size);
     229              : 
     230            0 :   return recv_size;
     231              : }
     232              : 
     233              : /**
     234              :  * @brief Register model file given by the offloading sender.
     235              :  */
     236              : static gboolean
     237            0 : _mlrs_model_register (gchar * service_key, nns_edge_data_h data_h,
     238              :     void *data, nns_size_t data_len, const gchar * dir_path)
     239              : {
     240            0 :   guint version = 0;
     241            0 :   g_autofree gchar *description = NULL;
     242            0 :   g_autofree gchar *name = NULL;
     243            0 :   g_autofree gchar *activate = NULL;
     244            0 :   g_autofree gchar *model_path = NULL;
     245            0 :   gboolean active_bool = TRUE;
     246            0 :   GError *error = NULL;
     247              : 
     248            0 :   if (NNS_EDGE_ERROR_NONE != nns_edge_data_get_info (data_h, "description",
     249              :           &description)
     250            0 :       || NNS_EDGE_ERROR_NONE != nns_edge_data_get_info (data_h, "name", &name)
     251            0 :       || NNS_EDGE_ERROR_NONE != nns_edge_data_get_info (data_h, "activate",
     252              :           &activate)) {
     253            0 :     _ml_loge ("Failed to get info from data handle.");
     254            0 :     return FALSE;
     255              :   }
     256              : 
     257            0 :   active_bool = _mlrs_parse_activate (activate);
     258            0 :   model_path = g_build_path (G_DIR_SEPARATOR_S, dir_path, name, NULL);
     259            0 :   if (!g_file_set_contents (model_path, (char *) data, data_len, &error)) {
     260            0 :     _ml_loge ("Failed to write data to file: %s",
     261              :         error ? error->message : "unknown error");
     262            0 :     g_clear_error (&error);
     263            0 :     return FALSE;
     264              :   }
     265              : 
     266              :   /**
     267              :    * @todo Hashing the path. Where is the default path to save the model file?
     268              :    */
     269            0 :   if (ML_ERROR_NONE != ml_service_model_register (service_key, model_path,
     270              :           active_bool, description, &version)) {
     271            0 :     _ml_loge ("Failed to register model, service key is '%s'.", service_key);
     272            0 :     return FALSE;
     273              :   }
     274              : 
     275            0 :   return TRUE;
     276              : }
     277              : 
     278              : /**
     279              :  * @brief Get path to save the model given from offloading sender.
     280              :  * @note The caller is responsible for freeing the returned data using g_free().
     281              :  */
     282              : static gchar *
     283            0 : _mlrs_get_model_dir_path (_ml_service_offloading_s * offloading_s,
     284              :     const gchar * service_key)
     285              : {
     286            0 :   g_autofree gchar *dir_path = NULL;
     287              : 
     288            0 :   if (offloading_s->path) {
     289            0 :     dir_path = g_strdup (offloading_s->path);
     290              :   } else {
     291            0 :     g_autofree gchar *current_dir = g_get_current_dir ();
     292              : 
     293            0 :     dir_path = g_build_path (G_DIR_SEPARATOR_S, current_dir, service_key, NULL);
     294            0 :     if (g_mkdir_with_parents (dir_path, 0755) < 0) {
     295            0 :       _ml_loge ("Failed to create directory '%s': %s", dir_path,
     296              :           g_strerror (errno));
     297            0 :       return NULL;
     298              :     }
     299              :   }
     300              : 
     301            0 :   return g_steal_pointer (&dir_path);
     302              : }
     303              : 
     304              : /**
     305              :  * @brief Get data from gievn uri
     306              :  */
     307              : static gboolean
     308            0 : _mlrs_get_data_from_uri (gchar * uri, GByteArray * array)
     309              : {
     310              :   CURL *curl;
     311              :   CURLcode res;
     312            0 :   gboolean ret = FALSE;
     313              : 
     314            0 :   curl = curl_easy_init ();
     315            0 :   if (curl) {
     316            0 :     if (CURLE_OK != curl_easy_setopt (curl, CURLOPT_URL, (gchar *) uri) ||
     317            0 :         CURLE_OK != curl_easy_setopt (curl, CURLOPT_FOLLOWLOCATION, 1L) ||
     318            0 :         CURLE_OK != curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION,
     319            0 :             curl_mem_write_cb) ||
     320            0 :         CURLE_OK != curl_easy_setopt (curl, CURLOPT_WRITEDATA,
     321              :             (void *) array)) {
     322            0 :       _ml_loge ("Failed to set option for curl easy handle.");
     323            0 :       ret = FALSE;
     324            0 :       goto done;
     325              :     }
     326              : 
     327            0 :     res = curl_easy_perform (curl);
     328              : 
     329            0 :     if (res != CURLE_OK) {
     330            0 :       _ml_loge ("curl_easy_perform failed: %s", curl_easy_strerror (res));
     331            0 :       ret = FALSE;
     332            0 :       goto done;
     333              :     }
     334              : 
     335            0 :     ret = TRUE;
     336              :   }
     337              : 
     338            0 : done:
     339            0 :   if (curl)
     340            0 :     curl_easy_cleanup (curl);
     341            0 :   return ret;
     342              : }
     343              : 
     344              : /**
     345              :  * @brief Process ml offloading service
     346              :  */
     347              : static int
     348            0 : _mlrs_process_service_offloading (nns_edge_data_h data_h, void *user_data)
     349              : {
     350              :   void *data;
     351              :   nns_size_t data_len;
     352            0 :   g_autofree gchar *service_str = NULL;
     353            0 :   g_autofree gchar *service_key = NULL;
     354            0 :   g_autofree gchar *dir_path = NULL;
     355              :   ml_service_offloading_type_e service_type;
     356            0 :   int ret = NNS_EDGE_ERROR_NONE;
     357            0 :   ml_service_s *mls = (ml_service_s *) user_data;
     358            0 :   _ml_service_offloading_s *offloading_s =
     359              :       (_ml_service_offloading_s *) mls->priv;
     360            0 :   ml_service_event_e event_type = ML_SERVICE_EVENT_UNKNOWN;
     361            0 :   ml_information_h info_h = NULL;
     362              : 
     363            0 :   ret = nns_edge_data_get (data_h, 0, &data, &data_len);
     364            0 :   if (NNS_EDGE_ERROR_NONE != ret) {
     365            0 :     _ml_error_report_return (ret,
     366              :         "Failed to get data while processing the ml-offloading service.");
     367              :   }
     368              : 
     369            0 :   ret = nns_edge_data_get_info (data_h, "service-type", &service_str);
     370            0 :   if (NNS_EDGE_ERROR_NONE != ret) {
     371            0 :     _ml_error_report_return (ret,
     372              :         "Failed to get service type while processing the ml-offloading service.");
     373              :   }
     374            0 :   service_type = _mlrs_get_service_type (service_str);
     375              : 
     376            0 :   ret = nns_edge_data_get_info (data_h, "service-key", &service_key);
     377            0 :   if (NNS_EDGE_ERROR_NONE != ret) {
     378            0 :     _ml_error_report_return (ret,
     379              :         "Failed to get service key while processing the ml-offloading service.");
     380              :   }
     381              : 
     382            0 :   dir_path = _mlrs_get_model_dir_path (offloading_s, service_key);
     383              : 
     384            0 :   if (offloading_s->offloading_mode == ML_SERVICE_OFFLOADING_MODE_TRAINING) {
     385            0 :     ret = ml_service_training_offloading_process_received_data (mls, data_h,
     386              :         dir_path, data, service_type);
     387            0 :     if (NNS_EDGE_ERROR_NONE != ret) {
     388            0 :       _ml_error_report_return (ret,
     389              :           "Failed to process received data on training offloading.");
     390              :     }
     391              : 
     392            0 :     if (service_type == ML_SERVICE_OFFLOADING_TYPE_REPLY) {
     393            0 :       if (!dir_path) {
     394            0 :         _ml_error_report_return (NNS_EDGE_ERROR_UNKNOWN,
     395              :             "Failed to get model directory path.");
     396              :       }
     397              : 
     398            0 :       if (!_mlrs_model_register (service_key, data_h, data, data_len, dir_path)) {
     399            0 :         _ml_error_report_return (NNS_EDGE_ERROR_UNKNOWN,
     400              :             "Failed to register model downloaded from: %s.", (gchar *) data);
     401              :       }
     402              :     }
     403              :   }
     404              : 
     405            0 :   switch (service_type) {
     406            0 :     case ML_SERVICE_OFFLOADING_TYPE_MODEL_URI:
     407              :     {
     408              :       GByteArray *array;
     409              : 
     410            0 :       if (!dir_path) {
     411            0 :         _ml_error_report_return (NNS_EDGE_ERROR_UNKNOWN,
     412              :             "Failed to get model directory path.");
     413              :       }
     414              : 
     415            0 :       array = g_byte_array_new ();
     416              : 
     417            0 :       if (!_mlrs_get_data_from_uri ((gchar *) data, array)) {
     418            0 :         g_byte_array_free (array, TRUE);
     419            0 :         _ml_error_report_return (NNS_EDGE_ERROR_IO,
     420              :             "Failed to get data from uri: %s.", (gchar *) data);
     421              :       }
     422              : 
     423            0 :       if (_mlrs_model_register (service_key, data_h, array->data, array->len,
     424              :               dir_path)) {
     425            0 :         event_type = ML_SERVICE_EVENT_MODEL_REGISTERED;
     426              :       } else {
     427            0 :         _ml_error_report ("Failed to register model downloaded from: %s.",
     428              :             (gchar *) data);
     429            0 :         ret = NNS_EDGE_ERROR_UNKNOWN;
     430              :       }
     431            0 :       g_byte_array_free (array, TRUE);
     432            0 :       break;
     433              :     }
     434            0 :     case ML_SERVICE_OFFLOADING_TYPE_MODEL_RAW:
     435              :     {
     436            0 :       if (!dir_path) {
     437            0 :         _ml_error_report_return (NNS_EDGE_ERROR_UNKNOWN,
     438              :             "Failed to get model directory path.");
     439              :       }
     440              : 
     441            0 :       if (_mlrs_model_register (service_key, data_h, data, data_len, dir_path)) {
     442            0 :         event_type = ML_SERVICE_EVENT_MODEL_REGISTERED;
     443              :       } else {
     444            0 :         _ml_error_report ("Failed to register model downloaded from: %s.",
     445              :             (gchar *) data);
     446            0 :         ret = NNS_EDGE_ERROR_UNKNOWN;
     447              :       }
     448            0 :       break;
     449              :     }
     450            0 :     case ML_SERVICE_OFFLOADING_TYPE_PIPELINE_URI:
     451              :     {
     452            0 :       GByteArray *array = g_byte_array_new ();
     453              : 
     454            0 :       ret = _mlrs_get_data_from_uri ((gchar *) data, array);
     455            0 :       if (!ret) {
     456            0 :         g_byte_array_free (array, TRUE);
     457            0 :         _ml_error_report_return (ret,
     458              :             "Failed to get data from uri: %s.", (gchar *) data);
     459              :       }
     460            0 :       ret = ml_service_pipeline_set (service_key, (gchar *) array->data);
     461            0 :       if (ML_ERROR_NONE == ret) {
     462            0 :         event_type = ML_SERVICE_EVENT_PIPELINE_REGISTERED;
     463              :       }
     464            0 :       g_byte_array_free (array, TRUE);
     465            0 :       break;
     466              :     }
     467            0 :     case ML_SERVICE_OFFLOADING_TYPE_PIPELINE_RAW:
     468            0 :       ret = ml_service_pipeline_set (service_key, (gchar *) data);
     469            0 :       if (ML_ERROR_NONE == ret) {
     470            0 :         event_type = ML_SERVICE_EVENT_PIPELINE_REGISTERED;
     471              :       }
     472            0 :       break;
     473            0 :     case ML_SERVICE_OFFLOADING_TYPE_REPLY:
     474              :     {
     475            0 :       ret = _ml_information_create (&info_h);
     476            0 :       if (ML_ERROR_NONE != ret) {
     477            0 :         _ml_error_report ("Failed to create information handle.");
     478            0 :         goto done;
     479              :       }
     480            0 :       ret = _ml_information_set (info_h, "data", (void *) data, NULL);
     481            0 :       if (ML_ERROR_NONE != ret) {
     482            0 :         _ml_error_report ("Failed to set data information.");
     483            0 :         goto done;
     484              :       }
     485            0 :       event_type = ML_SERVICE_EVENT_REPLY;
     486            0 :       break;
     487              :     }
     488            0 :     default:
     489            0 :       _ml_error_report ("Unknown service type '%d' or not supported yet.",
     490              :           service_type);
     491            0 :       break;
     492              :   }
     493              : 
     494            0 :   if (event_type != ML_SERVICE_EVENT_UNKNOWN) {
     495            0 :     ml_service_event_cb_info_s cb_info = { 0 };
     496              : 
     497            0 :     _ml_service_get_event_cb_info (mls, &cb_info);
     498              : 
     499            0 :     if (cb_info.cb) {
     500            0 :       cb_info.cb (event_type, info_h, cb_info.pdata);
     501              :     }
     502              :   }
     503              : 
     504            0 : done:
     505            0 :   if (info_h) {
     506            0 :     ml_information_destroy (info_h);
     507              :   }
     508              : 
     509            0 :   return ret;
     510              : }
     511              : 
     512              : /**
     513              :  * @brief Edge event callback.
     514              :  */
     515              : static int
     516            0 : _mlrs_edge_event_cb (nns_edge_event_h event_h, void *user_data)
     517              : {
     518            0 :   nns_edge_event_e event = NNS_EDGE_EVENT_UNKNOWN;
     519            0 :   nns_edge_data_h data_h = NULL;
     520            0 :   int ret = NNS_EDGE_ERROR_NONE;
     521              : 
     522            0 :   ret = nns_edge_event_get_type (event_h, &event);
     523            0 :   if (NNS_EDGE_ERROR_NONE != ret)
     524            0 :     return ret;
     525              : 
     526            0 :   switch (event) {
     527            0 :     case NNS_EDGE_EVENT_NEW_DATA_RECEIVED:
     528              :     {
     529            0 :       ret = nns_edge_event_parse_new_data (event_h, &data_h);
     530            0 :       if (NNS_EDGE_ERROR_NONE != ret)
     531            0 :         return ret;
     532              : 
     533            0 :       ret = _mlrs_process_service_offloading (data_h, user_data);
     534            0 :       break;
     535              :     }
     536            0 :     default:
     537            0 :       break;
     538              :   }
     539              : 
     540            0 :   if (data_h)
     541            0 :     nns_edge_data_destroy (data_h);
     542              : 
     543            0 :   return ret;
     544              : }
     545              : 
     546              : /**
     547              :  * @brief Create edge handle.
     548              :  */
     549              : static int
     550            0 : _mlrs_create_edge_handle (ml_service_s * mls, edge_info_s * edge_info)
     551              : {
     552            0 :   int ret = 0;
     553            0 :   nns_edge_h edge_h = NULL;
     554            0 :   _ml_service_offloading_s *offloading_s = NULL;
     555              : 
     556            0 :   ret = nns_edge_create_handle (edge_info->id, edge_info->conn_type,
     557              :       edge_info->node_type, &edge_h);
     558              : 
     559            0 :   if (NNS_EDGE_ERROR_NONE != ret) {
     560            0 :     _ml_error_report_return_continue (ret,
     561              :         "Failed to create edge handle for ml-service offloading. Internal error?");
     562              :   }
     563              : 
     564            0 :   offloading_s = (_ml_service_offloading_s *) mls->priv;
     565            0 :   ret = nns_edge_set_event_callback (edge_h, _mlrs_edge_event_cb, mls);
     566            0 :   if (NNS_EDGE_ERROR_NONE != ret) {
     567            0 :     _ml_error_report
     568              :         ("Failed to set event callback in edge handle for ml-service offloading. Internal error?");
     569            0 :     goto error;
     570              :   }
     571              : 
     572            0 :   _mlrs_set_edge_info (edge_info, edge_h);
     573              : 
     574            0 :   ret = nns_edge_start (edge_h);
     575            0 :   if (NNS_EDGE_ERROR_NONE != ret) {
     576            0 :     _ml_error_report
     577              :         ("Failed to start edge for ml-service offloading. Internal error?");
     578            0 :     goto error;
     579              :   }
     580              : 
     581            0 :   if (edge_info->node_type == NNS_EDGE_NODE_TYPE_QUERY_CLIENT) {
     582            0 :     ret = nns_edge_connect (edge_h, edge_info->dest_host, edge_info->dest_port);
     583              : 
     584            0 :     if (NNS_EDGE_ERROR_NONE != ret) {
     585            0 :       _ml_error_report
     586              :           ("Failed to connect edge for ml-service offloading. Internal error?");
     587            0 :       goto error;
     588              :     }
     589              :   }
     590              : 
     591            0 :   offloading_s->edge_h = edge_h;
     592              : 
     593            0 : error:
     594            0 :   if (ret != NNS_EDGE_ERROR_NONE) {
     595            0 :     nns_edge_release_handle (edge_h);
     596              :   }
     597              : 
     598            0 :   return ret;
     599              : }
     600              : 
     601              : /**
     602              :  * @brief Set offloading mode and private data.
     603              :  */
     604              : int
     605            0 : ml_service_offloading_set_mode (ml_service_h handle,
     606              :     ml_service_offloading_mode_e mode, void *priv)
     607              : {
     608            0 :   ml_service_s *mls = (ml_service_s *) handle;
     609              :   _ml_service_offloading_s *offloading_s;
     610              : 
     611            0 :   if (!_ml_service_handle_is_valid (mls)) {
     612            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     613              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance.");
     614              :   }
     615              : 
     616            0 :   offloading_s = (_ml_service_offloading_s *) mls->priv;
     617              : 
     618            0 :   offloading_s->offloading_mode = mode;
     619            0 :   offloading_s->priv = priv;
     620              : 
     621            0 :   return ML_ERROR_NONE;
     622              : }
     623              : 
     624              : /**
     625              :  * @brief Get offloading mode and private data.
     626              :  */
     627              : int
     628            0 : ml_service_offloading_get_mode (ml_service_h handle,
     629              :     ml_service_offloading_mode_e * mode, void **priv)
     630              : {
     631            0 :   ml_service_s *mls = (ml_service_s *) handle;
     632              :   _ml_service_offloading_s *offloading_s;
     633              : 
     634            0 :   if (!_ml_service_handle_is_valid (mls)) {
     635            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     636              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance.");
     637              :   }
     638              : 
     639            0 :   if (!mode || !priv) {
     640            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     641              :         "The parameter, mode or priv, is null. It should be a valid pointer.");
     642              :   }
     643              : 
     644            0 :   offloading_s = (_ml_service_offloading_s *) mls->priv;
     645              : 
     646            0 :   *mode = offloading_s->offloading_mode;
     647            0 :   *priv = offloading_s->priv;
     648              : 
     649            0 :   return ML_ERROR_NONE;
     650              : }
     651              : 
     652              : /**
     653              :  * @brief Internal function to release ml-service offloading data.
     654              :  */
     655              : int
     656            0 : ml_service_offloading_release_internal (ml_service_s * mls)
     657              : {
     658              :   _ml_service_offloading_s *offloading_s;
     659              : 
     660              :   /* Supposed internal function call to release handle. */
     661            0 :   if (!mls || !mls->priv)
     662            0 :     return ML_ERROR_NONE;
     663              : 
     664            0 :   offloading_s = (_ml_service_offloading_s *) mls->priv;
     665              : 
     666            0 :   if (offloading_s->offloading_mode == ML_SERVICE_OFFLOADING_MODE_TRAINING) {
     667              :     /**
     668              :      * 'ml_service_training_offloading_destroy' transfers internally trained models.
     669              :      * So keep offloading handle.
     670              :      */
     671              :     if (ML_ERROR_NONE != ml_service_training_offloading_destroy (mls)) {
     672            0 :       _ml_error_report
     673              :           ("Failed to release ml-service training offloading handle");
     674              :     }
     675              :   }
     676              : 
     677            0 :   if (offloading_s->edge_h) {
     678            0 :     nns_edge_release_handle (offloading_s->edge_h);
     679            0 :     offloading_s->edge_h = NULL;
     680              :   }
     681              : 
     682            0 :   if (offloading_s->table) {
     683            0 :     g_hash_table_destroy (offloading_s->table);
     684            0 :     offloading_s->table = NULL;
     685              :   }
     686              : 
     687            0 :   g_free (offloading_s->path);
     688            0 :   g_free (offloading_s);
     689            0 :   mls->priv = NULL;
     690              : 
     691            0 :   return ML_ERROR_NONE;
     692              : }
     693              : 
     694              : /**
     695              :  * @brief Set value in ml-service offloading handle.
     696              :  */
     697              : int
     698            0 : ml_service_offloading_set_information (ml_service_h handle, const gchar * name,
     699              :     const gchar * value)
     700              : {
     701            0 :   ml_service_s *mls = (ml_service_s *) handle;
     702              :   _ml_service_offloading_s *offloading_s;
     703            0 :   int ret = ML_ERROR_NONE;
     704              : 
     705            0 :   if (!_ml_service_handle_is_valid (mls)) {
     706            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     707              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance.");
     708              :   }
     709              : 
     710            0 :   offloading_s = (_ml_service_offloading_s *) mls->priv;
     711              : 
     712            0 :   if (g_ascii_strcasecmp (name, "path") == 0) {
     713            0 :     if (!g_file_test (value, G_FILE_TEST_IS_DIR)) {
     714            0 :       _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     715              :           "The given param, dir path '%s' is invalid or the dir is not found or accessible.",
     716              :           value);
     717              :     }
     718              : 
     719            0 :     if (g_access (value, W_OK) != 0) {
     720            0 :       _ml_error_report_return (ML_ERROR_PERMISSION_DENIED,
     721              :           "Write permission to dir '%s' is denied.", value);
     722              :     }
     723              : 
     724            0 :     g_free (offloading_s->path);
     725            0 :     offloading_s->path = g_strdup (value);
     726              : 
     727            0 :     if (offloading_s->offloading_mode == ML_SERVICE_OFFLOADING_MODE_TRAINING) {
     728            0 :       ret = ml_service_training_offloading_set_path (mls, offloading_s->path);
     729              :     }
     730              :   }
     731              : 
     732            0 :   return ret;
     733              : }
     734              : 
     735              : /**
     736              :  * @brief Internal function to set the services in ml-service offloading handle.
     737              :  */
     738              : static int
     739            0 : _ml_service_offloading_set_service (ml_service_s * mls, const gchar * key,
     740              :     const gchar * value)
     741              : {
     742              :   _ml_service_offloading_s *offloading_s;
     743              : 
     744            0 :   if (!STR_IS_VALID (key) || !STR_IS_VALID (value)) {
     745            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     746              :         "The parameter, 'key' or 'value' is null or empty string. It should be a valid string.");
     747              :   }
     748            0 :   offloading_s = (_ml_service_offloading_s *) mls->priv;
     749              : 
     750            0 :   g_hash_table_insert (offloading_s->table, g_strdup (key), g_strdup (value));
     751              : 
     752            0 :   return ML_ERROR_NONE;
     753              : }
     754              : 
     755              : /**
     756              :  * @brief Internal function to parse service info from config file.
     757              :  */
     758              : static int
     759            0 : _ml_service_offloading_parse_services (ml_service_s * mls, JsonObject * object)
     760              : {
     761              :   GList *list, *iter;
     762            0 :   int status = ML_ERROR_NONE;
     763              : 
     764            0 :   list = json_object_get_members (object);
     765            0 :   for (iter = list; iter != NULL; iter = g_list_next (iter)) {
     766            0 :     const gchar *key = iter->data;
     767            0 :     JsonNode *json_node = json_object_get_member (object, key);
     768            0 :     gchar *val = json_to_string (json_node, TRUE);
     769              : 
     770            0 :     if (val) {
     771            0 :       status = _ml_service_offloading_set_service (mls, key, val);
     772            0 :       g_free (val);
     773              : 
     774            0 :       if (status != ML_ERROR_NONE) {
     775            0 :         _ml_error_report ("Failed to set service key '%s'.", key);
     776            0 :         break;
     777              :       }
     778              :     }
     779              :   }
     780            0 :   g_list_free (list);
     781              : 
     782            0 :   return status;
     783              : }
     784              : 
     785              : /**
     786              :  * @brief Internal function to create ml-offloading data with given ml-option handle.
     787              :  */
     788              : static int
     789            0 : _ml_service_offloading_create_from_option (ml_service_s * mls,
     790              :     ml_option_h option)
     791              : {
     792              :   _ml_service_offloading_s *offloading_s;
     793            0 :   edge_info_s *edge_info = NULL;
     794            0 :   int ret = ML_ERROR_NONE;
     795            0 :   gchar *_path = NULL;
     796              : 
     797            0 :   mls->priv = offloading_s = g_try_new0 (_ml_service_offloading_s, 1);
     798            0 :   if (offloading_s == NULL) {
     799            0 :     _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
     800              :         "Failed to allocate memory for the service handle's private data. Out of memory?");
     801              :   }
     802              : 
     803            0 :   offloading_s->table =
     804            0 :       g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
     805            0 :   if (!offloading_s->table) {
     806            0 :     _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
     807              :         "Failed to allocate memory for the table of ml-service offloading. Out of memory?");
     808              :   }
     809              : 
     810            0 :   if (ML_ERROR_NONE == ml_option_get (option, "path", (void **) (&_path))) {
     811            0 :     ret = ml_service_offloading_set_information (mls, "path", _path);
     812            0 :     if (ML_ERROR_NONE != ret) {
     813            0 :       _ml_error_report_return (ret,
     814              :           "Failed to set path in ml-service offloading handle.");
     815              :     }
     816              :   }
     817              : 
     818            0 :   _mlrs_get_edge_info (option, &edge_info);
     819              : 
     820            0 :   offloading_s->node_type = edge_info->node_type;
     821            0 :   ret = _mlrs_create_edge_handle (mls, edge_info);
     822            0 :   _mlrs_release_edge_info (edge_info);
     823              : 
     824            0 :   return ret;
     825              : }
     826              : 
     827              : /**
     828              :  * @brief Internal function to convert json (string member) to ml-option.
     829              :  */
     830              : static int
     831            0 : _ml_service_offloading_convert_to_option (JsonObject * object,
     832              :     ml_option_h * option_h)
     833              : {
     834            0 :   ml_option_h tmp = NULL;
     835            0 :   int status = ML_ERROR_NONE;
     836              :   const gchar *key, *val;
     837              :   GList *list, *iter;
     838              : 
     839            0 :   if (!object || !option_h)
     840            0 :     return ML_ERROR_INVALID_PARAMETER;
     841              : 
     842            0 :   status = ml_option_create (&tmp);
     843            0 :   if (status != ML_ERROR_NONE) {
     844            0 :     _ml_error_report_return (status,
     845              :         "Failed to convert json to ml-option, cannot create ml-option handle.");
     846              :   }
     847              : 
     848            0 :   list = json_object_get_members (object);
     849            0 :   for (iter = list; iter != NULL; iter = g_list_next (iter)) {
     850            0 :     key = iter->data;
     851              : 
     852            0 :     if (g_ascii_strcasecmp (key, "training") == 0) {
     853              :       /* It is not a value to set for option. */
     854            0 :       continue;
     855              :     }
     856              : 
     857            0 :     val = json_object_get_string_member (object, key);
     858              : 
     859            0 :     status = ml_option_set (tmp, key, g_strdup (val), g_free);
     860            0 :     if (status != ML_ERROR_NONE) {
     861            0 :       _ml_error_report ("Failed to set %s option: %s.", key, val);
     862            0 :       break;
     863              :     }
     864              :   }
     865            0 :   g_list_free (list);
     866              : 
     867            0 :   if (status == ML_ERROR_NONE) {
     868            0 :     *option_h = tmp;
     869              :   } else {
     870            0 :     ml_option_destroy (tmp);
     871              :   }
     872              : 
     873            0 :   return status;
     874              : }
     875              : 
     876              : /**
     877              :  * @brief Internal function to parse configuration file to create offloading service.
     878              :  */
     879              : int
     880            0 : ml_service_offloading_create (ml_service_h handle, JsonObject * object)
     881              : {
     882            0 :   ml_service_s *mls = (ml_service_s *) handle;
     883              :   int status;
     884            0 :   ml_option_h option = NULL;
     885              :   JsonObject *offloading;
     886              : 
     887            0 :   if (!mls || !object) {
     888            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     889              :         "Failed to create offloading handle, invalid parameter.");
     890              :   }
     891              : 
     892            0 :   offloading = json_object_get_object_member (object, "offloading");
     893            0 :   if (!offloading) {
     894            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     895              :         "Failed to get 'offloading' member from configuration file.");
     896              :   }
     897              : 
     898            0 :   status = _ml_service_offloading_convert_to_option (offloading, &option);
     899            0 :   if (status != ML_ERROR_NONE) {
     900            0 :     _ml_error_report ("Failed to set ml-option from configuration file.");
     901            0 :     goto done;
     902              :   }
     903              : 
     904            0 :   status = _ml_service_offloading_create_from_option (mls, option);
     905            0 :   if (status != ML_ERROR_NONE) {
     906            0 :     _ml_error_report ("Failed to create ml-service offloading.");
     907            0 :     goto done;
     908              :   }
     909              : 
     910            0 :   if (json_object_has_member (object, "services")) {
     911              :     JsonObject *svc_object;
     912              : 
     913            0 :     svc_object = json_object_get_object_member (object, "services");
     914            0 :     status = _ml_service_offloading_parse_services (mls, svc_object);
     915            0 :     if (status != ML_ERROR_NONE) {
     916            0 :       _ml_logw ("Failed to parse services from configuration file.");
     917              :     }
     918              :   }
     919              : 
     920            0 :   if (json_object_has_member (offloading, "training")) {
     921            0 :     status = ml_service_training_offloading_create (mls, offloading);
     922            0 :     if (status != ML_ERROR_NONE) {
     923            0 :       _ml_logw ("Failed to parse training from configuration file.");
     924              :     }
     925              :   }
     926              : 
     927            0 : done:
     928            0 :   if (option)
     929            0 :     ml_option_destroy (option);
     930              : 
     931            0 :   return status;
     932              : }
     933              : 
     934              : /**
     935              :  * @brief Internal function to start ml-service offloading.
     936              :  */
     937              : int
     938            0 : ml_service_offloading_start (ml_service_h handle)
     939              : {
     940            0 :   ml_service_s *mls = (ml_service_s *) handle;
     941              :   _ml_service_offloading_s *offloading_s;
     942            0 :   int ret = ML_ERROR_NONE;
     943              : 
     944            0 :   if (!_ml_service_handle_is_valid (mls)) {
     945            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     946              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance.");
     947              :   }
     948              : 
     949            0 :   offloading_s = (_ml_service_offloading_s *) mls->priv;
     950              : 
     951            0 :   if (offloading_s->offloading_mode == ML_SERVICE_OFFLOADING_MODE_TRAINING) {
     952            0 :     ret = ml_service_training_offloading_start (mls);
     953            0 :     if (ret != ML_ERROR_NONE) {
     954            0 :       _ml_error_report ("Failed to start training offloading.");
     955              :     }
     956              :   }
     957              : 
     958            0 :   return ret;
     959              : }
     960              : 
     961              : /**
     962              :  * @brief Internal function to stop ml-service offloading.
     963              :  */
     964              : int
     965            0 : ml_service_offloading_stop (ml_service_h handle)
     966              : {
     967            0 :   ml_service_s *mls = (ml_service_s *) handle;
     968              :   _ml_service_offloading_s *offloading_s;
     969            0 :   int ret = ML_ERROR_NONE;
     970              : 
     971            0 :   if (!_ml_service_handle_is_valid (mls)) {
     972            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
     973              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance.");
     974              :   }
     975              : 
     976            0 :   offloading_s = (_ml_service_offloading_s *) mls->priv;
     977              : 
     978            0 :   if (offloading_s->offloading_mode == ML_SERVICE_OFFLOADING_MODE_TRAINING) {
     979            0 :     ret = ml_service_training_offloading_stop (mls);
     980            0 :     if (ret != ML_ERROR_NONE) {
     981            0 :       _ml_error_report ("Failed to stop training offloading.");
     982              :     }
     983              :   }
     984              : 
     985            0 :   return ret;
     986              : }
     987              : 
     988              : /**
     989              :  * @brief Register new information, such as neural network models or pipeline descriptions, on a offloading server.
     990              :  */
     991              : int
     992            0 : ml_service_offloading_request (ml_service_h handle, const char *key,
     993              :     const ml_tensors_data_h input)
     994              : {
     995            0 :   ml_service_s *mls = (ml_service_s *) handle;
     996            0 :   _ml_service_offloading_s *offloading_s = NULL;
     997            0 :   const gchar *service_key = NULL;
     998            0 :   nns_edge_data_h data_h = NULL;
     999            0 :   int ret = NNS_EDGE_ERROR_NONE;
    1000            0 :   const gchar *service_str = NULL;
    1001            0 :   const gchar *description = NULL;
    1002            0 :   const gchar *name = NULL;
    1003            0 :   const gchar *activate = NULL;
    1004            0 :   ml_tensors_data_s *_in = NULL;
    1005              :   JsonNode *service_node;
    1006              :   JsonObject *service_obj;
    1007              :   guint i;
    1008              : 
    1009            0 :   if (!_ml_service_handle_is_valid (mls)) {
    1010            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1011              :         "The parameter, 'handle' (ml_service_h), is invalid. It should be a valid ml_service_h instance.");
    1012              :   }
    1013              : 
    1014            0 :   if (!STR_IS_VALID (key)) {
    1015            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1016              :         "The parameter, 'key' is NULL. It should be a valid string.");
    1017              :   }
    1018              : 
    1019            0 :   if (!input)
    1020            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1021              :         "The parameter, input (ml_tensors_data_h), is NULL. It should be a valid ml_tensor_data_h instance, which is usually created by ml_tensors_data_create().");
    1022              : 
    1023            0 :   offloading_s = (_ml_service_offloading_s *) mls->priv;
    1024              : 
    1025            0 :   service_str = g_hash_table_lookup (offloading_s->table, key);
    1026            0 :   if (!service_str) {
    1027            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1028              :         "The given service key, %s, is not registered in the ml-service offloading handle.",
    1029              :         key);
    1030              :   }
    1031              : 
    1032            0 :   service_node = json_from_string (service_str, NULL);
    1033            0 :   if (!service_node) {
    1034            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1035              :         "Failed to parse the json string, %s.", service_str);
    1036              :   }
    1037            0 :   service_obj = json_node_get_object (service_node);
    1038            0 :   if (!service_obj) {
    1039            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1040              :         "Failed to get the json object from the json node.");
    1041              :   }
    1042              : 
    1043            0 :   service_str = json_object_get_string_member (service_obj, "service-type");
    1044            0 :   if (!service_str) {
    1045            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1046              :         "Failed to get service type from the json object.");
    1047              :   }
    1048              : 
    1049            0 :   service_key = json_object_get_string_member (service_obj, "service-key");
    1050            0 :   if (!service_key) {
    1051            0 :     _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
    1052              :         "Failed to get service key from the json object.");
    1053              :   }
    1054              : 
    1055            0 :   ret = nns_edge_data_create (&data_h);
    1056            0 :   if (NNS_EDGE_ERROR_NONE != ret) {
    1057            0 :     _ml_error_report ("Failed to create an edge data.");
    1058            0 :     return ret;
    1059              :   }
    1060              : 
    1061            0 :   ret = nns_edge_data_set_info (data_h, "service-type", service_str);
    1062            0 :   if (NNS_EDGE_ERROR_NONE != ret) {
    1063            0 :     _ml_error_report ("Failed to set service type in edge data.");
    1064            0 :     goto done;
    1065              :   }
    1066            0 :   ret = nns_edge_data_set_info (data_h, "service-key", service_key);
    1067            0 :   if (NNS_EDGE_ERROR_NONE != ret) {
    1068            0 :     _ml_error_report ("Failed to set service key in edge data.");
    1069            0 :     goto done;
    1070              :   }
    1071              : 
    1072            0 :   description = json_object_get_string_member (service_obj, "description");
    1073            0 :   if (description) {
    1074            0 :     ret = nns_edge_data_set_info (data_h, "description", description);
    1075            0 :     if (NNS_EDGE_ERROR_NONE != ret) {
    1076            0 :       _ml_logi ("Failed to set description in edge data.");
    1077              :     }
    1078              :   }
    1079              : 
    1080            0 :   name = json_object_get_string_member (service_obj, "name");
    1081            0 :   if (name) {
    1082            0 :     ret = nns_edge_data_set_info (data_h, "name", name);
    1083            0 :     if (NNS_EDGE_ERROR_NONE != ret) {
    1084            0 :       _ml_logi ("Failed to set name in edge data.");
    1085              :     }
    1086              :   }
    1087              : 
    1088            0 :   activate = json_object_get_string_member (service_obj, "activate");
    1089            0 :   if (activate) {
    1090            0 :     ret = nns_edge_data_set_info (data_h, "activate", activate);
    1091            0 :     if (NNS_EDGE_ERROR_NONE != ret) {
    1092            0 :       _ml_logi ("Failed to set activate in edge data.");
    1093              :     }
    1094              :   }
    1095            0 :   _in = (ml_tensors_data_s *) input;
    1096            0 :   for (i = 0; i < _in->num_tensors; i++) {
    1097              :     ret =
    1098            0 :         nns_edge_data_add (data_h, _in->tensors[i].data, _in->tensors[i].size,
    1099              :         NULL);
    1100            0 :     if (NNS_EDGE_ERROR_NONE != ret) {
    1101            0 :       _ml_error_report ("Failed to add camera data to the edge data.");
    1102            0 :       goto done;
    1103              :     }
    1104              :   }
    1105              : 
    1106            0 :   ret = nns_edge_send (offloading_s->edge_h, data_h);
    1107            0 :   if (NNS_EDGE_ERROR_NONE != ret) {
    1108            0 :     _ml_error_report
    1109              :         ("Failed to publish the data to register the offloading service.");
    1110              :   }
    1111              : 
    1112            0 : done:
    1113            0 :   if (data_h)
    1114            0 :     nns_edge_data_destroy (data_h);
    1115            0 :   return ret;
    1116              : }
        

Generated by: LCOV version 2.0-1