@crvouga/mockingbird-service-aws-iot (英语)
本地模拟器。 真正的API合同. 部分 嘲笑鸟。 。 。 .
国家模拟器 AWS IOT 核心数据平面 测试套房和地方开发:
IoTData 计划 Publish hTTP 有签名版本 4 验证和 MQTT 5 信件
tCP和WebSocket的经纪人(/mqtt)与自定义授权政策,AWS IoT的持久性
课程规则及其与 MQTT 规格的偏离。 它在测试中运行
在没有 AWS 账户的 OS 指定端口上进行处理,会话到期会跟随套件的时钟
移动而不是等待.
- 行动覆盖( HTTP): 支助
- 没有AWS账户被用作甲骨文. 行为遵循 发布 API 引用, (中文(简体) ), 页:1 MQTT 数据, (中文(简体) ), 自定义认证, (中文(简体) ), 政策 财务报告和审定财务报表 配额 页面,以及AWS的SDK标志. 未结算的列在下面 未核实。 。 。 .
- 这不是EM Q的模仿者 与另一个名字:
(单位:千美元)
@crvouga/mockingbird-service-emqx)),各随自取.
安装
npm install -D @crvouga/mockingbird-service-aws-iot
仅限无害环境管理。 节点 22或 Bun 1.2. 无土生属地. 给它服务
npx mockingbird-aws-iot serve 或者说 createServer 从 ./server (节点和邦). createRuntime
(默认条目)是可移植的:服务 Publish 结束 fetch 和 MQTT 通过
runtime.attach没有听者.
使用量
将应用程序的 IOT 数据端点指向 url 及其在 mqttUrl 或者说 wsUrl没有
TLS: 使用 http://, (中文(简体) ), mqtt:// 财务报告和审定财务报表 ws:// 给定的 URL .
import { createServer } from "@crvouga/mockingbird-service-aws-iot/server"
import { IoTDataPlaneClient, PublishCommand } from "@aws-sdk/client-iot-data-plane"
import mqtt from "mqtt"
// Test setup: start the emulator with the credentials and authorizer policies the test needs.
const arn = (resource: string) => `arn:aws:iot:us-east-1:123456789012:${resource}`
const iot = await createServer({
settings: {
// HTTP: SigV4 signatures are verified against these keys.
credentials: [{ accessKeyId: "test-key", secretAccessKey: "test-secret" }],
// MQTT: what the custom authorizer answers for a username and password.
authorizers: [
{
username: "alice",
password: "alice-token",
policyDocuments: [
{
Version: "2012-10-17",
Statement: [
{ Effect: "Allow", Action: "iot:Connect", Resource: arn("client/alice-*") },
{ Effect: "Allow", Action: "iot:Subscribe", Resource: arn("topicfilter/user/alice") },
{ Effect: "Allow", Action: "iot:Receive", Resource: arn("topic/user/alice") },
],
},
],
},
],
},
})
// Application code: the MQTT client and AWS SDK client it already uses, pointed at the emulator.
const device = await mqtt.connectAsync(iot.mqttUrl, {
protocolVersion: 5,
clientId: "alice-phone",
clean: false,
properties: { sessionExpiryInterval: 600 },
username: "alice",
password: "alice-token",
})
await device.subscribeAsync("user/alice", { qos: 1 })
const client = new IoTDataPlaneClient({
region: "us-east-1",
endpoint: iot.url,
credentials: { accessKeyId: "test-key", secretAccessKey: "test-secret" },
})
await client.send(new PublishCommand({ topic: "user/alice", qos: 1, payload: '{"hello":"alice"}' }))
await device.endAsync()
await iot.close() // closes every listener and drops every client
npx mockingbird-aws-iot serve --port 8851 --mqtt-port 8883 \
--credential test-key:test-secret --settings ./aws-iot-settings.json
每个 createServer() 是它自己拥有自己的港口的经纪人,其中两个没有分享任何东西。 下
邦顿, mqtt节点 WebSocket 传输没有启动( Bun) ws 没有
createWebSocketStream,所以连接到 wsUrl 与库的浏览器传输
(单位:千美元)new MqttClient((c) => browserStreamBuilder(c, options), options) 从 mqtt/lib/connect/ws, (中文(简体) ),
或用途 connectStream(runtime) 从 ./server 用于无套接字连接。 在平原的节点上
mqtt.connect("ws://…/mqtt") 工作时.
话题是客户发送的。 AWS IOT 与 / 并给出 : 没有意义,
因此,一个名为主题的应用程序 user:example 并公布为 user/example 这样做
映射本身;模拟器像AWS一样,从未看到第一个形式.
路线
| 路线 | 行为 |
|---|---|
POST /topics/{topic}?qos=0|1 | IoTData 计划 Publish身体是有效载荷,作为发送的字节。 话题为 %- 解码一次( Q)user%2Fexample 实值 user/example· ; a%252Fb 字义 a%2Fb);未编码的鞭打也被接受,如AWS本身的例子. 200 {"message": "OK", "traceId": "…"} 无论是否有人订阅。 另见: retain, (中文(简体) ), contentType, (中文(简体) ), responseTopic, (中文(简体) ), messageExpiry (调整为1-60480) x-amz-mqtt5-user-properties, (中文(简体) ), x-amz-mqtt5-payload-format-indicator 财务报告和审定财务报表 x-amz-mqtt5-correlation-data 信头, 以 MQTT 5 属性覆盖订阅者 . |
| 错误 | {"message": "…", "traceId": "…"} 与 x-amzn-ErrorType。 。 。 . 400 InvalidRequestException 对于一个已空出、有通配符、超过256字节或7下划线或从 $页:1 qos 0或1以外; 错误 retain, (中文(简体) ), messageExpiry 或 MQTT 5 头; 畸形% 逃出; 有效载荷超过 128 KB. 401 UnauthorizedException 当签名身份政策不允许时 iot:Publish 关于这个话题. 403 (单位:千美元)Forbidden请求未经签字或其签字未核实. 405 MethodNotAllowedException 对于任何其他动词或路径。 一个 x-mockingbird-reason 信头显示检查失败 . |
SigV4 (英语). 与 credentials 空的, 任何包含一个完整格式的请求
Authorization: AWS4-HMAC-SHA256 … 信头不被验证(作为Mockingbird的另一个AWS)
模拟者也这样做),未签名的请求仍然被拒绝. 已配置了证书
签名必须验证:服务 iotdata,配置的区域, host 财务报告和审定财务报表 x-amz-date 签名,
路径在犬科请求中编码了第二次(除了S3之外的所有服务),有效载荷
将身体的SHA -256,和 x-amz-security-token 匹配临时证书.
证书的 policyDocuments当给定时,必须允许 iot:Publish 打开
arn:aws:iot:<region>:<account>:topic/<topic>。 。 。 .
MQTT 数据
MQTT 5.0 在TCP和WebSocket上运行 /mqtt (副议定书) mqtt) (中文(简体) ). 都一样
各届会议和同一届会议 Publish 送货给.
| 区域 | 行为 |
|---|---|
| 认证 | 只自定义认证 . authorizers 使用 MQTT 用户名和密码( 用户名) 列出自定义授权者的结果 ?x-amz-customauthorizer-name=… 查询读取或删除;或 通过 authorizer 改为 createRuntime,接收 Lambda 事件的函数(protocolData.mqtt.{username, password (base64), clientId}返回时 {isAuthenticated, principalId, policyDocuments}。没有匹配条目, isAuthenticated: false,或不允许 iot:Connect 打开 client/<clientId> 关闭 0x87。由于既没有配置每个客户端的连接,所以允许一切. |
| 政策 | iot:Connect 打开 client/<id>, (中文(简体) ), iot:Publish 财务报告和审定财务报表 iot:Receive 打开 topic/<name>, (中文(简体) ), iot:Subscribe 打开 topicfilter/<filter>默认拒绝; 明示 Deny 覆盖任意 Allow。 。 。 . * 财务报告和审定财务报表 ? 为通配符( e)* ; MQTT 级别 + 财务报告和审定财务报表 # 在策略中是普通字符,所以策略必须给客户端订阅的过滤器命名. ${iot:ClientId} 扩张。 一个否认的子公司是SUBACK 0x87; 被拒绝的Qos 1 PUBLISH 是 PUBACK 0x87; 无 iot:Receive 对于一个话题,默默地从它没有得到任何东西. |
| 结束 | 最大QoS 1, 保留可用 0 (见下文), 最大包大小 149504, Topy Alias 最大 8, 接受最大 100, Wildcard 订阅 可用 1, 订阅标识 可用 0, 共享订阅 可用 0. 服务器在 AWS 更改客户端时保持存活 : 1200 for 0 或超过1200人,30人不满30人. |
| 常年会议 | Clean Start 0,会话间隔超过 0 。 间隔以账户配额为上限(persistentSessionExpirySeconds,默认1小时,最多7天),调整后的价值在CONNACK中返回. 一个会话只保留其订阅和QoS 1消息(QoS 0没有被存储). 连接结束时开始计时器; 到期时会话及其队列被丢弃 . |
| 客户端 ID | 最多128个字节( CONNACK) 0x85 页:1 接受与连接客户端 ID 的第二个连接,并发送第一个 DICONNECT 0x8E。 。 。 . |
| 专题 | 最多 256 字节和 7 前向斜线; 话题和过滤器开始 $ 被拒绝(SUBACK) 0x8F胶片 0x90) (中文(简体) ). sensor/# 匹配 sensor/ 财务报告和审定财务报表 sensor/a/b 没有 sensor。 。 。 . |
| 基辅语Name | 0和1. 要求QoS 2的子公司得不到分包;QoS 2 PUBLISH被回答 0x9B。没有人订阅的刊物会被确认 0x00。 。 。 . |
| 有效载荷 | 最多128 KB;一个更大的PUBLISH断开客户端. |
| 订阅标识符 | 不支持,如关于AWS:DICONNECT 0xA1。 。 。 . |
管理员(超过标准合同)
| 路线 | 效果 |
|---|---|
GET /__admin/publishes | {total, publishes}: 接受的最后1000种出版物为元数据(topic, (中文(简体) ), qos, (中文(简体) ), bytes, (中文(简体) ), source: "http" | "mqtt" | "admin", (中文(简体) ), clientId, (中文(简体) ), matched, (中文(简体) ), at) (中文(简体) ). 有效载荷从不保存. |
GET /__admin/clients, (中文(简体) ), GET /__admin/clients/:clientId | 会话 : connected, (中文(简体) ), transport, (中文(简体) ), sessionExpiryInterval, (中文(简体) ), expiresAt,计数 subscriptions, (中文(简体) ), queued, (中文(简体) ), inflight; 其中一会还列出其 topics。 。 。 . |
GET /__admin/subscriptions?clientId= | 订阅: topicFilter,准予 qos,选项. |
POST /__admin/inject | {topic, payload | payloadBase64, qos?: 0 | 1}:向该话题的订阅者提供生字节,绕过签名,验证并发布政策(iot:Receive 页:1 用它来表示一个消费者的解析器必须拒绝。 答复 {matched}。 。 。 . |
POST /__admin/transport/cut | {clientId?}:一个客户端或所有客户端的网络断电. 现场连接因没有DICONNECT而死亡,新的CONNECT被放弃,没有得到答复. 会话未受影响,按自己的时间安排过期. |
POST /__admin/transport/restore | {clientId?}:结束停产. GET /__admin/transport 列出切出的内容. |
POST /__admin/clients/:clientId/disconnect | {reasonCode?}: 发送 DICONNECT( 默认) 0x98)和结束;会议将停止. |
GET 编号 : PUT /__admin/settings | {credentials?, authorizers?, region?, accountId?, persistentSessionExpirySeconds?} 呼叫的命名空间。 无法评估的仿真文件被拒绝使用 400重置运行时间创建的值的返回. |
POST /__admin/clock | 标准 移动时钟解决会话即时失效. |
POST /__admin/reset检查站 | 标准 重置会降低每个连接和会话 。 恢复检查点会恢复会话,订阅和队列,并会减少直播连接. |
错误预设( E)POST /__admin/faults {"preset": "<name>", "count"?: n}· ; GET /__admin/faults/presets:
publish_throttled (单位:千美元)429 ThrottlingException, (中文(简体) ), publish_unauthorized (单位:千美元)401 UnauthorizedException, (中文(简体) ), publish_internal_failure (单位:千美元)500 InternalFailureException, (中文(简体) ),
connect_not_authorized (结束) 0x87, (中文(简体) ), connect_bad_credentials (单位:千美元)0x86, (中文(简体) ),
connect_quota_exceeded (单位:千美元)0x97) (中文(简体) ). CONNECT是故障操作 MqttConnect,所以任何原因
代码可以强制 : {"operationId": "MqttConnect", "effect": "connack", "params": {"reasonCode": 137}}。 。 。 .
命名空间
平行工人通过命名空间孤立自己. HTTP : (韩语) x-mockingbird-namespace页:1
/__admin/ns/<name> 前缀在终点,或通过访问密钥 id
(单位:千美元)PUT /__admin/credentials {"credentials": {"<AWS_ACCESS_KEY_ID>": "<namespace>"}}(原始内容存档于2017-09-26). MQTT: the
WebSocket URL 网络软件 ws://…/__admin/ns/<name>/mqtt,或由 CONNECT 键入的同一证书地图
用户名(没有查询字符串),然后是其客户端 ID。 未实现客户端使用默认值
名称空间.
未核实
文档不会解决这些问题; 模拟者的选择被声明为套房不会 给卖家弄错了
- 圆满之体. API的参考文献说
Publish回答空正文; AWS 的自定义 认证教程显示{"message": "OK", "traceId": "…"}。模拟器发送 后者,SDK忽略了这一点. - 拒证. 未签名的请求或未验证仿真器的签名
答题
403 {"message": "Forbidden", "traceId"}与x-amzn-ErrorType: ForbiddenException数字 : 主体是拒绝的自定义授权签名的 AWS 文件、状态和 标题是推断的。 用于有效签名而无需iot:Publish它回答了文件401 UnauthorizedException;无论AWS回答401还是403,都没有确认. - AWS 是否发送
x-amzn-ErrorType,则message每个文本400,则 HTTP 错误 128 KB以上的有效载荷(模拟器用途)400 InvalidRequestException) (中文(简体) ). - "128 KB"和"146 KB"被取为131072和149504字节. AWS的MQTT页面也提到 最大包大小"不能超过128 KB";使用配额页146 KB.
- 客户所看到的
isAuthenticated: false(AWS说它"结束了连接"; 模拟器发送 CONNACK0x87首先,对于一个超越限制范围或始于$(AWS说此类操作"可以导致终止连接";模拟器回答 苏巴克0x8F/ 弹夹0x90并保持连接),以及超大小的MQTT有效载荷 (DISCONENECT 存档副本)0x95) (中文(简体) ). - 一个QoS 2 子公司获得没有SUBACK是AWS的有记录的行为,在没有协议的情况下声明 版本;它被应用于已写入的 MQTT 5 .
- 当服务器保持生存时,接收最大值(100, 从未承认出版物配额中提取)
发送,指定客户端 ID 的格式,以及 Lambda 事件是否
username包括查询字符串(模拟器将其剥去). - 签名日期不与时钟相对照,所以套房可以冻结时间.
故意不模拟
- MQTT 3.1和3.1.1(与该协议的回回码重用), TLS, X. 509 客户端 证书、 ALPN 和 SNI 以及 SigV4 指定的 WebSocket URL .
- 自定义对 HTTP 、 符号签名和
disconnectAfterInSeconds编号 :refreshAfterInSeconds(接受,未执行). - 政策
Condition, (中文(简体) ),NotAction财务报告和审定财务报表NotResource(拒绝使用这些文件)政策 变量${iot:ClientId},以及iot:RetainPublish。 。 。 . - 保留消息: CONNACK 表示保留可使用 0, 保留 MQTT 的发布被解答
分解系统
0x9A,以及retain=true超过HTTP是400AWS本身支持它们. - 将信件(收受于CONNECT,从未发布),共享订阅(SUBACK)
0x9E, (中文(简体) ), 保留动态超时、消息过期、外出主题别名和保留$aws/…专题. - 比率和计数配额(每秒publishes、每条连接或每条附属CRIBE、, 存储会话的每秒重放10个消息.
- 记录 阴影 规则和行动 工作 供给 其它数据平面 业务、账单和基础设施管理.
API 密码
| 导出 | 仁爱 | 说明 |
|---|---|---|
createRuntime | 函数 | 服务合同的模拟者。 选项 : settings, (中文(简体) ), authorizer, (中文(简体) ), clock, (中文(简体) ), seed, (中文(简体) ), adminPrefix, (中文(简体) ), adminKey, (中文(简体) ), onLog, (中文(简体) ), sqlite添加 attach(transport, info?, namespace?) 为 MQTT 连接, webSocketPath(pathname), (中文(简体) ), endpoints,以及 stop()。 。 。 . |
AwsIotAPI | 类 | 一个命名空间 : fetch(request) 页:1 Publish, (中文(简体) ), broker 为MQTT, state, (中文(简体) ), reset()选项: sqlite, (中文(简体) ), now, (中文(简体) ), namespace, (中文(简体) ), settings, (中文(简体) ), authorizer, (中文(简体) ), connectFault。 。 。 . |
AWS_IOT_PRESETS | 对象 | 每个命名的断层预设. |
AWS_IOT_NAMESPACE | 字符串 | 服务名称, "aws-iot"。 。 。 . |
SIGNING_NAME | 字符串 | "iotdata",SigV4签名名称. |
MQTT_CONNECT_OPERATION, (中文(简体) ), MQTT_WEBSOCKET_PATH | 字符串 | "MqttConnect"(一) 操作id出错规则用于CONNECT;以及 "/mqtt"。 。 。 . |
MAX_PAYLOAD_BYTES, (中文(简体) ), MAX_PACKET_SIZE, (中文(简体) ), MAX_TOPIC_BYTES, (中文(简体) ), MAX_TOPIC_SLASHES, (中文(简体) ), MAX_CLIENT_ID_BYTES, (中文(简体) ), MAX_MESSAGE_EXPIRY_SECONDS, (中文(简体) ), MAX_PERSISTENT_SESSION_EXPIRY_SECONDS, (中文(简体) ), KEEP_ALIVE_RANGE | 数字 | AWS IOT Core的极限是模拟器执行的. |
DEFAULT_SETTINGS | 对象 | 地区 us-east-1账户 123456789012,无证书或授权人,1小时会议配额. |
parseSettings | 函数 | 验证 JSON 的设置补丁; 丢出错误字段的命名 . |
parsePolicyDocument, (中文(简体) ), isAllowed, (中文(简体) ), resourceArn, (中文(简体) ), PolicyError | 函数,类 | 分析一个政策文件(对象或JSON字符串),对它进行动作和目标评价,并构建 ARN 以检查动作. |
accessKeyCredential, (中文(简体) ), splitUsername | 函数 | 已签名请求的存取密钥 ID; MQTT 用户名和授权方的查询字符串名( 如何将权限映射到命名空间) . |
ReasonCode | 对象 | MQTT 5 名下理性码. |
document, (中文(简体) ), operationIds, (中文(简体) ), supportedOperationIds | 数值 | HTTP合同及其操作代号. |
createServer, (中文(简体) ), connectStream, (中文(简体) ), loadSettingsFile, (中文(简体) ), serveTarget, (中文(简体) ), DEFAULT_PORT, (中文(简体) ), DEFAULT_MQTT_PORT (单位:千美元)./server(中文(简体) ) | 节点 | 服务HTTP、WebSocket和TCP{url, mqttUrl, mqttPort, wsUrl, runtime, close()}; 选项添加 port, (中文(简体) ), mqttPort, (中文(简体) ), host, (中文(简体) ), sweepMs; 正在处理的 MQTT 流; 读取 --settings 文件; 该 serve CLI目标;港口8851和8883. |
部分 嘲笑鸟。 。 。 .