first commit for opensource
first commit for opensource
This commit is contained in:
@@ -0,0 +1,936 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud.h"
|
||||
|
||||
__QCLOUD_STATIC__ qcloud_err_t shadow_client_construct(qcloud_shadow_client_t *client,
|
||||
mqtt_event_handler_fn_t handler,
|
||||
shadow_type_t shadow_type,
|
||||
qcloud_device_t *device)
|
||||
{
|
||||
int topic_len = 0;
|
||||
|
||||
client->shadow_type = shadow_type;
|
||||
client->event_handler.handler = handler;
|
||||
|
||||
client->version = 0;
|
||||
client->token_num = 0;
|
||||
client->sync_state = QCLOUD_SHADOW_SYNC_STATE_NONE;
|
||||
|
||||
client->request_list_counter = 0;
|
||||
qcloud_list_init(&client->request_list);
|
||||
|
||||
qcloud_list_init(&client->property_list);
|
||||
|
||||
memset(client->request_topic_subscribe, 0, sizeof(client->request_topic_subscribe));
|
||||
|
||||
if (shadow_type == SHADOW_TYPE_TEMPLATE) {
|
||||
topic_len = osal_snprintf(client->request_topic_subscribe, QCLOUD_MQTT_TOPIC_SIZE_MAX,
|
||||
"$template/operation/result/%s/%s",
|
||||
device->product_id, device->device_name);
|
||||
} else {
|
||||
topic_len = osal_snprintf(client->request_topic_subscribe, QCLOUD_MQTT_TOPIC_SIZE_MAX,
|
||||
"$shadow/operation/result/%s/%s",
|
||||
device->product_id, device->device_name);
|
||||
}
|
||||
|
||||
if (topic_len < 0 || topic_len >= QCLOUD_MQTT_TOPIC_SIZE_MAX) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
memset(client->request_topic_publish, 0, sizeof(client->request_topic_publish));
|
||||
|
||||
if (shadow_type == SHADOW_TYPE_TEMPLATE) {
|
||||
topic_len = osal_snprintf(client->request_topic_publish, QCLOUD_MQTT_TOPIC_SIZE_MAX,
|
||||
"$template/operation/%s/%s",
|
||||
device->product_id, device->device_name);
|
||||
} else {
|
||||
topic_len = osal_snprintf(client->request_topic_publish, QCLOUD_MQTT_TOPIC_SIZE_MAX,
|
||||
"$shadow/operation/%s/%s",
|
||||
device->product_id, device->device_name);
|
||||
}
|
||||
|
||||
if (topic_len < 0 || topic_len >= QCLOUD_MQTT_TOPIC_SIZE_MAX) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
strncpy(client->device_product_id, device->product_id, sizeof(client->device_product_id));
|
||||
client->device_product_id[QCLOUD_DEVICE_PRODUCT_ID_MAX] = '\0';
|
||||
|
||||
client->global_lock = osal_mutex_create();
|
||||
if (!client->global_lock) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
__QCLOUD_STATIC__ void shadow_incoming_msg_handler(void *client, void *context, mqtt_event_t *event)
|
||||
{
|
||||
uint16_t packet_id;
|
||||
mqtt_incoming_msg_t *mqtt_msg;
|
||||
qcloud_shadow_client_t *shadow_client = NULL;
|
||||
|
||||
shadow_client = (qcloud_shadow_client_t *)context;
|
||||
|
||||
switch (event->type) {
|
||||
case MQTT_EVENT_SUBCRIBE_SUCCESS:
|
||||
packet_id = *(uint16_t *)event->message;
|
||||
QCLOUD_LOG_D("subscribe success, packet id=%u", (uint32_t)packet_id);
|
||||
shadow_client->sync_state = QCLOUD_SHADOW_SYNC_STATE_SUCCESS;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_TIMEOUT:
|
||||
packet_id = *(uint16_t *)event->message;
|
||||
QCLOUD_LOG_D("subscribe wait ack timeout, packet id=%u", (uint32_t)packet_id);
|
||||
shadow_client->sync_state = QCLOUD_SHADOW_SYNC_STATE_TIMEOUT;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_SUBCRIBE_NACK:
|
||||
packet_id = *(uint16_t *)event->message;
|
||||
QCLOUD_LOG_D("subscribe nack, packet id=%u", (uint32_t)packet_id);
|
||||
shadow_client->sync_state = QCLOUD_SHADOW_SYNC_STATE_NACK;
|
||||
break;
|
||||
|
||||
case MQTT_EVENT_PUBLISH_RECVEIVED:
|
||||
mqtt_msg = (mqtt_incoming_msg_t *)event->message;
|
||||
QCLOUD_LOG_D("topic arrived without handler: topic=%.*s, payload=%.*s",
|
||||
mqtt_msg->topic_len,
|
||||
mqtt_msg->topic,
|
||||
mqtt_msg->payload_len,
|
||||
mqtt_msg->payload);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (shadow_client->event_handler.handler) {
|
||||
shadow_client->event_handler.handler(shadow_client, shadow_client->event_handler.context, event);
|
||||
}
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_create(qcloud_shadow_client_t *client,
|
||||
qcloud_device_t *device,
|
||||
mqtt_event_handler_fn_t handler,
|
||||
shadow_type_t shadow_type)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(device, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc;
|
||||
|
||||
memset(client, 0, sizeof(qcloud_shadow_client_t));
|
||||
|
||||
rc = qcloud_mqtt_client_create(&client->mqtt_client, device, shadow_incoming_msg_handler, (void *)client, QCLOUD_AUTO_CONN_STATE_ENABLED);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, QCLOUD_ERR_FAILURE);
|
||||
|
||||
rc = qcloud_mqtt_connect_opt_create(&client->mqtt_connect_opt, device, MQTT_VERSION_3_1_1, 240, MQTT_CLEAN_SESSION_STATE_ENABLED);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
rc = shadow_client_construct(client, handler, shadow_type, device);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
rc = qcloud_mqtt_client_connect(&client->mqtt_client, &client->mqtt_connect_opt);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
rc = shadow_glue_operation_request_subscribe(client);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
client->sync_state = QCLOUD_SHADOW_SYNC_STATE_PENDACK;
|
||||
|
||||
while (client->sync_state == QCLOUD_SHADOW_SYNC_STATE_PENDACK) {
|
||||
qcloud_shadow_client_yield(client, 100);
|
||||
}
|
||||
|
||||
if (client->sync_state != QCLOUD_SHADOW_SYNC_STATE_SUCCESS) {
|
||||
goto errout;
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
|
||||
errout:
|
||||
qcloud_mqtt_client_destroy(&client->mqtt_client);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_yield(qcloud_shadow_client_t *client, uint32_t timeout)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_NUMBERIC_SANITY_CHECK(timeout, QCLOUD_ERR_INVAL);
|
||||
|
||||
shadow_glue_request_list_scan(client);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(qcloud_mqtt_client_yield(&client->mqtt_client, &client->mqtt_connect_opt, timeout));
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_publish(qcloud_shadow_client_t *client, char *topic, mqtt_publish_opt_t *publish_opt)
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(topic, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(publish_opt, QCLOUD_ERR_INVAL);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(qcloud_mqtt_publish(&client->mqtt_client, topic, publish_opt));
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_subscribe(qcloud_shadow_client_t *client, const char *topic_filter, mqtt_subscribe_opt_t *subscribe_opt)
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(topic_filter, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(subscribe_opt, QCLOUD_ERR_INVAL);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(qcloud_mqtt_subscribe(&client->mqtt_client, topic_filter, subscribe_opt));
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_unsubscribe(qcloud_shadow_client_t *client, const char *topic_filter)
|
||||
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(topic_filter, QCLOUD_ERR_INVAL);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(qcloud_mqtt_unsubscribe(&client->mqtt_client, topic_filter));
|
||||
}
|
||||
|
||||
__QCLOUD_API__ int qcloud_shadow_client_is_connected(qcloud_shadow_client_t *client)
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
|
||||
return qcloud_mqtt_client_is_connected(&client->mqtt_client);
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_destroy(qcloud_shadow_client_t *client)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
|
||||
shadow_glue_operation_request_unsubscribe(client);
|
||||
|
||||
shadow_glue_property_list_destroy(client);
|
||||
shadow_glue_request_list_destroy(client);
|
||||
|
||||
qcloud_mqtt_client_destroy(&client->mqtt_client);
|
||||
|
||||
if (client->global_lock) {
|
||||
osal_mutex_destroy(client->global_lock);
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS)
|
||||
}
|
||||
|
||||
__QCLOUD_STATIC__ int shadow_device_property_is_exist(qcloud_shadow_client_t *client, shadow_dev_property_t *that_dev_property)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
qcloud_list_t *curr, *next;
|
||||
qcloud_shadow_prop_info_t *property_info = NULL;
|
||||
shadow_dev_property_t *this_dev_property = NULL;
|
||||
|
||||
if (qcloud_list_empty(&client->property_list)) {
|
||||
return QCLOUD_FALSE;
|
||||
}
|
||||
|
||||
osal_mutex_lock(client->global_lock);
|
||||
|
||||
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &client->property_list) {
|
||||
property_info = QCLOUD_LIST_ENTRY(curr, qcloud_shadow_prop_info_t, list);
|
||||
this_dev_property = property_info->dev_property;
|
||||
|
||||
if (strcmp(this_dev_property->key, that_dev_property->key) != 0 ||
|
||||
this_dev_property->type != that_dev_property->type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
osal_mutex_unlock(client->global_lock);
|
||||
return QCLOUD_TRUE;
|
||||
}
|
||||
|
||||
osal_mutex_unlock(client->global_lock);
|
||||
|
||||
return QCLOUD_FALSE;
|
||||
}
|
||||
|
||||
__QCLOUD_STATIC__ qcloud_err_t shadow_device_property_do_register(qcloud_shadow_client_t *client,
|
||||
shadow_dev_property_t *dev_property,
|
||||
shadow_property_delta_handler_fn_t handler)
|
||||
{
|
||||
qcloud_shadow_prop_info_t *property_info = NULL;
|
||||
|
||||
property_info = (qcloud_shadow_prop_info_t *)osal_malloc(sizeof(qcloud_shadow_prop_info_t));
|
||||
if (!property_info) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
|
||||
}
|
||||
|
||||
qcloud_list_init(&property_info->list);
|
||||
property_info->dev_property = dev_property;
|
||||
property_info->handler = handler;
|
||||
qcloud_list_add(&property_info->list, &client->property_list);
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_device_property_register(qcloud_shadow_client_t *client,
|
||||
shadow_dev_property_t *dev_property,
|
||||
shadow_property_delta_handler_fn_t handler)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(dev_property, QCLOUD_ERR_INVAL);
|
||||
|
||||
if (!qcloud_mqtt_client_is_connected(&client->mqtt_client)) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
if (shadow_device_property_is_exist(client, dev_property)) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SHADOW_PROPERTY_EXIST);
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_device_property_do_register(client, dev_property, handler));
|
||||
}
|
||||
|
||||
__QCLOUD_STATIC__ qcloud_err_t shadow_device_property_do_unregister(qcloud_shadow_client_t *client, shadow_dev_property_t *that_dev_property)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
qcloud_list_t *curr, *next;
|
||||
qcloud_shadow_prop_info_t *property_info = NULL;
|
||||
shadow_dev_property_t *this_dev_property = NULL;
|
||||
|
||||
if (qcloud_list_empty(&client->property_list)) {
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
|
||||
osal_mutex_lock(client->global_lock);
|
||||
|
||||
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &client->property_list) {
|
||||
property_info = QCLOUD_LIST_ENTRY(curr, qcloud_shadow_prop_info_t, list);
|
||||
this_dev_property = property_info->dev_property;
|
||||
|
||||
if (strcmp(this_dev_property->key, that_dev_property->key) != 0 ||
|
||||
this_dev_property->type != that_dev_property->type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
qcloud_list_del(&property_info->list);
|
||||
osal_free(property_info);
|
||||
|
||||
osal_mutex_unlock(client->global_lock);
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
osal_mutex_unlock(client->global_lock);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_device_property_unregister(qcloud_shadow_client_t *client, shadow_dev_property_t *dev_property)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(dev_property, QCLOUD_ERR_INVAL);
|
||||
|
||||
if (!qcloud_mqtt_client_is_connected(&client->mqtt_client)) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
if (!shadow_device_property_is_exist(client, dev_property)) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SHADOW_NOT_PROPERTY_EXIST);
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_device_property_do_unregister(client, dev_property));
|
||||
}
|
||||
|
||||
__QCLOUD_STATIC__ void shadow_req_state_update_handler(void *client, qcloud_shadow_req_method_t method, qcloud_shadow_req_state_t req_state, const char *json_doc, void *context)
|
||||
{
|
||||
QCLOUD_LOG_D("request state=%d", req_state);
|
||||
|
||||
if (json_doc) {
|
||||
QCLOUD_LOG_D("json doc=%s", json_doc);
|
||||
} else {
|
||||
QCLOUD_LOG_D("json doc NULL");
|
||||
}
|
||||
|
||||
*((qcloud_shadow_req_state_t *)context) = req_state;
|
||||
}
|
||||
|
||||
__QCLOUD_STATIC__ qcloud_err_t shadow_request_state2errno(qcloud_shadow_req_state_t state)
|
||||
{
|
||||
switch (state) {
|
||||
case QCLOUD_SHADOW_REQUEST_STATE_ACCEPTED:
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
|
||||
case QCLOUD_SHADOW_REQUEST_STATE_TIMEOUT:
|
||||
return QCLOUD_ERR_SHADOW_UPDATE_TIMEOUT;
|
||||
|
||||
case QCLOUD_SHADOW_REQUEST_STATE_REJECTED:
|
||||
return QCLOUD_ERR_SHADOW_UPDATE_REJECTED;
|
||||
}
|
||||
|
||||
return QCLOUD_ERR_INVAL;
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_update_async(qcloud_shadow_client_t *client,
|
||||
char *json_doc,
|
||||
size_t json_doc_size,
|
||||
shadow_requset_handler_fn_t handler,
|
||||
void *context,
|
||||
uint32_t timeout)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_NUMBERIC_SANITY_CHECK(timeout, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_shadow_req_opt_t request_opt;
|
||||
|
||||
if (!qcloud_mqtt_client_is_connected(&client->mqtt_client)) {
|
||||
QCLOUD_LOG_E("mqtt disconnected");
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
// 如果没有之前没有订阅$shadow/operation/result成功,再一次订阅
|
||||
if (client->sync_state != QCLOUD_SHADOW_SYNC_STATE_SUCCESS) {
|
||||
shadow_glue_operation_request_subscribe(client);
|
||||
}
|
||||
|
||||
QCLOUD_LOG_D("update request docment: %s", json_doc);
|
||||
|
||||
request_opt.method = QCLOUD_SHADOW_REQUEST_METHOD_UPDATE;
|
||||
request_opt.handler = handler;
|
||||
request_opt.context = context;
|
||||
request_opt.timeout = timeout; // in seconds
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_glue_request_post(client, &request_opt, json_doc, json_doc_size));
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_update_sync(qcloud_shadow_client_t *client, char *json_doc, size_t json_doc_size, uint32_t timeout)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_NUMBERIC_SANITY_CHECK(timeout, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc = QCLOUD_ERR_SUCCESS;
|
||||
qcloud_shadow_req_state_t req_state = QCLOUD_SHADOW_REQUEST_STATE_NONE;
|
||||
|
||||
if (!qcloud_mqtt_client_is_connected(&client->mqtt_client)) {
|
||||
QCLOUD_LOG_E("shadow disconnected");
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
rc = qcloud_shadow_client_update_async(client, json_doc, json_doc_size, shadow_req_state_update_handler, &req_state, timeout);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, QCLOUD_ERR_FAILURE);
|
||||
|
||||
while (req_state == QCLOUD_SHADOW_REQUEST_STATE_NONE) {
|
||||
qcloud_shadow_client_yield(client, 200);
|
||||
}
|
||||
|
||||
return shadow_request_state2errno(req_state);
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_get_async(qcloud_shadow_client_t *client,
|
||||
shadow_requset_handler_fn_t handler,
|
||||
void *context,
|
||||
uint32_t timeout)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(handler, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_NUMBERIC_SANITY_CHECK(timeout, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc;
|
||||
qcloud_shadow_req_opt_t request_opt;
|
||||
char request_json_buffer[QCLOUD_SHADOW_JSON_WITH_CLIENT_TOKEN_MAX];
|
||||
|
||||
if (!qcloud_mqtt_client_is_connected(&client->mqtt_client)) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
// 如果没有之前没有订阅$shadow/operation/result成功,再一次订阅
|
||||
if (client->sync_state != QCLOUD_SHADOW_SYNC_STATE_SUCCESS) {
|
||||
shadow_glue_operation_request_subscribe(client);
|
||||
}
|
||||
|
||||
++client->token_num;
|
||||
rc = shadow_json_empty_doc_build(request_json_buffer, client->token_num, client->device_product_id);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
QCLOUD_LOG_D("get request document: %s", request_json_buffer);
|
||||
|
||||
request_opt.method = QCLOUD_SHADOW_REQUEST_METHOD_GET;
|
||||
request_opt.handler = handler;
|
||||
request_opt.context = context;
|
||||
request_opt.timeout = timeout; // in seconds
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_glue_request_post(client, &request_opt, request_json_buffer, sizeof(request_json_buffer)));
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_get_sync(qcloud_shadow_client_t *client, uint32_t timeout)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_NUMBERIC_SANITY_CHECK(timeout, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc = QCLOUD_ERR_SUCCESS;
|
||||
qcloud_shadow_req_state_t req_state = QCLOUD_SHADOW_REQUEST_STATE_NONE;
|
||||
|
||||
if (!qcloud_mqtt_client_is_connected(&client->mqtt_client)) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_MQTT_NO_CONN);
|
||||
}
|
||||
|
||||
rc = qcloud_shadow_client_get_async(client, shadow_req_state_update_handler, &req_state, timeout);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, QCLOUD_ERR_FAILURE);
|
||||
|
||||
while (req_state == QCLOUD_SHADOW_REQUEST_STATE_NONE) {
|
||||
qcloud_shadow_client_yield(client, 200);
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_request_state2errno(req_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化一个JSON文档
|
||||
*
|
||||
* 本函数主要是为JSON文档添加state字段, 即 "{\"state\":{", 所以在生成JSON文档时, 请先调用该方法
|
||||
*
|
||||
* @param jsonBuffer 为存储JSON文档准备的字符串缓冲区
|
||||
* @param sizeOfBuffer 缓冲区大小
|
||||
* @return 返回QCLOUD_ERR_SUCCESS, 表示初始化成功
|
||||
*/
|
||||
__QCLOUD_STATIC__ qcloud_err_t shadow_jsondoc_init(qcloud_shadow_client_t *client,
|
||||
char *json_doc,
|
||||
size_t json_doc_size,
|
||||
int is_overwrite)
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
|
||||
int rc = 0;
|
||||
|
||||
if (is_overwrite) {
|
||||
rc = osal_snprintf(json_doc, json_doc_size, "{\"version\":%d, \"overwriteUpdate\":true, \"state\":{", client->version);
|
||||
} else {
|
||||
rc = osal_snprintf(json_doc, json_doc_size, "{\"version\":%d, \"state\":{", client->version);
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_json_snprintf_rc2errno(rc, json_doc_size));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在JSON文档中添加结尾部分的内容, 包括clientToken字段、version字段
|
||||
*
|
||||
* @param jsonBuffer 为存储JSON文档准备的字符串缓冲区
|
||||
* @param sizeOfBuffer 缓冲区大小
|
||||
* @return 返回QCLOUD_ERR_SUCCESS, 表示成功
|
||||
*/
|
||||
__QCLOUD_STATIC__ qcloud_err_t shadow_jsondoc_finalize(qcloud_shadow_client_t *client, char *json_doc, size_t json_doc_size)
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
|
||||
int rc_snprintf;
|
||||
qcloud_err_t rc;
|
||||
size_t remain_size = 0;
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_JSON_BUFFER_TOO_SHORT);
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc) - 1, remain_size, "}, \"%s\":\"", SHADOW_FIELD_CLIENT_TOKEN);
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_JSON_BUFFER_TOO_SHORT);
|
||||
}
|
||||
|
||||
++client->token_num;
|
||||
rc = shadow_json_client_token_generate(json_doc + strlen(json_doc), remain_size, client->token_num, client->device_product_id);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "\"}");
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_json_snprintf_rc2errno(rc_snprintf, remain_size));
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_report_construct(qcloud_shadow_client_t *client,
|
||||
char *json_doc,
|
||||
size_t json_doc_size,
|
||||
int count, ...)
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc;
|
||||
va_list args;
|
||||
size_t remain_size = 0;
|
||||
int i = 0, rc_snprintf = 0;
|
||||
shadow_dev_property_t *dev_property;
|
||||
|
||||
rc = shadow_jsondoc_init(client, json_doc, json_doc_size, QCLOUD_FALSE);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("json init failed: %d", rc);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_JSON_BUFFER_TOO_SHORT);
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "\"reported\":{");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
va_start(args, count);
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
dev_property = va_arg(args, shadow_dev_property_t *);
|
||||
if (!dev_property || !dev_property->key) {
|
||||
va_end(args);
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
|
||||
}
|
||||
|
||||
rc = shadow_json_node_add(json_doc, remain_size, dev_property->key, dev_property->data, dev_property->type);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
va_end(args);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc) - 1, remain_size, "},");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("json add report failed: %d", rc);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
rc = shadow_jsondoc_finalize(client, json_doc, json_doc_size);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_report_construct_array(qcloud_shadow_client_t *client,
|
||||
char *json_doc,
|
||||
size_t json_doc_size,
|
||||
int count,
|
||||
shadow_dev_property_t *dev_propertys[])
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(dev_propertys, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc;
|
||||
int8_t i = 0, rc_snprintf = 0;
|
||||
size_t remain_size = 0;
|
||||
shadow_dev_property_t *dev_property;
|
||||
|
||||
rc = shadow_jsondoc_init(client, json_doc, json_doc_size, QCLOUD_FALSE);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("json init failed: %d", rc);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_JSON_BUFFER_TOO_SHORT);
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "\"reported\":{");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
dev_property = dev_propertys[i];
|
||||
if (!dev_property || !dev_property->key) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
|
||||
}
|
||||
|
||||
rc = shadow_json_node_add(json_doc, remain_size, dev_property->key, dev_property->data, dev_property->type);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
}
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc) - 1, remain_size, "},");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("json add report failed: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = shadow_jsondoc_finalize(client, json_doc, json_doc_size);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_overwrite_report_construct(qcloud_shadow_client_t *client,
|
||||
char *json_doc,
|
||||
size_t json_doc_size,
|
||||
int count, ...)
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc;
|
||||
va_list args;
|
||||
size_t remain_size = 0;
|
||||
int rc_snprintf = 0, i = 0;
|
||||
shadow_dev_property_t *dev_property;
|
||||
|
||||
rc = shadow_jsondoc_init(client, json_doc, json_doc_size, QCLOUD_TRUE);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("json init failed: %d", rc);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_JSON_BUFFER_TOO_SHORT);
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "\"reported\":{");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
va_start(args, count);
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
dev_property = va_arg(args, shadow_dev_property_t *);
|
||||
if (!dev_property || !dev_property->key) {
|
||||
va_end(args);
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
|
||||
}
|
||||
|
||||
rc = shadow_json_node_add(json_doc, remain_size, dev_property->key, dev_property->data, dev_property->type);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
va_end(args);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc) - 1, remain_size, "},");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("shadow json add report failed: %d", rc);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
rc = shadow_jsondoc_finalize(client, json_doc, json_doc_size);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("shadow json finalize failed: %d", rc);
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_report_with_desire_null_construct(qcloud_shadow_client_t *client,
|
||||
char *json_doc,
|
||||
size_t json_doc_size,
|
||||
int count, ...)
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc;
|
||||
va_list args;
|
||||
size_t remain_size = 0;
|
||||
int rc_snprintf = 0, i = 0;
|
||||
shadow_dev_property_t *dev_property;
|
||||
|
||||
rc = shadow_jsondoc_init(client, json_doc, json_doc_size, QCLOUD_FALSE);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("json init failed: %d", rc);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_JSON_BUFFER_TOO_SHORT);
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "\"reported\":{");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
va_start(args, count);
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
dev_property = va_arg(args, shadow_dev_property_t *);
|
||||
|
||||
if (!dev_property || !dev_property->key) {
|
||||
va_end(args);
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
|
||||
}
|
||||
|
||||
rc = shadow_json_node_add(json_doc, remain_size, dev_property->key, dev_property->data, dev_property->type);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
va_end(args);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc) - 1, remain_size, "},");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("shadow json add report failed: %d", rc);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "\"desired\": null ");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_jsondoc_finalize(client, json_doc, json_doc_size));
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_desire_null_construct(qcloud_shadow_client_t *client,
|
||||
char *json_doc,
|
||||
size_t json_doc_size)
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc;
|
||||
size_t remain_size = 0;
|
||||
int rc_snprintf = 0;
|
||||
|
||||
rc = shadow_jsondoc_init(client, json_doc, json_doc_size, QCLOUD_FALSE);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("json init failed: %d", rc);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_JSON_BUFFER_TOO_SHORT);
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "\"desired\": null ");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_jsondoc_finalize(client, json_doc, json_doc_size));
|
||||
}
|
||||
|
||||
__QCLOUD_API__ qcloud_err_t qcloud_shadow_client_desire_construct(qcloud_shadow_client_t *client,
|
||||
char *json_doc,
|
||||
size_t json_doc_size,
|
||||
int count, ...)
|
||||
{
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc;
|
||||
va_list args;
|
||||
int i = 0, rc_snprintf = 0;
|
||||
size_t remain_size = 0;
|
||||
shadow_dev_property_t *dev_property;
|
||||
|
||||
rc = shadow_jsondoc_init(client, json_doc, json_doc_size, QCLOUD_FALSE);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("shadow json init failed: %d", rc);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_JSON_BUFFER_TOO_SHORT);
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "\"desired\":{");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
va_start(args, count);
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
dev_property = va_arg(args, shadow_dev_property_t *);
|
||||
if (!dev_property || !dev_property->key) {
|
||||
va_end(args);
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
|
||||
}
|
||||
|
||||
rc = shadow_json_node_add(json_doc, remain_size, dev_property->key, dev_property->data, dev_property->type);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
va_end(args);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_JSON_BUFFER_TOO_SHORT);
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc) - 1, remain_size, "},");
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
if (rc != QCLOUD_ERR_SUCCESS) {
|
||||
QCLOUD_LOG_E("json add desired failed: %d", rc);
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_jsondoc_finalize(client, json_doc, json_doc_size));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud.h"
|
||||
|
||||
static char incoming_msg_from_cloud[QCLOUD_SHADOW_JSON_BUF_MAX];
|
||||
|
||||
__QCLOUD_STATIC__ void shadow_glue_json_node_insert(char *json_doc, char *json_node, int pos)
|
||||
{
|
||||
int i, n;
|
||||
int len = strlen(json_doc);
|
||||
int nlen = strlen(json_node);
|
||||
|
||||
for (i = len - 1; i >= pos; --i) {
|
||||
*(json_doc + i + nlen) = *(json_doc + i);
|
||||
}
|
||||
|
||||
for (n = 0; n < nlen; n++) {
|
||||
*(json_doc + pos + n) = *json_node++;
|
||||
}
|
||||
|
||||
*(json_doc + len + nlen) = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据RequestParams、Method来给json填入type字段的值
|
||||
*/
|
||||
__QCLOUD_STATIC__ qcloud_err_t shadow_glue_json_request_method_set(char *json_doc, size_t json_doc_size, qcloud_shadow_req_method_t requst_method)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
|
||||
char *type = NULL;
|
||||
char json_node[64] = {0};
|
||||
size_t json_len, size_remaining, json_node_len;
|
||||
|
||||
switch (requst_method) {
|
||||
case QCLOUD_SHADOW_REQUEST_METHOD_GET:
|
||||
type = SHADOW_OPERATION_GET;
|
||||
break;
|
||||
|
||||
case QCLOUD_SHADOW_REQUEST_METHOD_UPDATE:
|
||||
type = SHADOW_OPERATION_UPDATE;
|
||||
break;
|
||||
}
|
||||
|
||||
json_len = strlen(json_doc);
|
||||
size_remaining = json_doc_size - json_len;
|
||||
|
||||
osal_snprintf(json_node, 64, "\"type\":\"%s\", ", type);
|
||||
json_node_len = strlen(json_node);
|
||||
|
||||
if (json_node_len >= size_remaining - 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
|
||||
}
|
||||
|
||||
shadow_glue_json_node_insert(json_doc, json_node, 1);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
__QCLOUD_STATIC__ void shadow_glue_request_destroy(qcloud_shadow_request_t *request)
|
||||
{
|
||||
qcloud_list_del(&request->list);
|
||||
osal_free(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行设备影子操作的回调函数
|
||||
*/
|
||||
__QCLOUD_STATIC__ void shadow_glue_operation_request_do_handle(qcloud_shadow_client_t *client, const char *client_token, const char *method_type)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK_RTN(client);
|
||||
QCLOUD_POINTER_SANITY_CHECK_RTN(client_token);
|
||||
QCLOUD_POINTER_SANITY_CHECK_RTN(method_type);
|
||||
|
||||
char *delta = NULL;
|
||||
int16_t result_code;
|
||||
qcloud_list_t *curr, *next;
|
||||
qcloud_shadow_request_t *request = NULL;
|
||||
qcloud_shadow_req_state_t req_state = QCLOUD_SHADOW_REQUEST_STATE_NONE;
|
||||
|
||||
if (qcloud_list_empty(&client->request_list)) {
|
||||
return;
|
||||
}
|
||||
|
||||
osal_mutex_lock(client->global_lock);
|
||||
|
||||
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &client->request_list) {
|
||||
request = QCLOUD_LIST_ENTRY(curr, qcloud_shadow_request_t, list);
|
||||
|
||||
if (strcmp(request->client_token, client_token) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// ͨ<><CDA8> payload <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> result <20><>ȷ<EFBFBD><C8B7><EFBFBD><EFBFBD>Ӧ<EFBFBD>IJ<EFBFBD><C4B2><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7>ɹ<EFBFBD>
|
||||
// <20><>result = 0ʱ<30><CAB1>payload<61><64>Ϊ<EFBFBD>գ<EFBFBD>result<6C><74>0ʱ<30><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>updateʧ<65><CAA7>
|
||||
if (!shadow_json_operation_result_code_parse(incoming_msg_from_cloud, &result_code)) {
|
||||
QCLOUD_LOG_E("parse result code failed.");
|
||||
shadow_glue_request_destroy(request);
|
||||
continue;
|
||||
}
|
||||
|
||||
req_state = (result_code == 0 ? QCLOUD_SHADOW_REQUEST_STATE_ACCEPTED : QCLOUD_SHADOW_REQUEST_STATE_REJECTED);
|
||||
|
||||
if ((strcmp(method_type, SHADOW_OPERATION_GET) == 0 && req_state == QCLOUD_SHADOW_REQUEST_STATE_ACCEPTED) ||
|
||||
(strcmp(method_type, SHADOW_OPERATION_UPDATE) == 0 && req_state == QCLOUD_SHADOW_REQUEST_STATE_REJECTED)) {
|
||||
if (shadow_json_operation_delta_get(incoming_msg_from_cloud, &delta)) {
|
||||
shadow_glue_delta_handle(client, delta);
|
||||
osal_free(delta);
|
||||
}
|
||||
}
|
||||
|
||||
if (request->handler) {
|
||||
request->handler(client, request->method, req_state, incoming_msg_from_cloud, request->context);
|
||||
}
|
||||
|
||||
shadow_glue_request_destroy(request);
|
||||
--client->request_list_counter;
|
||||
}
|
||||
|
||||
osal_mutex_unlock(client->global_lock);
|
||||
|
||||
QCLOUD_FUNC_EXIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 文档操作请求结果的回调函数
|
||||
* 客户端先订阅 $shadow/operation/result/{ProductId}/{DeviceName}, 收到该topic的消息则会调用该回调函数
|
||||
* 在这个回调函数中, 解析出各个设备影子文档操作的结果
|
||||
*/
|
||||
__QCLOUD_STATIC__ void shadow_glue_operation_result_handler(void *client, mqtt_incoming_msg_t *message, void *private_data)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK_RTN(client);
|
||||
QCLOUD_POINTER_SANITY_CHECK_RTN(message);
|
||||
|
||||
int cloud_rcv_len;
|
||||
uint32_t version = 0;
|
||||
char *client_token = NULL, *method_type = NULL, *delta = NULL;
|
||||
qcloud_mqtt_client_t *mqtt_client = NULL;
|
||||
qcloud_shadow_client_t *shadow_client = NULL;
|
||||
|
||||
mqtt_client = (qcloud_mqtt_client_t *)client;
|
||||
shadow_client = (qcloud_shadow_client_t*)mqtt_client->event_handler.context;
|
||||
|
||||
if (!message->topic || message->topic_len <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message->payload_len > QCLOUD_SHADOW_JSON_BUF_MAX) {
|
||||
QCLOUD_LOG_E("received len exceeds limit");
|
||||
goto out;
|
||||
}
|
||||
|
||||
cloud_rcv_len = QCLOUD_MIN(QCLOUD_SHADOW_JSON_BUF_MAX - 1, message->payload_len);
|
||||
memcpy(incoming_msg_from_cloud, message->payload, cloud_rcv_len + 1);
|
||||
incoming_msg_from_cloud[cloud_rcv_len] = '\0'; // json_parse relies on a string
|
||||
|
||||
// 解析shadow result topic消息类型
|
||||
if (!shadow_json_operation_type_parse(incoming_msg_from_cloud, &method_type)) {
|
||||
QCLOUD_LOG_E("fail to parse type!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
// 非delta消息的push,一定由设备端触发,找到设备段对应的client_token
|
||||
if (strcmp(method_type, SHADOW_OPERATION_DELTA) != 0 &&
|
||||
!shadow_json_client_token_parse(incoming_msg_from_cloud, &client_token)) {
|
||||
QCLOUD_LOG_E("fail to parse client token! json=%s", incoming_msg_from_cloud);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// 获取shadow push消息version,如果比本地的version则修改本地version,比本地可能是由于服务器回滚或出错
|
||||
if (shadow_json_version_parse(incoming_msg_from_cloud, &version) &&
|
||||
version > shadow_client->version) {
|
||||
shadow_client->version = version;
|
||||
}
|
||||
|
||||
if (strcmp(method_type, SHADOW_OPERATION_DELTA) == 0) {
|
||||
if (shadow_json_delta_parse(incoming_msg_from_cloud, &delta)) {
|
||||
QCLOUD_LOG_D("delta: %s", delta);
|
||||
shadow_glue_delta_handle(shadow_client, delta);
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (shadow_client) {
|
||||
shadow_glue_operation_request_do_handle(shadow_client, client_token, method_type);
|
||||
}
|
||||
|
||||
out:
|
||||
if (!method_type) {
|
||||
osal_free(method_type);
|
||||
}
|
||||
|
||||
if (!client_token) {
|
||||
osal_free(client_token);
|
||||
}
|
||||
|
||||
if (!delta) {
|
||||
osal_free(delta);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 发布文档请求到物联云
|
||||
*
|
||||
* @param client Qcloud_IoT_Client对象
|
||||
* @param method 文档操作方式
|
||||
* @param pJsonDoc 等待发送的文档
|
||||
* @return 返回QCLOUD_ERR_SUCCESS, 表示发布文档请求成功
|
||||
*/
|
||||
__QCLOUD_STATIC__ qcloud_err_t shadow_glue_operation_request_publish(qcloud_shadow_client_t *client,
|
||||
char *json_doc)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
mqtt_publish_opt_t publish_opt;
|
||||
|
||||
memset(&publish_opt, 0, sizeof(mqtt_publish_opt_t));
|
||||
publish_opt.qos = MQTT_QOS0;
|
||||
publish_opt.payload = (void *)json_doc;
|
||||
publish_opt.payload_len = strlen(json_doc);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(qcloud_mqtt_client_publish(&client->mqtt_client, client->request_topic_publish, &publish_opt));
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ qcloud_err_t shadow_glue_operation_request_subscribe(qcloud_shadow_client_t *client)
|
||||
{
|
||||
mqtt_subscribe_opt_t subscribe_opt;
|
||||
|
||||
subscribe_opt.message_handler = shadow_glue_operation_result_handler;
|
||||
subscribe_opt.private_data = NULL;
|
||||
subscribe_opt.qos = MQTT_QOS0;
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(qcloud_mqtt_client_subscribe(&client->mqtt_client, client->request_topic_subscribe, &subscribe_opt));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 取消订阅topic: $shadow/operation/result/{ProductId}/{DeviceName}
|
||||
*/
|
||||
__QCLOUD_INTERNAL__ qcloud_err_t shadow_glue_operation_request_unsubscribe(qcloud_shadow_client_t *client)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(qcloud_mqtt_client_unsubscribe(&client->mqtt_client, client->request_topic_subscribe));
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ qcloud_err_t shadow_glue_request_list_scan(qcloud_shadow_client_t *client)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_list_t *curr, *next;
|
||||
qcloud_shadow_request_t *request;
|
||||
|
||||
if (qcloud_list_empty(&client->request_list)) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
osal_mutex_lock(client->global_lock);
|
||||
|
||||
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &client->request_list) {
|
||||
request = QCLOUD_LIST_ENTRY(curr, qcloud_shadow_request_t, list);
|
||||
|
||||
// check whether the ack is timeout
|
||||
if (!osal_timer_is_expired(&request->timer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (request->handler) {
|
||||
request->handler(client, request->method, QCLOUD_SHADOW_REQUEST_STATE_TIMEOUT, incoming_msg_from_cloud, request->context);
|
||||
}
|
||||
|
||||
shadow_glue_request_destroy(request);
|
||||
--client->request_list_counter;
|
||||
}
|
||||
|
||||
osal_mutex_unlock(client->global_lock);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将设备影子文档的操作请求保存在列表中
|
||||
*/
|
||||
__QCLOUD_STATIC__ qcloud_err_t shadow_glue_request_record(qcloud_shadow_client_t *client,
|
||||
const char *client_token,
|
||||
qcloud_shadow_req_opt_t *request_opt)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
qcloud_shadow_request_t *request = NULL;
|
||||
|
||||
if (client->request_list_counter >= QCLOUD_SHADOW_REQUEST_PENDING_MAX) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_MAX_APPENDING_REQUEST);
|
||||
}
|
||||
|
||||
request = (qcloud_shadow_request_t *)osal_malloc(sizeof(qcloud_shadow_request_t));
|
||||
if (!request) {
|
||||
QCLOUD_LOG_E("malloc failed!");
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_FAILURE);
|
||||
}
|
||||
|
||||
request->handler = request_opt->handler;
|
||||
request->context = request_opt->context;
|
||||
request->method = request_opt->method;
|
||||
strncpy(request->client_token, client_token, QCLOUD_SHADOW_CLIENT_TOKEN_MAX);
|
||||
|
||||
osal_timer_init(&request->timer);
|
||||
osal_timer_countdown(&request->timer, request_opt->timeout);
|
||||
|
||||
qcloud_list_init(&request->list);
|
||||
|
||||
osal_mutex_lock(client->global_lock);
|
||||
qcloud_list_add(&request->list, &client->request_list);
|
||||
++client->request_list_counter;
|
||||
osal_mutex_unlock(client->global_lock);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_SUCCESS);
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ qcloud_err_t shadow_glue_request_post(qcloud_shadow_client_t *client,
|
||||
qcloud_shadow_req_opt_t *request_opt,
|
||||
char *json_doc,
|
||||
size_t json_doc_size)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
QCLOUD_POINTER_SANITY_CHECK(client, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(request_opt, QCLOUD_ERR_INVAL);
|
||||
QCLOUD_POINTER_SANITY_CHECK(json_doc, QCLOUD_ERR_INVAL);
|
||||
|
||||
qcloud_err_t rc = QCLOUD_ERR_SUCCESS;
|
||||
char *client_token = NULL;
|
||||
|
||||
// 解析文档中的clientToken, 如果解析失败, 直接返回错误
|
||||
if (!shadow_json_client_token_parse(json_doc, &client_token)) {
|
||||
QCLOUD_LOG_E("fail to parse client token!");
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_INVAL);
|
||||
}
|
||||
|
||||
rc = shadow_glue_json_request_method_set(json_doc, json_doc_size, request_opt->method);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
// 相应的 operation topic 订阅成功或已经订阅
|
||||
rc = shadow_glue_operation_request_publish(client, json_doc);
|
||||
if (rc == QCLOUD_ERR_SUCCESS) {
|
||||
rc = shadow_glue_request_record(client, client_token, request_opt);
|
||||
}
|
||||
|
||||
osal_free(client_token);
|
||||
|
||||
QCLOUD_FUNC_EXIT_RC(rc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 处理注册属性的回调函数
|
||||
* 当订阅的$shadow/operation/result/{ProductId}/{DeviceName}返回消息时,
|
||||
* 若对应的type为delta, 则执行该函数
|
||||
*
|
||||
*/
|
||||
__QCLOUD_INTERNAL__ void shadow_glue_delta_handle(qcloud_shadow_client_t *client, char *delta)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
qcloud_list_t *curr, *next;
|
||||
qcloud_shadow_prop_info_t *property_info = NULL;
|
||||
shadow_dev_property_t *dev_property = NULL;
|
||||
|
||||
if (qcloud_list_empty(&client->property_list)) {
|
||||
return;
|
||||
}
|
||||
|
||||
osal_mutex_lock(client->global_lock);
|
||||
|
||||
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &client->property_list) {
|
||||
property_info = QCLOUD_LIST_ENTRY(curr, qcloud_shadow_prop_info_t, list);
|
||||
dev_property = property_info->dev_property;
|
||||
|
||||
if (shadow_json_value_update(delta, dev_property)) {
|
||||
property_info->handler(client, delta, strlen(delta), dev_property);
|
||||
}
|
||||
}
|
||||
|
||||
osal_mutex_unlock(client->global_lock);
|
||||
|
||||
QCLOUD_FUNC_EXIT;
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ void shadow_glue_property_list_destroy(qcloud_shadow_client_t *client)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
qcloud_list_t *curr, *next;
|
||||
qcloud_shadow_prop_info_t *property_info = NULL;
|
||||
|
||||
if (qcloud_list_empty(&client->property_list)) {
|
||||
return;
|
||||
}
|
||||
|
||||
osal_mutex_lock(client->global_lock);
|
||||
|
||||
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &client->property_list) {
|
||||
property_info = QCLOUD_LIST_ENTRY(curr, qcloud_shadow_prop_info_t, list);
|
||||
|
||||
qcloud_list_del(&property_info->list);
|
||||
osal_free(property_info);
|
||||
}
|
||||
|
||||
osal_mutex_unlock(client->global_lock);
|
||||
|
||||
QCLOUD_FUNC_EXIT;
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ void shadow_glue_request_list_destroy(qcloud_shadow_client_t *client)
|
||||
{
|
||||
QCLOUD_FUNC_ENTRY;
|
||||
|
||||
qcloud_list_t *curr, *next;
|
||||
qcloud_shadow_request_t *request = NULL;
|
||||
|
||||
if (qcloud_list_empty(&client->request_list)) {
|
||||
return;
|
||||
}
|
||||
|
||||
osal_mutex_lock(client->global_lock);
|
||||
|
||||
QCLOUD_LIST_FOR_EACH_SAFE(curr, next, &client->request_list) {
|
||||
request = QCLOUD_LIST_ENTRY(curr, qcloud_shadow_request_t, list);
|
||||
|
||||
qcloud_list_del(&request->list);
|
||||
osal_free(request);
|
||||
}
|
||||
|
||||
osal_mutex_unlock(client->global_lock);
|
||||
|
||||
QCLOUD_FUNC_EXIT;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making IoT Hub available.
|
||||
* Copyright (C) 2016 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "qcloud.h"
|
||||
|
||||
#define PRIi32 "i"
|
||||
#define PRIi16 "i"
|
||||
#define PRIi8 "i"
|
||||
#define PRIu32 "u"
|
||||
#define PRIu16 "u"
|
||||
#define PRIu8 "u"
|
||||
#define SCNi8 "hhi"
|
||||
#define SCNu8 "hhu"
|
||||
#define SCNi16 "hi"
|
||||
#define SCNu16 "hu"
|
||||
#define SCNi32 "i"
|
||||
#define SCNu32 "u"
|
||||
|
||||
__QCLOUD_STATIC__ qcloud_err_t shadow_json_value_do_update(char *value, shadow_dev_property_t *dev_property)
|
||||
{
|
||||
switch (dev_property->type) {
|
||||
case JSON_DATA_TYPE_BOOL:
|
||||
return LITE_get_boolean(dev_property->data, value);
|
||||
|
||||
case JSON_DATA_TYPE_INT32:
|
||||
return LITE_get_int32(dev_property->data, value);
|
||||
|
||||
case JSON_DATA_TYPE_INT16:
|
||||
return LITE_get_int16(dev_property->data, value);
|
||||
|
||||
case JSON_DATA_TYPE_INT8:
|
||||
return LITE_get_int8(dev_property->data, value);
|
||||
|
||||
case JSON_DATA_TYPE_UINT32:
|
||||
return LITE_get_uint32(dev_property->data, value);
|
||||
|
||||
case JSON_DATA_TYPE_UINT16:
|
||||
return LITE_get_uint16(dev_property->data, value);
|
||||
|
||||
case JSON_DATA_TYPE_UINT8:
|
||||
return LITE_get_uint8(dev_property->data, value);
|
||||
|
||||
case JSON_DATA_TYPE_FLOAT:
|
||||
return LITE_get_float(dev_property->data, value);
|
||||
|
||||
case JSON_DATA_TYPE_DOUBLE:
|
||||
return LITE_get_double(dev_property->data, value);
|
||||
|
||||
case JSON_DATA_TYPE_STRING:
|
||||
case JSON_DATA_TYPE_OBJECT:
|
||||
QCLOUD_LOG_D("string/object to be deal, %d %s", dev_property->type, value);
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
|
||||
default:
|
||||
QCLOUD_LOG_E("unknow type, %d",dev_property->type);
|
||||
return QCLOUD_ERR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查函数snprintf的返回值
|
||||
*
|
||||
* @param returnCode 函数snprintf的返回值
|
||||
* @param maxSizeOfWrite 可写最大字节数
|
||||
* @return 返回QCLOUD_ERR_JSON, 表示出错; 返回QCLOUD_ERR_JSON_BUFFER_TRUNCATED, 表示截断
|
||||
*/
|
||||
__QCLOUD_INTERNAL__ qcloud_err_t shadow_json_snprintf_rc2errno(int rc, size_t write_max)
|
||||
{
|
||||
if (rc < 0) {
|
||||
return QCLOUD_ERR_JSON;
|
||||
}
|
||||
|
||||
if (rc >= write_max) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TRUNCATED;
|
||||
}
|
||||
|
||||
return QCLOUD_ERR_SUCCESS;
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ qcloud_err_t shadow_json_client_token_generate(char *json_doc, size_t json_doc_size, uint32_t token_num, char *device_product_id)
|
||||
{
|
||||
int rc_snprintf;
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc, json_doc_size, "%s-%u", device_product_id, token_num);
|
||||
return shadow_json_snprintf_rc2errno(rc_snprintf, json_doc_size);
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ qcloud_err_t shadow_json_node_add(char *json_doc, size_t json_doc_size, const char *key, void *data, json_data_type_t type)
|
||||
{
|
||||
qcloud_err_t rc;
|
||||
int32_t rc_snprintf = 0;
|
||||
size_t remain_size = 0;
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
return QCLOUD_ERR_JSON_BUFFER_TOO_SHORT;
|
||||
}
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "\"%s\":", key);
|
||||
rc = shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
QCLOUD_FUNC_EXIT_RC_IF_NOT(rc, QCLOUD_ERR_SUCCESS, rc);
|
||||
|
||||
if ((remain_size = json_doc_size - strlen(json_doc)) <= 1) {
|
||||
QCLOUD_FUNC_EXIT_RC(QCLOUD_ERR_JSON_BUFFER_TOO_SHORT);
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "null,");
|
||||
QCLOUD_FUNC_EXIT_RC(shadow_json_snprintf_rc2errno(rc_snprintf, remain_size));
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case JSON_DATA_TYPE_INT32:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "%"
|
||||
PRIi32
|
||||
",", *(int32_t *)(data));
|
||||
break;
|
||||
|
||||
case JSON_DATA_TYPE_INT16:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "%"
|
||||
PRIi16
|
||||
",", *(int16_t *)(data));
|
||||
break;
|
||||
|
||||
case JSON_DATA_TYPE_INT8:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "%"
|
||||
PRIi8
|
||||
",", *(int8_t *)(data));
|
||||
break;
|
||||
|
||||
|
||||
case JSON_DATA_TYPE_UINT32:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "%"
|
||||
PRIu32
|
||||
",", *(uint32_t *)(data));
|
||||
break;
|
||||
|
||||
case JSON_DATA_TYPE_UINT16:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "%"
|
||||
PRIu16
|
||||
",", *(uint16_t *)(data));
|
||||
break;
|
||||
|
||||
case JSON_DATA_TYPE_UINT8:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "%"
|
||||
PRIu8
|
||||
",", *(uint8_t *)(data));
|
||||
break;
|
||||
|
||||
case JSON_DATA_TYPE_DOUBLE:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "%f,", *(double *)(data));
|
||||
break;
|
||||
|
||||
case JSON_DATA_TYPE_FLOAT:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "%f,", *(float *)(data));
|
||||
break;
|
||||
|
||||
case JSON_DATA_TYPE_BOOL:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "%s,", *(bool *)(data) ? "true" : "false");
|
||||
break;
|
||||
|
||||
case JSON_DATA_TYPE_STRING:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "\"%s\",", (char *)(data));
|
||||
break;
|
||||
|
||||
case JSON_DATA_TYPE_OBJECT:
|
||||
rc_snprintf = osal_snprintf(json_doc + strlen(json_doc), remain_size, "%s,", (char *)(data));
|
||||
break;
|
||||
}
|
||||
|
||||
return shadow_json_snprintf_rc2errno(rc_snprintf, remain_size);
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ qcloud_err_t shadow_json_empty_doc_build(char *json_doc, uint32_t token_num, char *device_product_id)
|
||||
{
|
||||
int rc_snprintf;
|
||||
|
||||
rc_snprintf = osal_snprintf(json_doc, QCLOUD_SHADOW_JSON_WITH_CLIENT_TOKEN_MAX, "{\"clientToken\":\"%s-%u\"}", device_product_id, token_num);
|
||||
return shadow_json_snprintf_rc2errno(rc_snprintf, QCLOUD_SHADOW_JSON_WITH_CLIENT_TOKEN_MAX);
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ int shadow_json_client_token_parse(char *json_doc, char **client_token)
|
||||
{
|
||||
*client_token = LITE_json_value_of(SHADOW_FIELD_CLIENT_TOKEN, json_doc);
|
||||
return *client_token != NULL;
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ int shadow_json_version_parse(char *json_doc, uint32_t *version)
|
||||
{
|
||||
int rc = QCLOUD_TRUE;
|
||||
char *version_str;
|
||||
|
||||
version_str = LITE_json_value_of(SHADOW_PAYLOAD_VERSION, json_doc);
|
||||
if (!version_str) {
|
||||
return QCLOUD_FALSE;
|
||||
}
|
||||
|
||||
if (sscanf(version_str, "%" SCNu32, version) != 1) {
|
||||
QCLOUD_LOG_E("parse shadow version failed, rc: %d", QCLOUD_ERR_JSON_PARSE);
|
||||
rc = QCLOUD_FALSE;
|
||||
}
|
||||
|
||||
osal_free(version_str);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ int shadow_json_operation_type_parse(char *json_doc, char **type)
|
||||
{
|
||||
*type = LITE_json_value_of(SHADOW_FIELD_TYPE, json_doc);
|
||||
return *type != NULL;
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ int shadow_json_operation_result_code_parse(char *json_doc, int16_t *result_code)
|
||||
{
|
||||
int rc = QCLOUD_TRUE;
|
||||
char *result_code_str;
|
||||
|
||||
result_code_str = LITE_json_value_of(SHADOW_FIELD_RESULT, json_doc);
|
||||
if (!result_code_str) {
|
||||
return QCLOUD_FALSE;
|
||||
}
|
||||
|
||||
if (sscanf(result_code_str, "%" SCNi16, result_code) != 1) {
|
||||
QCLOUD_LOG_E("parse result code failed, %d", QCLOUD_ERR_JSON_PARSE);
|
||||
rc = QCLOUD_FALSE;
|
||||
}
|
||||
|
||||
osal_free(result_code_str);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ int shadow_json_delta_parse(char *json_doc, char **delta)
|
||||
{
|
||||
*delta = LITE_json_value_of(SHADOW_PAYLOAD_STATE, json_doc);
|
||||
return *delta != NULL;
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ int shadow_json_operation_delta_get(char *json_doc, char **delta)
|
||||
{
|
||||
*delta = LITE_json_value_of(SHADOW_PAYLOAD_STATE_DELTA, json_doc);
|
||||
return *delta != NULL;
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ int shadow_state_parse(char *json_doc, char **state)
|
||||
{
|
||||
*state = LITE_json_value_of(SHADOW_PAYLOAD_VERSION, json_doc);
|
||||
return *state != NULL;
|
||||
}
|
||||
|
||||
__QCLOUD_INTERNAL__ int shadow_json_value_update(char *json, shadow_dev_property_t *dev_property)
|
||||
{
|
||||
char *data;
|
||||
|
||||
data = LITE_json_value_of((char *)dev_property->key, json);
|
||||
if (!data || strncmp(data, "null", 4) == 0 || strncmp(data, "NULL", 4) == 0) {
|
||||
return QCLOUD_FALSE;
|
||||
}
|
||||
|
||||
shadow_json_value_do_update(data, dev_property);
|
||||
osal_free(data);
|
||||
|
||||
return QCLOUD_TRUE;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user