add new qloud-c-sdk component

This commit is contained in:
mculover666
2022-03-25 10:06:56 +08:00
parent 565cd29e94
commit a3ac2e56d8
166 changed files with 35027 additions and 0 deletions

View File

@@ -0,0 +1,435 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2022 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file file_manage.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2022-01-11
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022-01-11 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "qcloud_iot_file_manage.h"
#include "service_mqtt.h"
/**
* @brief Context of file manage, callback and user data.
*
*/
typedef struct {
IotFileManageCallback callback;
void *usr_data;
} FileManageContext;
/**
* @brief File manage down stream message type.
*
*/
typedef enum {
FILE_MANAGE_DOWN_MESSAGE_TYPE_UPDATE = 0,
FILE_MANAGE_DOWN_MESSAGE_TYPE_DEL,
FILE_MANAGE_DOWN_MESSAGE_TYPE_REPORT_VERSION_RESPONSE,
FILE_MANAGE_DOWN_MESSAGE_TYPE_POST_REQUEST_RESPONSE,
} FileManageDownMessageType;
/**
* @brief Method string of down stream message. Order @see FileManageDownMessageType.
*
*/
static const char *sg_file_manage_method_str[] = {
"update_resource", // FILE_MANAGE_DOWN_MESSAGE_TYPE_UPDATE
"del_resource", // FILE_MANAGE_DOWN_MESSAGE_TYPE_DEL
"report_version_rsp", // FILE_MANAGE_DOWN_MESSAGE_TYPE_REPORT_VERSION_RESPONSE
"request_url_resp", // FILE_MANAGE_DOWN_MESSAGE_TYPE_POST_REQUEST_RESPONSE
};
/**
* @brief Method string of down stream message. Order @see IotFileManageFileType.
*
*/
static const char *sg_file_manage_file_type_str[] = {
"FILE", // IOT_FILE_MANAGE_FILE_TYPE_FILE
"AUDIO", // IOT_FILE_MANAGE_FILE_TYPE_AUDIO
"VOICE", // IOT_FILE_MANAGE_FILE_TYPE_VOICE
"VIDEO", // IOT_FILE_MANAGE_FILE_TYPE_VIDEO
};
/**
* @brief Handle file mange down stream message.
*
* @param[in] type @see FileManageDownMessageType
* @param[in] message @see MQTTMessage
* @param[in] callback @see IotFileManageCallback
* @param[in,out] usr_data user define in IOT_FileManage_Init
*/
static void _parse_update_payload_and_callback(FileManageDownMessageType type, const MQTTMessage *message,
const IotFileManageCallback *callback, void *usr_data)
{
int rc, result_code;
uint32_t file_size = 0;
UtilsJsonValue file_name, file_type, version, md5sum, url, value_result_code, file_token, file_list = {0};
// callback
switch (type) {
case FILE_MANAGE_DOWN_MESSAGE_TYPE_UPDATE:
if (!callback->update_file_callback) {
return;
}
rc = utils_json_value_get("resource_name", sizeof("resource_name") - 1, message->payload_str,
message->payload_len, &file_name);
rc |= utils_json_value_get("resource_type", sizeof("resource_type") - 1, message->payload_str,
message->payload_len, &file_type);
rc |= utils_json_value_get("version", sizeof("version") - 1, message->payload_str, message->payload_len,
&version);
rc |= utils_json_value_get("url", sizeof("url") - 1, message->payload_str, message->payload_len, &url);
rc |= utils_json_value_get("md5sum", sizeof("md5sum") - 1, message->payload_str, message->payload_len,
&md5sum);
rc |= utils_json_get_uint32("file_size", sizeof("file_size") - 1, message->payload_str,
message->payload_len, &file_size);
if (rc) {
goto error;
}
callback->update_file_callback(file_name, file_type, version, url, md5sum, file_size, usr_data);
break;
case FILE_MANAGE_DOWN_MESSAGE_TYPE_DEL:
if (!callback->del_file_callback) {
return;
}
rc = utils_json_value_get("resource_name", sizeof("resource_name") - 1, message->payload_str,
message->payload_len, &file_name);
rc |= utils_json_value_get("resource_type", sizeof("resource_type") - 1, message->payload_str,
message->payload_len, &file_type);
rc |= utils_json_value_get("version", sizeof("version") - 1, message->payload_str, message->payload_len,
&version);
if (rc) {
goto error;
}
callback->del_file_callback(file_name, file_type, version, usr_data);
break;
case FILE_MANAGE_DOWN_MESSAGE_TYPE_REPORT_VERSION_RESPONSE:
if (!callback->report_file_version_reponse_callback) {
return;
}
// maybe no resource
utils_json_value_get("resource_list", sizeof("resource_list") - 1, message->payload_str,
message->payload_len, &file_list);
rc = utils_json_value_get("result_code", sizeof("result_code") - 1, message->payload_str,
message->payload_len, &value_result_code);
rc |= utils_json_value_data_get(value_result_code, UTILS_JSON_VALUE_TYPE_INT32, &result_code);
if (rc) {
goto error;
}
callback->report_file_version_reponse_callback(file_list, result_code, usr_data);
break;
case FILE_MANAGE_DOWN_MESSAGE_TYPE_POST_REQUEST_RESPONSE:
if (!callback->request_file_url_response_callback) {
return;
}
rc = utils_json_value_get("resource_url", sizeof("resource_url") - 1, message->payload_str,
message->payload_len, &url);
rc |= utils_json_value_get("resource_token", sizeof("resource_token") - 1, message->payload_str,
message->payload_len, &file_token);
rc |= utils_json_value_get("result_code", sizeof("result_code") - 1, message->payload_str,
message->payload_len, &value_result_code);
rc |= utils_json_value_data_get(value_result_code, UTILS_JSON_VALUE_TYPE_INT32, &result_code);
if (rc) {
goto error;
}
callback->request_file_url_response_callback(file_list, file_token, result_code, usr_data);
break;
default:
break;
}
return;
error:
Log_e("invalid format of payload!");
return;
}
/**
* @brief Mqtt message callback for file manage.
*
* @param[in,out] client pointer to mqtt client
* @param[in] message message from topic
* @param[in,out] usr_data pointer to @see FileManageContext
*/
static void _file_manage_message_callback(void *client, const MQTTMessage *message, void *usr_data)
{
const char *file_manage_method_str[] = {
"update_resource", // FILE_MANAGE_DOWN_MESSAGE_TYPE_UPDATE
"del_resource", // FILE_MANAGE_DOWN_MESSAGE_TYPE_DEL
"report_version_rsp", // FILE_MANAGE_DOWN_MESSAGE_TYPE_REPORT_VERSION_RESPONSE
"request_url_resp", // FILE_MANAGE_DOWN_MESSAGE_TYPE_POST_REQUEST_RESPONSE
};
int rc, i = 0;
FileManageContext *file_manage_context = (FileManageContext *)usr_data;
UtilsJsonValue method;
Log_d("receive file manage message:%.*s", message->payload_len, message->payload_str);
rc = utils_json_value_get("method", sizeof("method") - 1, message->payload_str, message->payload_len, &method);
if (rc) {
Log_e("invalid file manage message!");
return;
}
for (i = FILE_MANAGE_DOWN_MESSAGE_TYPE_UPDATE; i <= FILE_MANAGE_DOWN_MESSAGE_TYPE_POST_REQUEST_RESPONSE; i++) {
if (!strncmp(method.value, file_manage_method_str[i], method.value_len)) {
Log_d("callback file manage message!");
_parse_update_payload_and_callback(i, message, &file_manage_context->callback,
file_manage_context->usr_data);
}
}
}
/**
* @brief File manage init, register handler to server list.
*
* @param[in,out] client pointer to mqtt client
* @param[in] callback @see IotFileManageCallback
* @param[in] usr_data usr data used in callback
* @return 0 for success, or err code (<0) @see IotReturnCode
*/
int IOT_FileManage_Init(void *client, IotFileManageCallback callback, void *usr_data)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
int rc = service_mqtt_init(client);
if (rc) {
return rc;
}
FileManageContext *file_manage_context = (FileManageContext *)HAL_Malloc(sizeof(FileManageContext));
if (!file_manage_context) {
return QCLOUD_ERR_MALLOC;
}
file_manage_context->callback = callback;
file_manage_context->usr_data = usr_data;
ServiceRegisterParams params = {
.type = SERVICE_TYPE_FILE_MANAGE,
.method_list = sg_file_manage_method_str,
.method_num = sizeof(sg_file_manage_method_str) / sizeof(sg_file_manage_method_str[0]),
.message_handle = _file_manage_message_callback,
.usr_data = file_manage_context,
.user_data_free = HAL_Free,
};
rc = service_mqtt_service_register(client, &params);
if (rc) {
HAL_Free(file_manage_context);
}
return rc;
}
/**
* @brief File manage deinit, unregister handler from server list.
*
* @param[in,out] client pointer to mqtt client
*/
void IOT_FileManage_Deinit(void *client)
{
POINTER_SANITY_CHECK_RTN(client);
service_mqtt_service_unregister(client, SERVICE_TYPE_FILE_MANAGE);
service_mqtt_deinit(client);
}
/**
* @brief Report file manage message.
*
* @param[in,out] client pointer to mqtt client
* @param[out] buf publish message buffer
* @param[in] buf_len buffer len
* @param[in] report_type @see IotFileManageReportType
* @param[in] progress progress using in IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOADING
* @param[in] file_name_or_token token using in post event;file name using in other event
* @param[in] version file version
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
*/
int IOT_FileManage_Report(void *client, char *buf, int buf_len, IotFileManageReportType report_type, int progress,
const char *file_name_or_token, const char *version)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
NUMBERIC_SANITY_CHECK(buf_len, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(file_name_or_token, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(version, QCLOUD_ERR_INVAL);
/**
* @brief order @see IotOTAReportType
*
*/
const char *state_string[] = {
"downloading", "burning", "done", "fail", "fail", "fail", "fail",
"fail", "fail", "done", "fail", "done", "fail",
};
int result_code[] = {0, 0, 0, -1, -2, -3, -4, -5, -6, 0, -7, 0, -8};
const char *result_msg[] = {
"",
"",
"",
"timeout",
"file not exit",
"auth fail",
"md5 not match",
"upgrade fail",
"space not enough",
"",
"del fail",
"",
"post fail",
};
int len;
switch (report_type) {
case IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOADING:
len = HAL_Snprintf(
buf, buf_len,
"{\"method\":\"report_progress\",\"report\":{\"progress\":{\"resource_name\":\"%s\",\"state\":\"%s\","
"\"percent\":\"%d\",\"result_code\":\"%d\",\"result_msg\":\"\"},\"version\":\"%s\"}}",
file_name_or_token, state_string[report_type], progress, result_code[report_type], version);
break;
case IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_BEGIN:
case IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_SUCCESS:
case IOT_FILE_MANAGE_REPORT_TYPE_DOWNLOAD_TIMEOUT:
case IOT_FILE_MANAGE_REPORT_TYPE_FILE_NOT_EXIST:
case IOT_FILE_MANAGE_REPORT_TYPE_AUTH_FAIL:
case IOT_FILE_MANAGE_REPORT_TYPE_MD5_NOT_MATCH:
case IOT_FILE_MANAGE_REPORT_TYPE_UPGRADE_FAIL:
case IOT_FILE_MANAGE_REPORT_TYPE_SPACE_NOT_ENOUGH:
len = HAL_Snprintf(buf, buf_len,
"{\"method\":\"report_result\",\"report\":{\"progress\":{\"resource_name\":\"%s\","
"\"state\":\"%s\",\"result_code\":\"%d\",\"result_msg\":\"%s\"},\"version\":\"%s\"}}",
file_name_or_token, state_string[report_type], result_code[report_type],
result_msg[report_type], version);
break;
case IOT_FILE_MANAGE_REPORT_TYPE_DEL_SUCCESS:
case IOT_FILE_MANAGE_REPORT_TYPE_DEL_FAIL:
len = HAL_Snprintf(buf, buf_len,
"{\"method\":\"del_result\",\"report\":{\"progress\":{\"resource_name\":\"%s\","
"\"state\":\"%s\",\"result_code\":\"%d\", \"result_msg\":\"%s\"}, \"version\":\"%s\"}}",
file_name_or_token, state_string[report_type], result_code[report_type],
result_msg[report_type], version);
break;
case IOT_FILE_MANAGE_REPORT_TYPE_POST_SUCCESS:
case IOT_FILE_MANAGE_REPORT_TYPE_POST_FAIL:
len = HAL_Snprintf(buf, buf_len,
"{\"method\":\"report_post_result\",\"report\":{\"progress\":{\"resource_token\":\"%s\","
"\"state\":\"%s\",\"result_code\":\"%d\", \"result_msg\":\"%s\"}}}",
file_name_or_token, state_string[report_type], result_code[report_type],
result_msg[report_type]);
break;
default:
return QCLOUD_ERR_INVAL;
}
return service_mqtt_publish(client, QOS0, buf, len);
}
/**
* @brief Report file list to server mqtt topic.
*
* @param[in,out] client pointer to mqtt client
* @param[out] buf publish message buffer
* @param[in] buf_len buffer len
* @param[in] file_list file list of @see IotFileManageFileInfo; file name which is "\0" means invalid.
* @param[in] max_num max num of file list.
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
*/
int IOT_FileManage_ReportFileList(void *client, char *buf, int buf_len, const IotFileManageFileInfo file_list[],
int max_num)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
NUMBERIC_SANITY_CHECK(buf_len, QCLOUD_ERR_INVAL);
int len = HAL_Snprintf(buf, buf_len, "{\"method\":\"report_version\",\"report\":{\"resource_list\":[");
for (int i = 0; i < max_num; i++) {
if (file_list[i].file_type == IOT_FILE_MANAGE_FILE_TYPE_UNKOWN) {
continue;
}
if (file_list[i].file_name[0] != '\0') {
len += HAL_Snprintf(buf + len, buf_len - len,
"{\"resource_name\":\"%s\",\"version\":\"%s\",\"resource_type\":\"%s\"},",
file_list[i].file_name, file_list[i].file_version,
sg_file_manage_file_type_str[file_list[i].file_type]);
}
}
if (buf[len - 1] != '[') {
len--; // remove the last ','
}
len += HAL_Snprintf(buf + len, buf_len - len, "]}}");
return service_mqtt_publish(client, QOS0, buf, len);
}
/**
* @brief Request url to upload.
*
* @param[in,out] client pointer to mqtt client
* @param[out] buf publish message buffer
* @param[in] buf_len buffer len
* @param[in] file_info file to upload, @see IotFileManageFileInfo
* @param[in] request_id user defined, to keep unique.
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
*/
int IOT_FileManage_PostRequest(void *client, char *buf, int buf_len, const IotFileManageFileInfo *file_info,
int request_id)
{
POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(buf, QCLOUD_ERR_INVAL);
NUMBERIC_SANITY_CHECK(buf_len, QCLOUD_ERR_INVAL);
POINTER_SANITY_CHECK(file_info, QCLOUD_ERR_INVAL);
NUMBERIC_SANITY_CHECK(file_info->file_type, QCLOUD_ERR_INVAL);
int len = HAL_Snprintf(buf, buf_len,
"{\"method\":\"request_url\",\"request_id\":\"%d\","
"\"report\":{\"resource_name\":\"%s\",\"version\":\"%s\",\"resource_type\":\"%s\"}}",
request_id, file_info->file_name, file_info->file_version,
sg_file_manage_file_type_str[file_info->file_type]);
return service_mqtt_publish(client, QOS0, buf, len);
}
/**
* @brief Get file type according to string. @see sg_file_manage_file_type_str.
*
* @param[in] file_type file type string
* @param[in] len string length
* @return @see IotFileManageFileType
*/
IotFileManageFileType IOT_FileManage_GetFileType(const char *file_type, int len)
{
for (int i = 0; i < sizeof(sg_file_manage_file_type_str) / sizeof(sg_file_manage_file_type_str[0]); i++) {
if (len != strlen(sg_file_manage_file_type_str[i])) {
continue;
}
if (!strncmp(file_type, sg_file_manage_file_type_str[i], len)) {
return i;
}
}
return IOT_FILE_MANAGE_FILE_TYPE_UNKOWN;
}

View File

@@ -0,0 +1,364 @@
/**
* @copyright
*
* Tencent is pleased to support the open source community by making IoT Hub available.
* Copyright(C) 2018 - 2022 THL A29 Limited, a Tencent company.All rights reserved.
*
* Licensed under the MIT License(the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*
* @file sevice_mqtt.c
* @brief
* @author fancyxu (fancyxu@tencent.com)
* @version 1.0
* @date 2022-01-11
*
* @par Change Log:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022-01-11 <td>1.0 <td>fancyxu <td>first commit
* </table>
*/
#include "service_mqtt.h"
/**
* @brief Direction(upstream/downstream) for topic.
*
*/
typedef enum {
SERVICE_TOPIC_DIRECTION_UP = 0,
SERVICE_TOPIC_DIRECTION_DOWN,
} ServiceTopicDirection;
/**
* @brief Context of service mqtt, callback and user data.
*
*/
typedef struct {
void *service_list;
void *usr_data;
} ServiceMqttContext;
/**
* @brief Service list conext.
*
*/
typedef struct {
const char *method;
int method_len;
const MQTTMessage *message;
} ServiceListContext;
/**
* @brief Generate topic string.
*
* @param[out] buf buffer for topic name
* @param[in] buf_len buffer length
* @param[in] direction @see ServiceTopicDirection
* @param[in] product_id product id of device
* @param[in] device_name device name of device
* @return > 0 for length of topic name, others for fail.
*/
static int _service_mqtt_topic_generate(char *buf, int buf_len, ServiceTopicDirection direction, const char *product_id,
const char *device_name)
{
return HAL_Snprintf(buf, buf_len, "$thing/%s/service/%s/%s", direction ? "down" : "up",
STRING_PTR_PRINT_SANITY_CHECK(product_id), STRING_PTR_PRINT_SANITY_CHECK(device_name));
}
// ----------------------------------------------------------------------------
// server mqtt context
// ----------------------------------------------------------------------------
/**
* @brief Malloc service context and service list.
*
* @return @see ServiceMqttContext
*/
static ServiceMqttContext *_service_mqtt_context_malloc(void)
{
ServiceMqttContext *context = (ServiceMqttContext *)HAL_Malloc(sizeof(ServiceMqttContext));
if (!context) {
return NULL;
}
UtilsListFunc func = {
.list_malloc = HAL_Malloc,
.list_free = HAL_Free,
.list_lock_init = HAL_MutexCreate,
.list_lock = HAL_MutexLock,
.list_unlock = HAL_MutexUnlock,
.list_lock_deinit = HAL_MutexDestroy,
};
context->service_list = utils_list_create(func, 10);
if (!context->service_list) {
HAL_Free(context);
context = NULL;
}
return context;
}
/**
* @brief Free service context and service list.
*
* @param usr_data @see ServiceMqttContext
*/
static void _service_mqtt_context_free(void *usr_data)
{
ServiceMqttContext *context = (ServiceMqttContext *)usr_data;
utils_list_destroy(context->service_list);
HAL_Free(context);
}
/**
* @brief Get service mqtt context from client.
*
* @param[in,out] client pointer to mqtt client
* @return @see ServiceMqttContext
*/
static ServiceMqttContext *_service_mqtt_context_get(void *client)
{
char service_mqtt_topic[MAX_SIZE_OF_CLOUD_TOPIC];
_service_mqtt_topic_generate(service_mqtt_topic, MAX_SIZE_OF_CLOUD_TOPIC, SERVICE_TOPIC_DIRECTION_DOWN,
IOT_MQTT_GetDeviceInfo(client)->product_id,
IOT_MQTT_GetDeviceInfo(client)->device_name);
return (ServiceMqttContext *)IOT_MQTT_GetSubUsrData(client, service_mqtt_topic);
}
// ----------------------------------------------------------------------------
// server list
// ----------------------------------------------------------------------------
/**
* @brief Unregister server from server list.
*
* @param[in] list pointer to server list
* @param[in] node pointer tot server list node
* @param[in] val @see ServiceRegisterParams
* @param[in] usr_data @see ServiceType
* @return @see UtilsListResult
*/
static UtilsListResult _server_list_unregister_callback(void *list, void *node, void *val, void *usr_data)
{
ServiceRegisterParams *params = (ServiceRegisterParams *)val;
ServiceType type = *(ServiceType *)usr_data;
if (params->type == type) {
if (params->user_data_free) {
params->user_data_free(params->usr_data);
}
utils_list_remove(list, node);
return LIST_TRAVERSE_BREAK;
}
return LIST_TRAVERSE_CONTINUE;
}
/**
* @brief Callback server handler from server list.
*
* @param[in] list pointer to server list
* @param[in] node pointer tot server list node
* @param[in] val @see ServiceRegisterParams
* @param[in] usr_data @see ServiceListContext
* @return @see UtilsListResult
*/
static UtilsListResult _server_list_process_message_callback(void *list, void *node, void *val, void *usr_data)
{
ServiceRegisterParams *params = (ServiceRegisterParams *)val;
ServiceListContext *context = (ServiceListContext *)usr_data;
for (int i = 0; i < params->method_num; i++) {
int len = strlen(params->method_list[i]);
if (len == context->method_len && !strncmp(context->method, params->method_list[i], len)) {
params->message_handle(usr_data, context->message, params->usr_data);
return LIST_TRAVERSE_BREAK;
}
}
return LIST_TRAVERSE_CONTINUE;
}
// ----------------------------------------------------------------------------
// mqtt
// ----------------------------------------------------------------------------
/**
* @brief Handle server mqtt topic down stream message.
*
* @param[in,out] client pointer to mqtt client
* @param[in] message @see MQTTMessage
* @param[in] usr_data @see ServiceMqttContext
*/
static void _service_mqtt_message_handle(void *client, const MQTTMessage *message, void *usr_data)
{
Log_d("receive service message:%.*s", message->payload_len, message->payload_str);
UtilsJsonValue method;
int rc = utils_json_value_get("method", sizeof("method") - 1, message->payload_str, message->payload_len, &method);
if (rc) {
return;
}
// process list
ServiceListContext server_list_context = {
.method = method.value,
.method_len = method.value_len,
.message = message,
};
void *list = ((ServiceMqttContext *)usr_data)->service_list;
utils_list_process(list, LIST_HEAD, _server_list_process_message_callback, &server_list_context);
}
/**
* @brief Check if topic already subscribed, if not then subscribe.
*
* @param[in,out] client pointer to mqtt client
* @return @see IotReturnCode
*/
int _service_mqtt_topic_check_and_sub(void *client)
{
char service_mqtt_topic[MAX_SIZE_OF_CLOUD_TOPIC];
_service_mqtt_topic_generate(service_mqtt_topic, MAX_SIZE_OF_CLOUD_TOPIC, SERVICE_TOPIC_DIRECTION_DOWN,
IOT_MQTT_GetDeviceInfo(client)->product_id,
IOT_MQTT_GetDeviceInfo(client)->device_name);
int rc = 0;
ServiceMqttContext *context = _service_mqtt_context_malloc();
if (!context) {
return QCLOUD_ERR_MALLOC;
}
SubscribeParams sub_params = DEFAULT_SUB_PARAMS;
sub_params.on_message_handler = _service_mqtt_message_handle;
sub_params.qos = QOS1;
sub_params.user_data = context;
sub_params.user_data_free = _service_mqtt_context_free;
rc = IOT_MQTT_SubscribeSync(client, service_mqtt_topic, &sub_params);
if (rc) {
_service_mqtt_context_free(context);
Log_e("subscribe topic %s failed!", service_mqtt_topic);
}
return rc;
}
/**
* @brief Unsubscribe service mqtt topic.
*
* @param[in,out] client pointer to mqtt client
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
*/
int _service_mqtt_unsubscribe(void *client)
{
char service_mqtt_topic[MAX_SIZE_OF_CLOUD_TOPIC];
_service_mqtt_topic_generate(service_mqtt_topic, MAX_SIZE_OF_CLOUD_TOPIC, SERVICE_TOPIC_DIRECTION_DOWN,
IOT_MQTT_GetDeviceInfo(client)->product_id,
IOT_MQTT_GetDeviceInfo(client)->device_name);
return IOT_MQTT_Unsubscribe(client, service_mqtt_topic);
}
// ----------------------------------------------------------------------------
// api
// ----------------------------------------------------------------------------
/**
* @brief Subscribe service mqtt.
*
* @param[in,out] client pointer to mqtt client
* @return @see IotReturnCode
*/
int service_mqtt_init(void *client)
{
return _service_mqtt_topic_check_and_sub(client);
}
/**
* @brief If no service in the service list, then unsubscribe.
*
* @param[in,out] client pointer to mqtt client
*/
void service_mqtt_deinit(void *client)
{
ServiceMqttContext *context = _service_mqtt_context_get(client);
if (!context) {
return;
}
if (!utils_list_len_get(context->service_list)) {
_service_mqtt_unsubscribe(client);
}
}
/**
* @brief Publish to service mqtt topic.
*
* @param[in,out] client pointer to mqtt client
* @param[in] qos @see QoS
* @param[in] payload payload of mqtt packet
* @param[in] payload_len payload len
* @return packet id (>=0) when success, or err code (<0) @see IotReturnCode
*/
int service_mqtt_publish(void *client, QoS qos, const char *payload, int payload_len)
{
char service_mqtt_topic[MAX_SIZE_OF_CLOUD_TOPIC];
_service_mqtt_topic_generate(service_mqtt_topic, MAX_SIZE_OF_CLOUD_TOPIC, SERVICE_TOPIC_DIRECTION_UP,
IOT_MQTT_GetDeviceInfo(client)->product_id,
IOT_MQTT_GetDeviceInfo(client)->device_name);
PublishParams pub_params = DEFAULT_PUB_PARAMS;
pub_params.qos = qos;
pub_params.payload = (void *)payload;
pub_params.payload_len = payload_len;
return IOT_MQTT_Publish(client, service_mqtt_topic, &pub_params);
}
/**
* @brief Register server handler to server list.
*
* @param[in,out] client pointer to mqtt client
* @param[in] params @see ServiceRegisterParams
* @return @see IotReturnCode
*/
int service_mqtt_service_register(void *client, const ServiceRegisterParams *params)
{
ServiceMqttContext *context = _service_mqtt_context_get(client);
if (!context) {
return QCLOUD_ERR_FAILURE;
}
ServiceRegisterParams *register_params = (ServiceRegisterParams *)HAL_Malloc(sizeof(ServiceRegisterParams));
if (!register_params) {
return QCLOUD_ERR_MALLOC;
}
memcpy(register_params, params, sizeof(ServiceRegisterParams));
void *node = utils_list_push(context->service_list, register_params);
if (!node) {
HAL_Free(register_params);
return QCLOUD_ERR_MALLOC;
}
return QCLOUD_RET_SUCCESS;
}
/**
* @brief Unregister server handler from server list.
*
* @param[in,out] client pointer to mqtt client
* @param[in] type @see ServiceType
*/
void service_mqtt_service_unregister(void *client, ServiceType type)
{
ServiceMqttContext *context = _service_mqtt_context_get(client);
if (!context) {
return;
}
utils_list_process(context->service_list, LIST_HEAD, _server_list_unregister_callback, &type);
}