Полное раскрытие, я задал этот вопрос на Azure IoT SDK C проекте github, но так как они рекомендуют смотреть на StackOverflow, я решил опубликовать здесь также.
У меня проблемы с реализацией обработчика метода прямого модуля в моем модуле IoT Edge на основе azure -iot-sdk- c. Мне не удалось найти страницу документации с примером реализации, поэтому я собрал свою реализацию из различных страниц документации SDK и «примеров» модульных тестов.
Чтобы проверить это, у меня есть выделенный Linux основанный P C (Ubuntu 18.04) под управлением iotedge 1.0.8-2. Я вижу, что мой модуль запускается, печатает свою версию и запускает сообщение обратного вызова состояния соединения. Я даже вижу, что обратный вызов ModuleTwin запускается и печатает полезную нагрузку, когда я вручную редактирую идентификатор модуля для своего устройства на портале.
Однако, когда я пытаюсь вручную вызвать метод Direct для моего модуля в моем устройстве на портале, я не вижу ничего напечатанного и получаю следующую ошибку на портале:
{"message":"GatewayTimeout:{\r\n \"Message\": \"{\\\"errorCode\\\":504101,\\\"trackingId\\\":\\\"8215e001484d41a19245639844f44f78-G:9-TimeStamp:01/14/2020 21:20:42-G:0-TimeStamp:01/14/2020 21:20:42\\\",\\\"message\\\":\\\"Timed out waiting for the response from device.\\\",\\\"info\\\":{},\\\"timestampUtc\\\":\\\"2020-01-14T21:20:42.0556758Z\\\"}\",\r\n \"ExceptionMessage\": \"\"\r\n}"}
Соответствующий код ниже. Я посмотрел на StackOverflow, но примеры не основаны на C SDK. Где я иду не так с прямыми методами модуля? Спасибо!
Обновление : Интересное наблюдение состоит в том, что если я изменю этот код на использование MQTT из AMQP, то все будет работать. Разве AMQP не поддерживается для методов прямого модуля?
#include <iothub_module_client_ll.h>
#include <iothub_client_options.h>
#include <iothub_message.h>
#include <azure_c_shared_utility/threadapi.h>
#include <azure_c_shared_utility/crt_abstractions.h>
#include <azure_c_shared_utility/platform.h>
#include <azure_c_shared_utility/shared_util_options.h>
#include <iothubtransportamqp.h>
#include <iothub.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
// Linker defined build information (see Makefile)
extern char __BUILD_DATE;
extern char __BUILD_NUMBER;
// Set the default value for module communication (e.g. AMQP) log tracing, yet
// allow compile time overrides.
#ifndef LOG_TRACE_ENABLED
#define LOG_TRACE_ENABLED 0
#endif
static void moduleTwinCallback(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* /*userContextCallback*/)
{
EPRINT("DEBUG: Module Twin callback called with (state=%s)", MU_ENUM_TO_STRING(DEVICE_TWIN_UPDATE_STATE, update_state));
EPRINT("DEBUG: payload=%.*s", (int)size, (const char *)payLoad);
fflush(NULL);
//JSON_Value *root_value = json_parse_string(payLoad);
//JSON_Object *root_object = json_value_get_object(root_value);
//if (json_object_dotget_value(root_object, "desired.TemperatureThreshold") != NULL) {
// temperatureThreshold = json_object_dotget_number(root_object, "desired.TemperatureThreshold");
//}
//if (json_object_get_value(root_object, "TemperatureThreshold") != NULL) {
// temperatureThreshold = json_object_get_number(root_object, "TemperatureThreshold");
//}
}
static int DirectMethodCb(const char* method_name, const unsigned char* payload, size_t size, unsigned char** response, size_t* resp_size, void* /*userContextCallback*/)
{
const char *METHOD_NAME = "TestMethod";
const int METHOD_RESPONSE_SUCCESS = 200;
const int METHOD_RESPONSE_ERROR = 401;
int responseCode;
EPRINT("DEBUG: Method name: %s", method_name);
EPRINT("DEBUG: Method payload: %.*s", (int)size, (const char*)payload);
if (strcmp(METHOD_NAME, method_name))
{
EPRINT("Method name incorrect - expected %s but got %s", METHOD_NAME, method_name);
responseCode = METHOD_RESPONSE_ERROR;
}
/*
else if (size != strlen(expectedMethodPayload))
{
LogError("payload size incorect - expected %zu but got %zu", strlen(expectedMethodPayload), size);
responseCode = METHOD_RESPONSE_ERROR;
}
else if (memcmp(payload, expectedMethodPayload, size))
{
LogError("Payload strings do not match");
responseCode = METHOD_RESPONSE_ERROR;
}
*/
else
{
*resp_size = size;
if (size == 0)
{
*response = NULL;
EPRINT("DEBUG: Empty, but good response");
responseCode = METHOD_RESPONSE_SUCCESS;
}
else
{
if ((*response = (unsigned char*)malloc(*resp_size)) == NULL)
{
EPRINT("allocation failure");
responseCode = METHOD_RESPONSE_ERROR;
}
else
{
(void)memcpy(*response, payload, *resp_size);
EPRINT("DEBUG: All good - echoing back the payload");
responseCode = METHOD_RESPONSE_SUCCESS;
}
}
}
EPRINT("DEBUG: completing with return code %d", responseCode);
fflush(NULL);
return responseCode;
}
static void ConnectionStatusCb(IOTHUB_CLIENT_CONNECTION_STATUS result, IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason, void* /*userContextCallback*/)
{
EPRINT("DEBUG: ConnectionStatusCb(status=%d %s, reason=%d %s",
result, MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONNECTION_STATUS, result),
reason, MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONNECTION_STATUS_REASON, reason)
);
fflush(NULL);
}
int main(void)
{
IOTHUB_MODULE_CLIENT_LL_HANDLE iotHubModuleClientHandle = nullptr;
int retval = 1;
do
{
printf("\n\n=======================\n");
printf("Build date : %lu\n", (unsigned long) &__BUILD_DATE);
printf("Build number: %lu\n", (unsigned long) &__BUILD_NUMBER);
fflush(NULL);
srand((unsigned int)time(NULL));
if (0 != IoTHub_Init())
{
EPRINT("Failed to initialize the platform.");
break;
}
iotHubModuleClientHandle = IoTHubModuleClient_LL_CreateFromEnvironment(AMQP_Protocol);
if (nullptr == iotHubModuleClientHandle)
{
EPRINT("IoTHubModuleClient_LL_CreateFromEnvironment failed");
break;
}
IOTHUB_CLIENT_RESULT result = IoTHubModuleClient_LL_SetModuleMethodCallback(iotHubModuleClientHandle, DirectMethodCb, iotHubModuleClientHandle);
if (IOTHUB_CLIENT_OK != result)
{
EPRINT("IoTHubModuleClient_SetModuleMethodCallback failed: %d", result);
break;
}
result = IoTHubModuleClient_LL_SetConnectionStatusCallback(iotHubModuleClientHandle, ConnectionStatusCb, iotHubModuleClientHandle);
if (IOTHUB_CLIENT_OK != result)
{
EPRINT("IoTHubDeviceClient_SetConnectionStatusCallback failed: %d", result);
break;
}
#if LOG_TRACE_ENABLED
bool traceOn = true;
IoTHubModuleClient_LL_SetOption(iotHubModuleClientHandle, OPTION_LOG_TRACE, &traceOn);
#endif // LOG_TRACE_ENABLED
result = IoTHubModuleClient_LL_SetModuleTwinCallback(iotHubModuleClientHandle, moduleTwinCallback, iotHubModuleClientHandle);
if (IOTHUB_CLIENT_OK != result)
{
EPRINT("IoTHubModuleClient_LL_SetModuleTwinCallback failed: %d", result);
break;
}
while (true)
{
IoTHubModuleClient_LL_DoWork(iotHubModuleClientHandle);
ThreadAPI_Sleep(100);
}
} while(false);
if (nullptr != iotHubModuleClientHandle)
{
IoTHubModuleClient_LL_Destroy(iotHubModuleClientHandle);
}
IoTHub_Deinit();
return retval;
}