Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions misc/dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ greengrasscoreipc
greengrassv
HEALTHD
htobe
ikhck
INET
iotcored
iotcoredfleet
Expand All @@ -86,6 +87,7 @@ LOGE
LOGI
LOGT
LOGW
MISRA
mqtt
mqttproxy
mtls
Expand Down Expand Up @@ -149,6 +151,7 @@ unrefp
unsuback
uriparser
uuid
vcnnpodt
venv
wbio
WERROR
Expand Down
8 changes: 4 additions & 4 deletions modules/ggipcd/src/ipc_dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
#include <stdint.h>

static const GglIpcService *const SERVICE_TABLE[]
= { &ggl_ipc_service_pubsub, &ggl_ipc_service_mqttproxy,
&ggl_ipc_service_config, &ggl_ipc_service_cli,
&ggl_ipc_service_private, &ggl_ipc_service_lifecycle,
&ggl_ipc_service_token_validation };
= { &ggl_ipc_service_pubsub, &ggl_ipc_service_mqttproxy,
&ggl_ipc_service_config, &ggl_ipc_service_cli,
&ggl_ipc_service_private, &ggl_ipc_service_lifecycle,
&ggl_ipc_service_token_validation, &ggl_ipc_service_shadow };

static const size_t SERVICE_COUNT
= sizeof(SERVICE_TABLE) / sizeof(SERVICE_TABLE[0]);
Expand Down
1 change: 1 addition & 0 deletions modules/ggipcd/src/ipc_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ extern GglIpcService ggl_ipc_service_cli;
extern GglIpcService ggl_ipc_service_private;
extern GglIpcService ggl_ipc_service_lifecycle;
extern GglIpcService ggl_ipc_service_token_validation;
extern GglIpcService ggl_ipc_service_shadow;

#endif
207 changes: 207 additions & 0 deletions modules/ggipcd/src/services/shadow/delete_thing_shadow.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
// aws-greengrass-lite - AWS IoT Greengrass runtime for constrained devices
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

#include "../../ipc_error.h"
#include "../../ipc_server.h"
#include "../../ipc_service.h"
#include "shadow.h"
#include <gg/arena.h>
#include <gg/buffer.h>
#include <gg/error.h>
#include <gg/flags.h>
#include <gg/log.h>
#include <gg/map.h>
#include <gg/object.h>
#include <gg/types.h>
#include <ggl/core_bus/aws_iot_mqtt.h>
#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>

typedef struct {
uint32_t handle;
int32_t stream_id;
bool response_received;
} DeleteThingShadowContext;

static GgError on_shadow_response(void *ctx, uint32_t handle, GgObject data) {
(void) handle;
(void) data;
DeleteThingShadowContext *shadow_ctx = ctx;

if (shadow_ctx->response_received) {
return GG_ERR_OK;
}
shadow_ctx->response_received = true;

(void) ggl_ipc_response_send(
shadow_ctx->handle,
shadow_ctx->stream_id,
GG_STR("aws.greengrass#DeleteThingShadowResponse"),
(GgMap) { 0 }
);
return GG_ERR_OK;
}

static void on_shadow_close(void *ctx, uint32_t handle) {
(void) handle;
DeleteThingShadowContext *shadow_ctx = ctx;

if (!shadow_ctx->response_received) {
(void) ggl_ipc_response_send(
shadow_ctx->handle,
shadow_ctx->stream_id,
GG_STR("aws.greengrass#ServiceError"),
(GgMap) { 0 }
);
}
}

GgError ggl_handle_delete_thing_shadow(
const GglIpcOperationInfo *info,
GgMap args,
uint32_t handle,
int32_t stream_id,
GglIpcError *ipc_error,
GgArena *alloc
) {
(void) info;
GgObject *thing_name_obj;
GgObject *shadow_name_obj;
GgError ret = gg_map_validate(
args,
GG_MAP_SCHEMA(
{ GG_STR("thingName"), GG_REQUIRED, GG_TYPE_BUF, &thing_name_obj },
{ GG_STR("shadowName"),
GG_OPTIONAL,
GG_TYPE_BUF,
&shadow_name_obj },
)
);
if (ret != GG_ERR_OK) {
GG_LOGE("Received invalid parameters.");
*ipc_error = (GglIpcError) { .error_code = GGL_IPC_ERR_SERVICE_ERROR,
.message
= GG_STR("Received invalid parameters.") };
return GG_ERR_INVALID;
}

GgBuffer thing_name = gg_obj_into_buf(*thing_name_obj);
GgBuffer shadow_name = GG_STR("");
if (shadow_name_obj != NULL) {
shadow_name = gg_obj_into_buf(*shadow_name_obj);
}

static uint8_t topic_mem[256];
int topic_len;

if (shadow_name.len == 0) {
topic_len = snprintf(
(char *) topic_mem,
sizeof(topic_mem),
"$aws/things/%.*s/shadow/delete",
(int) thing_name.len,
thing_name.data
);
} else {
topic_len = snprintf(
(char *) topic_mem,
sizeof(topic_mem),
"$aws/things/%.*s/shadow/name/%.*s/delete",
(int) thing_name.len,
thing_name.data,
(int) shadow_name.len,
shadow_name.data
);
}
if (topic_len < 0 || (size_t) topic_len >= sizeof(topic_mem)) {
GG_LOGE("Failed to format shadow topic.");
*ipc_error = (GglIpcError
) { .error_code = GGL_IPC_ERR_SERVICE_ERROR,
.message = GG_STR("Failed to format shadow topic.") };
return GG_ERR_NOMEM;
}
GgBuffer topic = { .data = topic_mem, .len = (size_t) topic_len };

static uint8_t filter_mem[256];
int filter_len;

if (shadow_name.len == 0) {
filter_len = snprintf(
(char *) filter_mem,
sizeof(filter_mem),
"$aws/things/%.*s/shadow/delete/+",
(int) thing_name.len,
thing_name.data
);
} else {
filter_len = snprintf(
(char *) filter_mem,
sizeof(filter_mem),
"$aws/things/%.*s/shadow/name/%.*s/delete/+",
(int) thing_name.len,
thing_name.data,
(int) shadow_name.len,
shadow_name.data
);
}
if (filter_len < 0 || (size_t) filter_len >= sizeof(filter_mem)) {
GG_LOGE("Failed to format shadow filter.");
*ipc_error = (GglIpcError
) { .error_code = GGL_IPC_ERR_SERVICE_ERROR,
.message = GG_STR("Failed to format shadow filter.") };
return GG_ERR_NOMEM;
}
GgBuffer filter = { .data = filter_mem, .len = (size_t) filter_len };

DeleteThingShadowContext *ctx = gg_arena_alloc(
alloc,
sizeof(DeleteThingShadowContext),
alignof(DeleteThingShadowContext)
);
if (ctx == NULL) {
*ipc_error
= (GglIpcError) { .error_code = GGL_IPC_ERR_SERVICE_ERROR,
.message = GG_STR("Memory allocation failed.") };
return GG_ERR_NOMEM;
}
*ctx = (DeleteThingShadowContext) {
.handle = handle,
.stream_id = stream_id,
.response_received = false,
};

uint32_t sub_handle;
ret = ggl_aws_iot_mqtt_subscribe(
GG_STR("aws_iot_mqtt"),
(GgBufList) { .bufs = &filter, .len = 1 },
0,
true,
on_shadow_response,
on_shadow_close,
ctx,
&sub_handle
);
if (ret != GG_ERR_OK) {
GG_LOGE("Failed to subscribe to shadow response topic.");
*ipc_error = (GglIpcError
) { .error_code = GGL_IPC_ERR_SERVICE_ERROR,
.message = GG_STR("Failed to subscribe to shadow response.") };
return ret;
}

ret = ggl_aws_iot_mqtt_publish(
GG_STR("aws_iot_mqtt"), topic, GG_STR(""), 0, false
);
if (ret != GG_ERR_OK) {
GG_LOGE("Failed to publish shadow delete request.");
*ipc_error = (GglIpcError
) { .error_code = GGL_IPC_ERR_SERVICE_ERROR,
.message = GG_STR("Failed to publish shadow request.") };
return ret;
}

return GG_ERR_OK;
}
Loading