

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用 AWS IoT Device SDK 与 Greengrass 原子核、其他组件进行通信，以及 AWS IoT Core
<a name="interprocess-communication"></a>

在核心设备上运行的组件可以使用中的 AWS IoT Greengrass 核心进程间通信 (IPC) 库与 AWS IoT Greengrass 核心和其他 Gre AWS IoT Device SDK engrass 组件进行通信。要开发和运行使用 IPC 的自定义组件，必须使用连接 AWS IoT Device SDK 到 C AWS IoT Greengrass ore IPC 服务并执行 IPC 操作。

IPC 接口支持两种类型的操作：
+ **请求/响应**

  组件向 IPC 服务发送请求并接收包含请求结果的响应。
+ **订阅**

  组件向 IPC 服务发送订阅请求，并期望响应中包含事件消息流。组件提供订阅处理程序，用于处理事件消息、错误和流关闭。 AWS IoT Device SDK 包括一个处理程序接口，其中包含每个 IPC 操作的正确响应和事件类型。有关更多信息，请参阅 [订阅 IPC 事件流](#ipc-subscribe-operations)。

**Topics**
+ [IPC 客户端版本](#ipc-client-versions)
+ [SDKs 支持进程间通信](#ipc-requirements)
+ [Connect 到 C AWS IoT Greengrass ore IPC 服务](#ipc-service-connect)
+ [授权组件执行 IPC 操作](#ipc-authorization-policies)
+ [订阅 IPC 事件流](#ipc-subscribe-operations)
+ [IPC 最佳实践](#ipc-best-practices)
+ [发布/订阅本地消息](ipc-publish-subscribe.md)
+ [发布/订阅 AWS IoT Core MQTT 消息](ipc-iot-core-mqtt.md)
+ [与组件生命周期交互](ipc-component-lifecycle.md)
+ [与组件配置交互](ipc-component-configuration.md)
+ [检索密钥值](ipc-secret-manager.md)
+ [与本地影子交互](ipc-local-shadows.md)
+ [管理本地部署和组件](ipc-local-deployments-components.md)
+ [对客户端设备进行身份验证和授权](ipc-client-device-auth.md)

## IPC 客户端版本
<a name="ipc-client-versions"></a>

在更高版本的 Java 和 Python 中 SDKs， AWS IoT Greengrass 提供了 IPC 客户端的改进版本，名为 IPC 客户端 V2。IPC 客户端 V2：
+ 减少使用 IPC 操作所需的代码量，并有助于避免 IPC 客户端 V1 可能出现的常见错误。
+ 在独立的线程中调用订阅处理程序回调，因此您现在可以在订阅处理程序回调中运行阻止代码，包括其他 IPC 函数调用。IPC 客户端 V1 使用相同的线程与 IPC 服务器通信并调用订阅处理程序回调。
+ 允许您使用 Lambda 表达式（Java）或函数（Python）调用订阅操作。IPC 客户端 V1 要求您定义订阅处理程序类。
+ 提供每个 IPC 操作的同步和异步版本。IPC 客户端 V1 仅提供每个操作的异步版本。

我们建议使用 IPC 客户端 V2 以利用这些改进。但是，本文档和一些在线内容中的许多示例仅演示如何使用 IPC 客户端 V1。您可以使用以下示例和教程来查看使用 IPC 客户端 V2 的示例组件：
+ [PublishToTopic例子](ipc-publish-subscribe.md#ipc-operation-publishtotopic-examples)
+ [SubscribeToTopic例子](ipc-publish-subscribe.md#ipc-operation-subscribetotopic-examples)
+ [教程：开发可延迟组件更新的 Greengrass 组件](defer-component-updates-tutorial.md)
+ [教程：通过 MQTT 与本地 IoT 设备进行交互](client-devices-tutorial.md)

目前， AWS IoT Device SDK 适用于 C\$1\$1 的 v2 仅支持 IPC 客户端 V1。

## SDKs 支持进程间通信
<a name="ipc-requirements"></a>

C AWS IoT Greengrass ore IPC 库包含在以下 AWS IoT Device SDK 版本中。


| SDK | 最低版本 | 用法 | 
| --- | --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.6.0  |  请参阅 [用 AWS IoT Device SDK 于 Java v2（IPC 客户端 V2）](#ipc-java-v2)。  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.9.0  |  请参阅 [用 AWS IoT Device SDK 于 Python v2（IPC 客户端 V2）](#ipc-python-v2)。  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.17.0  |  请参阅 [用 AWS IoT Device SDK 于 C\$1\$1 v2](#ipc-cpp)。  | 
|  [AWS IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  |  请参阅 [用 AWS IoT Device SDK 于 JavaScript v2（IPC 客户端 V1）](#ipc-nodejs)。  | 

## Connect 到 C AWS IoT Greengrass ore IPC 服务
<a name="ipc-service-connect"></a>

要在自定义组件中使用进程间通信，必须创建与 C AWS IoT Greengrass ore 软件运行的 IPC 服务器套接字的连接。完成以下任务，下载并使用您选择 AWS IoT Device SDK 的语言。

### 用 AWS IoT Device SDK 于 Java v2（IPC 客户端 V2）
<a name="ipc-java-v2"></a>

**要使用 AWS IoT Device SDK 适用于 Java v2（IPC 客户端 V2）**

1. 下载[适用于 Java v2 的AWS IoT Device SDK](https://github.com/aws/aws-iot-device-sdk-java-v2)（v1.6.0 或更高版本）

1. <a name="use-ipc-java-component-install-step"></a>执行以下某种操作以在组件中运行自定义代码：
   + 将您的组件构建为包含的 JAR 文件 AWS IoT Device SDK，然后在组件配方中运行此 JAR 文件。
   + 将 AWS IoT Device SDK JAR 定义为组件工件，并在组件配方中运行应用程序时将该构件添加到类路径中。

1. 使用以下代码创建 IPC 客户端。

   ```
   try (GreengrassCoreIPCClientV2 ipcClient = GreengrassCoreIPCClientV2.builder().build()) {
       // Use client.
   } catch (Exception e) {
       LOGGER.log(Level.SEVERE, "Exception occurred when using IPC.", e);
       System.exit(1);
   }
   ```

### 用 AWS IoT Device SDK 于 Python v2（IPC 客户端 V2）
<a name="ipc-python-v2"></a>

**要使用 AWS IoT Device SDK 适用于 Python v2（IPC 客户端 V2）**

1. 下载[适用于 Python 的AWS IoT Device SDK](https://github.com/aws/aws-iot-device-sdk-python-v2)（v1.9.0 或更高版本）。

1. <a name="use-ipc-python-component-install-step"></a>将 SDK 的[安装步骤](https://github.com/aws/aws-iot-device-sdk-python-v2#installation)添加到组件配方中的安装生命周期。

1. 创建与 AWS IoT Greengrass 核心 IPC 服务的连接。使用以下代码创建 IPC 客户端。

   ```
   from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2
   
   try:
       ipc_client = GreengrassCoreIPCClientV2()
       # Use IPC client.
   except Exception:
       print('Exception occurred when using IPC.', file=sys.stderr)
       traceback.print_exc()
       exit(1)
   ```

### 用 AWS IoT Device SDK 于 C\$1\$1 v2
<a name="ipc-cpp"></a>

<a name="iot-device-sdk-cpp-v2-build-requirements-intro"></a>要构建 C\$1\$1 版 AWS IoT Device SDK v2，设备必须具有以下工具：<a name="iot-device-sdk-cpp-v2-build-requirements"></a>
+ C\$1\$1 11 或更高版本
+ CMake 3.1 或更高版本
+ 以下编译器之一：
  + GCC 4.8 或更高版本
  + Clang 3.9 或更高版本
  + MSVC 2015 或更高版本

**要使用 AWS IoT Device SDK 适用于 C\$1\$1 v2 的**

1. 下载[适用于 C\$1\$1 v2 的AWS IoT Device SDK](https://github.com/aws/aws-iot-device-sdk-cpp-v2)（v1.17.0 或更高版本）。

1. 按照[自述文件中的安装说明](https://github.com/aws/aws-iot-device-sdk-cpp-v2#Installation)从源代码构建 C\$1\$1 v2 版。 AWS IoT Device SDK 

1. 在 C\$1\$1 构建工具中，链接您在上一步中构建的 Greengrass IPC 库 `AWS::GreengrassIpc-cpp`。以下`CMakeLists.txt`示例将 Greengrass IPC 库链接到您用来构建的项目。 CMake

   ```
   cmake_minimum_required(VERSION 3.1)
   project (greengrassv2_pubsub_subscriber)
   
   file(GLOB MAIN_SRC
           "*.h"
           "*.cpp"
           )
   add_executable(${PROJECT_NAME} ${MAIN_SRC})
   
   set_target_properties(${PROJECT_NAME} PROPERTIES
           LINKER_LANGUAGE CXX
           CXX_STANDARD 11)
   find_package(aws-crt-cpp PATHS ~/sdk-cpp-workspace/build)
   find_package(EventstreamRpc-cpp PATHS ~/sdk-cpp-workspace/build)
   find_package(GreengrassIpc-cpp PATHS ~/sdk-cpp-workspace/build)
   target_link_libraries(${PROJECT_NAME} AWS::GreengrassIpc-cpp)
   ```

1. 在组件代码中，创建与 C AWS IoT Greengrass ore IPC 服务的连接以创建 IPC 客户端 () `Aws::Greengrass::GreengrassCoreIpcClient`。您必须定义 IPC 连接生命周期处理程序，用于处理 IPC 连接、断开连接和错误事件。以下示例创建了 IPC 客户端和 IPC 连接生命周期处理程序，在 IPC 客户端连接、断开连接和遇到错误时进行打印。

   ```
   #include <iostream>
   
   #include <aws/crt/Api.h>
   #include <aws/greengrass/GreengrassCoreIpcClient.h>
   
   using namespace Aws::Crt;
   using namespace Aws::Greengrass;
   
   class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
       void OnConnectCallback() override {
           std::cout << "OnConnectCallback" << std::endl;
       }
   
       void OnDisconnectCallback(RpcError error) override {
           std::cout << "OnDisconnectCallback: " << error.StatusToString() << std::endl;
           exit(-1);
       }
   
       bool OnErrorCallback(RpcError error) override {
           std::cout << "OnErrorCallback: " << error.StatusToString() << std::endl;
           return true;
       }
   };
   
   int main() {
       // Create the IPC client.
       ApiHandle apiHandle(g_allocator);
       Io::EventLoopGroup eventLoopGroup(1);
       Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
       Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
       IpcClientLifecycleHandler ipcLifecycleHandler;
       GreengrassCoreIpcClient ipcClient(bootstrap);
       auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
       if (!connectionStatus) {
           std::cerr << "Failed to establish IPC connection: " << connectionStatus.StatusToString() << std::endl;
           exit(-1);
       }
       
       // Use the IPC client to create an operation request.
       
       // Activate the operation request.
       auto activate = operation.Activate(request, nullptr);
       activate.wait();
   
       // Wait for Greengrass Core to respond to the request.
       auto responseFuture = operation.GetResult();
       if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
           std::cerr << "Operation timed out while waiting for response from Greengrass Core." << std::endl;
           exit(-1);
       }
   
       // Check the result of the request.
       auto response = responseFuture.get();
       if (response) {
           std::cout << "Successfully published to topic: " << topic << std::endl;
       } else {
           // An error occurred.
           std::cout << "Failed to publish to topic: " << topic << std::endl;
           auto errorType = response.GetResultType();
           if (errorType == OPERATION_ERROR) {
               auto *error = response.GetOperationError();
               std::cout << "Operation error: " << error->GetMessage().value() << std::endl;
           } else {
               std::cout << "RPC error: " << response.GetRpcError() << std::endl;
           }
           exit(-1);
       }
       
       return 0;
   }
   ```

1. 要在组件中运行自定义代码，请将代码构建为二进制构件，然后在组件配方中运行二进制构件。将构件的`Execute`权限设置为`OWNER`，以使 AWS IoT Greengrass 核心软件能够运行二进制工件。

   组件配方的 `Manifests` 部分可能类似于以下示例。

------
#### [ JSON ]

   ```
   {
     ...
     "Manifests": [
       {
         "Lifecycle": {
           "Run": "{artifacts:path}/greengrassv2_pubsub_subscriber"
         },
         "Artifacts": [
           {
             "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubSubscriberCpp/1.0.0/greengrassv2_pubsub_subscriber",
             "Permission": {
               "Execute": "OWNER"
             }
           }
         ]
       }
     ]
   }
   ```

------
#### [ YAML ]

   ```
   ...
   Manifests:
     - Lifecycle:
         Run: {artifacts:path}/greengrassv2_pubsub_subscriber
       Artifacts:
         - URI: s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubSubscriberCpp/1.0.0/greengrassv2_pubsub_subscriber
           Permission:
             Execute: OWNER
   ```

------

### 用 AWS IoT Device SDK 于 JavaScript v2（IPC 客户端 V1）
<a name="ipc-nodejs"></a>

<a name="iot-device-sdk-nodejs-build-requirements-intro"></a>要编译 AWS IoT Device SDK 适用于 JavaScript v2 的，以便与 NodeJS 一起使用，设备必须具有以下工具：<a name="iot-device-sdk-nodejs-build-requirements"></a>
+ NodeJS 10.0 或更高版本
  + 运行 `node -v` 以检查 Node 版本。
+ CMake 3.1 或更高版本

**要使用 AWS IoT Device SDK 适用于 JavaScript v2 的（IPC 客户端 V1）**

1. 下载[AWS IoT Device SDK 适用于 JavaScript v2（v](https://github.com/aws/aws-iot-device-sdk-js-v2) 1.12.10 或更高版本）的。

1. 按照[自述文件中的安装说明](https://github.com/aws/aws-iot-device-sdk-js-v2/tree/v1.12.1#installation)从源代码构建 JavaScript v2 版。 AWS IoT Device SDK 

1. 创建与 AWS IoT Greengrass 核心 IPC 服务的连接。完成以下步骤，以创建 IPC 客户端并建立连接。

1. 使用以下代码创建 IPC 客户端。

   ```
   import * as greengrascoreipc from 'aws-iot-device-sdk-v2';
   
   let client = greengrascoreipc.createClient();
   ```

1. 使用以下代码，建立从组件到 Greengrass Nucleus 的连接。

   ```
   await client.connect();
   ```

## 授权组件执行 IPC 操作
<a name="ipc-authorization-policies"></a>

要允许您的自定义组件使用某些 IPC 操作，您必须定义*授权策略*，允许组件对某些资源执行操作。每个授权策略都定义了策略允许的操作列表和资源列表。例如， publish/subscribe 消息 IPC 服务定义了主题资源的发布和订阅操作。您可以使用 `*` 通配符以允许访问所有操作或所有资源。

您可以使用 `accessControl` 配置参数定义授权策略。您可以在组件配方中或在部署组件时设置该参数。`accessControl` 对象将 IPC 服务标识符映射到授权策略列表。您可以为每个 IPC 服务定义多个授权策略来控制访问权限。每个授权策略都有一个策略 ID，该 ID 在所有组件中必须唯一。

**提示**  
要创建唯一的策略 IDs，您可以组合组件名称、IPC 服务名称和计数器。例如，名为的组件`com.example.HelloWorld`可以定义两个 publish/subscribe 授权策略，如下所示 IDs：  
`com.example.HelloWorld:pubsub:1`
`com.example.HelloWorld:pubsub:2`

授权策略使用以下格式。此对象是 `accessControl` 配置参数。

------
#### [ JSON ]

```
{
  "IPC service identifier": {
    "policyId": {
      "policyDescription": "description",
      "operations": [
        "operation1",
        "operation2"
      ],
      "resources": [
        "resource1",
        "resource2"
      ]
    }
  }
}
```

------
#### [ YAML ]

```
IPC service identifier:
  policyId:
    policyDescription: description
    operations:
      - operation1
      - operation2
    resources:
      - resource1
      - resource2
```

------

### 授权策略中的通配符
<a name="ipc-authorization-policy-wildcards"></a>

您可以在 IPC 授权策略的 `resources` 元素中使用 `*` 通配符，以允许访问单个授权策略中的多个资源。
+ 在所有版本的 [Greengrass Nucleus](greengrass-nucleus-component.md) 中，您可以指定单个 `*` 作为资源，以允许访问所有资源。
+ 在 [Greengrass Nucleus](greengrass-nucleus-component.md) v2.6.0 及更高版本中，您可以在资源中指定 `*` 字符，以匹配任何字符组合。例如，您可以指定 `factory/1/devices/Thermostat*/status`，以允许访问工厂中所有恒温器设备的状态主题，其中每台设备的名称都以 `Thermostat` 开头。

在为 AWS IoT Core MQTT IPC 服务定义授权策略时，也可以使用 MQTT 通配符（`+`和`#`）来匹配多个资源。有关更多信息，请参阅 [MQTT IPC 授权策略中的 AWS IoT Core MQTT 通配符](ipc-iot-core-mqtt.md#ipc-iot-core-mqtt-authorization-mqtt-wildcards)。

### 授权策略中的配方变量
<a name="ipc-authorization-policy-recipe-variables"></a>

[如果你使用 [Greengrass](greengrass-nucleus-component.md) nucleus v2.6.0 或更高版本，并且将 Greeng [interpolateComponentConfiguration](greengrass-nucleus-component.md#greengrass-nucleus-component-configuration-interpolate-component-configuration)rass nucleus 的配置选项设置为，则可以在授权策略中使用配方变量。`true``{iot:thingName}`](component-recipe-reference.md#recipe-variables)当您需要包含核心设备名称的授权策略（例如针对 MQTT 主题或设备影子）时，您可以使用此配方变量为一组核心设备配置单个授权策略。例如，您可以允许组件访问以下适用于影子 IPC 操作的资源。

```
$aws/things/{iot:thingName}/shadow/
```

### 授权策略中的特殊字符
<a name="ipc-authorization-policy-special-characters"></a>

要在授权策略中指定文字 `*` 或 `?` 字符，您必须使用转义序列。以下转义序列指示 AWS IoT Greengrass Core 软件使用字面值而不是字符的特殊含义。例如，`*` 字符是与任意字符组合匹配的[通配符](#ipc-authorization-policy-wildcards)。


| 文字字符 | 转义序列 | 注意 | 
| --- | --- | --- | 
|  `*`  |  `${*}`  |  | 
|  `?`  |  `${?}`  |  AWS IoT Greengrass 目前不支持与任何单个字符匹配的`?`通配符。  | 
|  `$`  |  `${$}`  |  使用此转义序列可匹配包含 `${` 的资源。例如，要匹配名为 `${resourceName}` 的资源，您必须指定 `${$}{resourceName}`。否则，要匹配包含 `$` 的资源，您可以使用文字 `$`，例如允许访问以 `$aws` 开头的主题。  | 

### 授权策略示例
<a name="ipc-authorization-policy-examples"></a>

您可以参考以下授权策略示例，帮助您为组件配置授权策略。

**Example 具有授权策略的组件配方示例**  
以下示例组件配方包括可定义授权策略的 `accessControl` 对象。此策略授权 `com.example.HelloWorld` 组件发布到 `test/topic` 主题。  

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.HelloWorld",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.HelloWorld:pubsub:1": {
            "policyDescription": "Allows access to publish to test/topic.",
            "operations": [
              "aws.greengrass#PublishToTopic"
            ],
            "resources": [
              "test/topic"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Lifecycle": {
        "Run": "java -jar {artifacts:path}/HelloWorld.jar"
      }
    }
  ]
}
```

```
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.HelloWorld
ComponentVersion: '1.0.0'
ComponentDescription: A component that publishes messages.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.pubsub:
        "com.example.HelloWorld:pubsub:1":
          policyDescription: Allows access to publish to test/topic.
          operations:
            - "aws.greengrass#PublishToTopic"
          resources:
            - "test/topic"
Manifests:
  - Lifecycle:
      Run: |-
        java -jar {artifacts:path}/HelloWorld.jar
```

**Example 使用授权策略的组件配置更新示例**  
部署中的以下配置更新示例指定使用可定义授权策略的 `accessControl` 对象来配置组件。此策略授权 `com.example.HelloWorld` 组件发布到 `test/topic` 主题。    
**要合并的配置**  

```
{
  "accessControl": {
    "aws.greengrass.ipc.pubsub": {
      "com.example.HelloWorld:pubsub:1": {
        "policyDescription": "Allows access to publish to test/topic.",
        "operations": [
          "aws.greengrass#PublishToTopic"
        ],
        "resources": [
          "test/topic"
        ]
      }
    }
  }
}
```
以下命令会创建对核心设备的部署。  

```
aws greengrassv2 create-deployment --cli-input-json file://hello-world-deployment.json
```
`hello-world-deployment.json` 文件包含以下 JSON 文档。  

```
{
  "targetArn": "arn:aws:iot:us-west-2:123456789012:thing/MyGreengrassCore",
  "deploymentName": "Deployment for MyGreengrassCore",
  "components": {
    "com.example.HelloWorld": {
      "componentVersion": "1.0.0",
      "configurationUpdate": {
        "merge": "{\"accessControl\":{\"aws.greengrass.ipc.pubsub\":{\"com.example.HelloWorld:pubsub:1\":{\"policyDescription\":\"Allows access to publish to test/topic.\",\"operations\":[\"aws.greengrass#PublishToTopic\"],\"resources\":[\"test/topic\"]}}}}"
      }
    }
  }
}
```
以下 [Greengrass CLI](greengrass-cli-component.md) 命令会在核心设备上创建本地部署。  

```
sudo greengrass-cli deployment create \
  --recipeDir recipes \
  --artifactDir artifacts \
  --merge "com.example.HelloWorld=1.0.0" \
  --update-config hello-world-configuration.json
```
`hello-world-configuration.json` 文件包含以下 JSON 文档。  

```
{
  "com.example.HelloWorld": {
    "MERGE": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.HelloWorld:pubsub:1": {
            "policyDescription": "Allows access to publish to test/topic.",
            "operations": [
              "aws.greengrass#PublishToTopic"
            ],
            "resources": [
              "test/topic"
            ]
          }
        }
      }
    }
  }
}
```

## 订阅 IPC 事件流
<a name="ipc-subscribe-operations"></a>

您可以使用 IPC 操作在 Greengrass 核心设备上订阅事件流。要使用订阅操作，请定义*订阅处理程序*并创建对 IPC 服务的请求。然后，每次核心设备将事件消息流式传输到您的组件时，IPC 客户端都会运行订阅处理程序的函数。

您可以关闭订阅以停止处理事件消息。为此，请在您用于打开订阅的订阅操作对象上调用 `closeStream()`（Java）、`close()`（Python）或 `Close()`（C\$1\$1）。

C AWS IoT Greengrass ore IPC 服务支持以下订阅操作：
+ [SubscribeToTopic](ipc-publish-subscribe.md#ipc-operation-subscribetotopic)
+ [SubscribeToIoTCore](ipc-iot-core-mqtt.md#ipc-operation-subscribetoiotcore)
+ [SubscribeToComponentUpdates](ipc-component-lifecycle.md#ipc-operation-subscribetocomponentupdates)
+ [SubscribeToConfigurationUpdate](ipc-component-configuration.md#ipc-operation-subscribetoconfigurationupdate)
+ [SubscribeToValidateConfigurationUpdates](ipc-component-configuration.md#ipc-operation-subscribetovalidateconfigurationupdates)

**Topics**
+ [定义订阅处理程序](#ipc-define-subscription-handlers)
+ [订阅处理程序示例](#ipc-subscription-handler-examples)

### 定义订阅处理程序
<a name="ipc-define-subscription-handlers"></a>

要定义订阅处理程序，请定义回调函数，处理事件消息、错误和流关闭。如果您使用 IPC 客户端 V1，则必须在类中定义这些函数。如果您使用 IPC 客户端 V2（在 Java 和 Python 的更高版本中可用） SDKs，则无需创建订阅处理程序类即可定义这些函数。

------
#### [ Java ]

如果您使用 IPC 客户端 V1，则必须实现通用`software.amazon.awssdk.eventstreamrpc.StreamResponseHandler<StreamEventType>`接口。 *StreamEventType*是订阅操作的事件消息的类型。定义以下函数以处理事件消息、错误和流关闭。

如果您使用 IPC 客户端 V2，则可以在订阅处理程序类之外定义这些函数，也可以使用 [Lambda 表达式](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)。

`void onStreamEvent(StreamEventType event)`  
IPC 客户端在收到事件消息（例如 MQTT 消息或组件更新通知）时调用的回调。

`boolean onStreamError(Throwable error)`  
IPC 客户端在流错误发生时调用的回调。  
<a name="ipc-subscription-handler-on-stream-error-return-value"></a>如果出现错误，则返回 True 以关闭订阅流，或返回 False 以保持流处于打开状态。

`void onStreamClosed()`  
IPC 客户端在流关闭时调用的回调。

------
#### [ Python ]

如果您使用 IPC 客户端 V1，则必须扩展与订阅操作对应的流响应处理程序类。 AWS IoT Device SDK 包括每个订阅操作的订阅处理程序类。 *StreamEventType*是订阅操作的事件消息的类型。定义以下函数以处理事件消息、错误和流关闭。

如果您使用 IPC 客户端 V2，则可以在订阅处理程序类之外定义这些函数，也可以使用 [Lambda 表达式](https://docs.python.org/3/tutorial/controlflow.html#lambda-expressions)。

`def on_stream_event(self, event: StreamEventType) -> None`  
IPC 客户端在收到事件消息（例如 MQTT 消息或组件更新通知）时调用的回调。

`def on_stream_error(self, error: Exception) -> bool`  
IPC 客户端在流错误发生时调用的回调。  
<a name="ipc-subscription-handler-on-stream-error-return-value"></a>如果出现错误，则返回 True 以关闭订阅流，或返回 False 以保持流处于打开状态。

`def on_stream_closed(self) -> None`  
IPC 客户端在流关闭时调用的回调。

------
#### [ C\$1\$1 (IPC client V1) ]

实施从与订阅操作对应的流响应处理程序类派生的类。 AWS IoT Device SDK 包括每个订阅操作的订阅处理程序基类。 *StreamEventType*是订阅操作的事件消息的类型。定义以下函数以处理事件消息、错误和流关闭。

`void OnStreamEvent(StreamEventType *event)`  
IPC 客户端在收到事件消息（例如 MQTT 消息或组件更新通知）时调用的回调。

`bool OnStreamError(OperationError *error)`  
IPC 客户端在流错误发生时调用的回调。  
<a name="ipc-subscription-handler-on-stream-error-return-value"></a>如果出现错误，则返回 True 以关闭订阅流，或返回 False 以保持流处于打开状态。

`void OnStreamClosed()`  
IPC 客户端在流关闭时调用的回调。

------
#### [ JavaScript ]

实施从与订阅操作对应的流响应处理程序类派生的类。 AWS IoT Device SDK 包括每个订阅操作的订阅处理程序基类。 *StreamEventType*是订阅操作的事件消息的类型。定义以下函数以处理事件消息、错误和流关闭。

`on(event: 'ended', listener: StreamingOperationEndedListener)`  
IPC 客户端在流关闭时调用的回调。

`on(event: 'streamError', listener: StreamingRpcErrorListener)`  
IPC 客户端在流错误发生时调用的回调。  
<a name="ipc-subscription-handler-on-stream-error-return-value"></a>如果出现错误，则返回 True 以关闭订阅流，或返回 False 以保持流处于打开状态。

`on(event: 'message', listener: (message: InboundMessageType) => void)`  
IPC 客户端在收到事件消息（例如 MQTT 消息或组件更新通知）时调用的回调。

------

### 订阅处理程序示例
<a name="ipc-subscription-handler-examples"></a>

以下示例演示如何使用 [SubscribeToTopic](ipc-publish-subscribe.md#ipc-operation-subscribetotopic) 操作和订阅处理程序来订阅本地发布/订阅消息。

------
#### [ Java (IPC client V2) ]

**Example 示例：订阅本地 publish/subscribe 消息**  <a name="ipc-operation-subscribetotopic-example-java-v2"></a>

```
package com.aws.greengrass.docs.samples.ipc;

import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClientV2;
import software.amazon.awssdk.aws.greengrass.SubscribeToTopicResponseHandler;
import software.amazon.awssdk.aws.greengrass.model.*;

import java.nio.charset.StandardCharsets;
import java.util.Optional;

public class SubscribeToTopicV2 {

    public static void main(String[] args) {
        String topic = args[0];
        try (GreengrassCoreIPCClientV2 ipcClient = GreengrassCoreIPCClientV2.builder().build()) {
            SubscribeToTopicRequest request = new SubscribeToTopicRequest().withTopic(topic);
            GreengrassCoreIPCClientV2.StreamingResponse<SubscribeToTopicResponse,
                    SubscribeToTopicResponseHandler> response =
                    ipcClient.subscribeToTopic(request, SubscribeToTopicV2::onStreamEvent,
                            Optional.of(SubscribeToTopicV2::onStreamError),
                            Optional.of(SubscribeToTopicV2::onStreamClosed));
            SubscribeToTopicResponseHandler responseHandler = response.getHandler();
            System.out.println("Successfully subscribed to topic: " + topic);

            // Keep the main thread alive, or the process will exit.
            try {
                while (true) {
                    Thread.sleep(10000);
                }
            } catch (InterruptedException e) {
                System.out.println("Subscribe interrupted.");
            }

            // To stop subscribing, close the stream.
            responseHandler.closeStream();
        } catch (Exception e) {
            if (e.getCause() instanceof UnauthorizedError) {
                System.err.println("Unauthorized error while publishing to topic: " + topic);
            } else {
                System.err.println("Exception occurred when using IPC.");
            }
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static void onStreamEvent(SubscriptionResponseMessage subscriptionResponseMessage) {
        try {
            BinaryMessage binaryMessage = subscriptionResponseMessage.getBinaryMessage();
            String message = new String(binaryMessage.getMessage(), StandardCharsets.UTF_8);
            String topic = binaryMessage.getContext().getTopic();
            System.out.printf("Received new message on topic %s: %s%n", topic, message);
        } catch (Exception e) {
            System.err.println("Exception occurred while processing subscription response " +
                    "message.");
            e.printStackTrace();
        }
    }

    public static boolean onStreamError(Throwable error) {
        System.err.println("Received a stream error.");
        error.printStackTrace();
        return false; // Return true to close stream, false to keep stream open.
    }

    public static void onStreamClosed() {
        System.out.println("Subscribe to topic stream closed.");
    }
}
```

------
#### [ Python (IPC client V2) ]

**Example 示例：订阅本地 publish/subscribe 消息**  <a name="ipc-operation-subscribetotopic-example-python-v2"></a>

```
import sys
import time
import traceback

from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2
from awsiot.greengrasscoreipc.model import (
    SubscriptionResponseMessage,
    UnauthorizedError
)


def main():
    args = sys.argv[1:]
    topic = args[0]

    try:
        ipc_client = GreengrassCoreIPCClientV2()
        # Subscription operations return a tuple with the response and the operation.
        _, operation = ipc_client.subscribe_to_topic(topic=topic, on_stream_event=on_stream_event,
                                                     on_stream_error=on_stream_error, on_stream_closed=on_stream_closed)
        print('Successfully subscribed to topic: ' + topic)

        # Keep the main thread alive, or the process will exit.
        try:
            while True:
                time.sleep(10)
        except InterruptedError:
            print('Subscribe interrupted.')

        # To stop subscribing, close the stream.
        operation.close()
    except UnauthorizedError:
        print('Unauthorized error while subscribing to topic: ' +
              topic, file=sys.stderr)
        traceback.print_exc()
        exit(1)
    except Exception:
        print('Exception occurred', file=sys.stderr)
        traceback.print_exc()
        exit(1)


def on_stream_event(event: SubscriptionResponseMessage) -> None:
    try:
        message = str(event.binary_message.message, 'utf-8')
        topic = event.binary_message.context.topic
        print('Received new message on topic %s: %s' % (topic, message))
    except:
        traceback.print_exc()


def on_stream_error(error: Exception) -> bool:
    print('Received a stream error.', file=sys.stderr)
    traceback.print_exc()
    return False  # Return True to close stream, False to keep stream open.


def on_stream_closed() -> None:
    print('Subscribe to topic stream closed.')


if __name__ == '__main__':
    main()
```

------
#### [ C\$1\$1 (IPC client V1) ]

**Example 示例：订阅本地 publish/subscribe 消息**  <a name="ipc-operation-subscribetotopic-example-cpp"></a>

```
#include <iostream>

#include </crt/Api.h>
#include <aws/greengrass/GreengrassCoreIpcClient.h>

using namespace Aws::Crt;
using namespace Aws::Greengrass;

class SubscribeResponseHandler : public SubscribeToTopicStreamHandler {
    public:
        virtual ~SubscribeResponseHandler() {}

    private:
        void OnStreamEvent(SubscriptionResponseMessage *response) override {
            auto jsonMessage = response->GetJsonMessage();
            if (jsonMessage.has_value() && jsonMessage.value().GetMessage().has_value()) {
                auto messageString = jsonMessage.value().GetMessage().value().View().WriteReadable();
                // Handle JSON message.
            } else {
                auto binaryMessage = response->GetBinaryMessage();
                if (binaryMessage.has_value() && binaryMessage.value().GetMessage().has_value()) {
                    auto messageBytes = binaryMessage.value().GetMessage().value();
                    std::string messageString(messageBytes.begin(), messageBytes.end());
                    // Handle binary message.
                }
            }
        }

        bool OnStreamError(OperationError *error) override {
            // Handle error.
            return false; // Return true to close stream, false to keep stream open.
        }

        void OnStreamClosed() override {
            // Handle close.
        }
};

class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
    void OnConnectCallback() override {
        // Handle connection to IPC service.
    }

    void OnDisconnectCallback(RpcError error) override {
        // Handle disconnection from IPC service.
    }

    bool OnErrorCallback(RpcError error) override {
        // Handle IPC service connection error.
        return true;
    }
};

int main() {
    ApiHandle apiHandle(g_allocator);
    Io::EventLoopGroup eventLoopGroup(1);
    Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
    Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
    IpcClientLifecycleHandler ipcLifecycleHandler;
    GreengrassCoreIpcClient ipcClient(bootstrap);
    auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
    if (!connectionStatus) {
        std::cerr << "Failed to establish IPC connection: " << connectionStatus.StatusToString() << std::endl;
        exit(-1);
    }

    String topic("my/topic");
    int timeout = 10;

    SubscribeToTopicRequest request;
    request.SetTopic(topic);

    //SubscribeResponseHandler streamHandler;
    auto streamHandler = MakeShared<SubscribeResponseHandler>(DefaultAllocator());
    auto operation = ipcClient.NewSubscribeToTopic(streamHandler);
    auto activate = operation->Activate(request, nullptr);
    activate.wait();

    auto responseFuture = operation->GetResult();
    if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
        std::cerr << "Operation timed out while waiting for response from Greengrass Core." << std::endl;
        exit(-1);
    }

    auto response = responseFuture.get();
    if (!response) {
        // Handle error.
        auto errorType = response.GetResultType();
        if (errorType == OPERATION_ERROR) {
            auto *error = response.GetOperationError();
            (void)error;
            // Handle operation error.
        } else {
            // Handle RPC error.
        }
        exit(-1);
    }

    // Keep the main thread alive, or the process will exit.
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }

    operation->Close();
    return 0;
}
```

------
#### [ JavaScript ]

**Example 示例：订阅本地 publish/subscribe 消息**  <a name="ipc-operation-subscribetotopic-example-nodejs"></a>

```
import * as greengrasscoreipc from "aws-iot-device-sdk-v2/dist/greengrasscoreipc";
import {SubscribeToTopicRequest, SubscriptionResponseMessage} from "aws-iot-device-sdk-v2/dist/greengrasscoreipc/model";
import {RpcError} from "aws-iot-device-sdk-v2/dist/eventstream_rpc";
 
class SubscribeToTopic {
    private ipcClient : greengrasscoreipc.Client
    private readonly topic : string;
 
    constructor() {
        // define your own constructor, e.g.
        this.topic = "<define_your_topic>";
        this.subscribeToTopic().then(r => console.log("Started workflow"));
    }
 
    private async subscribeToTopic() {
        try {
            this.ipcClient = await getIpcClient();
 
            const subscribeToTopicRequest : SubscribeToTopicRequest = {
                topic: this.topic,
            }
 
            const streamingOperation = this.ipcClient.subscribeToTopic(subscribeToTopicRequest, undefined); // conditionally apply options
 
            streamingOperation.on("message", (message: SubscriptionResponseMessage) => {
                // parse the message depending on your use cases, e.g.
                if(message.binaryMessage && message.binaryMessage.message) {
                    const receivedMessage = message.binaryMessage?.message.toString();
                }
            });
 
            streamingOperation.on("streamError", (error : RpcError) => {
                // define your own error handling logic
            })
 
            streamingOperation.on("ended", () => {
                // define your own logic
            })
 
            await streamingOperation.activate();
 
            // Keep the main thread alive, or the process will exit.
            await new Promise((resolve) => setTimeout(resolve, 10000))
        } catch (e) {
            // parse the error depending on your use cases
            throw e
        }
    }
}
 
export async function getIpcClient(){
    try {
        const ipcClient = greengrasscoreipc.createClient();
        await ipcClient.connect()
            .catch(error => {
                // parse the error depending on your use cases
                throw error;
            });
        return ipcClient
    } catch (err) {
        // parse the error depending on your use cases
        throw err
    }
}
 
// starting point
const subscribeToTopic = new SubscribeToTopic();
```

------
#### [ Rust ]

**Example 示例：订阅本地 publish/subscribe 消息**  

```
use gg_sdk::{Sdk, SubscribeToTopicPayload};
use std::{thread, time::Duration};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    let topic = "my/topic";

    let callback = |topic: &str, payload: SubscribeToTopicPayload| match payload
    {
        SubscribeToTopicPayload::Binary(message) => {
            let message = String::from_utf8_lossy(message);
            println!("Received new message on topic {topic}: {message}");
        }
        SubscribeToTopicPayload::Json(_) => {
            println!("Received new message on topic {topic}: (JSON message)");
        }
    };

    let _sub = sdk
        .subscribe_to_topic(topic, &callback)
        .expect("Failed to subscribe to topic");

    println!("Successfully subscribed to topic: {topic}");

    // Keep the main thread alive, or the process will exit.
    loop {
        thread::sleep(Duration::from_secs(10));
    }
}
```

------
#### [ C ]

**Example 示例：订阅本地 publish/subscribe 消息**  

```
#include <assert.h>
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <gg/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

static void on_subscription_response(
    void *ctx, GgBuffer topic, GgObject payload, GgIpcSubscriptionHandle handle
) {
    (void) ctx;
    (void) handle;

    if (gg_obj_type(payload) == GG_TYPE_BUF) {
        GgBuffer message = gg_obj_into_buf(payload);
        printf(
            "Received new message on topic %.*s: %.*s\n",
            (int) topic.len,
            topic.data,
            (int) message.len,
            message.data
        );
    } else {
        assert(gg_obj_type(payload) == GG_TYPE_MAP);
        printf(
            "Received new message on topic %.*s: (JSON message)\n",
            (int) topic.len,
            topic.data
        );
    }
}

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    GgBuffer topic = GG_STR("my/topic");

    GgIpcSubscriptionHandle handle;
    err = ggipc_subscribe_to_topic(
        topic, on_subscription_response, NULL, &handle
    );
    if (err != GG_ERR_OK) {
        fprintf(
            stderr,
            "Failed to subscribe to topic: %.*s\n",
            (int) topic.len,
            topic.data
        );
        exit(-1);
    }

    printf(
        "Successfully subscribed to topic: %.*s\n", (int) topic.len, topic.data
    );

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }

    // To stop subscribing, close the stream.
    ggipc_close_subscription(handle);
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：订阅本地 publish/subscribe 消息**  

```
#include <gg/ipc/client.hpp>
#include <gg/object.hpp>
#include <unistd.h>
#include <cassert>
#include <iostream>

class ResponseHandler : public gg::ipc::LocalTopicCallback {
    void operator()(
        std::string_view topic,
        gg::Object payload,
        gg::ipc::Subscription &handle
    ) override {
        (void) handle;
        if (payload.index() == GG_TYPE_BUF) {
            std::cout << "Received new message on topic " << topic << ": "
                      << get<gg::Buffer>(payload) << "\n";
        } else {
            assert(payload.index() == GG_TYPE_MAP);
            std::cout << "Received new message on topic " << topic
                      << ": (JSON message)\n";
        }
    }
};

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    std::string_view topic = "my/topic";

    static ResponseHandler handler;
    error = client.subscribe_to_topic(topic, handler);
    if (error) {
        std::cerr << "Failed to subscribe to topic: " << topic << "\n";
        exit(-1);
    }

    std::cout << "Successfully subscribed to topic: " << topic << "\n";

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }
}
```

------

## IPC 最佳实践
<a name="ipc-best-practices"></a>

在自定义组件中使用 IPC 的最佳实践与在 IPC 客户端 V1 和 IPC 客户端 V2 之间有所不同。请遵循适用于您所使用的 IPC 客户端版本的最佳实践。

------
#### [ IPC client V2 ]

IPC 客户端 V2 在单独的线程中运行回调函数，因此与 IPC 客户端 V1 相比，在使用 IPC 和编写订阅处理程序函数时，您需要遵循的准则较少。
+ <a name="ipc-best-practice-reuse-one-client"></a>**重复使用一个 IPC 客户端**

  创建 IPC 客户端后，请将其保持打开状态并重复用于所有 IPC 操作。创建多个客户端会消耗额外的资源，并可能导致资源泄漏。
+ **处理异常**

  IPC 客户端 V2 记录订阅处理程序函数中未捕获的异常。您应该捕获处理程序函数中的异常，以处理代码中发生的错误。

------
#### [ IPC client V1 ]

IPC 客户端 V1 使用单线程，与 IPC 服务器通信并调用订阅处理程序。在编写订阅处理程序函数时，您必须考虑这种同步行为。
+ <a name="ipc-best-practice-reuse-one-client"></a>**重复使用一个 IPC 客户端**

  创建 IPC 客户端后，请将其保持打开状态并重复用于所有 IPC 操作。创建多个客户端会消耗额外的资源，并可能导致资源泄漏。
+ **异步运行阻止代码**

  当线程被阻止时，IPC 客户端 V1 无法发送新请求或处理新的事件消息。您应该在从处理程序函数运行的独立线程中运行阻止代码。阻塞代码包括`sleep`调用、持续运行的循环以及需要一段时间才能完成的同步 I/O 请求。
+ **异步发送新的 IPC 请求**

  IPC 客户端 V1 无法从订阅处理程序函数中发送新请求，因为如果您等待响应，该请求会阻止处理程序函数。您应该在从处理程序函数运行的独立线程中发送 IPC 请求。
+ **处理异常**

  IPC 客户端 V1 不处理订阅处理函数中未捕获的异常。如果您的处理函数抛出异常，则订阅关闭，并且该异常不会出现在您的组件日志中。您应该捕获处理程序函数中的异常，以确保订阅保持打开状态并记录代码中发生的错误。

------

# 发布/订阅本地消息
<a name="ipc-publish-subscribe"></a>

发布/订阅 (pubsub) 消息收发允许您向主题发送和接收消息。组件可以向主题发布消息，以将消息发送给其他组件。然后，订阅该主题的组件可以对它们收到的消息进行操作。

**注意**  
您不能使用此 publish/subscribe IPC 服务发布或订阅 AWS IoT Core MQTT。有关如何使用 AWS IoT Core MQTT 交换消息的更多信息，请参阅[发布/订阅 AWS IoT Core MQTT 消息](ipc-iot-core-mqtt.md)。

**Topics**
+ [最低 SDK 版本](#ipc-publish-subscribe-sdk-versions)
+ [Authorization](#ipc-publish-subscribe-authorization)
+ [PublishToTopic](#ipc-operation-publishtotopic)
+ [SubscribeToTopic](#ipc-operation-subscribetotopic)
+ [示例](#ipc-publish-subscribe-examples)

## 最低 SDK 版本
<a name="ipc-publish-subscribe-sdk-versions"></a>

下表列出了在向本地主题发布和订阅消息时必须使用的最低版本。 AWS IoT Device SDK 


| SDK | 最低版本 | 
| --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.2.10  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.5.3  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.17.0  | 
|  [AWS IoT Device SDK for JavaScript](https://github.com/aws/aws-iot-device-sdk-js-v2) v2  |  v1.12.0  | 

## Authorization
<a name="ipc-publish-subscribe-authorization"></a>

要在自定义组件中使用本地 publish/subscribe 消息，必须定义允许您的组件向主题发送和接收消息的授权策略。有关定义授权策略的信息，请参阅[授权组件执行 IPC 操作](interprocess-communication.md#ipc-authorization-policies)。

 publish/subscribe 消息传递的授权策略具有以下属性。

**IPC 服务标识符：**`aws.greengrass.ipc.pubsub`


| 操作 | 说明 | 资源 | 
| --- | --- | --- | 
|  `aws.greengrass#PublishToTopic`  |  允许组件向您指定的主题发布消息。  |  主题字符串，例如 `test/topic`。`*` 使用匹配主题中的任意字符组合。 此主题字符串不支持 MQTT 主题通配符（`#` 和 `+`）。  | 
|  `aws.greengrass#SubscribeToTopic`  |  允许组件订阅您指定主题的消息。  |  主题字符串，例如 `test/topic`。`*` 使用匹配主题中的任意字符组合。 <a name="ipc-local-publish-subscribe-authorization-mqtt-wildcards"></a>在 [Greengrass Nucleus](greengrass-nucleus-component.md) v2.6.0 及更高版本中，您可以订阅包含 MQTT 主题通配符（`#` 和 `+`）的主题。此主题字符串支持 MQTT 主题通配符作为文字字符。例如，如果组件的授权策略授予访问 `test/topic/#` 的权限，则该组件可以订阅 `test/topic/#`，但无法订阅 `test/topic/filter`。  | 
|  `*`  |  允许组件为您指定的主题发布和订阅消息。  |  主题字符串，例如 `test/topic`。`*` 使用匹配主题中的任意字符组合。 <a name="ipc-local-publish-subscribe-authorization-mqtt-wildcards"></a>在 [Greengrass Nucleus](greengrass-nucleus-component.md) v2.6.0 及更高版本中，您可以订阅包含 MQTT 主题通配符（`#` 和 `+`）的主题。此主题字符串支持 MQTT 主题通配符作为文字字符。例如，如果组件的授权策略授予访问 `test/topic/#` 的权限，则该组件可以订阅 `test/topic/#`，但无法订阅 `test/topic/filter`。  | 

### 授权策略示例
<a name="ipc-publish-subscribe-authorization-policy-examples"></a>

您可以参考以下授权策略示例，帮助您为组件配置授权策略。

**Example 示例授权策略**  
以下示例授权策略允许组件发布和订阅所有主题。  

```
{
  "accessControl": {
    "aws.greengrass.ipc.pubsub": {
      "com.example.MyLocalPubSubComponent:pubsub:1": {
        "policyDescription": "Allows access to publish/subscribe to all topics.",
        "operations": [
          "aws.greengrass#PublishToTopic",
          "aws.greengrass#SubscribeToTopic"
        ],
        "resources": [
          "*"
        ]
      }
    }
  }
}
```

## PublishToTopic
<a name="ipc-operation-publishtotopic"></a>

向主题发布消息。

### 请求
<a name="ipc-operation-publishtotopic-request"></a>

此操作的请求包含以下参数：

`topic`  
要向其发布消息的主题。

`publishMessage` (Python: `publish_message`)  
待发布的消息。该对象 `PublishMessage` 包含以下信息。您必须指定 `jsonMessage` 和 `binaryMessage` 中的一个。  <a name="ipc-publish-subscribe-message-shape"></a>  
`jsonMessage` (Python: `json_message`)  
（可选）一条 JSON 消息。该对象 `JsonMessage` 包含以下信息：    
`message`  
作为对象的 JSON 消息。  
`context`  <a name="ipc-publish-subscribe-message-context-variable"></a>
消息的上下文，例如消息发布的主题。  
此功能适用于 [Greengrass Nucleus 组件](greengrass-nucleus-component.md)的 v2.6.0 及更高版本。下表列出了访问消息上下文时必须使用的最低 AWS IoT Device SDK 版本。      
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-publish-subscribe.html)
C AWS IoT Greengrass ore 软件在`PublishToTopic`和`SubscribeToTopic`操作中使用相同的消息对象。当您订阅时， AWS IoT Greengrass Core 软件会在消息中设置此上下文对象，并在您发布的消息中忽略此上下文对象。
该对象 `MessageContext` 包含以下信息：    
`topic`  
消息发布的主题。  
`binaryMessage` (Python: `binary_message`)  
（可选）二进制消息。该对象 `BinaryMessage` 包含以下信息：    
`message`  
以 blob 形式呈现的二进制消息。  
`context`  <a name="ipc-publish-subscribe-message-context-variable"></a>
消息的上下文，例如消息发布的主题。  
此功能适用于 [Greengrass Nucleus 组件](greengrass-nucleus-component.md)的 v2.6.0 及更高版本。下表列出了访问消息上下文时必须使用的最低 AWS IoT Device SDK 版本。      
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-publish-subscribe.html)
C AWS IoT Greengrass ore 软件在`PublishToTopic`和`SubscribeToTopic`操作中使用相同的消息对象。当您订阅时， AWS IoT Greengrass Core 软件会在消息中设置此上下文对象，并在您发布的消息中忽略此上下文对象。
该对象 `MessageContext` 包含以下信息：    
`topic`  
消息发布的主题。

### 响应
<a name="ipc-operation-publishtotopic-response"></a>

此操作在其响应中未提供任何信息。

### 示例
<a name="ipc-operation-publishtotopic-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Java (IPC client V2) ]

**Example 示例：发布二进制消息**  

```
package com.aws.greengrass.docs.samples.ipc;

import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClientV2;
import software.amazon.awssdk.aws.greengrass.model.BinaryMessage;
import software.amazon.awssdk.aws.greengrass.model.PublishMessage;
import software.amazon.awssdk.aws.greengrass.model.PublishToTopicRequest;
import software.amazon.awssdk.aws.greengrass.model.PublishToTopicResponse;
import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError;

import java.nio.charset.StandardCharsets;

public class PublishToTopicV2 {

    public static void main(String[] args) {
        String topic = args[0];
        String message = args[1];
        try (GreengrassCoreIPCClientV2 ipcClient = GreengrassCoreIPCClientV2.builder().build()) {
            PublishToTopicV2.publishBinaryMessageToTopic(ipcClient, topic, message);
            System.out.println("Successfully published to topic: " + topic);
        } catch (Exception e) {
            if (e.getCause() instanceof UnauthorizedError) {
                System.err.println("Unauthorized error while publishing to topic: " + topic);
            } else {
                System.err.println("Exception occurred when using IPC.");
            }
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static PublishToTopicResponse publishBinaryMessageToTopic(
            GreengrassCoreIPCClientV2 ipcClient, String topic, String message) throws InterruptedException {
        BinaryMessage binaryMessage =
                new BinaryMessage().withMessage(message.getBytes(StandardCharsets.UTF_8));
        PublishMessage publishMessage = new PublishMessage().withBinaryMessage(binaryMessage);
        PublishToTopicRequest publishToTopicRequest =
                new PublishToTopicRequest().withTopic(topic).withPublishMessage(publishMessage);
        return ipcClient.publishToTopic(publishToTopicRequest);
    }
}
```

------
#### [ Python (IPC client V2) ]

**Example 示例：发布二进制消息**  

```
import sys
import traceback

from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2
from awsiot.greengrasscoreipc.model import (
    PublishMessage,
    BinaryMessage
)


def main():
    args = sys.argv[1:]
    topic = args[0]
    message = args[1]

    try:
        ipc_client = GreengrassCoreIPCClientV2()
        publish_binary_message_to_topic(ipc_client, topic, message)
        print('Successfully published to topic: ' + topic)
    except Exception:
        print('Exception occurred', file=sys.stderr)
        traceback.print_exc()
        exit(1)


def publish_binary_message_to_topic(ipc_client, topic, message):
    binary_message = BinaryMessage(message=bytes(message, 'utf-8'))
    publish_message = PublishMessage(binary_message=binary_message)
    return ipc_client.publish_to_topic(topic=topic, publish_message=publish_message)


if __name__ == '__main__':
    main()
```

------
#### [ C\$1\$1 (IPC client V1) ]

**Example 示例：发布二进制消息**  

```
#include <iostream>

#include <aws/crt/Api.h>
#include <aws/greengrass/GreengrassCoreIpcClient.h>

using namespace Aws::Crt;
using namespace Aws::Greengrass;

class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
    void OnConnectCallback() override {
        // Handle connection to IPC service.
    }

    void OnDisconnectCallback(RpcError error) override {
        // Handle disconnection from IPC service.
    }

    bool OnErrorCallback(RpcError error) override {
        // Handle IPC service connection error.
        return true;
    }
};

int main() {
    ApiHandle apiHandle(g_allocator);
    Io::EventLoopGroup eventLoopGroup(1);
    Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
    Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
    IpcClientLifecycleHandler ipcLifecycleHandler;
    GreengrassCoreIpcClient ipcClient(bootstrap);
    auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
    if (!connectionStatus) {
        std::cerr << "Failed to establish IPC connection: " << connectionStatus.StatusToString() << std::endl;
        exit(-1);
    }

    String topic("my/topic");
    String message("Hello, World!");
    int timeout = 10;

    PublishToTopicRequest request;
    Vector<uint8_t> messageData({message.begin(), message.end()});
    BinaryMessage binaryMessage;
    binaryMessage.SetMessage(messageData);
    PublishMessage publishMessage;
    publishMessage.SetBinaryMessage(binaryMessage);
    request.SetTopic(topic);
    request.SetPublishMessage(publishMessage);

    auto operation = ipcClient.NewPublishToTopic();
    auto activate = operation->Activate(request, nullptr);
    activate.wait();

    auto responseFuture = operation->GetResult();
    if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
        std::cerr << "Operation timed out while waiting for response from Greengrass Core." << std::endl;
        exit(-1);
    }

    auto response = responseFuture.get();
    if (!response) {
        // Handle error.
        auto errorType = response.GetResultType();
        if (errorType == OPERATION_ERROR) {
            auto *error = response.GetOperationError();
            (void)error;
            // Handle operation error.
        } else {
            // Handle RPC error.
        }
    }
    return 0;
}
```

------
#### [ JavaScript ]

**Example 示例：发布二进制消息**  

```
    
import * as greengrasscoreipc from "aws-iot-device-sdk-v2/dist/greengrasscoreipc";
import {BinaryMessage, PublishMessage, PublishToTopicRequest} from "aws-iot-device-sdk-v2/dist/greengrasscoreipc/model";
 
class PublishToTopic {
    private ipcClient : greengrasscoreipc.Client
    private readonly topic : string;
    private readonly messageString : string;
 
    constructor() {
        // define your own constructor, e.g.
        this.topic = "<define_your_topic>";
        this.messageString = "<define_your_message_string>";
        this.publishToTopic().then(r => console.log("Started workflow"));
    }
 
    private async publishToTopic() {
        try {
            this.ipcClient = await getIpcClient();
 
            const binaryMessage : BinaryMessage = {
                message: this.messageString
            }
 
            const publishMessage : PublishMessage = {
                binaryMessage: binaryMessage
            }
 
            const request : PublishToTopicRequest = {
                topic: this.topic,
                publishMessage: publishMessage
            }
 
            this.ipcClient.publishToTopic(request).finally(() => console.log(`Published message ${publishMessage.binaryMessage?.message} to topic`))
 
        } catch (e) {
            // parse the error depending on your use cases
            throw e
        }
    }
}
 
 
export async function getIpcClient(){
    try {
        const ipcClient = greengrasscoreipc.createClient();
        await ipcClient.connect()
            .catch(error => {
                // parse the error depending on your use cases
                throw error;
            });
        return ipcClient
    } catch (err) {
        // parse the error depending on your use cases
        throw err
    }
}
 
// starting point
const publishToTopic = new PublishToTopic();
```

------
#### [ Rust ]

**Example 示例：发布二进制消息**  

```
use gg_sdk::Sdk;

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    let message = b"Hello, World";
    let topic = "my/topic";

    sdk.publish_to_topic_binary(topic, message)
        .expect("Failed to publish to topic");

    println!("Successfully published to topic: {topic}");
}
```

------
#### [ C ]

**Example 示例：发布二进制消息**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/sdk.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    GgBuffer message = GG_STR("Hello, World");
    GgBuffer topic = GG_STR("my/topic");

    err = ggipc_publish_to_topic_binary(topic, message);
    if (err != GG_ERR_OK) {
        fprintf(
            stderr,
            "Failed to publish to topic: %.*s\n",
            (int) topic.len,
            topic.data
        );
        exit(-1);
    }

    printf(
        "Successfully published to topic: %.*s\n", (int) topic.len, topic.data
    );
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：发布二进制消息**  

```
#include <gg/ipc/client.hpp>
#include <iostream>

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    std::string_view message = "Hello, World";
    std::string_view topic = "my/topic";

    error = client.publish_to_topic(topic, message);
    if (error) {
        std::cerr << "Failed to publish to topic: " << topic << "\n";
        exit(-1);
    }

    std::cout << "Successfully published to topic: " << topic << "\n";
}
```

------

## SubscribeToTopic
<a name="ipc-operation-subscribetotopic"></a>

订阅有关某个主题的消息。

<a name="ipc-subscribe-operation-note"></a>此操作是一种订阅操作，您可以在其中订阅事件消息流。要使用此操作，请定义一个流响应处理程序，其中包含处理事件消息、错误和流关闭的函数。有关更多信息，请参阅 [订阅 IPC 事件流](interprocess-communication.md#ipc-subscribe-operations)。

**事件消息类型：**`SubscriptionResponseMessage`

### 请求
<a name="ipc-operation-subscribetotopic-request"></a>

此操作的请求包含以下参数：

`topic`  
要订阅的主题。  
在 [Greengrass Nucleus](greengrass-nucleus-component.md) v2.6.0 及更高版本中，本主题支持 MQTT 主题通配符（`#` 和 `+`）。

`receiveMode` (Python: `receive_mode`)  
（可选）指定组件是否从自身接收消息的行为。您可以更改此行为以允许组件根据自己的消息进行操作。默认行为取决于主题是否包含 MQTT 通配符。从以下选项中进行选择：  
+ `RECEIVE_ALL_MESSAGES` – 接收与该主题匹配的所有消息，包括来自订阅组件的消息。

  当您订阅不包含 MQTT 通配符的主题时，此模式为默认选项。
+ `RECEIVE_MESSAGES_FROM_OTHERS` – 接收与该主题匹配的所有消息，不包括来自订阅组件的消息。

  当您订阅包含 MQTT 通配符的主题时，此模式为默认选项。
此功能适用于 [Greengrass Nucleus 组件](greengrass-nucleus-component.md)的 v2.6.0 及更高版本。下表列出了在设置接收模式时 AWS IoT Device SDK 必须使用的最低版本。      
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-publish-subscribe.html)

### 响应
<a name="ipc-operation-subscribetotopic-response"></a>

此操作的响应包含以下信息：

`messages`  
消息流。该对象 `SubscriptionResponseMessage` 包含以下信息。每条消息都包含 `jsonMessage` 或 `binaryMessage`。  <a name="ipc-publish-subscribe-message-shape"></a>  
`jsonMessage` (Python: `json_message`)  
（可选）一条 JSON 消息。该对象 `JsonMessage` 包含以下信息：    
`message`  
作为对象的 JSON 消息。  
`context`  <a name="ipc-publish-subscribe-message-context-variable"></a>
消息的上下文，例如消息发布的主题。  
此功能适用于 [Greengrass Nucleus 组件](greengrass-nucleus-component.md)的 v2.6.0 及更高版本。下表列出了访问消息上下文时必须使用的最低 AWS IoT Device SDK 版本。      
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-publish-subscribe.html)
C AWS IoT Greengrass ore 软件在`PublishToTopic`和`SubscribeToTopic`操作中使用相同的消息对象。当您订阅时， AWS IoT Greengrass Core 软件会在消息中设置此上下文对象，并在您发布的消息中忽略此上下文对象。
该对象 `MessageContext` 包含以下信息：    
`topic`  
消息发布的主题。  
`binaryMessage` (Python: `binary_message`)  
（可选）二进制消息。该对象 `BinaryMessage` 包含以下信息：    
`message`  
以 blob 形式呈现的二进制消息。  
`context`  <a name="ipc-publish-subscribe-message-context-variable"></a>
消息的上下文，例如消息发布的主题。  
此功能适用于 [Greengrass Nucleus 组件](greengrass-nucleus-component.md)的 v2.6.0 及更高版本。下表列出了访问消息上下文时必须使用的最低 AWS IoT Device SDK 版本。      
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-publish-subscribe.html)
C AWS IoT Greengrass ore 软件在`PublishToTopic`和`SubscribeToTopic`操作中使用相同的消息对象。当您订阅时， AWS IoT Greengrass Core 软件会在消息中设置此上下文对象，并在您发布的消息中忽略此上下文对象。
该对象 `MessageContext` 包含以下信息：    
`topic`  
消息发布的主题。

`topicName` (Python: `topic_name`)  
消息被发布到的主题。  
目前尚未使用该属性。在 [Greengrass Nucleus](greengrass-nucleus-component.md) v2.6.0 及更高版本中，您可以从 `SubscriptionResponseMessage` 中获取 `(jsonMessage|binaryMessage).context.topic` 值以获取消息发布的主题。

### 示例
<a name="ipc-operation-subscribetotopic-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Java (IPC client V2) ]

**Example 示例：订阅本地 publish/subscribe 消息**  <a name="ipc-operation-subscribetotopic-example-java-v2"></a>

```
package com.aws.greengrass.docs.samples.ipc;

import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClientV2;
import software.amazon.awssdk.aws.greengrass.SubscribeToTopicResponseHandler;
import software.amazon.awssdk.aws.greengrass.model.*;

import java.nio.charset.StandardCharsets;
import java.util.Optional;

public class SubscribeToTopicV2 {

    public static void main(String[] args) {
        String topic = args[0];
        try (GreengrassCoreIPCClientV2 ipcClient = GreengrassCoreIPCClientV2.builder().build()) {
            SubscribeToTopicRequest request = new SubscribeToTopicRequest().withTopic(topic);
            GreengrassCoreIPCClientV2.StreamingResponse<SubscribeToTopicResponse,
                    SubscribeToTopicResponseHandler> response =
                    ipcClient.subscribeToTopic(request, SubscribeToTopicV2::onStreamEvent,
                            Optional.of(SubscribeToTopicV2::onStreamError),
                            Optional.of(SubscribeToTopicV2::onStreamClosed));
            SubscribeToTopicResponseHandler responseHandler = response.getHandler();
            System.out.println("Successfully subscribed to topic: " + topic);

            // Keep the main thread alive, or the process will exit.
            try {
                while (true) {
                    Thread.sleep(10000);
                }
            } catch (InterruptedException e) {
                System.out.println("Subscribe interrupted.");
            }

            // To stop subscribing, close the stream.
            responseHandler.closeStream();
        } catch (Exception e) {
            if (e.getCause() instanceof UnauthorizedError) {
                System.err.println("Unauthorized error while publishing to topic: " + topic);
            } else {
                System.err.println("Exception occurred when using IPC.");
            }
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static void onStreamEvent(SubscriptionResponseMessage subscriptionResponseMessage) {
        try {
            BinaryMessage binaryMessage = subscriptionResponseMessage.getBinaryMessage();
            String message = new String(binaryMessage.getMessage(), StandardCharsets.UTF_8);
            String topic = binaryMessage.getContext().getTopic();
            System.out.printf("Received new message on topic %s: %s%n", topic, message);
        } catch (Exception e) {
            System.err.println("Exception occurred while processing subscription response " +
                    "message.");
            e.printStackTrace();
        }
    }

    public static boolean onStreamError(Throwable error) {
        System.err.println("Received a stream error.");
        error.printStackTrace();
        return false; // Return true to close stream, false to keep stream open.
    }

    public static void onStreamClosed() {
        System.out.println("Subscribe to topic stream closed.");
    }
}
```

------
#### [ Python (IPC client V2) ]

**Example 示例：订阅本地 publish/subscribe 消息**  <a name="ipc-operation-subscribetotopic-example-python-v2"></a>

```
import sys
import time
import traceback

from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2
from awsiot.greengrasscoreipc.model import (
    SubscriptionResponseMessage,
    UnauthorizedError
)


def main():
    args = sys.argv[1:]
    topic = args[0]

    try:
        ipc_client = GreengrassCoreIPCClientV2()
        # Subscription operations return a tuple with the response and the operation.
        _, operation = ipc_client.subscribe_to_topic(topic=topic, on_stream_event=on_stream_event,
                                                     on_stream_error=on_stream_error, on_stream_closed=on_stream_closed)
        print('Successfully subscribed to topic: ' + topic)

        # Keep the main thread alive, or the process will exit.
        try:
            while True:
                time.sleep(10)
        except InterruptedError:
            print('Subscribe interrupted.')

        # To stop subscribing, close the stream.
        operation.close()
    except UnauthorizedError:
        print('Unauthorized error while subscribing to topic: ' +
              topic, file=sys.stderr)
        traceback.print_exc()
        exit(1)
    except Exception:
        print('Exception occurred', file=sys.stderr)
        traceback.print_exc()
        exit(1)


def on_stream_event(event: SubscriptionResponseMessage) -> None:
    try:
        message = str(event.binary_message.message, 'utf-8')
        topic = event.binary_message.context.topic
        print('Received new message on topic %s: %s' % (topic, message))
    except:
        traceback.print_exc()


def on_stream_error(error: Exception) -> bool:
    print('Received a stream error.', file=sys.stderr)
    traceback.print_exc()
    return False  # Return True to close stream, False to keep stream open.


def on_stream_closed() -> None:
    print('Subscribe to topic stream closed.')


if __name__ == '__main__':
    main()
```

------
#### [ C\$1\$1 (IPC client V1) ]

**Example 示例：订阅本地 publish/subscribe 消息**  <a name="ipc-operation-subscribetotopic-example-cpp"></a>

```
#include <iostream>

#include </crt/Api.h>
#include <aws/greengrass/GreengrassCoreIpcClient.h>

using namespace Aws::Crt;
using namespace Aws::Greengrass;

class SubscribeResponseHandler : public SubscribeToTopicStreamHandler {
    public:
        virtual ~SubscribeResponseHandler() {}

    private:
        void OnStreamEvent(SubscriptionResponseMessage *response) override {
            auto jsonMessage = response->GetJsonMessage();
            if (jsonMessage.has_value() && jsonMessage.value().GetMessage().has_value()) {
                auto messageString = jsonMessage.value().GetMessage().value().View().WriteReadable();
                // Handle JSON message.
            } else {
                auto binaryMessage = response->GetBinaryMessage();
                if (binaryMessage.has_value() && binaryMessage.value().GetMessage().has_value()) {
                    auto messageBytes = binaryMessage.value().GetMessage().value();
                    std::string messageString(messageBytes.begin(), messageBytes.end());
                    // Handle binary message.
                }
            }
        }

        bool OnStreamError(OperationError *error) override {
            // Handle error.
            return false; // Return true to close stream, false to keep stream open.
        }

        void OnStreamClosed() override {
            // Handle close.
        }
};

class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
    void OnConnectCallback() override {
        // Handle connection to IPC service.
    }

    void OnDisconnectCallback(RpcError error) override {
        // Handle disconnection from IPC service.
    }

    bool OnErrorCallback(RpcError error) override {
        // Handle IPC service connection error.
        return true;
    }
};

int main() {
    ApiHandle apiHandle(g_allocator);
    Io::EventLoopGroup eventLoopGroup(1);
    Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
    Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
    IpcClientLifecycleHandler ipcLifecycleHandler;
    GreengrassCoreIpcClient ipcClient(bootstrap);
    auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
    if (!connectionStatus) {
        std::cerr << "Failed to establish IPC connection: " << connectionStatus.StatusToString() << std::endl;
        exit(-1);
    }

    String topic("my/topic");
    int timeout = 10;

    SubscribeToTopicRequest request;
    request.SetTopic(topic);

    //SubscribeResponseHandler streamHandler;
    auto streamHandler = MakeShared<SubscribeResponseHandler>(DefaultAllocator());
    auto operation = ipcClient.NewSubscribeToTopic(streamHandler);
    auto activate = operation->Activate(request, nullptr);
    activate.wait();

    auto responseFuture = operation->GetResult();
    if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
        std::cerr << "Operation timed out while waiting for response from Greengrass Core." << std::endl;
        exit(-1);
    }

    auto response = responseFuture.get();
    if (!response) {
        // Handle error.
        auto errorType = response.GetResultType();
        if (errorType == OPERATION_ERROR) {
            auto *error = response.GetOperationError();
            (void)error;
            // Handle operation error.
        } else {
            // Handle RPC error.
        }
        exit(-1);
    }

    // Keep the main thread alive, or the process will exit.
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }

    operation->Close();
    return 0;
}
```

------
#### [ JavaScript ]

**Example 示例：订阅本地 publish/subscribe 消息**  <a name="ipc-operation-subscribetotopic-example-nodejs"></a>

```
import * as greengrasscoreipc from "aws-iot-device-sdk-v2/dist/greengrasscoreipc";
import {SubscribeToTopicRequest, SubscriptionResponseMessage} from "aws-iot-device-sdk-v2/dist/greengrasscoreipc/model";
import {RpcError} from "aws-iot-device-sdk-v2/dist/eventstream_rpc";
 
class SubscribeToTopic {
    private ipcClient : greengrasscoreipc.Client
    private readonly topic : string;
 
    constructor() {
        // define your own constructor, e.g.
        this.topic = "<define_your_topic>";
        this.subscribeToTopic().then(r => console.log("Started workflow"));
    }
 
    private async subscribeToTopic() {
        try {
            this.ipcClient = await getIpcClient();
 
            const subscribeToTopicRequest : SubscribeToTopicRequest = {
                topic: this.topic,
            }
 
            const streamingOperation = this.ipcClient.subscribeToTopic(subscribeToTopicRequest, undefined); // conditionally apply options
 
            streamingOperation.on("message", (message: SubscriptionResponseMessage) => {
                // parse the message depending on your use cases, e.g.
                if(message.binaryMessage && message.binaryMessage.message) {
                    const receivedMessage = message.binaryMessage?.message.toString();
                }
            });
 
            streamingOperation.on("streamError", (error : RpcError) => {
                // define your own error handling logic
            })
 
            streamingOperation.on("ended", () => {
                // define your own logic
            })
 
            await streamingOperation.activate();
 
            // Keep the main thread alive, or the process will exit.
            await new Promise((resolve) => setTimeout(resolve, 10000))
        } catch (e) {
            // parse the error depending on your use cases
            throw e
        }
    }
}
 
export async function getIpcClient(){
    try {
        const ipcClient = greengrasscoreipc.createClient();
        await ipcClient.connect()
            .catch(error => {
                // parse the error depending on your use cases
                throw error;
            });
        return ipcClient
    } catch (err) {
        // parse the error depending on your use cases
        throw err
    }
}
 
// starting point
const subscribeToTopic = new SubscribeToTopic();
```

------
#### [ Rust ]

**Example 示例：订阅本地 publish/subscribe 消息**  

```
use gg_sdk::{Sdk, SubscribeToTopicPayload};
use std::{thread, time::Duration};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    let topic = "my/topic";

    let callback = |topic: &str, payload: SubscribeToTopicPayload| match payload
    {
        SubscribeToTopicPayload::Binary(message) => {
            let message = String::from_utf8_lossy(message);
            println!("Received new message on topic {topic}: {message}");
        }
        SubscribeToTopicPayload::Json(_) => {
            println!("Received new message on topic {topic}: (JSON message)");
        }
    };

    let _sub = sdk
        .subscribe_to_topic(topic, &callback)
        .expect("Failed to subscribe to topic");

    println!("Successfully subscribed to topic: {topic}");

    // Keep the main thread alive, or the process will exit.
    loop {
        thread::sleep(Duration::from_secs(10));
    }
}
```

------
#### [ C ]

**Example 示例：订阅本地 publish/subscribe 消息**  

```
#include <assert.h>
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <gg/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

static void on_subscription_response(
    void *ctx, GgBuffer topic, GgObject payload, GgIpcSubscriptionHandle handle
) {
    (void) ctx;
    (void) handle;

    if (gg_obj_type(payload) == GG_TYPE_BUF) {
        GgBuffer message = gg_obj_into_buf(payload);
        printf(
            "Received new message on topic %.*s: %.*s\n",
            (int) topic.len,
            topic.data,
            (int) message.len,
            message.data
        );
    } else {
        assert(gg_obj_type(payload) == GG_TYPE_MAP);
        printf(
            "Received new message on topic %.*s: (JSON message)\n",
            (int) topic.len,
            topic.data
        );
    }
}

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    GgBuffer topic = GG_STR("my/topic");

    GgIpcSubscriptionHandle handle;
    err = ggipc_subscribe_to_topic(
        topic, on_subscription_response, NULL, &handle
    );
    if (err != GG_ERR_OK) {
        fprintf(
            stderr,
            "Failed to subscribe to topic: %.*s\n",
            (int) topic.len,
            topic.data
        );
        exit(-1);
    }

    printf(
        "Successfully subscribed to topic: %.*s\n", (int) topic.len, topic.data
    );

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }

    // To stop subscribing, close the stream.
    ggipc_close_subscription(handle);
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：订阅本地 publish/subscribe 消息**  

```
#include <gg/ipc/client.hpp>
#include <gg/object.hpp>
#include <unistd.h>
#include <cassert>
#include <iostream>

class ResponseHandler : public gg::ipc::LocalTopicCallback {
    void operator()(
        std::string_view topic,
        gg::Object payload,
        gg::ipc::Subscription &handle
    ) override {
        (void) handle;
        if (payload.index() == GG_TYPE_BUF) {
            std::cout << "Received new message on topic " << topic << ": "
                      << get<gg::Buffer>(payload) << "\n";
        } else {
            assert(payload.index() == GG_TYPE_MAP);
            std::cout << "Received new message on topic " << topic
                      << ": (JSON message)\n";
        }
    }
};

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    std::string_view topic = "my/topic";

    static ResponseHandler handler;
    error = client.subscribe_to_topic(topic, handler);
    if (error) {
        std::cerr << "Failed to subscribe to topic: " << topic << "\n";
        exit(-1);
    }

    std::cout << "Successfully subscribed to topic: " << topic << "\n";

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }
}
```

------

## 示例
<a name="ipc-publish-subscribe-examples"></a>

使用以下示例来学习如何在组件中使用 publish/subscribe IPC 服务。

### publish/subscribe 发布者示例（Java、IPC 客户端 V1）
<a name="ipc-publish-subscribe-example-publisher-java"></a>

以下示例配方允许该组件发布至所有主题。

------
#### [ JSON ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubPublisherJava",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubPublisherJava:pubsub:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": [
              "aws.greengrass#PublishToTopic"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Lifecycle": {
        "Run": "java -jar {artifacts:path}/PubSubPublisher.jar"
      }
    }
  ]
}
```

------
#### [ YAML ]

```
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.PubSubPublisherJava
ComponentVersion: '1.0.0'
ComponentDescription: A component that publishes messages.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.pubsub:
        'com.example.PubSubPublisherJava:pubsub:1':
          policyDescription: Allows access to publish to all topics.
          operations:
            - 'aws.greengrass#PublishToTopic'
          resources:
            - '*'
Manifests:
  - Lifecycle:
      Run: |-
        java -jar {artifacts:path}/PubSubPublisher.jar
```

------

以下示例 Java 应用程序演示了如何使用发布/订阅 IPC 服务向其他组件发布消息。

```
/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0 */

package com.example.ipc.pubsub;

import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient;
import software.amazon.awssdk.aws.greengrass.model.*;
import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection;

import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class PubSubPublisher {

    public static void main(String[] args) {
        String message = "Hello from the pub/sub publisher (Java).";
        String topic = "test/topic/java";

        try (EventStreamRPCConnection eventStreamRPCConnection = IPCUtils.getEventStreamRpcConnection()) {
            GreengrassCoreIPCClient ipcClient = new GreengrassCoreIPCClient(eventStreamRPCConnection);

            while (true) {
                PublishToTopicRequest publishRequest = new PublishToTopicRequest();
                PublishMessage publishMessage = new PublishMessage();
                BinaryMessage binaryMessage = new BinaryMessage();
                binaryMessage.setMessage(message.getBytes(StandardCharsets.UTF_8));
                publishMessage.setBinaryMessage(binaryMessage);
                publishRequest.setPublishMessage(publishMessage);
                publishRequest.setTopic(topic);
                CompletableFuture<PublishToTopicResponse> futureResponse = ipcClient
                        .publishToTopic(publishRequest, Optional.empty()).getResponse();

                try {
                    futureResponse.get(10, TimeUnit.SECONDS);
                    System.out.println("Successfully published to topic: " + topic);
                } catch (TimeoutException e) {
                    System.err.println("Timeout occurred while publishing to topic: " + topic);
                } catch (ExecutionException e) {
                    if (e.getCause() instanceof UnauthorizedError) {
                        System.err.println("Unauthorized error while publishing to topic: " + topic);
                    } else {
                        System.err.println("Execution exception while publishing to topic: " + topic);
                    }
                    throw e;
                }
                Thread.sleep(5000);
            }
        } catch (InterruptedException e) {
            System.out.println("Publisher interrupted.");
        } catch (Exception e) {
            System.err.println("Exception occurred when using IPC.");
            e.printStackTrace();
            System.exit(1);
        }
    }
}
```

### publish/subscribe 订阅者示例（Java、IPC 客户端 V1）
<a name="ipc-publish-subscribe-example-subscriber-java"></a>

以下示例配方允许该组件订阅所有主题。

------
#### [ JSON ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubSubscriberJava",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubSubscriberJava:pubsub:1": {
            "policyDescription": "Allows access to subscribe to all topics.",
            "operations": [
              "aws.greengrass#SubscribeToTopic"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Lifecycle": {
        "Run": "java -jar {artifacts:path}/PubSubSubscriber.jar"
      }
    }
  ]
}
```

------
#### [ YAML ]

```
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.PubSubSubscriberJava
ComponentVersion: '1.0.0'
ComponentDescription: A component that subscribes to messages.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.pubsub:
        'com.example.PubSubSubscriberJava:pubsub:1':
          policyDescription: Allows access to subscribe to all topics.
          operations:
            - 'aws.greengrass#SubscribeToTopic'
          resources:
            - '*'
Manifests:
  - Lifecycle:
      Run: |-
        java -jar {artifacts:path}/PubSubSubscriber.jar
```

------

以下示例 Java 应用程序演示了如何使用发布/订阅 IPC 服务向其他组件订阅消息。

```
/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0 */

package com.example.ipc.pubsub;

import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient;
import software.amazon.awssdk.aws.greengrass.SubscribeToTopicResponseHandler;
import software.amazon.awssdk.aws.greengrass.model.SubscribeToTopicRequest;
import software.amazon.awssdk.aws.greengrass.model.SubscribeToTopicResponse;
import software.amazon.awssdk.aws.greengrass.model.SubscriptionResponseMessage;
import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError;
import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection;
import software.amazon.awssdk.eventstreamrpc.StreamResponseHandler;

import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class PubSubSubscriber {

    public static void main(String[] args) {
        String topic = "test/topic/java";

        try (EventStreamRPCConnection eventStreamRPCConnection = IPCUtils.getEventStreamRpcConnection()) {
            GreengrassCoreIPCClient ipcClient = new GreengrassCoreIPCClient(eventStreamRPCConnection);

            SubscribeToTopicRequest subscribeRequest = new SubscribeToTopicRequest();
            subscribeRequest.setTopic(topic);
            SubscribeToTopicResponseHandler operationResponseHandler = ipcClient
                    .subscribeToTopic(subscribeRequest, Optional.of(new SubscribeResponseHandler()));
            CompletableFuture<SubscribeToTopicResponse> futureResponse = operationResponseHandler.getResponse();

            try {
                futureResponse.get(10, TimeUnit.SECONDS);
                System.out.println("Successfully subscribed to topic: " + topic);
            } catch (TimeoutException e) {
                System.err.println("Timeout occurred while subscribing to topic: " + topic);
                throw e;
            } catch (ExecutionException e) {
                if (e.getCause() instanceof UnauthorizedError) {
                    System.err.println("Unauthorized error while subscribing to topic: " + topic);
                } else {
                    System.err.println("Execution exception while subscribing to topic: " + topic);
                }
                throw e;
            }

            // Keep the main thread alive, or the process will exit.
            try {
                while (true) {
                    Thread.sleep(10000);
                }
            } catch (InterruptedException e) {
                System.out.println("Subscribe interrupted.");
            }
        } catch (Exception e) {
            System.err.println("Exception occurred when using IPC.");
            e.printStackTrace();
            System.exit(1);
        }
    }

    private static class SubscribeResponseHandler implements StreamResponseHandler<SubscriptionResponseMessage> {

        @Override
        public void onStreamEvent(SubscriptionResponseMessage subscriptionResponseMessage) {
            try {
                String message = new String(subscriptionResponseMessage.getBinaryMessage()
                        .getMessage(), StandardCharsets.UTF_8);
                System.out.println("Received new message: " + message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        @Override
        public boolean onStreamError(Throwable error) {
            System.err.println("Received a stream error.");
            error.printStackTrace();
            return false; // Return true to close stream, false to keep stream open.
        }

        @Override
        public void onStreamClosed() {
            System.out.println("Subscribe to topic stream closed.");
        }
    }
}
```

### publish/subscribe 发布者示例（Python、IPC 客户端 V1）
<a name="ipc-publish-subscribe-example-publisher-python"></a>

以下示例配方允许该组件发布至所有主题。

------
#### [ JSON ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubPublisherPython",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubPublisherPython:pubsub:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": [
              "aws.greengrass#PublishToTopic"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux"
      },
      "Lifecycle": {
        "install": "python3 -m pip install --user awsiotsdk",
        "Run": "python3 -u {artifacts:path}/pubsub_publisher.py"
      }
    },
    {
      "Platform": {
        "os": "windows"
      },
      "Lifecycle": {
        "install": "py -3 -m pip install --user awsiotsdk",
        "Run": "py -3 -u {artifacts:path}/pubsub_publisher.py"
      }
    }
  ]
}
```

------
#### [ YAML ]

```
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.PubSubPublisherPython
ComponentVersion: 1.0.0
ComponentDescription: A component that publishes messages.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.pubsub:
        com.example.PubSubPublisherPython:pubsub:1:
          policyDescription: Allows access to publish to all topics.
          operations:
            - aws.greengrass#PublishToTopic
          resources:
            - "*"
Manifests:
  - Platform:
      os: linux
    Lifecycle:
      install: python3 -m pip install --user awsiotsdk
      Run: python3 -u {artifacts:path}/pubsub_publisher.py
  - Platform:
      os: windows
    Lifecycle:
      install: py -3 -m pip install --user awsiotsdk
      Run: py -3 -u {artifacts:path}/pubsub_publisher.py
```

------

以下示例 Python 应用程序演示了如何使用发布/订阅 IPC 服务向其他组件发布消息。

```
import concurrent.futures
import sys
import time
import traceback

import awsiot.greengrasscoreipc
from awsiot.greengrasscoreipc.model import (
    PublishToTopicRequest,
    PublishMessage,
    BinaryMessage,
    UnauthorizedError
)

                    
topic = "test/topic/python"
message = "Hello from the pub/sub publisher (Python)."
TIMEOUT = 10

try:
    ipc_client = awsiot.greengrasscoreipc.connect()

    while True:
        request = PublishToTopicRequest()
        request.topic = topic
        publish_message = PublishMessage()
        publish_message.binary_message = BinaryMessage()
        publish_message.binary_message.message = bytes(message, "utf-8")
        request.publish_message = publish_message
        operation = ipc_client.new_publish_to_topic()
        operation.activate(request)
        future_response = operation.get_response()

        try:
            future_response.result(TIMEOUT)
            print('Successfully published to topic: ' + topic)
        except concurrent.futures.TimeoutError:
            print('Timeout occurred while publishing to topic: ' + topic, file=sys.stderr)
        except UnauthorizedError as e:
            print('Unauthorized error while publishing to topic: ' + topic, file=sys.stderr)
            raise e
        except Exception as e:
            print('Exception while publishing to topic: ' + topic, file=sys.stderr)
            raise e
        time.sleep(5)
except InterruptedError:
    print('Publisher interrupted.')
except Exception:
    print('Exception occurred when using IPC.', file=sys.stderr)
    traceback.print_exc()
    exit(1)
```

### publish/subscribe 订阅者示例（Python、IPC 客户端 V1）
<a name="ipc-publish-subscribe-example-subscriber-python"></a>

以下示例配方允许该组件订阅所有主题。

------
#### [ JSON ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubSubscriberPython",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubSubscriberPython:pubsub:1": {
            "policyDescription": "Allows access to subscribe to all topics.",
            "operations": [
              "aws.greengrass#SubscribeToTopic"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux"
      },
      "Lifecycle": {
        "install": "python3 -m pip install --user awsiotsdk",
        "Run": "python3 -u {artifacts:path}/pubsub_subscriber.py"
      }
    },
    {
      "Platform": {
        "os": "windows"
      },
      "Lifecycle": {
        "install": "py -3 -m pip install --user awsiotsdk",
        "Run": "py -3 -u {artifacts:path}/pubsub_subscriber.py"
      }
    }
  ]
}
```

------
#### [ YAML ]

```
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.PubSubSubscriberPython
ComponentVersion: 1.0.0
ComponentDescription: A component that subscribes to messages.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.pubsub:
        com.example.PubSubSubscriberPython:pubsub:1:
          policyDescription: Allows access to subscribe to all topics.
          operations:
            - aws.greengrass#SubscribeToTopic
          resources:
            - "*"
Manifests:
  - Platform:
      os: linux
    Lifecycle:
      install: python3 -m pip install --user awsiotsdk
      Run: python3 -u {artifacts:path}/pubsub_subscriber.py
  - Platform:
      os: windows
    Lifecycle:
      install: py -3 -m pip install --user awsiotsdk
      Run: py -3 -u {artifacts:path}/pubsub_subscriber.py
```

------

以下示例 Python 应用程序演示了如何使用发布/订阅 IPC 服务向其他组件订阅消息。

```
import concurrent.futures
import sys
import time
import traceback

import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import (
    SubscribeToTopicRequest,
    SubscriptionResponseMessage,
    UnauthorizedError
)

topic = "test/topic/python"
TIMEOUT = 10

                    
class StreamHandler(client.SubscribeToTopicStreamHandler):
    def __init__(self):
        super().__init__()

    def on_stream_event(self, event: SubscriptionResponseMessage) -> None:
        try:
            message = str(event.binary_message.message, "utf-8")
            print("Received new message: " + message)
        except:
            traceback.print_exc()

    def on_stream_error(self, error: Exception) -> bool:
        print("Received a stream error.", file=sys.stderr)
        traceback.print_exc()
        return False  # Return True to close stream, False to keep stream open.

    def on_stream_closed(self) -> None:
        print('Subscribe to topic stream closed.')


try:
    ipc_client = awsiot.greengrasscoreipc.connect()

    request = SubscribeToTopicRequest()
    request.topic = topic
    handler = StreamHandler()
    operation = ipc_client.new_subscribe_to_topic(handler)
    operation.activate(request)
    future_response = operation.get_response()
    
    try:
        future_response.result(TIMEOUT)
        print('Successfully subscribed to topic: ' + topic)
    except concurrent.futures.TimeoutError as e:
        print('Timeout occurred while subscribing to topic: ' + topic, file=sys.stderr)
        raise e
    except UnauthorizedError as e:
        print('Unauthorized error while subscribing to topic: ' + topic, file=sys.stderr)
        raise e
    except Exception as e:
        print('Exception while subscribing to topic: ' + topic, file=sys.stderr)
        raise e

    # Keep the main thread alive, or the process will exit.
    try:
        while True:
            time.sleep(10)
    except InterruptedError:
        print('Subscribe interrupted.')
except Exception:
    print('Exception occurred when using IPC.', file=sys.stderr)
    traceback.print_exc()
    exit(1)
```

### publish/subscribe 发布者示例（C\$1\$1，IPC 客户端 V1）
<a name="ipc-publish-subscribe-example-publisher-cpp"></a>

以下示例配方允许该组件发布至所有主题。

------
#### [ JSON ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubPublisherCpp",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubPublisherCpp:pubsub:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": [
              "aws.greengrass#PublishToTopic"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Lifecycle": {
        "Run": "{artifacts:path}/greengrassv2_pubsub_publisher"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubPublisherCpp/1.0.0/greengrassv2_pubsub_publisher",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

------
#### [ YAML ]

```
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.PubSubPublisherCpp
ComponentVersion: 1.0.0
ComponentDescription: A component that publishes messages.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.pubsub:
        com.example.PubSubPublisherCpp:pubsub:1:
          policyDescription: Allows access to publish to all topics.
          operations:
            - aws.greengrass#PublishToTopic
          resources:
            - "*"
Manifests:
  - Lifecycle:
      Run: "{artifacts:path}/greengrassv2_pubsub_publisher"
    Artifacts:
      - URI: s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubPublisherCpp/1.0.0/greengrassv2_pubsub_publisher
        Permission:
          Execute: OWNER
```

------

以下示例 C\$1\$1 应用程序演示了如何使用发布/订阅 IPC 服务向其他组件发布消息。

```
#include <iostream>

#include <aws/crt/Api.h>
#include <aws/greengrass/GreengrassCoreIpcClient.h>

using namespace Aws::Crt;
using namespace Aws::Greengrass;

class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
    void OnConnectCallback() override {
        std::cout << "OnConnectCallback" << std::endl;
    }

    void OnDisconnectCallback(RpcError error) override {
        std::cout << "OnDisconnectCallback: " << error.StatusToString() << std::endl;
        exit(-1);
    }

    bool OnErrorCallback(RpcError error) override {
        std::cout << "OnErrorCallback: " << error.StatusToString() << std::endl;
        return true;
    }
};

int main() {
    String message("Hello from the pub/sub publisher (C++).");
    String topic("test/topic/cpp");
    int timeout = 10;

    ApiHandle apiHandle(g_allocator);
    Io::EventLoopGroup eventLoopGroup(1);
    Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
    Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
    IpcClientLifecycleHandler ipcLifecycleHandler;
    GreengrassCoreIpcClient ipcClient(bootstrap);
    auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
    if (!connectionStatus) {
        std::cerr << "Failed to establish IPC connection: " << connectionStatus.StatusToString() << std::endl;
        exit(-1);
    }

    while (true) {
        PublishToTopicRequest request;
        Vector<uint8_t> messageData({message.begin(), message.end()});
        BinaryMessage binaryMessage;
        binaryMessage.SetMessage(messageData);
        PublishMessage publishMessage;
        publishMessage.SetBinaryMessage(binaryMessage);
        request.SetTopic(topic);
        request.SetPublishMessage(publishMessage);

        auto operation = ipcClient.NewPublishToTopic();
        auto activate = operation->Activate(request, nullptr);
        activate.wait();

        auto responseFuture = operation->GetResult();
        if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
            std::cerr << "Operation timed out while waiting for response from Greengrass Core." << std::endl;
            exit(-1);
        }

        auto response = responseFuture.get();
        if (response) {
            std::cout << "Successfully published to topic: " << topic << std::endl;
        } else {
            // An error occurred.
            std::cout << "Failed to publish to topic: " << topic << std::endl;
            auto errorType = response.GetResultType();
            if (errorType == OPERATION_ERROR) {
                auto *error = response.GetOperationError();
                std::cout << "Operation error: " << error->GetMessage().value() << std::endl;
            } else {
                std::cout << "RPC error: " << response.GetRpcError() << std::endl;
            }
            exit(-1);
        }

        std::this_thread::sleep_for(std::chrono::seconds(5));
    }

    return 0;
}
```

### publish/subscribe 订阅者示例（C\$1\$1、IPC 客户端 V1）
<a name="ipc-publish-subscribe-example-subscriber-cpp"></a>

以下示例配方允许该组件订阅所有主题。

------
#### [ JSON ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubSubscriberCpp",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubSubscriberCpp:pubsub:1": {
            "policyDescription": "Allows access to subscribe to all topics.",
            "operations": [
              "aws.greengrass#SubscribeToTopic"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Lifecycle": {
        "Run": "{artifacts:path}/greengrassv2_pub_sub_subscriber"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubSubscriberCpp/1.0.0/greengrassv2_pub_sub_subscriber",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

------
#### [ YAML ]

```
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.PubSubSubscriberCpp
ComponentVersion: 1.0.0
ComponentDescription: A component that subscribes to messages.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.pubsub:
        com.example.PubSubSubscriberCpp:pubsub:1:
          policyDescription: Allows access to subscribe to all topics.
          operations:
            - aws.greengrass#SubscribeToTopic
          resources:
            - "*"
Manifests:
  - Lifecycle:
      Run: "{artifacts:path}/greengrassv2_pub_sub_subscriber"
    Artifacts:
      - URI: s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubSubscriberCpp/1.0.0/greengrassv2_pub_sub_subscriber
        Permission:
          Execute: OWNER
```

------

以下示例 C\$1\$1 应用程序演示了如何使用发布/订阅 IPC 服务向其他组件订阅消息。

```
#include <iostream>

#include <aws/crt/Api.h>
#include <aws/greengrass/GreengrassCoreIpcClient.h>

using namespace Aws::Crt;
using namespace Aws::Greengrass;

class SubscribeResponseHandler : public SubscribeToTopicStreamHandler {
    public:
        virtual ~SubscribeResponseHandler() {}

    private:
        void OnStreamEvent(SubscriptionResponseMessage *response) override {
            auto jsonMessage = response->GetJsonMessage();
            if (jsonMessage.has_value() && jsonMessage.value().GetMessage().has_value()) {
                auto messageString = jsonMessage.value().GetMessage().value().View().WriteReadable();
                std::cout << "Received new message: " << messageString << std::endl;
            } else {
                auto binaryMessage = response->GetBinaryMessage();
                if (binaryMessage.has_value() && binaryMessage.value().GetMessage().has_value()) {
                    auto messageBytes = binaryMessage.value().GetMessage().value();
                    std::string messageString(messageBytes.begin(), messageBytes.end());
                    std::cout << "Received new message: " << messageString << std::endl;
                }
            }
        }

        bool OnStreamError(OperationError *error) override {
            std::cout << "Received an operation error: ";
            if (error->GetMessage().has_value()) {
                std::cout << error->GetMessage().value();
            }
            std::cout << std::endl;
            return false; // Return true to close stream, false to keep stream open.
        }

        void OnStreamClosed() override {
            std::cout << "Subscribe to topic stream closed." << std::endl;
        }
};

class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
    void OnConnectCallback() override {
        std::cout << "OnConnectCallback" << std::endl;
    }

    void OnDisconnectCallback(RpcError error) override {
        std::cout << "OnDisconnectCallback: " << error.StatusToString() << std::endl;
        exit(-1);
    }

    bool OnErrorCallback(RpcError error) override {
        std::cout << "OnErrorCallback: " << error.StatusToString() << std::endl;
        return true;
    }
};

int main() {
    String topic("test/topic/cpp");
    int timeout = 10;

    ApiHandle apiHandle(g_allocator);
    Io::EventLoopGroup eventLoopGroup(1);
    Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
    Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
    IpcClientLifecycleHandler ipcLifecycleHandler;
    GreengrassCoreIpcClient ipcClient(bootstrap);
    auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
    if (!connectionStatus) {
        std::cerr << "Failed to establish IPC connection: " << connectionStatus.StatusToString() << std::endl;
        exit(-1);
    }

    SubscribeToTopicRequest request;
    request.SetTopic(topic);
    auto streamHandler = MakeShared<SubscribeResponseHandler>(DefaultAllocator());
    auto operation = ipcClient.NewSubscribeToTopic(streamHandler);
    auto activate = operation->Activate(request, nullptr);
    activate.wait();

    auto responseFuture = operation->GetResult();
    if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
        std::cerr << "Operation timed out while waiting for response from Greengrass Core." << std::endl;
        exit(-1);
    }

    auto response = responseFuture.get();
    if (response) {
        std::cout << "Successfully subscribed to topic: " << topic << std::endl;
    } else {
        // An error occurred.
        std::cout << "Failed to subscribe to topic: " << topic << std::endl;
        auto errorType = response.GetResultType();
        if (errorType == OPERATION_ERROR) {
            auto *error = response.GetOperationError();
            std::cout << "Operation error: " << error->GetMessage().value() << std::endl;
        } else {
            std::cout << "RPC error: " << response.GetRpcError() << std::endl;
        }
        exit(-1);
    }

    // Keep the main thread alive, or the process will exit.
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }

    operation->Close();
    return 0;
}
```

### 示例 publish/subscribe 发布者 (Rust)
<a name="ipc-publish-subscribe-example-publisher-rust"></a>

以下示例配方允许该组件发布至所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubPublisherRust",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubPublisherRust:pubsub:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": ["aws.greengrass#PublishToTopic"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/publish_to_topic"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubPublisherRust/1.0.0/publish_to_topic",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 Rust 应用程序演示了如何使用发布/订阅 IPC 服务将消息发布到其他组件。

```
use gg_sdk::Sdk;

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    let message = b"Hello, World";
    let topic = "my/topic";

    sdk.publish_to_topic_binary(topic, message)
        .expect("Failed to publish to topic");

    println!("Successfully published to topic: {topic}");
}
```

### publish/subscribe 订阅者示例 (Rust)
<a name="ipc-publish-subscribe-example-subscriber-rust"></a>

以下示例配方允许该组件订阅所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubSubscriberRust",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubSubscriberRust:pubsub:1": {
            "policyDescription": "Allows access to subscribe to all topics.",
            "operations": ["aws.greengrass#SubscribeToTopic"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/subscribe_to_topic"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubSubscriberRust/1.0.0/subscribe_to_topic",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 Rust 应用程序演示了如何使用发布/订阅 IPC 服务来订阅来自其他组件的消息。

```
use gg_sdk::{Sdk, SubscribeToTopicPayload};
use std::{thread, time::Duration};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    let topic = "my/topic";

    let callback = |topic: &str, payload: SubscribeToTopicPayload| match payload
    {
        SubscribeToTopicPayload::Binary(message) => {
            let message = String::from_utf8_lossy(message);
            println!("Received new message on topic {topic}: {message}");
        }
        SubscribeToTopicPayload::Json(_) => {
            println!("Received new message on topic {topic}: (JSON message)");
        }
    };

    let _sub = sdk
        .subscribe_to_topic(topic, &callback)
        .expect("Failed to subscribe to topic");

    println!("Successfully subscribed to topic: {topic}");

    // Keep the main thread alive, or the process will exit.
    loop {
        thread::sleep(Duration::from_secs(10));
    }
}
```

### publish/subscribe 发布者示例 (C)
<a name="ipc-publish-subscribe-example-publisher-c"></a>

以下示例配方允许该组件发布至所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubPublisherC",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubPublisherC:pubsub:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": ["aws.greengrass#PublishToTopic"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/sample_publish_to_topic"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubPublisherC/1.0.0/sample_publish_to_topic",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 C 应用程序演示如何使用发布/订阅 IPC 服务将消息发布到其他组件。

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/sdk.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    GgBuffer message = GG_STR("Hello, World");
    GgBuffer topic = GG_STR("my/topic");

    err = ggipc_publish_to_topic_binary(topic, message);
    if (err != GG_ERR_OK) {
        fprintf(
            stderr,
            "Failed to publish to topic: %.*s\n",
            (int) topic.len,
            topic.data
        );
        exit(-1);
    }

    printf(
        "Successfully published to topic: %.*s\n", (int) topic.len, topic.data
    );
}
```

### publish/subscribe 订阅者示例 (C)
<a name="ipc-publish-subscribe-example-subscriber-c"></a>

以下示例配方允许该组件订阅所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubSubscriberC",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubSubscriberC:pubsub:1": {
            "policyDescription": "Allows access to subscribe to all topics.",
            "operations": ["aws.greengrass#SubscribeToTopic"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/sample_subscribe_to_topic"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubSubscriberC/1.0.0/sample_subscribe_to_topic",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 C 应用程序演示如何使用发布/订阅 IPC 服务来订阅来自其他组件的消息。

```
#include <assert.h>
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <gg/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

static void on_subscription_response(
    void *ctx, GgBuffer topic, GgObject payload, GgIpcSubscriptionHandle handle
) {
    (void) ctx;
    (void) handle;

    if (gg_obj_type(payload) == GG_TYPE_BUF) {
        GgBuffer message = gg_obj_into_buf(payload);
        printf(
            "Received new message on topic %.*s: %.*s\n",
            (int) topic.len,
            topic.data,
            (int) message.len,
            message.data
        );
    } else {
        assert(gg_obj_type(payload) == GG_TYPE_MAP);
        printf(
            "Received new message on topic %.*s: (JSON message)\n",
            (int) topic.len,
            topic.data
        );
    }
}

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    GgBuffer topic = GG_STR("my/topic");

    GgIpcSubscriptionHandle handle;
    err = ggipc_subscribe_to_topic(
        topic, on_subscription_response, NULL, &handle
    );
    if (err != GG_ERR_OK) {
        fprintf(
            stderr,
            "Failed to subscribe to topic: %.*s\n",
            (int) topic.len,
            topic.data
        );
        exit(-1);
    }

    printf(
        "Successfully subscribed to topic: %.*s\n", (int) topic.len, topic.data
    );

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }

    // To stop subscribing, close the stream.
    ggipc_close_subscription(handle);
}
```

### 示例 publish/subscribe 发布者（C\$1\$1、组件 SDK）
<a name="ipc-publish-subscribe-example-publisher-cpp-component-sdk"></a>

以下示例配方允许该组件发布至所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubPublisherCpp",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubPublisherCpp:pubsub:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": ["aws.greengrass#PublishToTopic"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/sample_cpp_publish_to_topic"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubPublisherCpp/1.0.0/sample_cpp_publish_to_topic",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 C\$1\$1 应用程序演示了如何使用发布/订阅 IPC 服务向其他组件发布消息。

```
#include <gg/ipc/client.hpp>
#include <iostream>

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    std::string_view message = "Hello, World";
    std::string_view topic = "my/topic";

    error = client.publish_to_topic(topic, message);
    if (error) {
        std::cerr << "Failed to publish to topic: " << topic << "\n";
        exit(-1);
    }

    std::cout << "Successfully published to topic: " << topic << "\n";
}
```

### publish/subscribe 订阅者示例（C\$1\$1、组件 SDK）
<a name="ipc-publish-subscribe-example-subscriber-cpp-component-sdk"></a>

以下示例配方允许该组件订阅所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PubSubSubscriberCpp",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to messages.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.pubsub": {
          "com.example.PubSubSubscriberCpp:pubsub:1": {
            "policyDescription": "Allows access to subscribe to all topics.",
            "operations": ["aws.greengrass#SubscribeToTopic"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/sample_cpp_subscribe_to_topic"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.PubSubSubscriberCpp/1.0.0/sample_cpp_subscribe_to_topic",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 C\$1\$1 应用程序演示了如何使用发布/订阅 IPC 服务来订阅来自其他组件的消息。

```
#include <gg/ipc/client.hpp>
#include <gg/object.hpp>
#include <unistd.h>
#include <cassert>
#include <iostream>

class ResponseHandler : public gg::ipc::LocalTopicCallback {
    void operator()(
        std::string_view topic,
        gg::Object payload,
        gg::ipc::Subscription &handle
    ) override {
        (void) handle;
        if (payload.index() == GG_TYPE_BUF) {
            std::cout << "Received new message on topic " << topic << ": "
                      << get<gg::Buffer>(payload) << "\n";
        } else {
            assert(payload.index() == GG_TYPE_MAP);
            std::cout << "Received new message on topic " << topic
                      << ": (JSON message)\n";
        }
    }
};

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    std::string_view topic = "my/topic";

    static ResponseHandler handler;
    error = client.subscribe_to_topic(topic, handler);
    if (error) {
        std::cerr << "Failed to subscribe to topic: " << topic << "\n";
        exit(-1);
    }

    std::cout << "Successfully subscribed to topic: " << topic << "\n";

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }
}
```

# 发布/订阅 AWS IoT Core MQTT 消息
<a name="ipc-iot-core-mqtt"></a>

 AWS IoT Core MQTT 消息传递 IPC 服务允许您发送和接收 MQTT 消息。 AWS IoT Core组件可以向其他来源发布消息 AWS IoT Core 和订阅主题，以处理来自其他来源的 MQTT 消息。有关 MQTT AWS IoT Core 实现的更多信息，请参阅《*AWS IoT Core 开发人员*指南》中的 [MQTT](https://docs.aws.amazon.com/iot/latest/developerguide/mqtt.html)。

**注意**  
此 MQTT 消息 IPC 服务允许您与交换消息。 AWS IoT Core有关如何在组件之间交换消息的更多信息，请参阅[发布/订阅本地消息](ipc-publish-subscribe.md)。

**Topics**
+ [最低 SDK 版本](#ipc-iot-core-mqtt-sdk-versions)
+ [Authorization](#ipc-iot-core-mqtt-authorization)
+ [PublishToIoTCore](#ipc-operation-publishtoiotcore)
+ [SubscribeToIoTCore](#ipc-operation-subscribetoiotcore)
+ [示例](#ipc-iot-core-mqtt-examples)

## 最低 SDK 版本
<a name="ipc-iot-core-mqtt-sdk-versions"></a>

下表列出了在发布和订阅 MQTT 消息时必须使用的最低版本。 AWS IoT Device SDK AWS IoT Core


| SDK | 最低版本 | 
| --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.2.10  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.5.3  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.17.0  | 
|  [AWS IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  | 

## Authorization
<a name="ipc-iot-core-mqtt-authorization"></a>

要在自定义组件中使用 AWS IoT Core MQTT 消息传递，您必须定义授权策略，允许您的组件发送和接收有关主题的消息。有关定义授权策略的信息，请参阅[授权组件执行 IPC 操作](interprocess-communication.md#ipc-authorization-policies)。

 AWS IoT Core MQTT 消息传递的授权策略具有以下属性。

**IPC 服务标识符：**`aws.greengrass.ipc.mqttproxy`


| 操作 | 说明 | 资源 | 
| --- | --- | --- | 
|  `aws.greengrass#PublishToIoTCore`  |  允许组件在您指定的 MQTT 主题 AWS IoT Core 上向其发布消息。  |  允许访问所有主题的主题字符串（例如 `test/topic` 或 `*`）。您可以使用 MQTT 主题通配符（`#` 和 `+`）来匹配多个资源。  | 
|  `aws.greengrass#SubscribeToIoTCore`  |  允许组件订阅来自您指定 AWS IoT Core 主题的消息。  |  允许访问所有主题的主题字符串（例如 `test/topic` 或 `*`）。您可以使用 MQTT 主题通配符（`#` 和 `+`）来匹配多个资源。  | 
|  `*`  |  允许组件发布和订阅您指定的主题的 AWS IoT Core MQTT 消息。  |  允许访问所有主题的主题字符串（例如 `test/topic` 或 `*`）。您可以使用 MQTT 主题通配符（`#` 和 `+`）来匹配多个资源。  | 

### MQTT 授权策略中的 M AWS IoT Core QTT 通配符
<a name="ipc-iot-core-mqtt-authorization-mqtt-wildcards"></a>

您可以在 MQTT IPC 授权策略中使用 AWS IoT Core MQTT 通配符。组件可以发布和订阅与您在授权策略中允许的主题筛选条件相匹配的主题。例如，如果组件的授权策略授予 `test/topic/#` 访问权限，则该组件可以订阅 `test/topic/#`，也可以发布和订阅 `test/topic/filter`。

### AWS IoT Core MQTT 授权策略中的配方变量
<a name="ipc-iot-core-mqtt-authorization-recipe-variables"></a>

如果您使用的是 [Greengrass Nucleus](greengrass-nucleus-component.md) v2.6.0 或更高版本，则可以在授权策略中使用 `{iot:thingName}` 配方变量。此功能使您可以为一组核心设备配置单个授权策略，其中每台核心设备只能访问包含自己名称的主题。例如，您可以允许组件访问以下主题资源。

```
devices/{iot:thingName}/messages
```

有关更多信息，请参阅[配方变量](component-recipe-reference.md#recipe-variables)和[在合并更新中使用配方变量](update-component-configurations.md#merge-configuration-update-recipe-variables)。

### 授权策略示例
<a name="ipc-iot-core-mqtt-authorization-policy-examples"></a>

您可以参考以下授权策略示例，帮助您为组件配置授权策略。

**Example 具有无限制访问权限的示例授权策略**  
以下示例授权策略允许组件发布和订阅所有主题。  

```
{
  "accessControl": {
    "aws.greengrass.ipc.mqttproxy": {
      "com.example.MyIoTCorePubSubComponent:mqttproxy:1": {
        "policyDescription": "Allows access to publish/subscribe to all topics.",
        "operations": [
          "aws.greengrass#PublishToIoTCore",
          "aws.greengrass#SubscribeToIoTCore"
        ],
        "resources": [
          "*"
        ]
      }
    }
  }
}
```

```
---
accessControl:
  aws.greengrass.ipc.mqttproxy:
    com.example.MyIoTCorePubSubComponent:mqttproxy:1:
      policyDescription: Allows access to publish/subscribe to all topics.
      operations:
        - aws.greengrass#PublishToIoTCore
        - aws.greengrass#SubscribeToIoTCore
      resources:
        - "*"
```

**Example 具有有限访问权限的示例授权策略**  
以下示例授权策略允许组件发布和订阅名为 `factory/1/events` 和 `factory/1/actions` 的两个主题。  

```
{
  "accessControl": {
    "aws.greengrass.ipc.mqttproxy": {
      "com.example.MyIoTCorePubSubComponent:mqttproxy:1": {
        "policyDescription": "Allows access to publish/subscribe to factory 1 topics.",
        "operations": [
          "aws.greengrass#PublishToIoTCore",
          "aws.greengrass#SubscribeToIoTCore"
        ],
        "resources": [
          "factory/1/actions",
          "factory/1/events"
        ]
      }
    }
  }
}
```

```
---
accessControl:
  aws.greengrass.ipc.mqttproxy:
    "com.example.MyIoTCorePubSubComponent:mqttproxy:1":
      policyDescription: Allows access to publish/subscribe to factory 1 topics.
      operations:
        - aws.greengrass#PublishToIoTCore
        - aws.greengrass#SubscribeToIoTCore
      resources:
        - factory/1/actions
        - factory/1/events
```

**Example 核心设备组的示例授权策略**  
此示例使用了 [Greengrass nucleus 组件](greengrass-nucleus-component.md)的 v2.6.0 及更高版本中提供的功能。Greengrass Nucleus v2.6.0 在组件配置中添加了对大多数[配方变量](component-recipe-reference.md#recipe-variables)（例如 `{iot:thingName}`）的支持。
以下示例授权策略允许组件发布和订阅包含运行该组件的核心设备名称的主题。  

```
{
  "accessControl": {
    "aws.greengrass.ipc.mqttproxy": {
      "com.example.MyIoTCorePubSubComponent:mqttproxy:1": {
        "policyDescription": "Allows access to publish/subscribe to all topics.",
        "operations": [
          "aws.greengrass#PublishToIoTCore",
          "aws.greengrass#SubscribeToIoTCore"
        ],
        "resources": [
          "factory/1/devices/{iot:thingName}/controls"
        ]
      }
    }
  }
}
```

```
---
accessControl:
  aws.greengrass.ipc.mqttproxy:
    "com.example.MyIoTCorePubSubComponent:mqttproxy:1":
      policyDescription: Allows access to publish/subscribe to all topics.
      operations:
        - aws.greengrass#PublishToIoTCore
        - aws.greengrass#SubscribeToIoTCore
      resources:
        - factory/1/devices/{iot:thingName}/controls
```

## PublishToIoTCore
<a name="ipc-operation-publishtoiotcore"></a>

向 AWS IoT Core 发布有关某个主题的 MQTT 消息。

当您向发布 MQTT 消息时 AWS IoT Core，有每秒 100 个交易的配额。如果超出此配额，消息将在 Greengrass 设备上排队等候处理。还有每秒 512 Kb 的数据配额，整个账户的配额为每秒 20,000 次发布（有些 AWS 区域有 2,000 次）。有关 AWS IoT Core中 MQTT 消息代理限制的更多信息，请参阅 [AWS IoT Core 消息代理和协议限制以及配额](https://docs.aws.amazon.com/general/latest/gr/iot-core.html#message-broker-limits)。

如果您超过这些配额，Greengrass 设备会将发布消息限制为。 AWS IoT Core消息存储在内存中的后台处理程序中。默认情况下，分配给后台处理程序的内存为 2.5 Mb。如果后台处理程序已满，则新消息将被拒绝。您可以增大后台处理程序的大小。有关更多信息，请参阅 [Greengrass Nucleus](greengrass-nucleus-component.md)文档中的 [配置](greengrass-nucleus-component.md#greengrass-nucleus-component-configuration)。为避免填满后台处理程序并且需要增加分配的内存，请将发布请求限制为每秒不超过 100 个请求。

当应用程序需要以更高的速率发送消息或发送更大的消息时，可以考虑使用 [流管理器](stream-manager-component.md) 向 Kinesis Data Streams 发送消息。流管理器组件旨在将大量数据传输到 AWS 云。有关更多信息，请参阅 [管理 Greengrass 核心设备上的数据流](manage-data-streams.md)。

### 请求
<a name="ipc-operation-publishtoiotcore-request"></a>

此操作的请求包含以下参数：

`topicName`（Python：`topic_name`）  
要向其发布消息的主题。

`qos`  <a name="ipc-iot-core-mqtt-qos"></a>
要使用的 MQTT QoS。此枚举 `QOS` 包含以下值：  
+ `AT_MOST_ONCE` – QoS 0。MQTT 消息至多传送一次。
+ `AT_LEAST_ONCE` – QoS 1。MQTT 消息至少传送一次。

`payload`  
（可选）以 Blob 形式显示的消息有效载荷。

使用 MQTT 5 时，以下功能适用于 [Greengrass Nucleus](greengrass-nucleus-component.md) v2.10.0 及更高版本。如果使用的是 MQTT 3.1.1，则会忽略这些功能。下表列出了访问这些功能必须使用的 AWS IoT 设备 SDK 的最低版本。


| SDK | 最低版本 | 
| --- | --- | 
| [AWS IoT Device SDK for Python](https://github.com/aws/aws-iot-device-sdk-python-v2) v2 | v1.15.0 | 
| [AWS IoT Device SDK for Java](https://github.com/aws/aws-iot-device-sdk-java-v2) v2 | v1.13.0 | 
| [AWS IoT Device SDK for C\$1\$1](https://github.com/aws/aws-iot-device-sdk-cpp-v2) v2 | v1.24.0 | 
| [AWS IoT Device SDK for JavaScript](https://github.com/aws/aws-iot-device-sdk-js-v2) v2  | v1.13.0 | 

`payloadFormat`  
（可选）消息有效载荷的格式。如果您未设置 `payloadFormat`，则假定类型为 `BYTES`。枚举包含以下值：  
+ `BYTES` – 有效载荷的内容是二进制 Blob。
+ `UTF8`— 有效载荷的内容是一 UTF8 串字符。

`retain`  
（可选）指示是否在发布时将 MQTT 保留选项设置为 `true`。

`userProperties`  
（可选）要发送的应用程序特定 `UserProperty` 对象的列表。`UserProperty` 对象定义如下：  

```
UserProperty:
  key: string
  value: string
```

`messageExpiryIntervalSeconds`  
（可选）消息过期并被服务器删除前等待的秒数。如果您未设置此值，消息不会过期。

`correlationData`  
（可选）已添加到请求中的信息，可用于将请求与响应相关联。

`responseTopic`  
（可选）应用于响应消息的主题。

`contentType`  
（可选）消息内容类型的应用程序特定标识符。

### 响应
<a name="ipc-operation-publishtoiotcore-response"></a>

此操作在其响应中未提供任何信息。

### 示例
<a name="ipc-operation-publishtoiotcore-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Java (IPC client V2) ]

**Example 示例：发布消息**  

```
package com.aws.greengrass.docs.samples.ipc;

import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClientV2;
import software.amazon.awssdk.aws.greengrass.model.PublishToIoTCoreRequest;
import software.amazon.awssdk.aws.greengrass.model.QOS;
import java.nio.charset.StandardCharsets;

public class PublishToIoTCore {

    public static void main(String[] args) {
        String topic = args[0];
        String message = args[1];
        QOS qos = QOS.get(args[2]);

        try (GreengrassCoreIPCClientV2 ipcClientV2 = GreengrassCoreIPCClientV2.builder().build()) {
            ipcClientV2.publishToIoTCore(new PublishToIoTCoreRequest()
                    .withTopicName(topic)
                    .withPayload(message.getBytes(StandardCharsets.UTF_8))
                    .withQos(qos));
            System.out.println("Successfully published to topic: " + topic);
        } catch (Exception e) {
            System.err.println("Exception occurred.");
            e.printStackTrace();
            System.exit(1);
        }
    }
}
```

------
#### [ Python (IPC client V2) ]

**Example 示例：发布消息**  
此示例假设您使用的是 Python v2 版本的 1.5.4 或更高版本。 AWS IoT Device SDK 

```
import awsiot.greengrasscoreipc.clientv2 as clientV2
                    
topic = 'my/topic'
qos = '1'
payload = 'Hello, World'

ipc_client = clientV2.GreengrassCoreIPCClientV2()
resp = ipc_client.publish_to_iot_core(topic_name=topic, qos=qos, payload=payload)
ipc_client.close()
```

------
#### [ Java (IPC client V1) ]

**Example 示例：发布消息**  
此示例使用一个`IPCUtils`类来创建与 C AWS IoT Greengrass ore IPC 服务的连接。有关更多信息，请参阅 [Connect 到 C AWS IoT Greengrass ore IPC 服务](interprocess-communication.md#ipc-service-connect)。

```
package com.aws.greengrass.docs.samples.ipc;

import com.aws.greengrass.docs.samples.ipc.util.IPCUtils;
import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient;
import software.amazon.awssdk.aws.greengrass.PublishToIoTCoreResponseHandler;
import software.amazon.awssdk.aws.greengrass.model.PublishToIoTCoreRequest;
import software.amazon.awssdk.aws.greengrass.model.PublishToIoTCoreResponse;
import software.amazon.awssdk.aws.greengrass.model.QOS;
import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError;
import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection;

import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class PublishToIoTCore {

    public static final int TIMEOUT_SECONDS = 10;

    public static void main(String[] args) {
        String topic = args[0];
        String message = args[1];
        QOS qos = QOS.get(args[2]);
        try (EventStreamRPCConnection eventStreamRPCConnection =
                     IPCUtils.getEventStreamRpcConnection()) {
            GreengrassCoreIPCClient ipcClient =
                    new GreengrassCoreIPCClient(eventStreamRPCConnection);
            PublishToIoTCoreResponseHandler responseHandler =
                    PublishToIoTCore.publishBinaryMessageToTopic(ipcClient, topic, message, qos);
            CompletableFuture<PublishToIoTCoreResponse> futureResponse =
                    responseHandler.getResponse();
            try {
                futureResponse.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
                System.out.println("Successfully published to topic: " + topic);
            } catch (TimeoutException e) {
                System.err.println("Timeout occurred while publishing to topic: " + topic);
            } catch (ExecutionException e) {
                if (e.getCause() instanceof UnauthorizedError) {
                    System.err.println("Unauthorized error while publishing to topic: " + topic);
                } else {
                    throw e;
                }
            }
        } catch (InterruptedException e) {
            System.out.println("IPC interrupted.");
        } catch (ExecutionException e) {
            System.err.println("Exception occurred when using IPC.");
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static PublishToIoTCoreResponseHandler publishBinaryMessageToTopic(GreengrassCoreIPCClient greengrassCoreIPCClient, String topic, String message, QOS qos) {
        PublishToIoTCoreRequest publishToIoTCoreRequest = new PublishToIoTCoreRequest();
        publishToIoTCoreRequest.setTopicName(topic);
        publishToIoTCoreRequest.setPayload(message.getBytes(StandardCharsets.UTF_8));
        publishToIoTCoreRequest.setQos(qos);
        return greengrassCoreIPCClient.publishToIoTCore(publishToIoTCoreRequest, Optional.empty());
    }
}
```

------
#### [ Python (IPC client V1) ]

**Example 示例：发布消息**  
此示例假设您使用的是 Python v2 版本的 1.5.4 或更高版本。 AWS IoT Device SDK 

```
import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import (
    QOS,
    PublishToIoTCoreRequest
)

TIMEOUT = 10

ipc_client = awsiot.greengrasscoreipc.connect()
                    
topic = "my/topic"
message = "Hello, World"
qos = QOS.AT_LEAST_ONCE

request = PublishToIoTCoreRequest()
request.topic_name = topic
request.payload = bytes(message, "utf-8")
request.qos = qos
operation = ipc_client.new_publish_to_iot_core()
operation.activate(request)
future_response = operation.get_response()
future_response.result(TIMEOUT)
```

------
#### [ C\$1\$1 (IPC client V1) ]

**Example 示例：发布消息**  

```
#include <iostream>

#include <aws/crt/Api.h>
#include <aws/greengrass/GreengrassCoreIpcClient.h>

using namespace Aws::Crt;
using namespace Aws::Greengrass;

class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
    void OnConnectCallback() override {
        // Handle connection to IPC service.
    }

    void OnDisconnectCallback(RpcError error) override {
        // Handle disconnection from IPC service.
    }

    bool OnErrorCallback(RpcError error) override {
        // Handle IPC service connection error.
        return true;
    }
};

int main() {
    ApiHandle apiHandle(g_allocator);
    Io::EventLoopGroup eventLoopGroup(1);
    Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
    Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
    IpcClientLifecycleHandler ipcLifecycleHandler;
    GreengrassCoreIpcClient ipcClient(bootstrap);
    auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
    if (!connectionStatus) {
        std::cerr << "Failed to establish IPC connection: " << connectionStatus.StatusToString() << std::endl;
        exit(-1);
    }

    String message("Hello, World!");
    String topic("my/topic");
    QOS qos = QOS_AT_MOST_ONCE;
    int timeout = 10;

    PublishToIoTCoreRequest request;
    Vector<uint8_t> messageData({message.begin(), message.end()});
    request.SetTopicName(topic);
    request.SetPayload(messageData);
    request.SetQos(qos);

    auto operation = ipcClient.NewPublishToIoTCore();
    auto activate = operation->Activate(request, nullptr);
    activate.wait();

    auto responseFuture = operation->GetResult();
    if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
        std::cerr << "Operation timed out while waiting for response from Greengrass Core." << std::endl;
        exit(-1);
    }

    auto response = responseFuture.get();
    if (!response) {
        // Handle error.
        auto errorType = response.GetResultType();
        if (errorType == OPERATION_ERROR) {
            auto *error = response.GetOperationError();
            (void)error;
            // Handle operation error.
        } else {
            // Handle RPC error.
        }
    }

    return 0;
}
```

------
#### [ JavaScript ]

**Example 示例：发布消息**  

```
    
import * as greengrasscoreipc from "aws-iot-device-sdk-v2/dist/greengrasscoreipc";
import {QOS, PublishToIoTCoreRequest} from "aws-iot-device-sdk-v2/dist/greengrasscoreipc/model";
 
class PublishToIoTCore {
    private ipcClient: greengrasscoreipc.Client
    private readonly topic: string;
 
    constructor() {
        // define your own constructor, e.g.
        this.topic = "<define_your_topic>";
        this.publishToIoTCore().then(r => console.log("Started workflow"));
    }
 
    private async publishToIoTCore() {
        try {
            const request: PublishToIoTCoreRequest = {
                topicName: this.topic,
                qos: QOS.AT_LEAST_ONCE, // you can change this depending on your use case
            }
 
            this.ipcClient = await getIpcClient();
 
            await this.ipcClient.publishToIoTCore(request);
        } catch (e) {
            // parse the error depending on your use cases
            throw e
        }
    }
}
 
 
export async function getIpcClient(){
    try {
        const ipcClient = greengrasscoreipc.createClient();
        await ipcClient.connect()
            .catch(error => {
                // parse the error depending on your use cases
                throw error;
            });
        return ipcClient
    } catch (err) {
        // parse the error depending on your use cases
        throw err
    }
}
 
// starting point
const publishToIoTCore = new PublishToIoTCore();
```

------
#### [ Rust ]

**Example 示例：发布消息**  

```
use gg_sdk::{Qos, Sdk};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    let message = b"Hello, World";
    let topic = "my/topic";
    let qos = Qos::AtLeastOnce;

    sdk.publish_to_iot_core(topic, message, qos)
        .expect("Failed to publish to topic");

    println!("Successfully published to topic: {topic}");
}
```

------
#### [ C ]

**Example 示例：发布消息**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/sdk.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    GgBuffer message = GG_STR("Hello, World");
    GgBuffer topic = GG_STR("my/topic");
    uint8_t qos = 1;

    err = ggipc_publish_to_iot_core(topic, message, qos);
    if (err != GG_ERR_OK) {
        fprintf(
            stderr,
            "Failed to publish to topic: %.*s\n",
            (int) topic.len,
            topic.data
        );
        exit(-1);
    }

    printf(
        "Successfully published to topic: %.*s\n", (int) topic.len, topic.data
    );
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：发布消息**  

```
#include <gg/ipc/client.hpp>
#include <iostream>

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    std::string_view message = "Hello, World";
    std::string_view topic = "my/topic";
    uint8_t qos = 1;

    error = client.publish_to_iot_core(topic, message, qos);
    if (error) {
        std::cerr << "Failed to publish to topic: " << topic << "\n";
        exit(-1);
    }

    std::cout << "Successfully published to topic: " << topic << "\n";
}
```

------

## SubscribeToIoTCore
<a name="ipc-operation-subscribetoiotcore"></a>

通过主题或主题筛选器订阅 MQTT 消息。 AWS IoT Core 当组件的生命周期结束时，C AWS IoT Greengrass ore 软件会删除订阅。

<a name="ipc-subscribe-operation-note"></a>此操作是一种订阅操作，您可以在其中订阅事件消息流。要使用此操作，请定义一个流响应处理程序，其中包含处理事件消息、错误和流关闭的函数。有关更多信息，请参阅 [订阅 IPC 事件流](interprocess-communication.md#ipc-subscribe-operations)。

**事件消息类型：**`IoTCoreMessage`

### 请求
<a name="ipc-operation-subscribetoiotcore-request"></a>

此操作的请求包含以下参数：

`topicName`（Python：`topic_name`）  
要订阅的主题。您可以使用 MQTT 主题通配符（`#` 和 `+`）来订阅多个主题。

`qos`  <a name="ipc-iot-core-mqtt-qos"></a>
要使用的 MQTT QoS。此枚举 `QOS` 包含以下值：  
+ `AT_MOST_ONCE` – QoS 0。MQTT 消息至多传送一次。
+ `AT_LEAST_ONCE` – QoS 1。MQTT 消息至少传送一次。

### 响应
<a name="ipc-operation-subscribetoiotcore-response"></a>

此操作的响应包含以下信息：

`messages`  
MQTT 消息流。此对象 `IoTCoreMessage` 包含以下信息：    
`message`  
MQTT 消息。此对象 `MQTTMessage` 包含以下信息：    
`topicName`（Python：`topic_name`）  
消息被发布到的主题。  
`payload`  
（可选）以 Blob 形式显示的消息有效载荷。
使用 MQTT 5 时，以下功能适用于 [Greengrass Nucleus](greengrass-nucleus-component.md) v2.10.0 及更高版本。如果使用的是 MQTT 3.1.1，则会忽略这些功能。下表列出了访问这些功能必须使用的 AWS IoT 设备 SDK 的最低版本。      
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-iot-core-mqtt.html)  
`payloadFormat`  
（可选）消息有效载荷的格式。如果您未设置 `payloadFormat`，则假定类型为 `BYTES`。枚举包含以下值：  
+ `BYTES` – 有效载荷的内容是二进制 Blob。
+ `UTF8`— 有效载荷的内容是一 UTF8串字符。  
`retain`  
（可选）指示是否在发布时将 MQTT 保留选项设置为 `true`。  
`userProperties`  
（可选）要发送的应用程序特定 `UserProperty` 对象的列表。`UserProperty` 对象定义如下：  

```
UserProperty:
  key: string
  value: string
```  
`messageExpiryIntervalSeconds`  
（可选）消息过期并被服务器删除前等待的秒数。如果您未设置此值，消息不会过期。  
`correlationData`  
（可选）已添加到请求中的信息，可用于将请求与响应相关联。  
`responseTopic`  
（可选）应用于响应消息的主题。  
`contentType`  
（可选）消息内容类型的应用程序特定标识符。

### 示例
<a name="ipc-operation-subscribetoiotcore-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Java (IPC client V2) ]

**Example 示例：订阅消息**  

```
package com.aws.greengrass.docs.samples.ipc;

import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClientV2;
import software.amazon.awssdk.aws.greengrass.SubscribeToIoTCoreResponseHandler;
import software.amazon.awssdk.aws.greengrass.model.QOS;
import software.amazon.awssdk.aws.greengrass.model.IoTCoreMessage;
import software.amazon.awssdk.aws.greengrass.model.SubscribeToIoTCoreRequest;
import software.amazon.awssdk.aws.greengrass.model.SubscribeToIoTCoreResponse;

import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;


public class SubscribeToIoTCore {

    public static void main(String[] args) {
        String topic = args[0];
        QOS qos = QOS.get(args[1]);

        Consumer<IoTCoreMessage> onStreamEvent = ioTCoreMessage ->
                System.out.printf("Received new message on topic %s: %s%n",
                        ioTCoreMessage.getMessage().getTopicName(),
                        new String(ioTCoreMessage.getMessage().getPayload(), StandardCharsets.UTF_8));

        Optional<Function<Throwable, Boolean>> onStreamError =
                Optional.of(e -> {
                    System.err.println("Received a stream error.");
                    e.printStackTrace();
                    return false;
                });

        Optional<Runnable> onStreamClosed = Optional.of(() ->
                System.out.println("Subscribe to IoT Core stream closed."));

        try (GreengrassCoreIPCClientV2 ipcClientV2 = GreengrassCoreIPCClientV2.builder().build()) {
            SubscribeToIoTCoreRequest request = new SubscribeToIoTCoreRequest()
                    .withTopicName(topic)
                    .withQos(qos);

            GreengrassCoreIPCClientV2.StreamingResponse<SubscribeToIoTCoreResponse, SubscribeToIoTCoreResponseHandler>
                    streamingResponse = ipcClientV2.subscribeToIoTCore(request, onStreamEvent, onStreamError, onStreamClosed);

            streamingResponse.getResponse();
            System.out.println("Successfully subscribed to topic: " + topic);

            // Keep the main thread alive, or the process will exit.
            while (true) {
                Thread.sleep(10000);
            }

            // To stop subscribing, close the stream.
            streamingResponse.getHandler().closeStream();
        } catch (InterruptedException e) {
            System.out.println("Subscribe interrupted.");
        } catch (Exception e) {
            System.err.println("Exception occurred.");
            e.printStackTrace();
            System.exit(1);
        }
    }
}
```

------
#### [ Python (IPC client V2) ]

**Example 示例：订阅消息**  
此示例假设您使用的是 Python v2 版本的 1.5.4 或更高版本。 AWS IoT Device SDK 

```
import threading
import traceback

import awsiot.greengrasscoreipc.clientv2 as clientV2
                    
topic = 'my/topic'
qos = '1'

def on_stream_event(event):
    try:
        topic_name = event.message.topic_name
        message = str(event.message.payload, 'utf-8')
        print(f'Received new message on topic {topic_name}:  {message}')
    except:
        traceback.print_exc()

def on_stream_error(error):
    # Return True to close stream, False to keep stream open.
    return True  

def on_stream_closed():
    pass

ipc_client = clientV2.GreengrassCoreIPCClientV2()
resp, operation = ipc_client.subscribe_to_iot_core(
    topic_name=topic,
    qos=qos, 
    on_stream_event=on_stream_event,
    on_stream_error=on_stream_error,
    on_stream_closed=on_stream_closed
)

# Keep the main thread alive, or the process will exit.
event = threading.Event()
event.wait()

# To stop subscribing, close the operation stream.
operation.close()
ipc_client.close()
```

------
#### [ Java (IPC client V1) ]

**Example 示例：订阅消息**  
此示例使用一个`IPCUtils`类来创建与 C AWS IoT Greengrass ore IPC 服务的连接。有关更多信息，请参阅 [Connect 到 C AWS IoT Greengrass ore IPC 服务](interprocess-communication.md#ipc-service-connect)。

```
package com.aws.greengrass.docs.samples.ipc;

import com.aws.greengrass.docs.samples.ipc.util.IPCUtils;
import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient;
import software.amazon.awssdk.aws.greengrass.SubscribeToIoTCoreResponseHandler;
import software.amazon.awssdk.aws.greengrass.model.*;
import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection;
import software.amazon.awssdk.eventstreamrpc.StreamResponseHandler;

import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class SubscribeToIoTCore {

    public static final int TIMEOUT_SECONDS = 10;

    public static void main(String[] args) {
        String topic = args[0];
        QOS qos = QOS.get(args[1]);
        try (EventStreamRPCConnection eventStreamRPCConnection =
                     IPCUtils.getEventStreamRpcConnection()) {
            GreengrassCoreIPCClient ipcClient =
                    new GreengrassCoreIPCClient(eventStreamRPCConnection);
            StreamResponseHandler<IoTCoreMessage> streamResponseHandler =
                    new SubscriptionResponseHandler();
            SubscribeToIoTCoreResponseHandler responseHandler =
                    SubscribeToIoTCore.subscribeToIoTCore(ipcClient, topic, qos,
                            streamResponseHandler);
            CompletableFuture<SubscribeToIoTCoreResponse> futureResponse =
                    responseHandler.getResponse();
            try {
                futureResponse.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
                System.out.println("Successfully subscribed to topic: " + topic);
            } catch (TimeoutException e) {
                System.err.println("Timeout occurred while subscribing to topic: " + topic);
            } catch (ExecutionException e) {
                if (e.getCause() instanceof UnauthorizedError) {
                    System.err.println("Unauthorized error while subscribing to topic: " + topic);
                } else {
                    throw e;
                }
            }

            // Keep the main thread alive, or the process will exit.
            try {
                while (true) {
                    Thread.sleep(10000);
                }
            } catch (InterruptedException e) {
                System.out.println("Subscribe interrupted.");
            }

            // To stop subscribing, close the stream.
            responseHandler.closeStream();
        } catch (InterruptedException e) {
            System.out.println("IPC interrupted.");
        } catch (ExecutionException e) {
            System.err.println("Exception occurred when using IPC.");
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static SubscribeToIoTCoreResponseHandler subscribeToIoTCore(GreengrassCoreIPCClient greengrassCoreIPCClient, String topic, QOS qos, StreamResponseHandler<IoTCoreMessage> streamResponseHandler) {
        SubscribeToIoTCoreRequest subscribeToIoTCoreRequest = new SubscribeToIoTCoreRequest();
        subscribeToIoTCoreRequest.setTopicName(topic);
        subscribeToIoTCoreRequest.setQos(qos);
        return greengrassCoreIPCClient.subscribeToIoTCore(subscribeToIoTCoreRequest,
                Optional.of(streamResponseHandler));
    }

    public static class SubscriptionResponseHandler implements StreamResponseHandler<IoTCoreMessage> {

        @Override
        public void onStreamEvent(IoTCoreMessage ioTCoreMessage) {
            try {
                String topic = ioTCoreMessage.getMessage().getTopicName();
                String message = new String(ioTCoreMessage.getMessage().getPayload(),
                        StandardCharsets.UTF_8);
                System.out.printf("Received new message on topic %s: %s%n", topic, message);
            } catch (Exception e) {
                System.err.println("Exception occurred while processing subscription response " +
                        "message.");
                e.printStackTrace();
            }
        }

        @Override
        public boolean onStreamError(Throwable error) {
            System.err.println("Received a stream error.");
            error.printStackTrace();
            return false;
        }

        @Override
        public void onStreamClosed() {
            System.out.println("Subscribe to IoT Core stream closed.");
        }
    }
}
```

------
#### [ Python (IPC client V1) ]

**Example 示例：订阅消息**  
此示例假设您使用的是 Python v2 版本的 1.5.4 或更高版本。 AWS IoT Device SDK 

```
import time
import traceback

import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import (
    IoTCoreMessage,
    QOS,
    SubscribeToIoTCoreRequest
)

TIMEOUT = 10

ipc_client = awsiot.greengrasscoreipc.connect()

class StreamHandler(client.SubscribeToIoTCoreStreamHandler):
    def __init__(self):
        super().__init__()

    def on_stream_event(self, event: IoTCoreMessage) -> None:
        try:
            message = str(event.message.payload, "utf-8")
            topic_name = event.message.topic_name
            # Handle message.
        except:
            traceback.print_exc()

    def on_stream_error(self, error: Exception) -> bool:
        # Handle error.
        return True  # Return True to close stream, False to keep stream open.

    def on_stream_closed(self) -> None:
        # Handle close.
        pass


topic = "my/topic"
qos = QOS.AT_MOST_ONCE

request = SubscribeToIoTCoreRequest()
request.topic_name = topic
request.qos = qos
handler = StreamHandler()
operation = ipc_client.new_subscribe_to_iot_core(handler)
operation.activate(request)
future_response = operation.get_response() 
future_response.result(TIMEOUT)

# Keep the main thread alive, or the process will exit.
while True:
    time.sleep(10)
                  
# To stop subscribing, close the operation stream.
operation.close()
```

------
#### [ C\$1\$1 (IPC client V1) ]

**Example 示例：订阅消息**  

```
#include <iostream>

#include <aws/crt/Api.h>
#include <aws/greengrass/GreengrassCoreIpcClient.h>

using namespace Aws::Crt;
using namespace Aws::Greengrass;

class IoTCoreResponseHandler : public SubscribeToIoTCoreStreamHandler {

    public:
        virtual ~IoTCoreResponseHandler() {}

    private:
        void OnStreamEvent(IoTCoreMessage *response) override {
            auto message = response->GetMessage();
            if (message.has_value() && message.value().GetPayload().has_value()) {
                auto messageBytes = message.value().GetPayload().value();
                std::string messageString(messageBytes.begin(), messageBytes.end());
                std::string topicName = message.value().GetTopicName().value().c_str();
                // Handle message.
            }
        }

        bool OnStreamError(OperationError *error) override {
            // Handle error.
            return false; // Return true to close stream, false to keep stream open.
        }

        void OnStreamClosed() override {
            // Handle close.
        }
};

class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
    void OnConnectCallback() override {
        // Handle connection to IPC service.
    }

    void OnDisconnectCallback(RpcError error) override {
        // Handle disconnection from IPC service.
    }

    bool OnErrorCallback(RpcError error) override {
        // Handle IPC service connection error.
        return true;
    }
};

int main() {
    ApiHandle apiHandle(g_allocator);
    Io::EventLoopGroup eventLoopGroup(1);
    Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
    Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
    IpcClientLifecycleHandler ipcLifecycleHandler;
    GreengrassCoreIpcClient ipcClient(bootstrap);
    auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
    if (!connectionStatus) {
        std::cerr << "Failed to establish IPC connection: " << connectionStatus.StatusToString() << std::endl;
        exit(-1);
    }

    String topic("my/topic");
    QOS qos = QOS_AT_MOST_ONCE;
    int timeout = 10;

    SubscribeToIoTCoreRequest request;
    request.SetTopicName(topic);
    request.SetQos(qos);
    auto streamHandler = MakeShared<IoTCoreResponseHandler>(DefaultAllocator());
    auto operation = ipcClient.NewSubscribeToIoTCore(streamHandler);
    auto activate = operation->Activate(request, nullptr);
    activate.wait();

    auto responseFuture = operation->GetResult();
    if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
        std::cerr << "Operation timed out while waiting for response from Greengrass Core." << std::endl;
        exit(-1);
    }

    auto response = responseFuture.get();
    if (!response) {
        // Handle error.
        auto errorType = response.GetResultType();
        if (errorType == OPERATION_ERROR) {
            auto *error = response.GetOperationError();
            (void)error;
            // Handle operation error.
        } else {
            // Handle RPC error.
        }
        exit(-1);
    }

    // Keep the main thread alive, or the process will exit.
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }

    operation->Close();
    return 0;
}
```

------
#### [ JavaScript ]

**Example 示例：订阅消息**  

```
import * as greengrasscoreipc from "aws-iot-device-sdk-v2/dist/greengrasscoreipc";
import {IoTCoreMessage, QOS, SubscribeToIoTCoreRequest} from "aws-iot-device-sdk-v2/dist/greengrasscoreipc/model";
import {RpcError} from "aws-iot-device-sdk-v2/dist/eventstream_rpc";
 
class SubscribeToIoTCore {
    private ipcClient: greengrasscoreipc.Client
    private readonly topic: string;
 
    constructor() {
        // define your own constructor, e.g.
        this.topic = "<define_your_topic>";
        this.subscribeToIoTCore().then(r => console.log("Started workflow"));
    }
 
    private async subscribeToIoTCore() {
        try {
            const request: SubscribeToIoTCoreRequest = {
                topicName: this.topic,
                qos: QOS.AT_LEAST_ONCE, // you can change this depending on your use case
            }
 
            this.ipcClient = await getIpcClient();
 
            const streamingOperation = this.ipcClient.subscribeToIoTCore(request);
 
            streamingOperation.on('message', (message: IoTCoreMessage) => {
                // parse the message depending on your use cases, e.g.
                if (message.message && message.message.payload) {
                    const receivedMessage = message.message.payload.toString();
                }
            });
 
            streamingOperation.on('streamError', (error : RpcError) => {
                // define your own error handling logic
            });
 
            streamingOperation.on('ended', () => {
                // define your own logic
            });
 
            await streamingOperation.activate();
 
            // Keep the main thread alive, or the process will exit.
            await new Promise((resolve) => setTimeout(resolve, 10000))
        } catch (e) {
            // parse the error depending on your use cases
            throw e
        }
    }
}
 
export async function getIpcClient(){
    try {
        const ipcClient = greengrasscoreipc.createClient();
        await ipcClient.connect()
            .catch(error => {
                // parse the error depending on your use cases
                throw error;
            });
        return ipcClient
    } catch (err) {
        // parse the error depending on your use cases
        throw err
    }
}
 
// starting point
const subscribeToIoTCore = new SubscribeToIoTCore();
```

------
#### [ Rust ]

**Example 示例：订阅消息**  

```
use gg_sdk::{Qos, Sdk};
use std::{thread, time::Duration};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    let topic = "my/topic";
    let qos = Qos::AtLeastOnce;

    let callback = |topic: &str, payload: &[u8]| {
        let message = String::from_utf8_lossy(payload);
        println!("Received new message on topic {topic}: {message}");
    };

    let _sub = sdk
        .subscribe_to_iot_core(topic, qos, &callback)
        .expect("Failed to subscribe to topic");

    println!("Successfully subscribed to topic: {topic}");

    // Keep the main thread alive, or the process will exit.
    loop {
        thread::sleep(Duration::from_secs(10));
    }
}
```

------
#### [ C ]

**Example 示例：订阅消息**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/sdk.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

static void on_subscription_response(
    void *ctx, GgBuffer topic, GgBuffer payload, GgIpcSubscriptionHandle handle
) {
    (void) ctx;
    (void) handle;

    printf(
        "Received new message on topic %.*s: %.*s\n",
        (int) topic.len,
        topic.data,
        (int) payload.len,
        payload.data
    );
}

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    GgBuffer topic = GG_STR("my/topic");
    uint8_t qos = 1;

    GgIpcSubscriptionHandle handle;
    err = ggipc_subscribe_to_iot_core(
        topic, qos, on_subscription_response, NULL, &handle
    );
    if (err != GG_ERR_OK) {
        fprintf(
            stderr,
            "Failed to subscribe to topic: %.*s\n",
            (int) topic.len,
            topic.data
        );
        exit(-1);
    }

    printf(
        "Successfully subscribed to topic: %.*s\n", (int) topic.len, topic.data
    );

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }

    // To stop subscribing, close the subscription handle.
    ggipc_close_subscription(handle);
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：订阅消息**  

```
#include <gg/ipc/client.hpp>
#include <unistd.h>
#include <iostream>

class ResponseHandler : public gg::ipc::IotTopicCallback {
    void operator()(
        std::string_view topic,
        gg::Buffer payload,
        gg::ipc::Subscription &handle
    ) override {
        (void) handle;
        std::cout << "Received new message on topic " << topic << ": "
                  << payload << "\n";
    }
};

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    std::string_view topic = "my/topic";
    uint8_t qos = 1;

    static ResponseHandler handler;
    error = client.subscribe_to_iot_core(topic, qos, handler);
    if (error) {
        std::cerr << "Failed to subscribe to topic: " << topic << "\n";
        exit(-1);
    }

    std::cout << "Successfully subscribed to topic: " << topic << "\n";

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }
}
```

------

## 示例
<a name="ipc-iot-core-mqtt-examples"></a>

使用以下示例来学习如何在组件中使用 AWS IoT Core MQTT IPC 服务。

### AWS IoT Core MQTT 发布器示例（C\$1\$1，IPC 客户端 V1）
<a name="ipc-iot-core-mqtt-example-publisher-cpp"></a>

以下示例配方允许该组件发布至所有主题。

------
#### [ JSON ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.IoTCorePublisherCpp",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes MQTT messages to IoT Core.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.IoTCorePublisherCpp:mqttproxy:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": [
              "aws.greengrass#PublishToIoTCore"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Lifecycle": {
        "Run": "{artifacts:path}/greengrassv2_iotcore_publisher"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.IoTCorePublisherCpp/1.0.0/greengrassv2_iotcore_publisher",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

------
#### [ YAML ]

```
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.IoTCorePublisherCpp
ComponentVersion: 1.0.0
ComponentDescription: A component that publishes MQTT messages to IoT Core.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.mqttproxy:
        com.example.IoTCorePublisherCpp:mqttproxy:1:
          policyDescription: Allows access to publish to all topics.
          operations:
            - aws.greengrass#PublishToIoTCore
          resources:
            - "*"
Manifests:
  - Lifecycle:
      Run: "{artifacts:path}/greengrassv2_iotcore_publisher"
    Artifacts:
      - URI: s3://amzn-s3-demo-bucket/artifacts/com.example.IoTCorePublisherCpp/1.0.0/greengrassv2_iotcore_publisher
        Permission:
          Execute: OWNER
```

------

以下示例 C\$1\$1 应用程序演示了如何使用 AWS IoT Core MQTT IPC 服务向发布消息。 AWS IoT Core

```
#include <iostream>

#include <aws/crt/Api.h>
#include <aws/greengrass/GreengrassCoreIpcClient.h>

using namespace Aws::Crt;
using namespace Aws::Greengrass;

class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
    void OnConnectCallback() override {
        std::cout << "OnConnectCallback" << std::endl;
    }

    void OnDisconnectCallback(RpcError error) override {
        std::cout << "OnDisconnectCallback: " << error.StatusToString() << std::endl;
        exit(-1);
    }

    bool OnErrorCallback(RpcError error) override {
        std::cout << "OnErrorCallback: " << error.StatusToString() << std::endl;
        return true;
    }
};

int main() {
    String message("Hello from the Greengrass IPC MQTT publisher (C++).");
    String topic("test/topic/cpp");
    QOS qos = QOS_AT_LEAST_ONCE;
    int timeout = 10;

    ApiHandle apiHandle(g_allocator);
    Io::EventLoopGroup eventLoopGroup(1);
    Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
    Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
    IpcClientLifecycleHandler ipcLifecycleHandler;
    GreengrassCoreIpcClient ipcClient(bootstrap);
    auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
    if (!connectionStatus) {
        std::cerr << "Failed to establish IPC connection: " << connectionStatus.StatusToString() << std::endl;
        exit(-1);
    }

    while (true) {
        PublishToIoTCoreRequest request;
        Vector<uint8_t> messageData({message.begin(), message.end()});
        request.SetTopicName(topic);
        request.SetPayload(messageData);
        request.SetQos(qos);

        auto operation = ipcClient.NewPublishToIoTCore();
        auto activate = operation->Activate(request, nullptr);
        activate.wait();

        auto responseFuture = operation->GetResult();
        if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
            std::cerr << "Operation timed out while waiting for response from Greengrass Core." << std::endl;
            exit(-1);
        }

        auto response = responseFuture.get();
        if (response) {
            std::cout << "Successfully published to topic: " << topic << std::endl;
        } else {
            // An error occurred.
            std::cout << "Failed to publish to topic: " << topic << std::endl;
            auto errorType = response.GetResultType();
            if (errorType == OPERATION_ERROR) {
                auto *error = response.GetOperationError();
                std::cout << "Operation error: " << error->GetMessage().value() << std::endl;
            } else {
                std::cout << "RPC error: " << response.GetRpcError() << std::endl;
            }
            exit(-1);
        }

        std::this_thread::sleep_for(std::chrono::seconds(5));
    }

    return 0;
}
```

### AWS IoT Core MQTT 订阅者示例（C\$1\$1，IPC 客户端 V1）
<a name="ipc-iot-core-mqtt-example-subscriber-cpp"></a>

以下示例配方允许该组件订阅所有主题。

------
#### [ JSON ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.IoTCoreSubscriberCpp",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to MQTT messages from IoT Core.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.IoTCoreSubscriberCpp:mqttproxy:1": {
            "policyDescription": "Allows access to subscribe to all topics.",
            "operations": [
              "aws.greengrass#SubscribeToIoTCore"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Lifecycle": {
        "Run": "{artifacts:path}/greengrassv2_iotcore_subscriber"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.IoTCoreSubscriberCpp/1.0.0/greengrassv2_iotcore_subscriber",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

------
#### [ YAML ]

```
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.IoTCoreSubscriberCpp
ComponentVersion: 1.0.0
ComponentDescription: A component that subscribes to MQTT messages from IoT Core.
ComponentPublisher: Amazon
ComponentConfiguration:
  DefaultConfiguration:
    accessControl:
      aws.greengrass.ipc.mqttproxy:
        com.example.IoTCoreSubscriberCpp:mqttproxy:1:
          policyDescription: Allows access to subscribe to all topics.
          operations:
            - aws.greengrass#SubscribeToIoTCore
          resources:
            - "*"
Manifests:
  - Lifecycle:
      Run: "{artifacts:path}/greengrassv2_iotcore_subscriber"
    Artifacts:
      - URI: s3://amzn-s3-demo-bucket/artifacts/com.example.IoTCoreSubscriberCpp/1.0.0/greengrassv2_iotcore_subscriber
        Permission:
          Execute: OWNER
```

------

以下示例 C\$1\$1 应用程序演示了如何使用 AWS IoT Core MQTT IPC 服务订阅来自的消息。 AWS IoT Core

```
#include <iostream>

#include <aws/crt/Api.h>
#include <aws/greengrass/GreengrassCoreIpcClient.h>

using namespace Aws::Crt;
using namespace Aws::Greengrass;

class IoTCoreResponseHandler : public SubscribeToIoTCoreStreamHandler {

    public:
        virtual ~IoTCoreResponseHandler() {}

    private:

        void OnStreamEvent(IoTCoreMessage *response) override {
            auto message = response->GetMessage();
            if (message.has_value() && message.value().GetPayload().has_value()) {
                auto messageBytes = message.value().GetPayload().value();
                std::string messageString(messageBytes.begin(), messageBytes.end());
                std::string messageTopic = message.value().GetTopicName().value().c_str();
                std::cout << "Received new message on topic: " << messageTopic << std::endl;
                std::cout << "Message: " << messageString << std::endl;
            }
        }

        bool OnStreamError(OperationError *error) override {
            std::cout << "Received an operation error: ";
            if (error->GetMessage().has_value()) {
                std::cout << error->GetMessage().value();
            }
            std::cout << std::endl;
            return false; // Return true to close stream, false to keep stream open.
        }

        void OnStreamClosed() override {
            std::cout << "Subscribe to IoT Core stream closed." << std::endl;
        }
};

class IpcClientLifecycleHandler : public ConnectionLifecycleHandler {
    void OnConnectCallback() override {
        std::cout << "OnConnectCallback" << std::endl;
    }

    void OnDisconnectCallback(RpcError error) override {
        std::cout << "OnDisconnectCallback: " << error.StatusToString() << std::endl;
        exit(-1);
    }

    bool OnErrorCallback(RpcError error) override {
        std::cout << "OnErrorCallback: " << error.StatusToString() << std::endl;
        return true;
    }
};

int main() {
    String topic("test/topic/cpp");
    QOS qos = QOS_AT_LEAST_ONCE;
    int timeout = 10;

    ApiHandle apiHandle(g_allocator);
    Io::EventLoopGroup eventLoopGroup(1);
    Io::DefaultHostResolver socketResolver(eventLoopGroup, 64, 30);
    Io::ClientBootstrap bootstrap(eventLoopGroup, socketResolver);
    IpcClientLifecycleHandler ipcLifecycleHandler;
    GreengrassCoreIpcClient ipcClient(bootstrap);
    auto connectionStatus = ipcClient.Connect(ipcLifecycleHandler).get();
    if (!connectionStatus) {
        std::cerr << "Failed to establish IPC connection: " << connectionStatus.StatusToString() << std::endl;
        exit(-1);
    }

    SubscribeToIoTCoreRequest request;
    request.SetTopicName(topic);
    request.SetQos(qos);
    auto streamHandler = MakeShared<IoTCoreResponseHandler>(DefaultAllocator());
    auto operation = ipcClient.NewSubscribeToIoTCore(streamHandler);
    auto activate = operation->Activate(request, nullptr);
    activate.wait();

    auto responseFuture = operation->GetResult();
    if (responseFuture.wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout) {
        std::cerr << "Operation timed out while waiting for response from Greengrass Core." << std::endl;
        exit(-1);
    }

    auto response = responseFuture.get();
    if (response) {
        std::cout << "Successfully subscribed to topic: " << topic << std::endl;
    } else {
        // An error occurred.
        std::cout << "Failed to subscribe to topic: " << topic << std::endl;
        auto errorType = response.GetResultType();
        if (errorType == OPERATION_ERROR) {
            auto *error = response.GetOperationError();
            std::cout << "Operation error: " << error->GetMessage().value() << std::endl;
        } else {
            std::cout << "RPC error: " << response.GetRpcError() << std::endl;
        }
        exit(-1);
    }

    // Keep the main thread alive, or the process will exit.
    while (true) {
        std::this_thread::sleep_for(std::chrono::seconds(10));
    }

    operation->Close();
    return 0;
}
```

### 示例 AWS IoT Core MQTT 发布器 (Rust)
<a name="ipc-iot-core-mqtt-example-publisher-rust"></a>

以下示例配方允许该组件发布至所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.IoTCorePublisherRust",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes MQTT messages to IoT Core.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.IoTCorePublisherRust:mqttproxy:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": ["aws.greengrass#PublishToIoTCore"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/publish_to_iot_core"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.IoTCorePublisherRust/1.0.0/publish_to_iot_core",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 Rust 应用程序演示了如何使用 AWS IoT Core MQTT IPC 服务向发布消息。 AWS IoT Core

```
use gg_sdk::{Qos, Sdk};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    let message = b"Hello, World";
    let topic = "my/topic";
    let qos = Qos::AtLeastOnce;

    sdk.publish_to_iot_core(topic, message, qos)
        .expect("Failed to publish to topic");

    println!("Successfully published to topic: {topic}");
}
```

### 示例 AWS IoT Core MQTT 订阅者 (Rust)
<a name="ipc-iot-core-mqtt-example-subscriber-rust"></a>

以下示例配方允许该组件订阅所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.IoTCoreSubscriberRust",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to MQTT messages from IoT Core.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.IoTCoreSubscriberRust:mqttproxy:1": {
            "policyDescription": "Allows access to subscribe to all topics.",
            "operations": ["aws.greengrass#SubscribeToIoTCore"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/subscribe_to_iot_core"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.IoTCoreSubscriberRust/1.0.0/subscribe_to_iot_core",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 Rust 应用程序演示了如何使用 AWS IoT Core MQTT IPC 服务订阅来自的消息。 AWS IoT Core

```
use gg_sdk::{Qos, Sdk};
use std::{thread, time::Duration};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    let topic = "my/topic";
    let qos = Qos::AtLeastOnce;

    let callback = |topic: &str, payload: &[u8]| {
        let message = String::from_utf8_lossy(payload);
        println!("Received new message on topic {topic}: {message}");
    };

    let _sub = sdk
        .subscribe_to_iot_core(topic, qos, &callback)
        .expect("Failed to subscribe to topic");

    println!("Successfully subscribed to topic: {topic}");

    // Keep the main thread alive, or the process will exit.
    loop {
        thread::sleep(Duration::from_secs(10));
    }
}
```

### 示例 AWS IoT Core MQTT 发布器 (C)
<a name="ipc-iot-core-mqtt-example-publisher-c"></a>

以下示例配方允许该组件发布至所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.IoTCorePublisherC",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes MQTT messages to IoT Core.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.IoTCorePublisherC:mqttproxy:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": ["aws.greengrass#PublishToIoTCore"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/sample_publish_to_iot_core"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.IoTCorePublisherC/1.0.0/sample_publish_to_iot_core",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 C 应用程序演示如何使用 AWS IoT Core MQTT IPC 服务向发布消息。 AWS IoT Core

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/sdk.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    GgBuffer message = GG_STR("Hello, World");
    GgBuffer topic = GG_STR("my/topic");
    uint8_t qos = 1;

    err = ggipc_publish_to_iot_core(topic, message, qos);
    if (err != GG_ERR_OK) {
        fprintf(
            stderr,
            "Failed to publish to topic: %.*s\n",
            (int) topic.len,
            topic.data
        );
        exit(-1);
    }

    printf(
        "Successfully published to topic: %.*s\n", (int) topic.len, topic.data
    );
}
```

### 示例 AWS IoT Core MQTT 订阅者 (C)
<a name="ipc-iot-core-mqtt-example-subscriber-c"></a>

以下示例配方允许该组件订阅所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.IoTCoreSubscriberC",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to MQTT messages from IoT Core.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.IoTCoreSubscriberC:mqttproxy:1": {
            "policyDescription": "Allows access to subscribe to all topics.",
            "operations": ["aws.greengrass#SubscribeToIoTCore"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/sample_subscribe_to_iot_core"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.IoTCoreSubscriberC/1.0.0/sample_subscribe_to_iot_core",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 C 应用程序演示如何使用 AWS IoT Core MQTT IPC 服务订阅来自的消息。 AWS IoT Core

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/sdk.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

static void on_subscription_response(
    void *ctx, GgBuffer topic, GgBuffer payload, GgIpcSubscriptionHandle handle
) {
    (void) ctx;
    (void) handle;

    printf(
        "Received new message on topic %.*s: %.*s\n",
        (int) topic.len,
        topic.data,
        (int) payload.len,
        payload.data
    );
}

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    GgBuffer topic = GG_STR("my/topic");
    uint8_t qos = 1;

    GgIpcSubscriptionHandle handle;
    err = ggipc_subscribe_to_iot_core(
        topic, qos, on_subscription_response, NULL, &handle
    );
    if (err != GG_ERR_OK) {
        fprintf(
            stderr,
            "Failed to subscribe to topic: %.*s\n",
            (int) topic.len,
            topic.data
        );
        exit(-1);
    }

    printf(
        "Successfully subscribed to topic: %.*s\n", (int) topic.len, topic.data
    );

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }

    // To stop subscribing, close the subscription handle.
    ggipc_close_subscription(handle);
}
```

### AWS IoT Core MQTT 发布器示例（C\$1\$1，组件 SDK）
<a name="ipc-iot-core-mqtt-example-publisher-cpp-component-sdk"></a>

以下示例配方允许该组件发布至所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.IoTCorePublisherCpp",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that publishes MQTT messages to IoT Core.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.IoTCorePublisherCpp:mqttproxy:1": {
            "policyDescription": "Allows access to publish to all topics.",
            "operations": ["aws.greengrass#PublishToIoTCore"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/sample_cpp_publish_to_iot_core"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.IoTCorePublisherCpp/1.0.0/sample_cpp_publish_to_iot_core",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 C\$1\$1 应用程序演示了如何使用 AWS IoT Core MQTT IPC 服务向发布消息。 AWS IoT Core

```
#include <gg/ipc/client.hpp>
#include <iostream>

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    std::string_view message = "Hello, World";
    std::string_view topic = "my/topic";
    uint8_t qos = 1;

    error = client.publish_to_iot_core(topic, message, qos);
    if (error) {
        std::cerr << "Failed to publish to topic: " << topic << "\n";
        exit(-1);
    }

    std::cout << "Successfully published to topic: " << topic << "\n";
}
```

### AWS IoT Core MQTT 订阅者示例（C\$1\$1，组件 SDK）
<a name="ipc-iot-core-mqtt-example-subscriber-cpp-component-sdk"></a>

以下示例配方允许该组件订阅所有主题。

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.IoTCoreSubscriberCpp",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "A component that subscribes to MQTT messages from IoT Core.",
  "ComponentPublisher": "Amazon",
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "accessControl": {
        "aws.greengrass.ipc.mqttproxy": {
          "com.example.IoTCoreSubscriberCpp:mqttproxy:1": {
            "policyDescription": "Allows access to subscribe to all topics.",
            "operations": ["aws.greengrass#SubscribeToIoTCore"],
            "resources": ["*"]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux",
        "runtime": "*"
      },
      "Lifecycle": {
        "run": "{artifacts:path}/sample_cpp_subscribe_to_iot_core"
      },
      "Artifacts": [
        {
          "URI": "s3://amzn-s3-demo-bucket/artifacts/com.example.IoTCoreSubscriberCpp/1.0.0/sample_cpp_subscribe_to_iot_core",
          "Permission": {
            "Execute": "OWNER"
          }
        }
      ]
    }
  ]
}
```

以下示例 C\$1\$1 应用程序演示了如何使用 AWS IoT Core MQTT IPC 服务订阅来自的消息。 AWS IoT Core

```
#include <gg/ipc/client.hpp>
#include <unistd.h>
#include <iostream>

class ResponseHandler : public gg::ipc::IotTopicCallback {
    void operator()(
        std::string_view topic,
        gg::Buffer payload,
        gg::ipc::Subscription &handle
    ) override {
        (void) handle;
        std::cout << "Received new message on topic " << topic << ": "
                  << payload << "\n";
    }
};

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    std::string_view topic = "my/topic";
    uint8_t qos = 1;

    static ResponseHandler handler;
    error = client.subscribe_to_iot_core(topic, qos, handler);
    if (error) {
        std::cerr << "Failed to subscribe to topic: " << topic << "\n";
        exit(-1);
    }

    std::cout << "Successfully subscribed to topic: " << topic << "\n";

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }
}
```

# 与组件生命周期交互
<a name="ipc-component-lifecycle"></a>

使用组件生命周期 IPC 服务可以执行以下操作：
+ 更新核心设备上的组件状态。
+ 订阅组件状态更新。
+ 阻止 Nucleus 在部署期间停止组件以应用更新。
+ 暂停和恢复组件进程。

**Topics**
+ [最低 SDK 版本](#ipc-component-lifecycle-sdk-versions)
+ [Authorization](#ipc-component-lifecycle-authorization)
+ [UpdateState](#ipc-operation-updatestate)
+ [SubscribeToComponentUpdates](#ipc-operation-subscribetocomponentupdates)
+ [DeferComponentUpdate](#ipc-operation-defercomponentupdate)
+ [PauseComponent](#ipc-operation-pausecomponent)
+ [ResumeComponent](#ipc-operation-resumecomponent)

## 最低 SDK 版本
<a name="ipc-component-lifecycle-sdk-versions"></a>

下表列出了在与组件生命周期交互时必须使用的最低版本。 AWS IoT Device SDK 


| SDK | 最低版本 | 
| --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.2.10  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.5.3  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.17.0  | 
|  [AWS IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  | 

## Authorization
<a name="ipc-component-lifecycle-authorization"></a>

要暂停或恢复自定义组件中的其它组件，必须定义允许组件管理其它组件的授权策略。有关定义授权策略的信息，请参阅[授权组件执行 IPC 操作](interprocess-communication.md#ipc-authorization-policies)。

组件生命周期管理的授权策略具有以下属性。

**IPC 服务标识符：**`aws.greengrass.ipc.lifecycle`


| 操作 | 说明 | 资源 | 
| --- | --- | --- | 
|  `aws.greengrass#PauseComponent`  |  允许某个组件暂停您指定的组件。  |  组件名称，或使用 `*` 允许访问所有组件。  | 
|  `aws.greengrass#ResumeComponent`  |  允许某个组件恢复您指定的组件。  |  组件名称，或使用 `*` 允许访问所有组件。  | 
|  `*`  |  允许某个组件暂停和恢复您指定的组件。  |  组件名称，或使用 `*` 允许访问所有组件。  | 

### 授权策略示例
<a name="ipc-component-lifecycle-authorization-policy-examples"></a>

您可以参考以下授权策略示例，帮助您为组件配置授权策略。

**Example 示例授权策略**  
以下示例授权策略允许组件暂停和恢复所有组件。  

```
{
  "accessControl": {
    "aws.greengrass.ipc.lifecycle": {
      "com.example.MyLocalLifecycleComponent:lifecycle:1": {
        "policyDescription": "Allows access to pause/resume all components.",
        "operations": [
          "aws.greengrass#PauseComponent",
          "aws.greengrass#ResumeComponent"
        ],
        "resources": [
          "*"
        ]
      }
    }
  }
}
```

## UpdateState
<a name="ipc-operation-updatestate"></a>

更新核心设备上的组件状态。

### 请求
<a name="ipc-operation-updatestate-request"></a>

此操作的请求包含以下参数：

`state`  
要设置的状态。此枚举 `LifecycleState` 包含以下值：  
+ `RUNNING`
+ `ERRORED`

### 响应
<a name="ipc-operation-updatestate-response"></a>

此操作在其响应中未提供任何信息。

### 示例
<a name="ipc-operation-updatestate-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Rust ]

**Example 示例：更新状态**  

```
use gg_sdk::{ComponentState, Sdk};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    // Update component state to RUNNING
    sdk.update_state(ComponentState::Running)
        .expect("Failed to update component state");

    println!("Successfully updated component state to RUNNING.");
}
```

------
#### [ C ]

**Example 示例：更新状态**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/sdk.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    // Update component state to RUNNING
    err = ggipc_update_state(GG_COMPONENT_STATE_RUNNING);
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to update component state.\n");
        exit(-1);
    }

    printf("Successfully updated component state to RUNNING.\n");
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：更新状态**  

```
#include <gg/ipc/client.hpp>
#include <iostream>

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    // Update component state to RUNNING
    error = client.update_component_state(GG_COMPONENT_STATE_RUNNING);
    if (error) {
        std::cerr << "Failed to update component state.\n";
        exit(-1);
    }

    std::cout << "Successfully updated component state to RUNNING.\n";
}
```

------

## SubscribeToComponentUpdates
<a name="ipc-operation-subscribetocomponentupdates"></a>

订阅即可在 AWS IoT Greengrass 核心软件更新组件之前接收通知。该通知指定了在更新过程中 Nucleus 是否会重启。

只有当部署的组件更新策略指定通知组件时，Nucleus 才会发送更新通知。默认行为是通知组件。有关更多信息，请参阅[创建部署](create-deployments.md)以及您在调用[CreateDeployment](https://docs.aws.amazon.com/greengrass/v2/APIReference/API_CreateDeployment.html)操作时可以提供的[DeploymentComponentUpdatePolicy](https://docs.aws.amazon.com/greengrass/v2/APIReference/API_DeploymentComponentUpdatePolicy.html)对象。

**重要**  
本地部署不会在更新之前通知组件。

<a name="ipc-subscribe-operation-note"></a>此操作是一种订阅操作，您可以在其中订阅事件消息流。要使用此操作，请定义一个流响应处理程序，其中包含处理事件消息、错误和流关闭的函数。有关更多信息，请参阅 [订阅 IPC 事件流](interprocess-communication.md#ipc-subscribe-operations)。

**事件消息类型：**`ComponentUpdatePolicyEvents`

**提示**  
您可以按照教程了解如何开发一个有条件地推迟组件更新的组件。有关更多信息，请参阅 [教程：开发可延迟组件更新的 Greengrass 组件](defer-component-updates-tutorial.md)。

### 请求
<a name="ipc-operation-subscribetocomponentupdates-request"></a>

此操作的请求没有任何参数。

### 响应
<a name="ipc-operation-subscribetocomponentupdates-response"></a>

此操作的响应包含以下信息：

`messages`  
通知消息流。此对象 `ComponentUpdatePolicyEvents` 包含以下信息：    
`preUpdateEvent`（Python：`pre_update_event`）  
（可选）指示 Nucleus 想要更新组件的事件。您可以通过 [DeferComponentUpdate](#ipc-operation-defercomponentupdate) 操作进行响应，以确认更新或推迟更新，直到组件准备好重启为止。此对象 `PreComponentUpdateEvent` 包含以下信息：    
`deploymentId`（Python：`deployment_id`）  
更新组件的 AWS IoT Greengrass 部署的 ID。  
`isGgcRestarting`（Python：`is_ggc_restarting`）  
Nucleus 是否需要重启才能应用更新。  
`postUpdateEvent`（Python：`post_update_event`）  
（可选）指示 Nucleus 已更新组件的事件。此对象 `PostComponentUpdateEvent` 包含以下信息：    
`deploymentId`（Python：`deployment_id`）  
更新组件的 AWS IoT Greengrass 部署的 ID。  
此功能需要 v2.7.0 或更高版本的 Greengrass Nucleus 组件。

## DeferComponentUpdate
<a name="ipc-operation-defercomponentupdate"></a>

确认或推迟使用 [SubscribeToComponentUpdates](#ipc-operation-subscribetocomponentupdates) 发现的组件更新。您可以指定在 Nucleus 再次检查组件是否准备好让组件更新继续之前等待的时长。您也可以使用此操作告知 Nucleus 您的组件已准备好进行更新。

如果某个组件未响应组件更新通知，则 Nucleus 会按您在部署组件更新策略中指定的时间等待。超时之后，Nucleus 继续部署。组件更新超时默认值为 60 秒。有关更多信息，请参阅[创建部署](create-deployments.md)以及您在调用[CreateDeployment](https://docs.aws.amazon.com/greengrass/v2/APIReference/API_CreateDeployment.html)操作时可以提供的[DeploymentComponentUpdatePolicy](https://docs.aws.amazon.com/greengrass/v2/APIReference/API_DeploymentComponentUpdatePolicy.html)对象。

**提示**  
您可以按照教程了解如何开发一个有条件地推迟组件更新的组件。有关更多信息，请参阅 [教程：开发可延迟组件更新的 Greengrass 组件](defer-component-updates-tutorial.md)。

### 请求
<a name="ipc-operation-defercomponentupdate-request"></a>

此操作的请求包含以下参数：

`deploymentId`（Python：`deployment_id`）  
要推迟的 AWS IoT Greengrass 部署的 ID。

`message`  
（可选）要推迟更新的组件的名称。  
默认为发出请求的组件名称。

`recheckAfterMs`（Python：`recheck_after_ms`）  
推迟更新的时长（以毫秒为单位）。Nucleus 会等待这段时间，然后发送另一个可以通过 [SubscribeToComponentUpdates](#ipc-operation-subscribetocomponentupdates) 发现的 `PreComponentUpdateEvent`。  
指定 `0` 即可确认更新。这会告知 Nucleus 您的组件已准备好进行更新。  
默认为零毫秒，这意味着确认更新。

### 响应
<a name="ipc-operation-defercomponentupdate-response"></a>

此操作在其响应中未提供任何信息。

## PauseComponent
<a name="ipc-operation-pausecomponent"></a>

[此功能适用于 Greengrass nucleus 组件的 v2.4.0 及更高版本。](greengrass-nucleus-component.md) AWS IoT Greengrass 目前不支持在 Windows 核心设备上使用此功能。

暂停核心设备上的组件进程。要恢复组件，请使用[ResumeComponent](#ipc-operation-resumecomponent)操作。

只能暂停通用组件。如果您尝试暂停任何其它类型的组件，则此操作将引发 `InvalidRequestError`。

**注意**  
此操作无法暂停容器化进程，例如 Docker 容器。要暂停和恢复 Docker 容器，可以使用 [docker pause](https://docs.docker.com/engine/reference/commandline/pause/) 命令和 [docker unpause](https://docs.docker.com/engine/reference/commandline/unpause/) 命令。

此操作不会暂停组件依赖关系或依赖于您暂停的组件的组件。当暂停依赖于另一个组件的组件时，请考虑这种行为，因为依赖组件在暂停依赖关系时可能会遇到问题。

当您重启或关闭已暂停的组件时（例如通过部署），Greengrass nucleus 会恢复该组件并运行其关闭生命周期。有关重启组件的更多信息，请参阅 [RestartComponent](ipc-local-deployments-components.md#ipc-operation-restartcomponent)。

**重要**  
要使用此操作，您必须定义授权策略来授予使用此操作的权限。有关更多信息，请参阅 [Authorization](#ipc-component-lifecycle-authorization)。

### 最低 SDK 版本
<a name="ipc-operation-pausecomponent-sdk-versions"></a>

下表列出了暂停和恢复组件时 AWS IoT Device SDK 必须使用的最低版本。


| SDK | 最低版本 | 
| --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.4.3  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.6.2  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.13.1  | 
|  [AWS IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  | 

### 请求
<a name="ipc-operation-defercomponentupdate-request"></a>

此操作的请求包含以下参数：

`componentName`（Python：`component_name`）  
要暂停的组件的名称，该组件必须是通用组件。有关更多信息，请参阅 [组件类型](develop-greengrass-components.md#component-types)。

### 响应
<a name="ipc-operation-defercomponentupdate-response"></a>

此操作在其响应中未提供任何信息。

## ResumeComponent
<a name="ipc-operation-resumecomponent"></a>

[此功能适用于 Greengrass nucleus 组件的 v2.4.0 及更高版本。](greengrass-nucleus-component.md) AWS IoT Greengrass 目前不支持在 Windows 核心设备上使用此功能。

恢复核心设备上的组件进程。要暂停组件，请使用[PauseComponent](#ipc-operation-pausecomponent)操作。

您只能恢复已暂停的组件。如果您尝试恢复未暂停的组件，则此操作将引发 `InvalidRequestError`。

**重要**  
要使用此操作，您必须定义授权策略来授予执行此操作的权限。有关更多信息，请参阅 [Authorization](#ipc-component-lifecycle-authorization)。

### 最低 SDK 版本
<a name="ipc-operation-resumecomponent-sdk-versions"></a>

下表列出了暂停和恢复组件时 AWS IoT Device SDK 必须使用的最低版本。


| SDK | 最低版本 | 
| --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.4.3  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.6.2  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.13.1  | 
|  [AWS IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  | 

### 请求
<a name="ipc-operation-defercomponentupdate-request"></a>

此操作的请求包含以下参数：

`componentName`（Python：`component_name`）  
要恢复的组件的名称。

### 响应
<a name="ipc-operation-defercomponentupdate-response"></a>

此操作在其响应中未提供任何信息。

# 与组件配置交互
<a name="ipc-component-configuration"></a>

组件配置 IPC 服务让您可以执行以下操作：
+ 获取和设置组件配置参数。
+ 订阅组件配置更新。
+ 在 Nucleus 应用组件配置更新之前对其进行验证。

**Topics**
+ [最低 SDK 版本](#ipc-component-configuration-sdk-versions)
+ [GetConfiguration](#ipc-operation-getconfiguration)
+ [UpdateConfiguration](#ipc-operation-updateconfiguration)
+ [SubscribeToConfigurationUpdate](#ipc-operation-subscribetoconfigurationupdate)
+ [SubscribeToValidateConfigurationUpdates](#ipc-operation-subscribetovalidateconfigurationupdates)
+ [SendConfigurationValidityReport](#ipc-operation-sendconfigurationvalidityreport)

## 最低 SDK 版本
<a name="ipc-component-configuration-sdk-versions"></a>

下表列出了与组件配置交互时 AWS IoT Device SDK 必须使用的最低版本。


| SDK | 最低版本 | 
| --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.2.10  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.5.3  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.17.0  | 
|  [AWS IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  | 

## GetConfiguration
<a name="ipc-operation-getconfiguration"></a>

获取核心设备上某个组件的配置值。您可以指定要获取配置值的键路径。

### 请求
<a name="ipc-operation-getconfiguration-request"></a>

此操作的请求包含以下参数：

`componentName`（Python：`component_name`）  <a name="ipc-configuration-request-component-name"></a>
（可选）组件的名称。  
默认为发出请求的组件名称。

`keyPath`（Python：`key_path`）  
配置值的键路径。指定一个列表，其中每个条目都是配置对象中单个级别的键。例如，在以下配置中，指定 `["mqtt", "port"]` 以获取 `port` 的值。  

```
{
  "mqtt": {
    "port": 443
  }
}
```
要获取组件的完整配置，请指定一个空列表。

### 响应
<a name="ipc-operation-getconfiguration-response"></a>

此操作的响应包含以下信息：

`componentName`（Python：`component_name`）  <a name="ipc-configuration-response-component-name"></a>
组件名称。

`value`  
请求的配置，以对象形式表示。

### 示例
<a name="ipc-operation-getconfiguration-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Rust ]

**Example 示例：获取配置**  

```
use core::mem::MaybeUninit;
use gg_sdk::{Sdk, UnpackedObject};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    // Get a configuration value at key path ["mqtt", "port"]
    let mut buf = [MaybeUninit::uninit(); 1024];

    let value = sdk
        .get_config(&["mqtt", "port"], None, &mut buf)
        .expect("Failed to get configuration");

    if let UnpackedObject::I64(port) = value.unpack() {
        println!("Configuration value: {port}");
    }
}
```

------
#### [ C ]

**Example 示例：获取配置**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    // Get a configuration value at key path ["mqtt", "port"]
    uint8_t response_mem[1024];
    GgObject value;

    err = ggipc_get_config(
        GG_BUF_LIST(GG_STR("mqtt"), GG_STR("port")),
        NULL, // component_name (NULL = current component)
        GG_BUF(response_mem),
        &value
    );
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to get configuration.\n");
        exit(-1);
    }

    if (gg_obj_type(value) == GG_TYPE_I64) {
        printf("Configuration value: %" PRId64 "\n", gg_obj_into_i64(value));
    } else if (gg_obj_type(value) == GG_TYPE_BUF) {
        GgBuffer buf = gg_obj_into_buf(value);
        printf("Configuration value: %.*s\n", (int) buf.len, buf.data);
    } else {
        printf("Configuration value is of unexpected type.\n");
    }
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：获取配置**  

```
#include <gg/ipc/client.hpp>
#include <iostream>

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    // Get a configuration value at key path ["mqtt", "port"]
    std::array key_path = { gg::Buffer { "mqtt" }, gg::Buffer { "port" } };
    int64_t value = 0;

    error = client.get_config(key_path, std::nullopt, value);
    if (error) {
        std::cerr << "Failed to get configuration.\n";
        exit(-1);
    }

    std::cout << "Configuration value: " << value << "\n";
}
```

------

## UpdateConfiguration
<a name="ipc-operation-updateconfiguration"></a>

更新核心设备上此组件的配置值。

### 请求
<a name="ipc-operation-updateconfiguration-request"></a>

此操作的请求包含以下参数：

`keyPath`（Python：`key_path`）  
（可选）要更新的容器节点（对象）的键路径。指定一个列表，其中每个条目都是配置对象中单个级别的键。例如，在以下配置中指定键路径 `["mqtt"]` 和合并值 `{ "port": 443 }` 以设置 `port` 的值。  

```
{
  "mqtt": {
    "port": 443
  }
}
```
键路径必须在配置中指定容器节点（对象）。如果组件配置中不存在该节点，则此操作会创建该节点并将其值设置为 `valueToMerge` 中的对象。  
默认为配置对象的根目录。

`timestamp`  
当前 Unix 纪元时间（以毫秒为单位）。此操作使用此时间戳来解析键的并发更新。如果组件配置中的键的时间戳大于请求中的时间戳，则请求将失败。

`valueToMerge`（Python：`value_to_merge`）  
要在 `keyPath` 中指定的位置合并的配置对象。有关更多信息，请参阅 [更新组件配置](update-component-configurations.md)。

### 响应
<a name="ipc-operation-updateconfiguration-response"></a>

此操作在其响应中未提供任何信息。

### 示例
<a name="ipc-operation-updateconfiguration-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Rust ]

**Example 示例：更新配置**  

```
use gg_sdk::Sdk;

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    // Update configuration value at key path ["mqtt", "port"] to 443
    sdk.update_config(&["mqtt", "port"], None, 443)
        .expect("Failed to update configuration");

    println!("Successfully updated configuration.");
}
```

------
#### [ C ]

**Example 示例：更新配置**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    // Update configuration value at key path ["mqtt", "port"] to 443
    err = ggipc_update_config(
        GG_BUF_LIST(GG_STR("mqtt"), GG_STR("port")),
        NULL, // timestamp (NULL = current time)
        gg_obj_i64(443)
    );
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to update configuration.\n");
        exit(-1);
    }

    printf("Successfully updated configuration.\n");
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：更新配置**  

```
#include <gg/ipc/client.hpp>
#include <iostream>

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    // Update configuration value at key path ["mqtt", "port"] to 443
    std::array key_path = { gg::Buffer { "mqtt" }, gg::Buffer { "port" } };

    error = client.update_config(key_path, 443);
    if (error) {
        std::cerr << "Failed to update configuration.\n";
        exit(-1);
    }

    std::cout << "Successfully updated configuration.\n";
}
```

------

## SubscribeToConfigurationUpdate
<a name="ipc-operation-subscribetoconfigurationupdate"></a>

订阅即可在组件配置更新时接收通知。订阅某个键后，只要该键的任何子项有所更新，您都会收到通知。

<a name="ipc-subscribe-operation-note"></a>此操作是一种订阅操作，您可以在其中订阅事件消息流。要使用此操作，请定义一个流响应处理程序，其中包含处理事件消息、错误和流关闭的函数。有关更多信息，请参阅 [订阅 IPC 事件流](interprocess-communication.md#ipc-subscribe-operations)。

**事件消息类型：**`ConfigurationUpdateEvents`

### 请求
<a name="ipc-operation-subscribetoconfigurationupdate-request"></a>

此操作的请求包含以下参数：

`componentName`（Python：`component_name`）  <a name="ipc-configuration-request-component-name"></a>
（可选）组件的名称。  
默认为发出请求的组件名称。

`keyPath`（Python：`key_path`）  
要订阅的配置值的键路径。指定一个列表，其中每个条目都是配置对象中单个级别的键。例如，在以下配置中，指定 `["mqtt", "port"]` 以获取 `port` 的值。  

```
{
  "mqtt": {
    "port": 443
  }
}
```
要订阅组件配置中所有值的更新，请指定一个空列表。

### 响应
<a name="ipc-operation-subscribetoconfigurationupdate-response"></a>

此操作的响应包含以下信息：

`messages`  
通知消息流。此对象 `ConfigurationUpdateEvents` 包含以下信息：    
`configurationUpdateEvent`（Python：`configuration_update_event`）  
配置更新事件。此对象 `ConfigurationUpdateEvent` 包含以下信息：    
`componentName`（Python：`component_name`）  <a name="ipc-configuration-response-component-name"></a>
组件名称。  
`keyPath`（Python：`key_path`）  
已更新的配置值的键路径。

### 示例
<a name="ipc-operation-subscribetoconfigurationupdate-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Rust ]

**Example 示例：订阅配置更新**  

```
use gg_sdk::Sdk;
use std::{thread, time::Duration};

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    // Subscribe to configuration updates for key path ["mqtt"]
    let callback = |component_name: &str, key_path: &[&str]| {
        println!(
            "Received configuration update for component: {component_name}"
        );
        println!("Key path: {key_path:?}");
    };

    let _sub = sdk
        .subscribe_to_configuration_update(None, &["mqtt"], &callback)
        .expect("Failed to subscribe to configuration updates");

    println!("Successfully subscribed to configuration updates.");

    // Keep the main thread alive, or the process will exit.
    loop {
        thread::sleep(Duration::from_secs(10));
    }
}
```

------
#### [ C ]

**Example 示例：订阅配置更新**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/object.h>
#include <gg/sdk.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

static void on_subscription_response(
    void *ctx,
    GgBuffer component_name,
    GgList key_path,
    GgIpcSubscriptionHandle handle
) {
    (void) ctx;
    (void) handle;

    printf(
        "Received configuration update for component: %.*s\n",
        (int) component_name.len,
        component_name.data
    );

    printf("Key path: [");
    for (size_t i = 0; i < key_path.len; i++) {
        if (i > 0) {
            printf(", ");
        }
        GgObject *obj = &key_path.items[i];
        if (gg_obj_type(*obj) == GG_TYPE_BUF) {
            GgBuffer key = gg_obj_into_buf(*obj);
            printf("\"%.*s\"", (int) key.len, key.data);
        }
    }
    printf("]\n");
}

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    // Subscribe to configuration updates for key path ["mqtt"]
    GgIpcSubscriptionHandle handle;
    err = ggipc_subscribe_to_configuration_update(
        NULL, // component_name (NULL = current component)
        GG_BUF_LIST(GG_STR("mqtt")),
        on_subscription_response,
        NULL,
        &handle
    );
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to subscribe to configuration updates.\n");
        exit(-1);
    }

    printf("Successfully subscribed to configuration updates.\n");

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }

    // To stop subscribing, close the stream.
    ggipc_close_subscription(handle);
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：订阅配置更新**  

```
#include <gg/ipc/client.hpp>
#include <unistd.h>
#include <iostream>

class ResponseHandler : public gg::ipc::ConfigurationUpdateCallback {
    void operator()(
        std::string_view component_name,
        gg::List key_path,
        gg::ipc::Subscription &handle
    ) override {
        (void) handle;
        std::cout << "Received configuration update for component: "
                  << component_name << "\n";
        std::cout << "Key path: [";
        for (size_t i = 0; i < key_path.size(); i++) {
            if (i > 0) {
                std::cout << ", ";
            }
            std::cout << "\"" << get<gg::Buffer>(key_path[i]) << "\"";
        }
        std::cout << "]\n";
    }
};

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    // Subscribe to configuration updates for key path ["mqtt"]
    std::array key_path = { gg::Buffer { "mqtt" } };

    static ResponseHandler handler;
    error = client.subscribe_to_configuration_update(
        key_path, std::nullopt, handler
    );
    if (error) {
        std::cerr << "Failed to subscribe to configuration updates.\n";
        exit(-1);
    }

    std::cout << "Successfully subscribed to configuration updates.\n";

    // Keep the main thread alive, or the process will exit.
    while (1) {
        sleep(10);
    }
}
```

------

## SubscribeToValidateConfigurationUpdates
<a name="ipc-operation-subscribetovalidateconfigurationupdates"></a>

订阅即可在此组件配置更新之前接收通知。这样，组件就可以验证自己配置的更新。使用 [SendConfigurationValidityReport](#ipc-operation-sendconfigurationvalidityreport) 操作告知 Nucleus 配置是否有效。

**重要**  
本地部署不会通知组件更新。

<a name="ipc-subscribe-operation-note"></a>此操作是一种订阅操作，您可以在其中订阅事件消息流。要使用此操作，请定义一个流响应处理程序，其中包含处理事件消息、错误和流关闭的函数。有关更多信息，请参阅 [订阅 IPC 事件流](interprocess-communication.md#ipc-subscribe-operations)。

**事件消息类型：**`ValidateConfigurationUpdateEvents`

### 请求
<a name="ipc-operation-subscribetovalidateconfigurationupdates-request"></a>

此操作的请求没有任何参数。

### 响应
<a name="ipc-operation-subscribetovalidateconfigurationupdates-response"></a>

此操作的响应包含以下信息：

`messages`  
通知消息流。此对象 `ValidateConfigurationUpdateEvents` 包含以下信息：    
`validateConfigurationUpdateEvent`（Python：`validate_configuration_update_event`）  
配置更新事件。此对象 `ValidateConfigurationUpdateEvent` 包含以下信息：    
`deploymentId`（Python：`deployment_id`）  
更新组件的 AWS IoT Greengrass 部署的 ID。  
`configuration`  
包含新配置的对象。

## SendConfigurationValidityReport
<a name="ipc-operation-sendconfigurationvalidityreport"></a>

告知 Nucleus 对此组件的配置更新是否有效。如果您告知 Nucleus 新配置无效，则部署将失败。使用 [SubscribeToValidateConfigurationUpdates](#ipc-operation-subscribetovalidateconfigurationupdates) 操作订阅即可验证配置更新。

如果组件未响应验证配置更新通知，则 Nucleus 会按您在部署配置验证策略中指定的时间等待。超时之后，Nucleus 继续部署。默认组件验证超时值为 20 秒。有关更多信息，请参阅[创建部署](create-deployments.md)以及您在调用[CreateDeployment](https://docs.aws.amazon.com/greengrass/v2/APIReference/API_CreateDeployment.html)操作时可以提供的[DeploymentConfigurationValidationPolicy](https://docs.aws.amazon.com/greengrass/v2/APIReference/API_DeploymentConfigurationValidationPolicy.html)对象。

### 请求
<a name="ipc-operation-sendconfigurationvalidityreport-request"></a>

此操作的请求包含以下参数：

`configurationValidityReport`（Python：`configuration_validity_report`）  
告知 Nucleus 配置更新是否有效的报告。此对象 `ConfigurationValidityReport` 包含以下信息：    
`status`  
有效状态。此枚举 `ConfigurationValidityStatus` 包含以下值：  
+ `ACCEPTED` – 配置有效，Nucleus 可以将其应用于该组件。
+ `REJECTED` – 配置无效，部署失败。  
`deploymentId`（Python：`deployment_id`）  
请求配置更新的 AWS IoT Greengrass 部署的 ID。  
`message`  
（可选）用于报告配置无效原因的消息。

### 响应
<a name="ipc-operation-sendconfigurationvalidityreport-response"></a>

此操作在其响应中未提供任何信息。

# 检索密钥值
<a name="ipc-secret-manager"></a>

使用密钥管理器 IPC 服务从核心设备上的密钥中检索密钥值。您可以使用[密钥管理器组件](secret-manager-component.md)将加密密钥部署至核心设备。然后，您可以使用 IPC 操作来解密密钥并在自定义组件中使用其值。

**Topics**
+ [最低 SDK 版本](#ipc-secret-manager-sdk-versions)
+ [Authorization](#ipc-secret-manager-authorization)
+ [GetSecretValue](#ipc-operation-getsecretvalue)
+ [示例](#ipc-secret-manager-examples)

## 最低 SDK 版本
<a name="ipc-secret-manager-sdk-versions"></a>

下表列出了从核心设备上的密钥中检索密钥值时必须使用的最低版本。 AWS IoT Device SDK 


| SDK | 最低版本 | 
| --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.2.10  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.5.3  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.17.0  | 
|  [AWS IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  | 

## Authorization
<a name="ipc-secret-manager-authorization"></a>

要在自定义组件中使用密钥管理器，必须定义授权策略，允许您的组件获取存储在核心设备上的密钥值。有关定义授权策略的信息，请参阅[授权组件执行 IPC 操作](interprocess-communication.md#ipc-authorization-policies)。

密钥管理器授权策略具有以下属性。

**IPC 服务标识符：**`aws.greengrass.SecretManager`


| 操作 | 说明 | 资源 | 
| --- | --- | --- | 
|  `aws.greengrass#GetSecretValue` 或 `*`  |  允许组件获取在核心设备上加密的密钥值。  |  Secrets Manager 密钥 ARN，或者 `*` 用于允许访问所有密钥。  | 

### 授权策略示例
<a name="ipc-secret-manager-authorization-policy-examples"></a>

您可以参考以下授权策略示例，帮助您为组件配置授权策略。

**Example 示例授权策略**  
以下示例授权策略允许组件获取核心设备上的任何密钥值。  
我们建议在生产环境中缩小授权策略的范围，以便组件仅检索其使用的密钥。部署组件 ARNs 时，您可以将`*`通配符更改为密钥列表。

```
{
  "accessControl": {
    "aws.greengrass.SecretManager": {
      "com.example.MySecretComponent:secrets:1": {
        "policyDescription": "Allows access to a secret.",
        "operations": [
          "aws.greengrass#GetSecretValue"
        ],
        "resources": [
          "*"
        ]
      }
    }
  }
}
```

## GetSecretValue
<a name="ipc-operation-getsecretvalue"></a>

获取您存储在核心设备上的密钥值。

此操作与 Secrets Manager 操作类似，您可以使用该操作来获取 AWS 云中的密钥值。有关更多信息，请参阅《AWS Secrets Manager API Reference》**中的 [GetSecretValue](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html)。

### 请求
<a name="ipc-operation-getsecretvalue-request"></a>

此操作的请求包含以下参数：

`refresh`（Python：`refresh`）  
（可选）：是否将请求的密钥与 AWS Secrets Manager 服务中的最新值同步。  
设置为 true 时，密钥管理器将请求 AWS Secrets Manager 服务提供指定机密标签的最新值，并将该值作为响应返回。否则，将返回存储在本地的密钥值。  
 此参数不能与请求中的 `versionId` 参数一起使用。该参数与 Nucleus 2.13.0 及更高版本配合使用。

`secretId`（Python：`secret_id`）  
密钥名称。您可指定密钥的 Amazon 资源名称（ARN）或易记名称。

`versionId`（Python：`version_id`）  
（可选）版本 ID。  
您可指定 `versionId` 或 `versionStage`。  
若未指定 `versionId` 或 `versionStage`，则此操作默认为带有 `AWSCURRENT` 标签的版本。

`versionStage`（Python：`version_stage`）  
（可选）要获取的版本的暂存标签。  
您可指定 `versionId` 或 `versionStage`。  
若未指定 `versionId` 或 `versionStage`，则此操作默认为带有 `AWSCURRENT` 标签的版本。

### 响应
<a name="ipc-operation-getsecretvalue-response"></a>

此操作的响应包含以下信息：

`secretId` (Python: `secret_id`)  
密钥 ID。

`versionId` (Python: `version_id`)  
此版本密钥 ID。

`versionStage` (Python: `version_stage`)  
附加至此版本密钥的暂存标签列表。

`secretValue` (Python: `secret_value`)  
此版本密钥值。该对象 `SecretValue` 包含以下信息。    
`secretString` (Python: `secret_string`)  
您以字符串形式提供给 Secrets Manager 的受保护密钥信息的解密部分。  
`secretBinary` (Python: `secret_binary`)  
（可选）您以字节数组形式作为二进制数据提供给 Secrets Manager 的受保护密钥信息的解密部分。此属性包含以 base64 编码字符串的字符串形式提供的二进制数据。  
如果您在 Secrets Manager 控制台中创建密钥，则不会使用此属性。

### 示例
<a name="ipc-operation-getsecretvalue-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Java (IPC client V1) ]

**Example 示例：获取密钥值**  
此示例使用一个`IPCUtils`类来创建与 C AWS IoT Greengrass ore IPC 服务的连接。有关更多信息，请参阅 [Connect 到 C AWS IoT Greengrass ore IPC 服务](interprocess-communication.md#ipc-service-connect)。

```
package com.aws.greengrass.docs.samples.ipc;

import com.aws.greengrass.docs.samples.ipc.util.IPCUtils;
import software.amazon.awssdk.aws.greengrass.GetSecretValueResponseHandler;
import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient;
import software.amazon.awssdk.aws.greengrass.model.GetSecretValueRequest;
import software.amazon.awssdk.aws.greengrass.model.GetSecretValueResponse;
import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError;
import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class GetSecretValue {

    public static final int TIMEOUT_SECONDS = 10;

    public static void main(String[] args) {
        String secretArn = args[0];
        String versionStage = args[1];
        try (EventStreamRPCConnection eventStreamRPCConnection =
                     IPCUtils.getEventStreamRpcConnection()) {
            GreengrassCoreIPCClient ipcClient =
                    new GreengrassCoreIPCClient(eventStreamRPCConnection);
            GetSecretValueResponseHandler responseHandler =
                    GetSecretValue.getSecretValue(ipcClient, secretArn, versionStage);
            CompletableFuture<GetSecretValueResponse> futureResponse =
                    responseHandler.getResponse();
            try {
                GetSecretValueResponse response = futureResponse.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
                response.getSecretValue().postFromJson();
                String secretString = response.getSecretValue().getSecretString();
                System.out.println("Successfully retrieved secret value: " + secretString);
            } catch (TimeoutException e) {
                System.err.println("Timeout occurred while retrieving secret: " + secretArn);
            } catch (ExecutionException e) {
                if (e.getCause() instanceof UnauthorizedError) {
                    System.err.println("Unauthorized error while retrieving secret: " + secretArn);
                } else {
                    throw e;
                }
            }
        } catch (InterruptedException e) {
            System.out.println("IPC interrupted.");
        } catch (ExecutionException e) {
            System.err.println("Exception occurred when using IPC.");
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static GetSecretValueResponseHandler getSecretValue(GreengrassCoreIPCClient greengrassCoreIPCClient, String secretArn, String versionStage) {
        GetSecretValueRequest getSecretValueRequest = new GetSecretValueRequest();
        getSecretValueRequest.setSecretId(secretArn);
        getSecretValueRequest.setVersionStage(versionStage);
        return greengrassCoreIPCClient.getSecretValue(getSecretValueRequest, Optional.empty());
    }
}
```

------
#### [ Python (IPC client V1) ]

**Example 示例：获取密钥值**  
此示例假设您使用的是 Python v2 版本的 1.5.4 或更高版本。 AWS IoT Device SDK 

```
import json

import awsiot.greengrasscoreipc
from awsiot.greengrasscoreipc.model import (
    GetSecretValueRequest,
    GetSecretValueResponse,
    UnauthorizedError
)

secret_id = 'arn:aws:secretsmanager:us-west-2:123456789012:secret:MyGreengrassSecret-abcdef'
TIMEOUT = 10

ipc_client = awsiot.greengrasscoreipc.connect()

request = GetSecretValueRequest()
request.secret_id = secret_id
request.version_stage = 'AWSCURRENT'
operation = ipc_client.new_get_secret_value()
operation.activate(request)
future_response = operation.get_response()
response = future_response.result(TIMEOUT)
secret_json = json.loads(response.secret_value.secret_string)
# Handle secret value.
```

------
#### [ JavaScript ]

**Example 示例：获取密钥值**  

```
import {
    GetSecretValueRequest,
} from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc/model';
import * as greengrasscoreipc from "aws-iot-device-sdk-v2/dist/greengrasscoreipc";
 
class GetSecretValue {
    private readonly secretId : string;
    private readonly versionStage : string;
    private ipcClient : greengrasscoreipc.Client
 
    constructor() {
        this.secretId = "<define_your_own_secretId>"
        this.versionStage = "<define_your_own_versionStage>"
 
        this.getSecretValue().then(r => console.log("Started workflow"));
    }
 
    private async getSecretValue() {
        try {
            this.ipcClient = await getIpcClient();
 
            const getSecretValueRequest : GetSecretValueRequest = {
                secretId: this.secretId,
                versionStage: this.versionStage,
            };
 
            const result = await this.ipcClient.getSecretValue(getSecretValueRequest);
            const secretString = result.secretValue.secretString;
            console.log("Successfully retrieved secret value: " + secretString)
        } catch (e) {
            // parse the error depending on your use cases
            throw e
        }
    }
}
 
export async function getIpcClient(){
    try {
        const ipcClient = greengrasscoreipc.createClient();
        await ipcClient.connect()
            .catch(error => {
                // parse the error depending on your use cases
                throw error;
            });
        return ipcClient
    } catch (err) {
        // parse the error depending on your use cases
        throw err
    }
}
 
const getSecretValue = new GetSecretValue();
```

------

## 示例
<a name="ipc-secret-manager-examples"></a>

使用以下示例了解如何在组件中使用密钥管理器 IPC 服务。

### 示例：打印密钥（Python、IPC 客户端 V1）
<a name="ipc-secret-manager-example-print-secret-python"></a>

此示例组件打印您部署至核心设备的密钥值。

**重要**  
此示例组件会打印密钥值，因此请仅将其与存储测试数据的密钥一起使用。不要使用此组件来打印存储重要信息的密钥值。

**Topics**
+ [指南](#ipc-secret-manager-example-print-secret-python-recipe)
+ [构件](#ipc-secret-manager-example-print-secret-python-artifacts)
+ [用法](#ipc-secret-manager-example-print-secret-python-usage)

#### 指南
<a name="ipc-secret-manager-example-print-secret-python-recipe"></a>

以下示例配方定义了一个密钥 ARN 配置参数，并允许该组件获取核心设备上任何密钥值。

**注意**  <a name="ipc-secret-manager-authorization-policy-resource-wildcard"></a>
我们建议在生产环境中缩小授权策略的范围，以便组件仅检索其使用的密钥。部署组件 ARNs 时，您可以将`*`通配符更改为密钥列表。

------
#### [ JSON ]

```
{
  "RecipeFormatVersion": "2020-01-25",
  "ComponentName": "com.example.PrintSecret",
  "ComponentVersion": "1.0.0",
  "ComponentDescription": "Prints the value of an AWS Secrets Manager secret.",
  "ComponentPublisher": "Amazon",
  "ComponentDependencies": {
    "aws.greengrass.SecretManager": {
      "VersionRequirement": "^2.0.0",
      "DependencyType": "HARD"
    }
  },
  "ComponentConfiguration": {
    "DefaultConfiguration": {
      "SecretArn": "",
      "accessControl": {
        "aws.greengrass.SecretManager": {
          "com.example.PrintSecret:secrets:1": {
            "policyDescription": "Allows access to a secret.",
            "operations": [
              "aws.greengrass#GetSecretValue"
            ],
            "resources": [
              "*"
            ]
          }
        }
      }
    }
  },
  "Manifests": [
    {
      "Platform": {
        "os": "linux"
      },
      "Lifecycle": {
        "install": "python3 -m pip install --user awsiotsdk",
        "Run": "python3 -u {artifacts:path}/print_secret.py \"{configuration:/SecretArn}\""
      }
    },
    {
      "Platform": {
        "os": "windows"
      },
      "Lifecycle": {
        "install": "py -3 -m pip install --user awsiotsdk",
        "Run": "py -3 -u {artifacts:path}/print_secret.py \"{configuration:/SecretArn}\""
      }
    }
  ]
}
```

------
#### [ YAML ]

```
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.PrintSecret
ComponentVersion: 1.0.0
ComponentDescription: Prints the value of a Secrets Manager secret.
ComponentPublisher: Amazon
ComponentDependencies:
  aws.greengrass.SecretManager:
    VersionRequirement: "^2.0.0"
    DependencyType: HARD
ComponentConfiguration:
  DefaultConfiguration:
    SecretArn: ''
    accessControl:
      aws.greengrass.SecretManager:
        com.example.PrintSecret:secrets:1:
          policyDescription: Allows access to a secret.
          operations:
            - aws.greengrass#GetSecretValue
          resources:
            - "*"
Manifests:
  - Platform:
      os: linux
    Lifecycle:
      install: python3 -m pip install --user awsiotsdk
      Run: python3 -u {artifacts:path}/print_secret.py "{configuration:/SecretArn}"
  - Platform:
      os: windows
    Lifecycle:
      install: py -3 -m pip install --user awsiotsdk
      Run: py -3 -u {artifacts:path}/print_secret.py "{configuration:/SecretArn}"
```

------

#### 构件
<a name="ipc-secret-manager-example-print-secret-python-artifacts"></a>

以下示例 Python 应用程序演示了如何使用密钥管理器 IPC 服务获取核心设备上的密钥值。

```
import concurrent.futures
import json
import sys
import traceback

import awsiot.greengrasscoreipc
from awsiot.greengrasscoreipc.model import (
    GetSecretValueRequest,
    GetSecretValueResponse,
    UnauthorizedError
)

TIMEOUT = 10

if len(sys.argv) == 1:
    print('Provide SecretArn in the component configuration.', file=sys.stdout)
    exit(1)

secret_id = sys.argv[1]

try:
    ipc_client = awsiot.greengrasscoreipc.connect()

    request = GetSecretValueRequest()
    request.secret_id = secret_id
    operation = ipc_client.new_get_secret_value()
    operation.activate(request)
    future_response = operation.get_response()

    try:
        response = future_response.result(TIMEOUT)
        secret_json = json.loads(response.secret_value.secret_string)
        print('Successfully got secret: ' + secret_id)
        print('Secret value: ' + str(secret_json))
    except concurrent.futures.TimeoutError:
        print('Timeout occurred while getting secret: ' + secret_id, file=sys.stderr)
    except UnauthorizedError as e:
        print('Unauthorized error while getting secret: ' + secret_id, file=sys.stderr)
        raise e
    except Exception as e:
        print('Exception while getting secret: ' + secret_id, file=sys.stderr)
        raise e
except Exception:
    print('Exception occurred when using IPC.', file=sys.stderr)
    traceback.print_exc()
    exit(1)
```

#### 用法
<a name="ipc-secret-manager-example-print-secret-python-usage"></a>

您可以将此示例组件与[密钥管理器组件](secret-manager-component.md)一起使用，在核心设备上部署和打印密钥值。

**创建、部署和打印测试密钥**

1. 使用测试数据创建 Secrets Manager 密钥。

------
#### [ Linux or Unix ]

   ```
   aws secretsmanager create-secret \
     --name MyTestGreengrassSecret \
     --secret-string '{"my-secret-key": "my-secret-value"}'
   ```

------
#### [ Windows Command Prompt (CMD) ]

   ```
   aws secretsmanager create-secret ^
     --name MyTestGreengrassSecret ^
     --secret-string '{"my-secret-key": "my-secret-value"}'
   ```

------
#### [ PowerShell ]

   ```
   aws secretsmanager create-secret `
     --name MyTestGreengrassSecret `
     --secret-string '{"my-secret-key": "my-secret-value"}'
   ```

------

   保存密钥 ARN，以便在以下步骤中使用。

   有关更多信息，请参阅《AWS Secrets Manager 用户指南》**中的[创建密钥](https://docs.aws.amazon.com/secretsmanager/latest/userguide/manage_create-basic-secret.html)。

1. 使用以下配置合并更新部署[密钥管理器组件](secret-manager-component.md) (`aws.greengrass.SecretManager`)。指定您之前创建的密钥 ARN。

   ```
   {
     "cloudSecrets": [
       {
         "arn": "arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestGreengrassSecret-abcdef"
       }
     ]
   }
   ```

   有关更多信息，请参阅 [将 AWS IoT Greengrass 组件部署到设备](manage-deployments.md) 或 [Greengrass CLI 部署命令](gg-cli-deployment.md)。

1. 使用以下配置合并更新创建和部署本节中的示例组件。指定您之前创建的密钥 ARN。

   ```
   {
     "SecretArn": "arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestGreengrassSecret",
     "accessControl": {
       "aws.greengrass.SecretManager": {
         "com.example.PrintSecret:secrets:1": {
           "policyDescription": "Allows access to a secret.",
           "operations": [
             "aws.greengrass#GetSecretValue"
           ],
           "resources": [
             "arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestGreengrassSecret-abcdef"
           ]
         }
       }
     }
   }
   ```

   有关更多信息，请参阅 [创建 AWS IoT Greengrass 组件](create-components.md)。

1. 查看 AWS IoT Greengrass 核心软件日志以验证部署是否成功，并查看`com.example.PrintSecret`组件日志以查看打印的密钥值。有关更多信息，请参阅 [监控 AWS IoT Greengrass 日志](monitor-logs.md)。

# 与本地影子交互
<a name="ipc-local-shadows"></a>

使用影子 IPC 服务与设备上的本地影子交互。您选择与之交互的设备可以是您的核心设备或连接的客户端设备。

要使用这些 IPC 操作，请将[影子管理器组件](shadow-manager-component.md)作为依赖关系包含在自定义组件中。然后，您可以在自定义组件中使用 IPC 操作，通过影子管理器与设备上的本地影子交互。要使自定义组件能够对本地阴影状态的变化做出反应，您还可以使用 publish/subscribe IPC 服务订阅影子事件。有关使用该 publish/subscribe 服务的更多信息，请参阅[发布/订阅本地消息](ipc-publish-subscribe.md)。

**注意**  <a name="note-requirement-enable-shadow-manager-client-devices"></a>
要使核心设备能够与客户端设备影子交互，您还必须配置和部署 MQTT 网桥组件。有关更多信息，请参阅[启用影子管理器以与客户端设备通信](work-with-client-device-shadows.md)。

**Topics**
+ [最低 SDK 版本](#ipc-local-shadows-sdk-versions)
+ [Authorization](#ipc-local-shadow-authorization)
+ [GetThingShadow](#ipc-operation-getthingshadow)
+ [UpdateThingShadow](#ipc-operation-updatethingshadow)
+ [DeleteThingShadow](#ipc-operation-deletethingshadow)
+ [ListNamedShadowsForThing](#ipc-operation-listnamedshadowsforthing)

## 最低 SDK 版本
<a name="ipc-local-shadows-sdk-versions"></a>

下表列出了与本地阴影交互时必须使用的最低版本。 AWS IoT Device SDK 


| SDK | 最低版本 | 
| --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.4.0  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.6.0  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.17.0  | 
|  [AWS IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  | 

## Authorization
<a name="ipc-local-shadow-authorization"></a>

要在自定义组件中使用影子 IPC 服务，必须定义允许您的组件与影子交互的授权策略。有关定义授权策略的信息，请参阅[授权组件执行 IPC 操作](interprocess-communication.md#ipc-authorization-policies)。

影子交互授权策略具有以下属性。

**IPC 服务标识符：**`aws.greengrass.ShadowManager`


| 操作 | 说明 | 资源 | 
| --- | --- | --- | 
|  `aws.greengrass#GetThingShadow`  |  允许组件检索事物的影子。  |  以下字符串之一： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-local-shadows.html)  | 
|  `aws.greengrass#UpdateThingShadow`  |  允许组件更新事物的影子。  |  以下字符串之一： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-local-shadows.html)  | 
|  `aws.greengrass#DeleteThingShadow`  |  允许组件删除事物的影子。  |  以下字符串之一： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-local-shadows.html)  | 
|  `aws.greengrass#ListNamedShadowsForThing`  |  允许组件为事物检索已命名影子列表。  |  允许访问事物以列出其影子的事物名称字符串。 用 `*` 以允许访问所有事物。  | 

**IPC 服务标识符：**`aws.greengrass.ipc.pubsub`


| 操作 | 说明 | 资源 | 
| --- | --- | --- | 
|  `aws.greengrass#SubscribeToTopic`  |  允许组件订阅您指定主题的消息。  |  以下主题字符串之一： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-local-shadows.html) 主题前缀 `shadowTopicPrefix` 的值取决于影子类型： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/greengrass/v2/developerguide/ipc-local-shadows.html) 用 `*` 以允许访问所有主题。 <a name="ipc-local-publish-subscribe-authorization-mqtt-wildcards"></a>在 [Greengrass Nucleus](greengrass-nucleus-component.md) v2.6.0 及更高版本中，您可以订阅包含 MQTT 主题通配符（`#` 和 `+`）的主题。此主题字符串支持 MQTT 主题通配符作为文字字符。例如，如果组件的授权策略授予访问 `test/topic/#` 的权限，则该组件可以订阅 `test/topic/#`，但无法订阅 `test/topic/filter`。  | 

### 本地影子授权策略中的配方变量
<a name="ipc-local-shadow-authorization-recipe-variables"></a>

[如果您使用 Greengrass 核心的 v2.6.0 或更高版本，并且将 [Greengrass nucleus](greengrass-nucleus-component.md) 的配置选项设置为，则可以在授权策略中使用配方变量[interpolateComponentConfiguration](greengrass-nucleus-component.md#greengrass-nucleus-component-configuration-interpolate-component-configuration)。`true``{iot:thingName}`](component-recipe-reference.md#recipe-variables)此功能允许您为一组核心设备配置单个授权策略，其中每个核心设备只能访问自己的影子。例如，您可以允许组件访问以下适用于影子 IPC 操作的资源。

```
$aws/things/{iot:thingName}/shadow/
```

### 授权策略示例
<a name="ipc-local-shadow-authorization-policy-examples"></a>

您可以参考以下授权策略示例，帮助您为组件配置授权策略。

**Example 示例：允许一组核心设备与本地影子交互**  
 <a name="phrase-example-uses-recipe-variables-in-configuration"></a>此示例使用了 [Greengrass Nucleus 组件](greengrass-nucleus-component.md)的 v2.6.0 及更高版本中可用的功能。Greengrass Nucleus v2.6.0 在组件配置中添加了对大多数[配方变量](component-recipe-reference.md#recipe-variables)（例如 `{iot:thingName}`）的支持。要启用此功能，请将 Green [interpolateComponentConfiguration](greengrass-nucleus-component.md#greengrass-nucleus-component-configuration-interpolate-component-configuration)grass 核的配置选项设置为。`true`有关适用于所有版本 Greengrass Nucleus 的示例，请参阅[单个核心设备的授权策略示例](#ipc-local-shadows-authorization-example-single-device)。
以下示例授权策略允许组件 `com.example.MyShadowInteractionComponent` 与经典设备影子以及运行该组件的核心设备的已命名影子 `myNamedShadow` 进行交互。此策略还允许此组件接收这些影子的本地主题消息。  

```
{
  "accessControl": {
    "aws.greengrass.ShadowManager": {
      "com.example.MyShadowInteractionComponent:shadow:1": {
        "policyDescription": "Allows access to shadows",
        "operations": [
          "aws.greengrass#GetThingShadow",
          "aws.greengrass#UpdateThingShadow",
          "aws.greengrass#DeleteThingShadow"
        ],
        "resources": [
          "$aws/things/{iot:thingName}/shadow",
          "$aws/things/{iot:thingName}/shadow/name/myNamedShadow"
        ]
      },
      "com.example.MyShadowInteractionComponent:shadow:2": {
        "policyDescription": "Allows access to things with shadows",
        "operations": [
          "aws.greengrass#ListNamedShadowsForThing"
        ],
        "resources": [
          "{iot:thingName}"
        ]
      }    
    },
    "aws.greengrass.ipc.pubsub": {
      "com.example.MyShadowInteractionComponent:pubsub:1": {
        "policyDescription": "Allows access to shadow pubsub topics",
        "operations": [
          "aws.greengrass#SubscribeToTopic"
        ],
        "resources": [
          "$aws/things/{iot:thingName}/shadow/get/accepted",
          "$aws/things/{iot:thingName}/shadow/name/myNamedShadow/get/accepted"
        ]
      }
    }
  }
}
```

```
accessControl:
  aws.greengrass.ShadowManager:
    'com.example.MyShadowInteractionComponent:shadow:1':
      policyDescription: 'Allows access to shadows'
      operations:
        - 'aws.greengrass#GetThingShadow'
        - 'aws.greengrass#UpdateThingShadow'
        - 'aws.greengrass#DeleteThingShadow'
      resources:
        - $aws/things/{iot:thingName}/shadow
        - $aws/things/{iot:thingName}/shadow/name/myNamedShadow
    'com.example.MyShadowInteractionComponent:shadow:2':
      policyDescription: 'Allows access to things with shadows'
      operations:
        - 'aws.greengrass#ListNamedShadowsForThing'
      resources:
        - '{iot:thingName}'
  aws.greengrass.ipc.pubsub:
    'com.example.MyShadowInteractionComponent:pubsub:1':
      policyDescription: 'Allows access to shadow pubsub topics'
      operations:
        - 'aws.greengrass#SubscribeToTopic'
      resources:
        - $aws/things/{iot:thingName}/shadow/get/accepted
        - $aws/things/{iot:thingName}/shadow/name/myNamedShadow/get/accepted
```

**Example 示例：允许一组核心设备与客户端设备影子交互**  
此功能需要 [Greengrass Nucleus](greengrass-nucleus-component.md) v2.6.0 或更高版本、[影子管理器](shadow-manager-component.md) v2.2.0 或更高版本以及 [MQTT 网桥器](mqtt-bridge-component.md) v2.2.0 或更高版本。您必须配置 MQTT 网桥器才能[使影子管理器能够与客户端设备通信](work-with-client-device-shadows.md#enable-shadow-manager-client-devices)。
以下示例授权策略允许组件 `com.example.MyShadowInteractionComponent` 与名称以 `MyClientDevice` 开头的客户端设备的所有设备影子进行交互。  
要使核心设备能够与客户端设备影子交互，您还必须配置和部署 MQTT 网桥组件。有关更多信息，请参阅[启用影子管理器以与客户端设备通信](work-with-client-device-shadows.md)。

```
{
  "accessControl": {
    "aws.greengrass.ShadowManager": {
      "com.example.MyShadowInteractionComponent:shadow:1": {
        "policyDescription": "Allows access to shadows",
        "operations": [
          "aws.greengrass#GetThingShadow",
          "aws.greengrass#UpdateThingShadow",
          "aws.greengrass#DeleteThingShadow"
        ],
        "resources": [
          "$aws/things/MyClientDevice*/shadow",
          "$aws/things/MyClientDevice*/shadow/name/*"
        ]
      },
      "com.example.MyShadowInteractionComponent:shadow:2": {
        "policyDescription": "Allows access to things with shadows",
        "operations": [
          "aws.greengrass#ListNamedShadowsForThing"
        ],
        "resources": [
          "MyClientDevice*"
        ]
      }    
    }
  }
}
```

```
accessControl:
  aws.greengrass.ShadowManager:
    'com.example.MyShadowInteractionComponent:shadow:1':
      policyDescription: 'Allows access to shadows'
      operations:
        - 'aws.greengrass#GetThingShadow'
        - 'aws.greengrass#UpdateThingShadow'
        - 'aws.greengrass#DeleteThingShadow'
      resources:
        - $aws/things/MyClientDevice*/shadow
        - $aws/things/MyClientDevice*/shadow/name/*
    'com.example.MyShadowInteractionComponent:shadow:2':
      policyDescription: 'Allows access to things with shadows'
      operations:
        - 'aws.greengrass#ListNamedShadowsForThing'
      resources:
        - MyClientDevice*
```<a name="ipc-local-shadows-authorization-example-single-device"></a>

**Example 示例：允许单个核心设备与本地影子交互**  
以下示例授权策略允许组件 `com.example.MyShadowInteractionComponent` 与设备 `MyThingName` 的经典设备影子和已命名影子 `myNamedShadow` 进行交互。此策略还允许此组件接收这些影子的本地主题消息。  

```
{
  "accessControl": {
    "aws.greengrass.ShadowManager": {
      "com.example.MyShadowInteractionComponent:shadow:1": {
        "policyDescription": "Allows access to shadows",
        "operations": [
          "aws.greengrass#GetThingShadow",
          "aws.greengrass#UpdateThingShadow",
          "aws.greengrass#DeleteThingShadow"
        ],
        "resources": [
          "$aws/things/MyThingName/shadow",
          "$aws/things/MyThingName/shadow/name/myNamedShadow"
        ]
      },
      "com.example.MyShadowInteractionComponent:shadow:2": {
        "policyDescription": "Allows access to things with shadows",
        "operations": [
          "aws.greengrass#ListNamedShadowsForThing"
        ],
        "resources": [
          "MyThingName"
        ]
      }    
    },
    "aws.greengrass.ipc.pubsub": {
      "com.example.MyShadowInteractionComponent:pubsub:1": {
        "policyDescription": "Allows access to shadow pubsub topics",
        "operations": [
          "aws.greengrass#SubscribeToTopic"
        ],
        "resources": [
          "$aws/things/MyThingName/shadow/get/accepted",
          "$aws/things/MyThingName/shadow/name/myNamedShadow/get/accepted"
        ]
      }
    }
  }
}
```

```
accessControl:
  aws.greengrass.ShadowManager:
    'com.example.MyShadowInteractionComponent:shadow:1':
      policyDescription: 'Allows access to shadows'
      operations:
        - 'aws.greengrass#GetThingShadow'
        - 'aws.greengrass#UpdateThingShadow'
        - 'aws.greengrass#DeleteThingShadow'
      resources:
        - $aws/things/MyThingName/shadow
        - $aws/things/MyThingName/shadow/name/myNamedShadow
    'com.example.MyShadowInteractionComponent:shadow:2':
      policyDescription: 'Allows access to things with shadows'
      operations:
        - 'aws.greengrass#ListNamedShadowsForThing'
      resources:
        - MyThingName
  aws.greengrass.ipc.pubsub:
    'com.example.MyShadowInteractionComponent:pubsub:1':
      policyDescription: 'Allows access to shadow pubsub topics'
      operations:
        - 'aws.greengrass#SubscribeToTopic'
      resources:
        - $aws/things/MyThingName/shadow/get/accepted
        - $aws/things/MyThingName/shadow/name/myNamedShadow/get/accepted
```<a name="interact-with-shadows-react-example-authorization-policies"></a>

**Example 示例：允许一组核心设备对本地影子状态变化做出反应**  
 <a name="phrase-example-uses-recipe-variables-in-configuration"></a>此示例使用了 [Greengrass Nucleus 组件](greengrass-nucleus-component.md)的 v2.6.0 及更高版本中可用的功能。Greengrass Nucleus v2.6.0 在组件配置中添加了对大多数[配方变量](component-recipe-reference.md#recipe-variables)（例如 `{iot:thingName}`）的支持。要启用此功能，请将 Green [interpolateComponentConfiguration](greengrass-nucleus-component.md#greengrass-nucleus-component-configuration-interpolate-component-configuration)grass 核的配置选项设置为。`true`有关适用于所有版本 Greengrass Nucleus 的示例，请参阅[单个核心设备的授权策略示例](#interact-with-shadows-react-example-authorization-policy-single-device)。
以下示例访问控制策略允许自定义 `com.example.MyShadowReactiveComponent` 在运行该组件的每台核心设备上接收有关经典设备影子和已命名影子 `myNamedShadow` 的 `/update/delta` 主题消息。  

```
{
  "accessControl": {
    "aws.greengrass.ipc.pubsub": {
      "com.example.MyShadowReactiveComponent:pubsub:1": {
        "policyDescription": "Allows access to shadow pubsub topics",
        "operations": [
          "aws.greengrass#SubscribeToTopic"
        ],
        "resources": [
          "$aws/things/{iot:thingName}/shadow/update/delta",
          "$aws/things/{iot:thingName}/shadow/name/myNamedShadow/update/delta"
        ]
      }
    }
  }
}
```

```
accessControl:
  aws.greengrass.ipc.pubsub:
    "com.example.MyShadowReactiveComponent:pubsub:1":
      policyDescription: Allows access to shadow pubsub topics
      operations:
        - 'aws.greengrass#SubscribeToTopic'
      resources:
        - $aws/things/{iot:thingName}/shadow/update/delta
        - $aws/things/{iot:thingName}/shadow/name/myNamedShadow/update/delta
```<a name="interact-with-shadows-react-example-authorization-policy-single-device"></a>

**Example 示例：允许单个核心设备对本地影子状态变化做出反应**  
以下示例访问控制策略允许自定义 `com.example.MyShadowReactiveComponent` 接收有关设备 `MyThingName` 的经典设备影子和已命名影子 `myNamedShadow` 的 `/update/delta` 主题消息。  

```
{
  "accessControl": {
    "aws.greengrass.ipc.pubsub": {
      "com.example.MyShadowReactiveComponent:pubsub:1": {
        "policyDescription": "Allows access to shadow pubsub topics",
        "operations": [
          "aws.greengrass#SubscribeToTopic"
        ],
        "resources": [
          "$aws/things/MyThingName/shadow/update/delta",
          "$aws/things/MyThingName/shadow/name/myNamedShadow/update/delta"
        ]
      }
    }
  }
}
```

```
accessControl:
  aws.greengrass.ipc.pubsub:
    "com.example.MyShadowReactiveComponent:pubsub:1":
      policyDescription: Allows access to shadow pubsub topics
      operations:
        - 'aws.greengrass#SubscribeToTopic'
      resources:
        - $aws/things/MyThingName/shadow/update/delta
        - $aws/things/MyThingName/shadow/name/myNamedShadow/update/delta
```

## GetThingShadow
<a name="ipc-operation-getthingshadow"></a>

获取指定事物的影子。

### 请求
<a name="ipc-operation-getthingshadow-request"></a>

此操作的请求包含以下参数：

`thingName` (Python: `thing_name`)  <a name="ipc-local-shadows-thing-name"></a>
事物的名称。  
类型：`string`

`shadowName` (Python: `shadow_name`)  <a name="ipc-local-shadows-shadow-name"></a>
影子的名称。要指定事物的经典影子，请将此参数设置为空字符串 (`""`)。  
该 AWS IoT Greengrass 服务使用`AWSManagedGreengrassV2Deployment`命名的影子来管理针对单个核心设备的部署。这个名为 shadow 的保留供 AWS IoT Greengrass 服务使用。请勿更新或删除该已命名影子。
类型：`string`

### 响应
<a name="ipc-operation-getthingshadow-response"></a>

此操作的响应包含以下信息：

`payload`  
响应状态文档为 blob。  
类型：包含以下信息的 `object`：    
`state`  
状态信息。  
该对象包含以下信息。    
`desired`  
请求在设备中更新的状态属性和值。  
类型：键/值对 `map`  
`reported`  
设备报告的状态属性和值。  
类型：键/值对 `map`  
`delta`  
所需状态和报告的状态属性和值之间的差异。仅当 `desired` 和 `reported` 状态不同时，才会出现此属性。  
类型：键/值对 `map`  
`metadata`  
`desired` 和 `reported` 部分中每个属性的时间戳，因此，您可以确定状态的更新时间。  
类型：`string`  
`timestamp`  
生成响应时的 Epoch 日期和时间。  
类型：`integer`  
`clientToken` (Python: `clientToken`)  
用于匹配请求和相应响应的令牌。  
类型：`string`  
`version`  
本地影子文档版本。  
类型：`integer`

### 错误
<a name="ipc-operation-getthingshadow-errors"></a>

此操作可返回以下错误。

`InvalidArgumentsError`  <a name="ipc-invalidargumentserror"></a>
<a name="ipc-invalidargumentserror-para"></a>本地影子服务无法验证请求参数。如果请求包含格式错误的 JSON 或不支持的字符，则可能会发生这种情况。

`ResourceNotFoundError`  <a name="ipc-resourcenotfounderror"></a>
无法找到请求的本地影子文档。

`ServiceError`  <a name="ipc-serviceerror"></a>
发生了内部服务错误，或者对 IPC 服务的请求数超过了影子管理器组件中 `maxLocalRequestsPerSecondPerThing` 和 `maxTotalLocalRequestsRate` 配置参数中指定的限制。

`UnauthorizedError`  <a name="ipc-unauthorizederror"></a>
该组件的授权策略不包括此操作所需权限。

### 示例
<a name="ipc-operation-getthingshadow-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Java (IPC client V1) ]

**Example 示例：获取事物影子**  
此示例使用一个`IPCUtils`类来创建与 C AWS IoT Greengrass ore IPC 服务的连接。有关更多信息，请参阅 [Connect 到 C AWS IoT Greengrass ore IPC 服务](interprocess-communication.md#ipc-service-connect)。

```
package com.aws.greengrass.docs.samples.ipc;

import com.aws.greengrass.docs.samples.ipc.util.IPCUtils;
import software.amazon.awssdk.aws.greengrass.GetThingShadowResponseHandler;
import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient;
import software.amazon.awssdk.aws.greengrass.model.GetThingShadowRequest;
import software.amazon.awssdk.aws.greengrass.model.GetThingShadowResponse;
import software.amazon.awssdk.aws.greengrass.model.ResourceNotFoundError;
import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError;
import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection;

import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class GetThingShadow {

    public static final int TIMEOUT_SECONDS = 10;

    public static void main(String[] args) {
        // Use the current core device's name if thing name isn't set.
        String thingName = args[0].isEmpty() ? System.getenv("AWS_IOT_THING_NAME") : args[0];
        String shadowName = args[1];
        try (EventStreamRPCConnection eventStreamRPCConnection =
                     IPCUtils.getEventStreamRpcConnection()) {
            GreengrassCoreIPCClient ipcClient =
                    new GreengrassCoreIPCClient(eventStreamRPCConnection);
            GetThingShadowResponseHandler responseHandler =
                    GetThingShadow.getThingShadow(ipcClient, thingName, shadowName);
            CompletableFuture<GetThingShadowResponse> futureResponse =
                    responseHandler.getResponse();
            try {
                GetThingShadowResponse response = futureResponse.get(TIMEOUT_SECONDS,
                        TimeUnit.SECONDS);
                String shadowPayload = new String(response.getPayload(), StandardCharsets.UTF_8);
                System.out.printf("Successfully got shadow %s/%s: %s%n", thingName, shadowName,
                        shadowPayload);
            } catch (TimeoutException e) {
                System.err.printf("Timeout occurred while getting shadow: %s/%s%n", thingName,
                        shadowName);
            } catch (ExecutionException e) {
                if (e.getCause() instanceof UnauthorizedError) {
                    System.err.printf("Unauthorized error while getting shadow: %s/%s%n",
                            thingName, shadowName);
                } else if (e.getCause() instanceof ResourceNotFoundError) {
                    System.err.printf("Unable to find shadow to get: %s/%s%n", thingName,
                            shadowName);
                } else {
                    throw e;
                }
            }
        } catch (InterruptedException e) {
            System.out.println("IPC interrupted.");
        } catch (ExecutionException e) {
            System.err.println("Exception occurred when using IPC.");
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static GetThingShadowResponseHandler getThingShadow(GreengrassCoreIPCClient greengrassCoreIPCClient, String thingName, String shadowName) {
        GetThingShadowRequest getThingShadowRequest = new GetThingShadowRequest();
        getThingShadowRequest.setThingName(thingName);
        getThingShadowRequest.setShadowName(shadowName);
        return greengrassCoreIPCClient.getThingShadow(getThingShadowRequest, Optional.empty());
    }
}
```

------
#### [ Python (IPC client V1) ]

**Example 示例：获取事物影子**  

```
import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import GetThingShadowRequest

TIMEOUT = 10

def sample_get_thing_shadow_request(thingName, shadowName):
    try:
        # set up IPC client to connect to the IPC server
        ipc_client = awsiot.greengrasscoreipc.connect()
                
        # create the GetThingShadow request
        get_thing_shadow_request = GetThingShadowRequest()
        get_thing_shadow_request.thing_name = thingName
        get_thing_shadow_request.shadow_name = shadowName
        
        # retrieve the GetThingShadow response after sending the request to the IPC server
        op = ipc_client.new_get_thing_shadow()
        op.activate(get_thing_shadow_request)
        fut = op.get_response()
        
        result = fut.result(TIMEOUT)
        return result.payload
        
    except InvalidArgumentsError as e:
        # add error handling
        ...
    # except ResourceNotFoundError | UnauthorizedError | ServiceError
```

------
#### [ JavaScript ]

**Example 示例：获取事物影子**  

```
import {
    GetThingShadowRequest
} from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc/model';
import * as greengrasscoreipc from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc';

class GetThingShadow {
    private ipcClient: greengrasscoreipc.Client;
    private thingName: string;
    private shadowName: string;

    constructor() {
        // Define args parameters here           
        this.thingName = "<define_your_own_thingName>";
        this.shadowName = "<define_your_own_shadowName>";
        this.bootstrap();
    }

    async bootstrap() {
        try {
            this.ipcClient = await getIpcClient();
        } catch (err) {
            // parse the error depending on your use cases
            throw err
        }
        
        try {
            await this.handleGetThingShadowOperation(this.thingName,
                this.shadowName);
        } catch (err) {
            // parse the error depending on your use cases
            throw err
        }
    }

    async handleGetThingShadowOperation(
        thingName: string,
        shadowName: string
    ) {
        const request: GetThingShadowRequest = {
            thingName: thingName,
            shadowName: shadowName
        };
        const response = await this.ipcClient.getThingShadow(request);
    }
}

export async function getIpcClient() {
    try {
        const ipcClient = greengrasscoreipc.createClient();
        await ipcClient.connect()
            .catch(error => {
                // parse the error depending on your use cases
                throw error;
            });
        return ipcClient
    } catch (err) {
        // parse the error depending on your use caseså
        throw err
    }
}

const startScript = new GetThingShadow();
```

------

## UpdateThingShadow
<a name="ipc-operation-updatethingshadow"></a>

更新指定事物的影子。如果影子不存在，则会创建一个。

### 请求
<a name="ipc-operation-updatethingshadow-request"></a>

此操作的请求包含以下参数：

`thingName` (Python: `thing_name`)  <a name="ipc-local-shadows-thing-name"></a>
事物的名称。  
类型：`string`

`shadowName` (Python: `shadow_name`)  <a name="ipc-local-shadows-shadow-name"></a>
影子的名称。要指定事物的经典影子，请将此参数设置为空字符串 (`""`)。  
该 AWS IoT Greengrass 服务使用`AWSManagedGreengrassV2Deployment`命名的影子来管理针对单个核心设备的部署。这个名为 shadow 的保留供 AWS IoT Greengrass 服务使用。请勿更新或删除该已命名影子。
类型：`string`

`payload`  
请求状态文档为 blob。  
类型：包含以下信息的 `object`：    
`state`  
要更新的状态信息。此 IPC 操作仅影响指定字段。  
该对象包含以下信息。通常，您将使用 `desired` 或 `reported` 属性，但不能在同一请求中同时使用这两个属性。    
`desired`  
请求在设备中更新的状态属性和值。  
类型：键/值对 `map`  
`reported`  
设备报告的状态属性和值。  
类型：键/值对 `map`  
`clientToken`（Python：`client_token`）  
（可选）用于匹配请求和客户端令牌的相应响应的令牌。  
类型：`string`  
`version`  
（可选）待更新的本地影子文档版本。影子服务只有在指定的版本与其拥有的最新版本一致时才会处理更新。  
类型：`integer`

### 响应
<a name="ipc-operation-updatethingshadow-response"></a>

此操作的响应包含以下信息：

`payload`  
响应状态文档为 blob。  
类型：包含以下信息的 `object`：    
`state`  
状态信息。  
该对象包含以下信息。    
`desired`  
请求在设备中更新的状态属性和值。  
类型：键/值对 `map`  
`reported`  
设备报告的状态属性和值。  
类型：键/值对 `map`  
`delta`  
设备报告的状态属性和值。  
类型：键/值对 `map`  
`metadata`  
`desired` 和 `reported` 部分中每个属性的时间戳，因此，您可以确定状态的更新时间。  
类型：`string`  
`timestamp`  
生成响应时的 Epoch 日期和时间。  
类型：`integer`  
`clientToken` (Python: `client_token`)  
用于匹配请求和相应响应的令牌。  
类型：`string`  
`version`  
更新完成后的本地影子文档的版本。  
类型：`integer`

### 错误
<a name="ipc-operation-updatethingshadow-errors"></a>

此操作可返回以下错误。

`ConflictError`  
本地影子服务在更新操作期间遇到了版本冲突。当请求有效载荷中的版本与最新的可用本地影子文档中的版本不匹配时，就会发生这种情况。

`InvalidArgumentsError`  
<a name="ipc-invalidargumentserror-para"></a>本地影子服务无法验证请求参数。如果请求包含格式错误的 JSON 或不支持的字符，则可能会发生这种情况。  
有效的 `payload` 具有以下属性：  
+ 该 `state` 节点存在，并且是一个包含 `desired` 或 `reported` 状态信息的对象。
+ `desired` 和 `reported` 节点要么是对象，要么为空。这些对象中至少有一个必须包含有效的状态信息。
+ `desired` 和 `reported` 对象的深度不能超过八个节点。
+ `clientToken` 值的长度不能超过 64 个字符。
+  `version` 值必须为 `1` 或更高。

`ServiceError`  <a name="ipc-serviceerror"></a>
发生了内部服务错误，或者对 IPC 服务的请求数超过了影子管理器组件中 `maxLocalRequestsPerSecondPerThing` 和 `maxTotalLocalRequestsRate` 配置参数中指定的限制。

`UnauthorizedError`  <a name="ipc-unauthorizederror"></a>
该组件的授权策略不包括此操作所需权限。

### 示例
<a name="ipc-operation-updatethingshadow-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Java (IPC client V1) ]

**Example 示例：更新事物影子**  
此示例使用一个`IPCUtils`类来创建与 C AWS IoT Greengrass ore IPC 服务的连接。有关更多信息，请参阅 [Connect 到 C AWS IoT Greengrass ore IPC 服务](interprocess-communication.md#ipc-service-connect)。

```
package com.aws.greengrass.docs.samples.ipc;

import com.aws.greengrass.docs.samples.ipc.util.IPCUtils;
import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient;
import software.amazon.awssdk.aws.greengrass.UpdateThingShadowResponseHandler;
import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError;
import software.amazon.awssdk.aws.greengrass.model.UpdateThingShadowRequest;
import software.amazon.awssdk.aws.greengrass.model.UpdateThingShadowResponse;
import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection;

import java.nio.charset.StandardCharsets;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class UpdateThingShadow {

    public static final int TIMEOUT_SECONDS = 10;

    public static void main(String[] args) {
        // Use the current core device's name if thing name isn't set.
        String thingName = args[0].isEmpty() ? System.getenv("AWS_IOT_THING_NAME") : args[0];
        String shadowName = args[1];
        byte[] shadowPayload = args[2].getBytes(StandardCharsets.UTF_8);
        try (EventStreamRPCConnection eventStreamRPCConnection =
                     IPCUtils.getEventStreamRpcConnection()) {
            GreengrassCoreIPCClient ipcClient =
                    new GreengrassCoreIPCClient(eventStreamRPCConnection);
            UpdateThingShadowResponseHandler responseHandler =
                    UpdateThingShadow.updateThingShadow(ipcClient, thingName, shadowName,
                            shadowPayload);
            CompletableFuture<UpdateThingShadowResponse> futureResponse =
                    responseHandler.getResponse();
            try {
                futureResponse.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
                System.out.printf("Successfully updated shadow: %s/%s%n", thingName, shadowName);
            } catch (TimeoutException e) {
                System.err.printf("Timeout occurred while updating shadow: %s/%s%n", thingName,
                        shadowName);
            } catch (ExecutionException e) {
                if (e.getCause() instanceof UnauthorizedError) {
                    System.err.printf("Unauthorized error while updating shadow: %s/%s%n",
                            thingName, shadowName);
                } else {
                    throw e;
                }
            }
        } catch (InterruptedException e) {
            System.out.println("IPC interrupted.");
        } catch (ExecutionException e) {
            System.err.println("Exception occurred when using IPC.");
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static UpdateThingShadowResponseHandler updateThingShadow(GreengrassCoreIPCClient greengrassCoreIPCClient, String thingName, String shadowName, byte[] shadowPayload) {
        UpdateThingShadowRequest updateThingShadowRequest = new UpdateThingShadowRequest();
        updateThingShadowRequest.setThingName(thingName);
        updateThingShadowRequest.setShadowName(shadowName);
        updateThingShadowRequest.setPayload(shadowPayload);
        return greengrassCoreIPCClient.updateThingShadow(updateThingShadowRequest,
                Optional.empty());
    }
}
```

------
#### [ Python (IPC client V1) ]

**Example 示例：更新事物影子**  

```
import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import UpdateThingShadowRequest

TIMEOUT = 10

def sample_update_thing_shadow_request(thingName, shadowName, payload):
    try:
        # set up IPC client to connect to the IPC server
        ipc_client = awsiot.greengrasscoreipc.connect()
                
        # create the UpdateThingShadow request
        update_thing_shadow_request = UpdateThingShadowRequest()
        update_thing_shadow_request.thing_name = thingName
        update_thing_shadow_request.shadow_name = shadowName
        update_thing_shadow_request.payload = payload
                        
        # retrieve the UpdateThingShadow response after sending the request to the IPC server
        op = ipc_client.new_update_thing_shadow()
        op.activate(update_thing_shadow_request)
        fut = op.get_response()
        
        result = fut.result(TIMEOUT)
        return result.payload
        
    except InvalidArgumentsError as e:
        # add error handling
    ...
    # except ConflictError | UnauthorizedError | ServiceError
```

------
#### [ JavaScript ]

**Example 示例：更新事物影子**  

```
import {
    UpdateThingShadowRequest
} from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc/model';
import * as greengrasscoreipc from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc';

class UpdateThingShadow {
    private ipcClient: greengrasscoreipc.Client;
    private thingName: string;
    private shadowName: string;
    private shadowDocumentStr: string;

    constructor() {
        // Define args parameters here

        this.thingName = "<define_your_own_thingName>";
        this.shadowName = "<define_your_own_shadowName>";
        this.shadowDocumentStr = "<define_your_own_payload>";

        this.bootstrap();
    }

    async bootstrap() {
        try {
            this.ipcClient = await getIpcClient();
        } catch (err) {
            // parse the error depending on your use cases
            throw err
        }

        try {
            await this.handleUpdateThingShadowOperation(
                this.thingName,
                this.shadowName,
                this.shadowDocumentStr);
        } catch (err) {
            // parse the error depending on your use cases
            throw err
        }
    }

    async handleUpdateThingShadowOperation(
        thingName: string,
        shadowName: string,
        payloadStr: string
    ) {
        const request: UpdateThingShadowRequest = {
            thingName: thingName,
            shadowName: shadowName,
            payload: payloadStr
        }
        // make the UpdateThingShadow request
        const response = await this.ipcClient.updateThingShadow(request);
    }
}

export async function getIpcClient() {
    try {
        const ipcClient = greengrasscoreipc.createClient();
        await ipcClient.connect()
            .catch(error => {
                // parse the error depending on your use cases
                throw error;
            });
        return ipcClient
    } catch (err) {
        // parse the error depending on your use cases
        throw err
    }
}

const startScript = new UpdateThingShadow();
```

------

## DeleteThingShadow
<a name="ipc-operation-deletethingshadow"></a>

删除指定事物的影子。

从影子管理器 v2.0.4 开始，删除影子会增加版本号。例如，当您在版本 1 中删除影子 `MyThingShadow` 时，已删除影子的版本为 2。如果您随后使用名称 `MyThingShadow` 重新创建影子，则该影子的版本为 3。

### 请求
<a name="ipc-operation-deletethingshadow-request"></a>

此操作的请求包含以下参数：

`thingName` (Python: `thing_name`)  <a name="ipc-local-shadows-thing-name"></a>
事物的名称。  
类型：`string`

`shadowName` (Python: `shadow_name`)  <a name="ipc-local-shadows-shadow-name"></a>
影子的名称。要指定事物的经典影子，请将此参数设置为空字符串 (`""`)。  
该 AWS IoT Greengrass 服务使用`AWSManagedGreengrassV2Deployment`命名的影子来管理针对单个核心设备的部署。这个名为 shadow 的保留供 AWS IoT Greengrass 服务使用。请勿更新或删除该已命名影子。
类型：`string`

### 响应
<a name="ipc-operation-deletethingshadow-response"></a>

此操作的响应包含以下信息：

`payload`  
一个空的响应状态文档。

### 错误
<a name="ipc-operation-deletethingshadow-errors"></a>

此操作可返回以下错误。

`InvalidArgumentsError`  <a name="ipc-invalidargumentserror"></a>
<a name="ipc-invalidargumentserror-para"></a>本地影子服务无法验证请求参数。如果请求包含格式错误的 JSON 或不支持的字符，则可能会发生这种情况。

`ResourceNotFoundError`  <a name="ipc-resourcenotfounderror"></a>
无法找到请求的本地影子文档。

`ServiceError`  <a name="ipc-serviceerror"></a>
发生了内部服务错误，或者对 IPC 服务的请求数超过了影子管理器组件中 `maxLocalRequestsPerSecondPerThing` 和 `maxTotalLocalRequestsRate` 配置参数中指定的限制。

`UnauthorizedError`  <a name="ipc-unauthorizederror"></a>
该组件的授权策略不包括此操作所需权限。

### 示例
<a name="ipc-operation-deletethingshadow-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Java (IPC client V1) ]

**Example 示例：删除事物影子**  
此示例使用一个`IPCUtils`类来创建与 C AWS IoT Greengrass ore IPC 服务的连接。有关更多信息，请参阅 [Connect 到 C AWS IoT Greengrass ore IPC 服务](interprocess-communication.md#ipc-service-connect)。

```
package com.aws.greengrass.docs.samples.ipc;

import com.aws.greengrass.docs.samples.ipc.util.IPCUtils;
import software.amazon.awssdk.aws.greengrass.DeleteThingShadowResponseHandler;
import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient;
import software.amazon.awssdk.aws.greengrass.model.DeleteThingShadowRequest;
import software.amazon.awssdk.aws.greengrass.model.DeleteThingShadowResponse;
import software.amazon.awssdk.aws.greengrass.model.ResourceNotFoundError;
import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError;
import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection;

import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class DeleteThingShadow {

    public static final int TIMEOUT_SECONDS = 10;

    public static void main(String[] args) {
        // Use the current core device's name if thing name isn't set.
        String thingName = args[0].isEmpty() ? System.getenv("AWS_IOT_THING_NAME") : args[0];
        String shadowName = args[1];
        try (EventStreamRPCConnection eventStreamRPCConnection =
                     IPCUtils.getEventStreamRpcConnection()) {
            GreengrassCoreIPCClient ipcClient =
                    new GreengrassCoreIPCClient(eventStreamRPCConnection);
            DeleteThingShadowResponseHandler responseHandler =
                    DeleteThingShadow.deleteThingShadow(ipcClient, thingName, shadowName);
            CompletableFuture<DeleteThingShadowResponse> futureResponse =
                    responseHandler.getResponse();
            try {
                futureResponse.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
                System.out.printf("Successfully deleted shadow: %s/%s%n", thingName, shadowName);
            } catch (TimeoutException e) {
                System.err.printf("Timeout occurred while deleting shadow: %s/%s%n", thingName,
                        shadowName);
            } catch (ExecutionException e) {
                if (e.getCause() instanceof UnauthorizedError) {
                    System.err.printf("Unauthorized error while deleting shadow: %s/%s%n",
                            thingName, shadowName);
                } else if (e.getCause() instanceof ResourceNotFoundError) {
                    System.err.printf("Unable to find shadow to delete: %s/%s%n", thingName,
                            shadowName);
                } else {
                    throw e;
                }
            }
        } catch (InterruptedException e) {
            System.out.println("IPC interrupted.");
        } catch (ExecutionException e) {
            System.err.println("Exception occurred when using IPC.");
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static DeleteThingShadowResponseHandler deleteThingShadow(GreengrassCoreIPCClient greengrassCoreIPCClient, String thingName, String shadowName) {
        DeleteThingShadowRequest deleteThingShadowRequest = new DeleteThingShadowRequest();
        deleteThingShadowRequest.setThingName(thingName);
        deleteThingShadowRequest.setShadowName(shadowName);
        return greengrassCoreIPCClient.deleteThingShadow(deleteThingShadowRequest,
                Optional.empty());
    }
}
```

------
#### [ Python (IPC client V1) ]

**Example 示例：删除事物影子**  

```
import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import DeleteThingShadowRequest

TIMEOUT = 10

def sample_delete_thing_shadow_request(thingName, shadowName):
    try:
        # set up IPC client to connect to the IPC server
        ipc_client = awsiot.greengrasscoreipc.connect()
                
        # create the DeleteThingShadow request
        delete_thing_shadow_request = DeleteThingShadowRequest()
        delete_thing_shadow_request.thing_name = thingName
        delete_thing_shadow_request.shadow_name = shadowName
                        
        # retrieve the DeleteThingShadow response after sending the request to the IPC server
        op = ipc_client.new_delete_thing_shadow()
        op.activate(delete_thing_shadow_request)
        fut = op.get_response()
        
        result = fut.result(TIMEOUT)
        return result.payload
        
    except InvalidArgumentsError as e:
        # add error handling
    ...
    # except ResourceNotFoundError | UnauthorizedError | ServiceError
```

------
#### [ JavaScript ]

**Example 示例：删除事物影子**  

```
import {
    DeleteThingShadowRequest
} from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc/model';
import * as greengrasscoreipc from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc';

class DeleteThingShadow {
    private ipcClient: greengrasscoreipc.Client;
    private thingName: string;
    private shadowName: string;

    constructor() {
        // Define args parameters here
        this.thingName = "<define_your_own_thingName>";
        this.shadowName = "<define_your_own_shadowName>";
        this.bootstrap();
    }

    async bootstrap() {
        try {
            this.ipcClient = await getIpcClient();
        } catch (err) {
            // parse the error depending on your use cases
            throw err
        }

        try {
            await this.handleDeleteThingShadowOperation(this.thingName, this.shadowName)
        } catch (err) {
            // parse the error depending on your use cases
            throw err
        }
    }

    async handleDeleteThingShadowOperation(thingName: string, shadowName: string) {
        const request: DeleteThingShadowRequest = {
            thingName: thingName,
            shadowName: shadowName
        }
        // make the DeleteThingShadow request
        const response = await this.ipcClient.deleteThingShadow(request);
    }
}

export async function getIpcClient() {
    try {
        const ipcClient = greengrasscoreipc.createClient();
        await ipcClient.connect()
            .catch(error => {
                // parse the error depending on your use cases
                throw error;
            });
        return ipcClient
    } catch (err) {
        // parse the error depending on your use cases
        throw err
    }
}

const startScript = new DeleteThingShadow();
```

------

## ListNamedShadowsForThing
<a name="ipc-operation-listnamedshadowsforthing"></a>

列出指定事物的命名影子。

### 请求
<a name="ipc-operation-listnamedshadowsforthing-request"></a>

此操作的请求包含以下参数：

`thingName` (Python: `thing_name`)  <a name="ipc-local-shadows-thing-name"></a>
事物的名称。  
类型：`string`

`pageSize` (Python: `page_size`)  
（可选）在每个调用中返回的影子名称的数量。  
类型：`integer`  
默认值：25  
最大值：100

`nextToken`（Python：`next_token`）  
（可选）用于检索下一组结果的令牌。该值在分页结果中返回，并在返回下一页的调用中使用。  
类型：`string`

### 响应
<a name="ipc-operation-listnamedshadowsforthing-response"></a>

此操作的响应包含以下信息：

`results`  
影子名称列表。  
类型：`array`

`timestamp`  
（可选）生成响应的日期和时间。  
类型：`integer`

`nextToken` (Python: `next_token`)  
（可选）在检索序列中的下一页的分页请求中使用的令牌值。在没有其它要返回的影子名称时，该令牌不存在。  
类型：`string`  
如果请求的页面大小与响应中的影子名称数量完全匹配，则出现此令牌；但使用时，它会返回一个空列表。

### 错误
<a name="ipc-operation-listnamedshadowsforthing-errors"></a>

此操作可返回以下错误。

`InvalidArgumentsError`  <a name="ipc-invalidargumentserror"></a>
<a name="ipc-invalidargumentserror-para"></a>本地影子服务无法验证请求参数。如果请求包含格式错误的 JSON 或不支持的字符，则可能会发生这种情况。

`ResourceNotFoundError`  <a name="ipc-resourcenotfounderror"></a>
无法找到请求的本地影子文档。

`ServiceError`  <a name="ipc-serviceerror"></a>
发生了内部服务错误，或者对 IPC 服务的请求数超过了影子管理器组件中 `maxLocalRequestsPerSecondPerThing` 和 `maxTotalLocalRequestsRate` 配置参数中指定的限制。

`UnauthorizedError`  <a name="ipc-unauthorizederror"></a>
该组件的授权策略不包括此操作所需权限。

### 示例
<a name="ipc-operation-listnamedshadowsforthing-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Java (IPC client V1) ]

**Example 示例：列出事物的已命名影子**  
此示例使用一个`IPCUtils`类来创建与 C AWS IoT Greengrass ore IPC 服务的连接。有关更多信息，请参阅 [Connect 到 C AWS IoT Greengrass ore IPC 服务](interprocess-communication.md#ipc-service-connect)。

```
package com.aws.greengrass.docs.samples.ipc;

import com.aws.greengrass.docs.samples.ipc.util.IPCUtils;
import software.amazon.awssdk.aws.greengrass.GreengrassCoreIPCClient;
import software.amazon.awssdk.aws.greengrass.ListNamedShadowsForThingResponseHandler;
import software.amazon.awssdk.aws.greengrass.model.ListNamedShadowsForThingRequest;
import software.amazon.awssdk.aws.greengrass.model.ListNamedShadowsForThingResponse;
import software.amazon.awssdk.aws.greengrass.model.ResourceNotFoundError;
import software.amazon.awssdk.aws.greengrass.model.UnauthorizedError;
import software.amazon.awssdk.eventstreamrpc.EventStreamRPCConnection;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class ListNamedShadowsForThing {

    public static final int TIMEOUT_SECONDS = 10;

    public static void main(String[] args) {
        // Use the current core device's name if thing name isn't set.
        String thingName = args[0].isEmpty() ? System.getenv("AWS_IOT_THING_NAME") : args[0];
        try (EventStreamRPCConnection eventStreamRPCConnection =
                     IPCUtils.getEventStreamRpcConnection()) {
            GreengrassCoreIPCClient ipcClient =
                    new GreengrassCoreIPCClient(eventStreamRPCConnection);
            List<String> namedShadows = new ArrayList<>();
            String nextToken = null;
            try {
                // Send additional requests until there's no pagination token in the response.
                do {
                    ListNamedShadowsForThingResponseHandler responseHandler =
                            ListNamedShadowsForThing.listNamedShadowsForThing(ipcClient, thingName,
                                    nextToken, 25);
                    CompletableFuture<ListNamedShadowsForThingResponse> futureResponse =
                            responseHandler.getResponse();
                    ListNamedShadowsForThingResponse response =
                            futureResponse.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
                    List<String> responseNamedShadows = response.getResults();
                    namedShadows.addAll(responseNamedShadows);
                    nextToken = response.getNextToken();
                } while (nextToken != null);
                System.out.printf("Successfully got named shadows for thing %s: %s%n", thingName,
                        String.join(",", namedShadows));
            } catch (TimeoutException e) {
                System.err.println("Timeout occurred while listing named shadows for thing: " + thingName);
            } catch (ExecutionException e) {
                if (e.getCause() instanceof UnauthorizedError) {
                    System.err.println("Unauthorized error while listing named shadows for " +
                            "thing: " + thingName);
                } else if (e.getCause() instanceof ResourceNotFoundError) {
                    System.err.println("Unable to find thing to list named shadows: " + thingName);
                } else {
                    throw e;
                }
            }
        } catch (InterruptedException e) {
            System.out.println("IPC interrupted.");
        } catch (ExecutionException e) {
            System.err.println("Exception occurred when using IPC.");
            e.printStackTrace();
            System.exit(1);
        }
    }

    public static ListNamedShadowsForThingResponseHandler listNamedShadowsForThing(GreengrassCoreIPCClient greengrassCoreIPCClient, String thingName, String nextToken, int pageSize) {
        ListNamedShadowsForThingRequest listNamedShadowsForThingRequest =
                new ListNamedShadowsForThingRequest();
        listNamedShadowsForThingRequest.setThingName(thingName);
        listNamedShadowsForThingRequest.setNextToken(nextToken);
        listNamedShadowsForThingRequest.setPageSize(pageSize);
        return greengrassCoreIPCClient.listNamedShadowsForThing(listNamedShadowsForThingRequest,
                Optional.empty());
    }
}
```

------
#### [ Python (IPC client V1) ]

**Example 示例：列出事物的已命名影子**  

```
import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import ListNamedShadowsForThingRequest

TIMEOUT = 10

def sample_list_named_shadows_for_thing_request(thingName, nextToken, pageSize):
    try:
        # set up IPC client to connect to the IPC server
        ipc_client = awsiot.greengrasscoreipc.connect()
                
        # create the ListNamedShadowsForThingRequest request
        list_named_shadows_for_thing_request = ListNamedShadowsForThingRequest()
        list_named_shadows_for_thing_request.thing_name = thingName
        list_named_shadows_for_thing_request.next_token = nextToken
        list_named_shadows_for_thing_request.page_size = pageSize
        
        # retrieve the ListNamedShadowsForThingRequest response after sending the request to the IPC server
        op = ipc_client.new_list_named_shadows_for_thing()
        op.activate(list_named_shadows_for_thing_request)
        fut = op.get_response()
        
        list_result = fut.result(TIMEOUT)
        
        # additional returned fields
        timestamp = list_result.timestamp
        next_token = result.next_token
        named_shadow_list = list_result.results
        
        return named_shadow_list, next_token, timestamp
                
    except InvalidArgumentsError as e:
        # add error handling
    ...
    # except ResourceNotFoundError | UnauthorizedError | ServiceError
```

------
#### [ JavaScript ]

**Example 示例：列出事物的已命名影子**  

```
import {
    ListNamedShadowsForThingRequest
} from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc/model';
import * as greengrasscoreipc from 'aws-iot-device-sdk-v2/dist/greengrasscoreipc';

class listNamedShadowsForThing {
    private ipcClient: greengrasscoreipc.Client;
    private thingName: string;
    private pageSizeStr: string;
    private nextToken: string;

    constructor() {
        // Define args parameters here
        this.thingName = "<define_your_own_thingName>";
        this.pageSizeStr = "<define_your_own_pageSize>";
        this.nextToken = "<define_your_own_token>";
        this.bootstrap();
    }

    async bootstrap() {
        try {
            this.ipcClient = await getIpcClient();
        } catch (err) {
            // parse the error depending on your use cases
            throw err
        }
        
        try {
            await this.handleListNamedShadowsForThingOperation(this.thingName,
                this.nextToken, this.pageSizeStr);
        } catch (err) {
            // parse the error depending on your use cases
            throw err
        }
    }

    async handleListNamedShadowsForThingOperation(
        thingName: string,
        nextToken: string,
        pageSizeStr: string
    ) {
        let request: ListNamedShadowsForThingRequest = {
            thingName: thingName,
            nextToken: nextToken,
        };
        if (pageSizeStr) {
            request.pageSize = parseInt(pageSizeStr);
        }
        // make the ListNamedShadowsForThing request
        const response = await this.ipcClient.listNamedShadowsForThing(request);
        const shadowNames = response.results;
    }
}

export async function getIpcClient(){
    try {
        const ipcClient = greengrasscoreipc.createClient();
        await ipcClient.connect()
            .catch(error => {
                // parse the error depending on your use cases
                throw error;
            });
        return ipcClient
    } catch (err) {
        // parse the error depending on your use cases
        throw err
    }
}

const startScript = new listNamedShadowsForThing();
```

------

# 管理本地部署和组件
<a name="ipc-local-deployments-components"></a>

**注意**  
此功能适用于 [Greengrass Nucleus 组件](greengrass-nucleus-component.md)的 v2.6.0 及更高版本。

使用 Greengrass CLI IPC 服务来管理核心设备上的本地部署和 Greengrass 组件。

要使用这些 IPC 操作，请将 [Greengrass CLI 组件](greengrass-cli-component.md)的 2.6.0 或更高版本作为依赖关系包含在自定义组件中。然后，您可以在自定义组件中使用 IPC 操作来执行以下操作：
+ 创建本地部署，以修改和配置核心设备上的 Greengrass 组件。
+ 重启并停止核心设备上的 Greengrass 组件。
+ 生成可用于登录[本地调试控制台](local-debug-console-component.md)的密码。

**Topics**
+ [最低 SDK 版本](#ipc-local-deployments-components-sdk-versions)
+ [Authorization](#ipc-local-deployments-components-authorization)
+ [CreateLocalDeployment](#ipc-operation-createlocaldeployment)
+ [ListLocalDeployments](#ipc-operation-listlocaldeployments)
+ [GetLocalDeploymentStatus](#ipc-operation-getlocaldeploymentstatus)
+ [ListComponents](#ipc-operation-listcomponents)
+ [GetComponentDetails](#ipc-operation-getcomponentdetails)
+ [RestartComponent](#ipc-operation-restartcomponent)
+ [StopComponent](#ipc-operation-stopcomponent)
+ [CreateDebugPassword](#ipc-operation-createdebugpassword)

## 最低 SDK 版本
<a name="ipc-local-deployments-components-sdk-versions"></a>

下表列出了与 Greengras AWS IoT Device SDK s CLI IPC 服务进行交互时必须使用的最低版本。


| SDK | 最低版本 | 
| --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.2.10  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.5.3  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.17.0  | 
|  [AWS IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  | 

## Authorization
<a name="ipc-local-deployments-components-authorization"></a>

要在自定义组件中使用 Greengrass CLI IPC 服务，您必须定义允许组件管理本地部署和组件的授权策略。有关定义授权策略的信息，请参阅[授权组件执行 IPC 操作](interprocess-communication.md#ipc-authorization-policies)。

Greengrass CLI 的授权策略具有以下属性。

**IPC 服务标识符：**`aws.greengrass.Cli`


| 操作 | 说明 | 资源 | 
| --- | --- | --- | 
|  `aws.greengrass#CreateLocalDeployment`  |  允许组件在核心设备上创建本地部署。  |  `*`  | 
|  `aws.greengrass#ListLocalDeployments`  |  允许组件列出核心设备上的本地部署。  |  `*`  | 
|  `aws.greengrass#GetLocalDeploymentStatus`  |  允许组件获取核心设备上的本地部署状态。  |  本地部署 ID，或使用 `*` 来允许访问所有本地部署。  | 
|  `aws.greengrass#ListComponents`  |  允许组件列出核心设备上的组件。  |  `*`  | 
|  `aws.greengrass#GetComponentDetails`  |  允许组件获取有关核心设备上组件的详细信息。  |  组件名称（例如 `com.example.HelloWorld`），或使用 `*` 来允许访问所有组件。  | 
|  `aws.greengrass#RestartComponent`  |  允许组件在核心设备上重启组件。  |  组件名称（例如 `com.example.HelloWorld`），或使用 `*` 来允许访问所有组件。  | 
|  `aws.greengrass#StopComponent`  |  允许组件在核心设备上停止组件。  |  组件名称（例如 `com.example.HelloWorld`），或使用 `*` 来允许访问所有组件。  | 
|  `aws.greengrass#CreateDebugPassword`  |  允许组件生成用于登录[本地调试控制台组件](local-debug-console-component.md)的密码。  |  `*`  | 

**Example 示例授权策略**  
以下示例授权策略允许组件创建本地部署、查看所有本地部署和组件，以及重启并停止名为 `com.example.HelloWorld` 的组件。  

```
{
  "accessControl": {
    "aws.greengrass.Cli": {
      "com.example.MyLocalManagerComponent:cli:1": {
        "policyDescription": "Allows access to create local deployments and view deployments and components.",
        "operations": [
          "aws.greengrass#CreateLocalDeployment",
          "aws.greengrass#ListLocalDeployments",
          "aws.greengrass#GetLocalDeploymentStatus",
          "aws.greengrass#ListComponents",
          "aws.greengrass#GetComponentDetails"
        ],
        "resources": [
          "*"
        ]
      }
    },
    "aws.greengrass.Cli": {
      "com.example.MyLocalManagerComponent:cli:2": {
        "policyDescription": "Allows access to restart and stop the Hello World component.",
        "operations": [
          "aws.greengrass#RestartComponent",
          "aws.greengrass#StopComponent"
        ],
        "resources": [
          "com.example.HelloWorld"
        ]
      }
    }
  }
}
```

## CreateLocalDeployment
<a name="ipc-operation-createlocaldeployment"></a>

使用指定的组件配方、构件和运行时参数创建或更新本地部署。

此操作提供的功能与 Greengrass CLI 中的 [deployment create 命令](gg-cli-deployment.md#deployment-create)相同。

### 请求
<a name="ipc-operation-createlocaldeployment-request"></a>

此操作的请求包含以下参数：

`recipeDirectoryPath`（Python：`recipe_directory_path`）  
（可选）包含组件配方文件的文件夹的绝对路径。

`artifactDirectoryPath`（Python：`artifact_directory_path`）  
（可选）包含要在部署中添加的构件文件的文件夹的绝对路径。构件文件夹必须包含以下文件夹结构：  

```
/path/to/artifact/folder/component-name/component-version/artifacts
```

`rootComponentVersionsToAdd`（Python：`root_component_versions_to_add`）  
（可选）要安装在核心设备上的组件版本。此对象 (`ComponentToVersionMap`) 是一个包含以下键值对的映射：    
`key`  
组件名称。  
`value`  
组件版本。

`rootComponentsToRemove`（Python：`root_components_to_remove`）  
（可选）要从核心设备上卸载的组件。指定一个列表，其中每个条目都是组件的名称。

`componentToConfiguration`（Python：`component_to_configuration`）  
（可选）部署中每个组件的配置更新。此对象 (`ComponentToConfiguration`) 是一个包含以下键值对的映射：    
`key`  
组件名称。  
`value`  
组件的配置更新 JSON 对象。JSON 对象必须具有以下格式。  

```
{ 
  "MERGE": {
    "config-key": "config-value"
  },
  "RESET": [
    "path/to/reset/"
  ]
}
```
有关配置更新的更多信息，请参阅[更新组件配置](update-component-configurations.md)。

`componentToRunWithInfo`（Python：`component_to_run_with_info`）  
（可选）部署中每个组件的运行时配置。此配置包括拥有每个组件进程的系统用户以及要应用于每个组件的系统限制。此对象 (`ComponentToRunWithInfo`) 是一个包含以下键值对的映射：    
`key`  
组件名称。  
`value`  
组件的运行时配置。如果省略运行时配置参数，则 Core 软件将使用您在 Gre [engr](greengrass-nucleus-component.md) ass AWS IoT Greengrass 核心上配置的默认值。此对象 `RunWithInfo` 包含以下信息：    
`posixUser`（Python：`posix_user`）  
（可选）<a name="deployment-posix-user-definition"></a>用于在 Linux 核心设备上运行此组件的 POSIX 系统用户和（可选的）组。用户和组（如果已指定）必须存在于每台 Linux 核心设备上。使用以下格式指定由半角冒号（`:`）分隔的用户和组：`user:group`。组是可选的。如果您未指定群组，则 AWS IoT Greengrass Core 软件将使用该用户的主群组。有关更多信息，请参阅[配置运行组件的用户](configure-greengrass-core-v2.md#configure-component-user)。  
`windowsUser`（Python：`windows_user`）  
（可选）<a name="deployment-windows-user-definition"></a>用于在 Windows 核心设备上运行此组件的 Windows 用户。用户必须存在于每台 Windows 核心设备上，其用户名和密码必须存储在 LocalSystem 账户的凭据管理器实例中。有关更多信息，请参阅[配置运行组件的用户](configure-greengrass-core-v2.md#configure-component-user)。  
`systemResourceLimits`（Python：`system_resource_limits`）  
（可选）<a name="deployment-system-resource-limits-definition"></a>要应用于此组件进程的系统资源限制。您可以将系统资源限制应用于通用和非容器化 Lambda 组件。有关更多信息，请参阅[配置组件的系统资源限制](configure-greengrass-core-v2.md#configure-component-system-resource-limits)。  
AWS IoT Greengrass 目前不支持在 Windows 核心设备上使用此功能。  
此对象 `SystemResourceLimits` 包含以下信息：    
`cpus`  
（可选）<a name="system-resource-limits-cpu-definition-this"></a>此组件进程可在核心设备上使用的最大 CPU 时间。核心设备的总 CPU 时间等于 CPU 核心的设备数量。例如，在一台有 4 个 CPU 核心的核心设备上，您可以将此值设置为 `2`，以便将此组件进程限制为使用每个 CPU 核心的 50%。在一台有 1 个 CPU 核心的设备上，您可以将此值设置为 `0.25`，以便将此组件进程限制为使用 CPU 的 25%。如果将此值设置为大于 CPU 内核数的数字，则 AWS IoT Greengrass Core 软件不会限制组件的 CPU 使用率。  
`memory`  
（可选）<a name="system-resource-limits-memory-definition-this"></a>此组件进程可在核心设备上使用的最大 RAM 数量（以千字节表示）。

`groupName`（Python：`group_name`）  
（可选）此部署要针对的事物组的名称。

### 响应
<a name="ipc-operation-createlocaldeployment-response"></a>

此操作的响应包含以下信息：

`deploymentId`（Python：`deployment_id`）  
该请求创建的本地部署的 ID。

## ListLocalDeployments
<a name="ipc-operation-listlocaldeployments"></a>

获取最近 10 次本地部署的状态。

此操作提供的功能与 Greengrass CLI 中的 [deployment list 命令](gg-cli-deployment.md#deployment-list)相同。

### 请求
<a name="ipc-operation-listlocaldeployments-request"></a>

此操作的请求没有任何参数。

### 响应
<a name="ipc-operation-listlocaldeployments-response"></a>

此操作的响应包含以下信息：

`localDeployments`（Python：`local_deployments`）  
本地部署列表。此列表中的每个对象都是 `LocalDeployment` 对象，其中包含以下信息：  <a name="ipc-local-deployment-object-shape"></a>  
`deploymentId`（Python：`deployment_id`）  
本地部署的 ID。  
`status`  
本地部署的状态。此枚举 `DeploymentStatus` 包含以下值：  
+ `QUEUED`
+ `IN_PROGRESS`
+ `SUCCEEDED`
+ `FAILED`

## GetLocalDeploymentStatus
<a name="ipc-operation-getlocaldeploymentstatus"></a>

获取本地部署的状态。

此操作提供的功能与 Greengrass CLI 中的 [deployment status 命令](gg-cli-deployment.md#deployment-status)相同。

### 请求
<a name="ipc-operation-getlocaldeploymentstatus-request"></a>

此操作的请求包含以下参数：

`deploymentId`（Python：`deployment_id`）  
要获取的本地部署的 ID。

### 响应
<a name="ipc-operation-getlocaldeploymentstatus-response"></a>

此操作的响应包含以下信息：

`deployment`  
本地部署。此对象 `LocalDeployment` 包含以下信息：  <a name="ipc-local-deployment-object-shape"></a>  
`deploymentId`（Python：`deployment_id`）  
本地部署的 ID。  
`status`  
本地部署的状态。此枚举 `DeploymentStatus` 包含以下值：  
+ `QUEUED`
+ `IN_PROGRESS`
+ `SUCCEEDED`
+ `FAILED`

## ListComponents
<a name="ipc-operation-listcomponents"></a>

获取核心设备上每个根组件的名称、版本、状态和配置。*根组件*是您在部署中指定的组件。此响应不包括作为其它组件的依赖关系安装的组件。

此操作提供的功能与 Greengrass CLI 中的 [component list 命令](gg-cli-component.md#component-list)相同。

### 请求
<a name="ipc-operation-listcomponents-request"></a>

此操作的请求没有任何参数。

### 响应
<a name="ipc-operation-listcomponents-response"></a>

此操作的响应包含以下信息：

`components`  
核心设备上的根组件列表。此列表中的每个对象都是 `ComponentDetails` 对象，其中包含以下信息：  <a name="ipc-component-details-object-shape"></a>  
`componentName`（Python：`component_name`）  
组件名称。  
`version`  
组件版本。  
`state`  
组件的状态。此状态可能是以下状态之一：  
+ `BROKEN`
+ `ERRORED`
+ `FINISHED`
+ `INSTALLED`
+ `NEW`
+ `RUNNING`
+ `STARTING`
+ `STOPPING`  
`configuration`  
以 JSON 对象形式表示的组件配置。

## GetComponentDetails
<a name="ipc-operation-getcomponentdetails"></a>

获取核心设备上组件的版本、状态和配置。

此操作提供的功能与 Greengrass CLI 中的 [component details 命令](gg-cli-component.md#component-details)相同。

### 请求
<a name="ipc-operation-getcomponentdetails-request"></a>

此操作的请求包含以下参数：

`componentName`（Python：`component_name`）  
要获取的组件的名称。

### 响应
<a name="ipc-operation-getcomponentdetails-response"></a>

此操作的响应包含以下信息：

`componentDetails`（Python：`component_details`）  
组件的详细信息。此对象 `ComponentDetails` 包含以下信息：  <a name="ipc-component-details-object-shape"></a>  
`componentName`（Python：`component_name`）  
组件名称。  
`version`  
组件版本。  
`state`  
组件的状态。此状态可能是以下状态之一：  
+ `BROKEN`
+ `ERRORED`
+ `FINISHED`
+ `INSTALLED`
+ `NEW`
+ `RUNNING`
+ `STARTING`
+ `STOPPING`  
`configuration`  
以 JSON 对象形式表示的组件配置。

## RestartComponent
<a name="ipc-operation-restartcomponent"></a>

重启核心设备上的组件。

**注意**  
虽然您可以重启任何组件，但建议您仅重启[通用组件](develop-greengrass-components.md#component-types)。

此操作提供的功能与 Greengrass CLI 中的 [component restart 命令](gg-cli-component.md#component-restart)相同。

### 请求
<a name="ipc-operation-restartcomponent-request"></a>

此操作的请求包含以下参数：

`componentName`（Python：`component_name`）  
组件名称。

### 响应
<a name="ipc-operation-restartcomponent-response"></a>

此操作的响应包含以下信息：

`restartStatus`（Python：`restart_status`）  
重启请求的状态。请求状态可能是以下状态之一：  
+ `SUCCEEDED`
+ `FAILED`

`message`  
如果请求失败，则会显示一条消息，说明组件未能重启的原因。

### 示例
<a name="ipc-operation-restartcomponent-examples"></a>

以下示例演示了如何在自定义组件代码中调用该操作。

------
#### [ Rust ]

**Example 示例：重启组件**  

```
use gg_sdk::Sdk;

fn main() {
    let sdk = Sdk::init();
    sdk.connect().expect("Failed to establish IPC connection");

    let component_name = "com.example.HelloWorld";

    sdk.restart_component(component_name)
        .expect("Failed to restart component");

    println!("Successfully requested restart for component: {component_name}");
}
```

------
#### [ C ]

**Example 示例：重启组件**  

```
#include <gg/error.h>
#include <gg/ipc/client.h>
#include <gg/sdk.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    gg_sdk_init();

    GgError err = ggipc_connect();
    if (err != GG_ERR_OK) {
        fprintf(stderr, "Failed to establish IPC connection.\n");
        exit(-1);
    }

    GgBuffer component_name = GG_STR("com.example.HelloWorld");

    err = ggipc_restart_component(component_name);
    if (err != GG_ERR_OK) {
        fprintf(
            stderr,
            "Failed to restart component: %.*s\n",
            (int) component_name.len,
            component_name.data
        );
        exit(-1);
    }

    printf(
        "Successfully requested restart for component: %.*s\n",
        (int) component_name.len,
        component_name.data
    );
}
```

------
#### [ C\$1\$1 (Component SDK) ]

**Example 示例：重启组件**  

```
#include <gg/ipc/client.hpp>
#include <iostream>

int main() {
    auto &client = gg::ipc::Client::get();

    auto error = client.connect();
    if (error) {
        std::cerr << "Failed to establish IPC connection.\n";
        exit(-1);
    }

    std::string_view component_name = "com.example.HelloWorld";

    error = client.restart_component(component_name);
    if (error) {
        std::cerr << "Failed to restart component: " << component_name << "\n";
        exit(-1);
    }

    std::cout << "Successfully requested restart for component: "
              << component_name << "\n";
}
```

------

## StopComponent
<a name="ipc-operation-stopcomponent"></a>

停止核心设备上的组件进程。

**注意**  
虽然您可以停止任何组件，但建议您仅停止[通用组件](develop-greengrass-components.md#component-types)。

此操作提供的功能与 Greengrass CLI 中的 [component stop 命令](gg-cli-component.md#component-stop)相同。

### 请求
<a name="ipc-operation-stopcomponent-request"></a>

此操作的请求包含以下参数：

`componentName`（Python：`component_name`）  
组件名称。

### 响应
<a name="ipc-operation-stopcomponent-response"></a>

此操作的响应包含以下信息：

`stopStatus`（Python：`stop_status`）  
停止请求的状态。请求状态可能是以下状态之一：  
+ `SUCCEEDED`
+ `FAILED`

`message`  
如果请求失败，则会显示一条消息，说明组件未能停止的原因。

## CreateDebugPassword
<a name="ipc-operation-createdebugpassword"></a>

生成可用于登录[本地调试控制台组件](local-debug-console-component.md)的随机密码。密码将在生成 8 小时后过期。

此操作提供的功能与 Greengrass CLI 中的[get-debug-password 命令](gg-cli-get-debug-password.md)相同。

### 请求
<a name="ipc-operation-createdebugpassword-request"></a>

此操作的请求没有任何参数。

### 响应
<a name="ipc-operation-createdebugpassword-response"></a>

此操作的响应包含以下信息：

`username`  
用于登录的用户名。

`password`  
用于登录的密码。

`passwordExpiration`（Python：`password_expiration`）  
密码过期的时间。

`certificateSHA256Hash`（Python：`certificate_sha256_hash`）  
启用 HTTPS 时本地调试控制台使用的自签名证书的 SHA-256 指纹。打开本地调试控制台时，使用此指纹验证证书是否合法以及连接是否安全。

`certificateSHA1Hash`（Python：`certificate_sha1_hash`）  
启用 HTTPS 时本地调试控制台使用的自签名证书的 SHA-1 指纹。打开本地调试控制台时，使用此指纹验证证书是否合法以及连接是否安全。

# 对客户端设备进行身份验证和授权
<a name="ipc-client-device-auth"></a>

**注意**  
此功能适用于 [Greengrass Nucleus 组件](greengrass-nucleus-component.md)的 v2.6.0 及更高版本。

使用客户端设备身份验证 IPC 服务开发自定义本地代理组件，使本地 IoT 设备（例如客户端设备）可以连接。

要使用这些 IPC 操作，请在自定义组件中包含[客户端设备身份验证组件](client-device-auth-component.md)版本 2.2.0 或更高版本。然后，您可以在自定义组件中使用 IPC 操作来执行以下操作：
+ 验证连接到核心设备的客户端设备的身份。
+ 为客户端设备创建会话，以连接到核心设备。
+ 验证客户端设备是否有权执行某项操作。
+ 在核心设备的服务器证书轮换时接收通知。

**Topics**
+ [最低 SDK 版本](#ipc-client-device-auth-sdk-versions)
+ [Authorization](#ipc-client-device-auth-authorization)
+ [VerifyClientDeviceIdentity](#ipc-operation-verifyclientdeviceidentity)
+ [GetClientDeviceAuthToken](#ipc-operation-getclientdeviceauthtoken)
+ [AuthorizeClientDeviceAction](#ipc-operation-authorizeclientdeviceaction)
+ [SubscribeToCertificateUpdates](#ipc-operation-subscribetocertificateupdates)

## 最低 SDK 版本
<a name="ipc-client-device-auth-sdk-versions"></a>

下表列出了与客户端设备身份验证 IPC 服务交互时必须使用的最低版本。 AWS IoT Device SDK 


| SDK | 最低版本 | 
| --- | --- | 
|  [AWS IoT Device SDK 适用于 Java v2](https://github.com/aws/aws-iot-device-sdk-java-v2)  |  v1.9.3  | 
|  [AWS IoT Device SDK 适用于 Python v2](https://github.com/aws/aws-iot-device-sdk-python-v2)  |  v1.11.3  | 
|  [AWS IoT Device SDK 适用于 C\$1\$1 v2](https://github.com/aws/aws-iot-device-sdk-cpp-v2)  |  v1.18.3  | 
|  [AWS IoT Device SDK 适用于 JavaScript v2](https://github.com/aws/aws-iot-device-sdk-js-v2)  |  v1.12.0  | 

## Authorization
<a name="ipc-client-device-auth-authorization"></a>

要在自定义组件中使用客户端设备身份验证 IPC 服务，必须定义允许组件执行这些操作的授权策略。有关定义授权策略的信息，请参阅[授权组件执行 IPC 操作](interprocess-communication.md#ipc-authorization-policies)。

客户端设备身份验证和授权的授权策略具有以下属性。

**IPC 服务标识符：**`aws.greengrass.clientdevices.Auth`


| 操作 | 说明 | 资源 | 
| --- | --- | --- | 
|  `aws.greengrass#VerifyClientDeviceIdentity`  |  允许组件验证客户端设备的身份。  |  `*`  | 
|  `aws.greengrass#GetClientDeviceAuthToken`  |  允许组件验证客户端设备的凭证并为该客户端设备创建会话。  |  `*`  | 
|  `aws.greengrass#AuthorizeClientDeviceAction`  |  允许组件验证客户端设备是否有权执行某项操作。  |  `*`  | 
|  `aws.greengrass#SubscribeToCertificateUpdates`  |  允许组件在核心设备的服务器证书轮换时接收通知。  |  `*`  | 
|  `*`  |  允许组件执行所有客户端设备身份验证 IPC 服务操作。  |  `*`  | 

### 授权策略示例
<a name="ipc-client-device-auth-authorization-policy-examples"></a>

您可以参考以下授权策略示例，帮助您为组件配置授权策略。

**Example 示例授权策略**  
以下示例授权策略允许组件执行所有客户端设备身份验证 IPC 操作。  

```
{
  "accessControl": {
    "aws.greengrass.clientdevices.Auth": {
      "com.example.MyLocalBrokerComponent:clientdevices:1": {
        "policyDescription": "Allows access to authenticate and authorize client devices.",
        "operations": [
          "aws.greengrass#VerifyClientDeviceIdentity",
          "aws.greengrass#GetClientDeviceAuthToken",
          "aws.greengrass#AuthorizeClientDeviceAction",
          "aws.greengrass#SubscribeToCertificateUpdates"
        ],
        "resources": [
          "*"
        ]
      }
    }
  }
}
```

## VerifyClientDeviceIdentity
<a name="ipc-operation-verifyclientdeviceidentity"></a>

验证客户端设备的身份。此操作验证客户端设备是否有效 AWS IoT 。

### 请求
<a name="ipc-operation-verifyclientdeviceidentity-request"></a>

此操作的请求包含以下参数：

`credential`  
客户端设备的凭证。此对象 `ClientDeviceCredential` 包含以下信息：    
`clientDeviceCertificate`（Python：`client_device_certificate`）  
客户端设备的 X.509 设备证书。

### 响应
<a name="ipc-operation-verifyclientdeviceidentity-response"></a>

此操作的响应包含以下信息：

`isValidClientDevice`（Python：`is_valid_client_device`）  
客户端设备的身份是否有效。

## GetClientDeviceAuthToken
<a name="ipc-operation-getclientdeviceauthtoken"></a>

验证客户端设备的凭证并为客户端设备创建会话。此操作会返回一个会话令牌，您可以在后续请求中使用该令牌来[授权客户端设备操作](#ipc-operation-authorizeclientdeviceaction)。

要成功连接客户端设备，[客户端设备身份验证组件](client-device-auth-component.md#client-device-auth-component-configuration)必须向客户端设备使用的客户端 ID 授予 `mqtt:connect` 权限。

### 请求
<a name="ipc-operation-getclientdeviceauthtoken-request"></a>

此操作的请求包含以下参数：

`credential`  
客户端设备的凭证。此对象 `CredentialDocument` 包含以下信息：    
`mqttCredential`（Python：`mqtt_credential`）  
客户端设备的 MQTT 凭证。指定客户端设备用于连接的客户端 ID 和证书。此对象 `MQTTCredential` 包含以下信息：    
`clientId`（Python：`client_id`）  
用于连接的客户端 ID。  
`certificatePem`（Python：`certificate_pem`）  
用于连接的 X.509 设备证书。  
`username`  
目前尚未使用该属性。  
`password`  
目前尚未使用该属性。

### 响应
<a name="ipc-operation-getclientdeviceauthtoken-response"></a>

此操作的响应包含以下信息：

`clientDeviceAuthToken`（Python：`client_device_auth_token`）  
客户端设备的会话令牌。您可以在后续请求中使用此会话令牌来授权此客户端设备的操作。

## AuthorizeClientDeviceAction
<a name="ipc-operation-authorizeclientdeviceaction"></a>

验证客户端设备是否有权对资源执行某项操作。*客户端设备授权策略*指定了客户端设备在连接到核心设备时可以执行的权限。在配置[客户端设备身份验证组件](client-device-auth-component.md#client-device-auth-component-configuration)时，可以定义客户端设备授权策略。

### 请求
<a name="ipc-operation-authorizeclientdeviceaction-request"></a>

此操作的请求包含以下参数：

`clientDeviceAuthToken`（Python：`client_device_auth_token`）  
客户端设备的会话令牌。

`operation`  
要授权的操作。

`resource`  
客户端设备执行操作的资源。

### 响应
<a name="ipc-operation-authorizeclientdeviceaction-response"></a>

此操作的响应包含以下信息：

`isAuthorized`（Python：`is_authorized`）  
客户端设备是否有权对资源执行操作。

## SubscribeToCertificateUpdates
<a name="ipc-operation-subscribetocertificateupdates"></a>

订阅即可在每次轮换时接收核心设备的新服务器证书。服务器证书轮换时，代理必须使用新的服务器证书重新加载。

默认情况下，[客户端设备身份验证组件](client-device-auth-component.md)每 7 天轮换一次服务器证书。您可以将轮换间隔配置为 2 到 10 天。

<a name="ipc-subscribe-operation-note"></a>此操作是一种订阅操作，您可以在其中订阅事件消息流。要使用此操作，请定义一个流响应处理程序，其中包含处理事件消息、错误和流关闭的函数。有关更多信息，请参阅 [订阅 IPC 事件流](interprocess-communication.md#ipc-subscribe-operations)。

**事件消息类型：**`CertificateUpdateEvent`

### 请求
<a name="ipc-operation-subscribetocertificateupdates-request"></a>

此操作的请求包含以下参数：

`certificateOptions`（Python：`certificate_options`）  
要订阅的证书更新类型。此对象 `CertificateOptions` 包含以下信息：    
`certificateType`（Python：`certificate_type`）  
要订阅的证书更新类型。选择以下选项：  
+ `SERVER`

### 响应
<a name="ipc-operation-subscribetocertificateupdates-response"></a>

此操作的响应包含以下信息：

`messages`  
消息流。此对象 `CertificateUpdateEvent` 包含以下信息：    
`certificateUpdate`（Python：`certificate_update`）  
有关新证书的信息。此对象 `CertificateUpdate` 包含以下信息：    
`certificate`  
证书。  
`privateKey`（Python：`private_key`）  
证书的私钥。  
`publicKey`（Python：`public_key`）  
证书的公钥。  
`caCertificates`（Python：`ca_certificates`）  
证书的颁发机构（CA）证书链中的 CA 证书列表。