MQTT - emqx.io 서비스 소개
winget에서도 볼 수 있는 emqx.mqttx 서비스가 있는데요,
C:temp> winget search --name mqtt
Name Id Version
---------------------------------------------------
MQTT Explorer thomasnordquist.MQTT-Explorer 0.3.5
mqttx emqx.mqttx 1.5.2
해당 사이트에서 직접 zip 파일을 다운로드해,
EMQ X Broker
; https://www.emqx.io/downloads#broker
emqx-windows-4.3.2.zip
; https://www.emqx.io/downloads/broker/v4.3.2/emqx-windows-4.3.2.zip
압축 해제 후 실행해 볼 수도 있습니다. 관련한 명령행 옵션은 다음의 문서에서 확인할 수 있고,
Start EMQ X
; https://docs.emqx.io/en/broker/v4.3/getting-started/start.html
따라서 명령행에서 단순히 ".\bin\emqx start"를 관리자 권한으로 실행하면 erl.exe가 다음의 명령행으로 실행되고,
C:\tmp\emqx\erts-11.0\bin\erl.exe -e 256000 -- -root C:\tmp\emqx -progname erl.exe -- -home "C:\Users\SeongTae Jeong" -- -noshell -noinput -setcookie emqxsecretcookie -name emqx@127.0.0.1 -- -vm_args c:/tmp/emqx/data/configs/vm.2021.06.04.13.38.15.args -mnesia dir 'c:/tmp/emqx/data/mnesia/emqx@127.0.0.1' -- -boot C:\tmp\emqx\releases\4.3.2\start -config c:/tmp/emqx/data/configs/app.2021.06.04.13.38.15.config
서비스 상태는 이렇게 조회할 수 있으며,
C:\tmp\emqx> .\bin\emqx_ctl status
Node 'emqx@127.0.0.1' 4.3.2 is started
종료하려면 ".\bin\emqx stop" 명령어를 내리면 됩니다.
EMQ X Broker는 REST API를 제공하기 때문에 아래의 문서에 따라 쉽게 테스트하는 것이 가능합니다.
HTTP API
; https://docs.emqx.io/en/broker/v4.3/advanced/http-api.html#api-endpoints
몇 개를 추려서 한 번 실습해 볼까요? 우선 MQTT broker가 정상적으로 실행되었는지를 알 수 있습니다. (
json_pp 명령어)
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/brokers" 2> nul | json_ppM
{
"data": [
{
"version": "4.3.2",
"uptime": "1 hours, 6 minutes, 17 seconds",
"sysdescr": "EMQ X",
"otp_release": "23.0/11.0",
"node_status": "Running",
"node": "emqx@127.0.0.1",
"datetime": "2021-06-04 23:08:26"
}
],
"code": 0
}
보는 바와 같이 "emqx@127.0.0.1"로 식별되는 노드 1개가 실행 중임을 알 수 있고, 해당 broker만 지정해 조회할 수도 있습니다.
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/brokers/emqx@127.0.0.1"
node 개념이 있는 것을 보니 클러스터 구성이 가능한 것 같은데요, 그래서 nodes 조회로도 환경을 검색할 수 있습니다.
c:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/nodes" 2> nul | json_pp
{
"data": [
{
"version": "4.3.2",
"uptime": "1 hours, 9 minutes, 37 seconds",
"process_used": 326,
"process_available": 262144,
"otp_release": "23.0/11.0",
"node_status": "Running",
"node": "emqx@127.0.0.1",
"memory_used": "54.37M",
"memory_total": "71.69M",
"max_fds": 16384,
"load5": "0.00",
"load15": "0.00",
"load1": "0.00",
"connections": 1
}
],
"code": 0
}
이것 역시 node를 지정해 조회할 수 있습니다.
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/nodes/emqx@127.0.0.1"
MQTT broker에 대한 서비스를 제공하는 listener를 다음의 명령어로 조회할 수 있고,
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/listeners" 2> nul | json_pp
{
"data": [
{
"node": "emqx@127.0.0.1",
"listeners": [
{
"shutdown_count": [],
"protocol": "mqtt:ssl",
"max_conns": 102400,
"listen_on": "8883",
"identifier": "mqtt:ssl:external",
"current_conns": 0,
"acceptors": 16
},
{
"shutdown_count": [],
"protocol": "mqtt:tcp",
"max_conns": 1024000,
"listen_on": "0.0.0.0:1883",
"identifier": "mqtt:tcp:external",
"current_conns": 0,
"acceptors": 8
},
{
"shutdown_count": [],
"protocol": "mqtt:tcp",
"max_conns": 1024000,
"listen_on": "127.0.0.1:11883",
"identifier": "mqtt:tcp:internal",
"current_conns": 0,
"acceptors": 4
},
{
"shutdown_count": [],
"protocol": "http:dashboard",
"max_conns": 512,
"listen_on": "18083",
"current_conns": 0,
"acceptors": 4
},
{
"shutdown_count": [],
"protocol": "http:management",
"max_conns": 512,
"listen_on": "8081",
"current_conns": 1,
"acceptors": 2
},
{
"shutdown_count": [],
"protocol": "mqtt:ws:8083",
"max_conns": 102400,
"listen_on": "8083",
"current_conns": 0,
"acceptors": 4
},
{
"shutdown_count": [],
"protocol": "mqtt:wss:8084",
"max_conns": 16,
"listen_on": "8084",
"current_conns": 0,
"acceptors": 4
}
]
}
],
"code": 0
}
특정 리스너의 재시작도 가능합니다.
C:\temp> curl --basic -u admin:public -X PUT "http://localhost:8081/api/v4/listeners/mqtt:tcp:external/restart"
{"code":0}
여기서 mqtt:management는 우리가 지금 REST API를 수행할 수 있도록 하는 listener입니다. 그리고, mqtt:tcp가 바로 MQTT broker의 endpoint인데요, 실제로 이 포트로 지난 글에서 만든 MqttClient를,
C# - MQTT를 이용한 클라이언트/서버(Broker) 통신 예제
; https://www.sysnet.pe.kr/2/0/12661
포트만 mqtt:tcp가 대기하는 1883으로 바꾸면,
ManagedMqttClientOptions options = new ManagedMqttClientOptions();
options.ClientOptions = new MqttClientOptions()
{
ClientId = "MyMqttClient",
ChannelOptions = new MqttClientTcpOptions
{
Server = "localhost",
Port = 1883,
}
};
접속이 됩니다. 위와 같이 변경하고 실행하면 EMQ X Broker에 연결된 MQTT client를 다음의 API로 조회할 수 있습니다.
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/clients?_page=1&_limit=10"
실습할 때는 클라이언트가 몇 개 없을 테니 그냥 전체 조회를 해도 됩니다.
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/clients" 2> nul | json_pp
{
"meta": {
"page": 1,
"limit": 10000,
"hasnext": false,
"count": 1
},
"data": [
{
"recv_cnt": 5,
"heap_size": 2586,
"recv_pkt": 5,
"connected_at": "2021-06-04 23:00:21",
"node": "emqx@127.0.0.1",
"send_oct": 14,
"max_subscriptions": 0,
"send_msg": 0,
"reductions": 75586,
"proto_ver": 4,
"mqueue_dropped": 0,
"mqueue_len": 0,
"expiry_interval": 0,
"keepalive": 15,
"recv_oct": 104,
"is_bridge": false,
"send_pkt": 3,
"created_at": "2021-06-04 23:00:21",
"mailbox_len": 1,
"max_mqueue": 1000,
"port": 26175,
"zone": "external",
"inflight": 0,
"recv_msg": 3,
"mountpoint": "undefined",
"proto_name": "MQTT",
"awaiting_rel": 0,
"max_inflight": 32,
"subscriptions_cnt": 2,
"clientid": "MyMqttClient",
"username": "undefined",
"max_awaiting_rel": 100,
"clean_start": true,
"connected": true,
"send_cnt": 3,
"ip_address": "127.0.0.1"
}
],
"code": 0
}
보는 바와 같이 우리가 MQTTnet을 이용해 만든 "MyMqttClient"가 보입니다. 전체 조회뿐만 아니라, 특정 clientid를 지정해 조회할 수도 있고,
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/clients/MyMqttClient"
해당 클라이언트를 강제로 접속 해제하는 것도 가능합니다.
curl -i --basic -u admin:public -X DELETE "http://localhost:8081/api/v4/clients/MyMqttClient"
그런데 위의 명령어를 내린 후 다시 "GET /api/v4/clients"로 알아 보면 해당 클라이언트가 여전히 붙어 있습니다. 하지만 분명히 연결 종료는 되었는데, 이것은 Process Explorer를 통해 TCP 연결이 삭제된 것으로 확인할 수 있습니다. 연결이 여전히 붙어있는 이유는, 우리가 만든 MqttClient의 코드 중에 재접속을 자동으로 하는 옵션이 있었기 때문입니다.
options.AutoReconnectDelay = TimeSpan.FromSeconds(1);
이 설정으로 인해 1초 만에 재차 연결을 했기 때문에 "GET /api/v4/clients"를 했을 때 여전히 연결이 붙은 것처럼 보인 것입니다.
이하, 다음의 명령들은 직관적으로 어떤 결과를 나타낼지 상상할 수 있을 것입니다.
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/nodes/emqx@127.0.0.1/clients?_page=1&_limit=10"
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/nodes/emqx@127.0.0.1/clients"
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/nodes/emqx@127.0.0.1/clients/MyMqttClient"
curl --basic -u admin:public -X DELETE "http://localhost:8081/api/v4/nodes/emqx@127.0.0.1/clients/MyMqttClient"
(참고로, 위에서 nodes/.../clients/...로 DELETE하는 명령어는 제가 실습했을 때 정상 동작을 하지 않았습니다.)
재미있는 것은, Broker에 등록된 topic과 그 클라이언트 목록을 조회하는 것도 가능해서,
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/subscriptions?_page=1&_limit=10"
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/nodes/emqx@127.0.0.1/subscriptions?_page=1&limit=10"
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/nodes/emqx@127.0.0.1/subscriptions/MyMqttClient"
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/subscriptions/MyMqttClient"
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/subscriptions" 2> nul | json_pp
{
"meta": {
"page": 1,
"limit": 10000,
"hasnext": false,
"count": 2
},
"data": [
{
"topic": "xyz",
"qos": 0,
"node": "emqx@127.0.0.1",
"clientid": "MyMqttClient"
},
{
"topic": "abc",
"qos": 0,
"node": "emqx@127.0.0.1",
"clientid": "MyMqttClient"
}
],
"code": 0
}
개발 시 테스트 용도로 편리하게 사용할 수 있습니다. (위에서 "xyz", "abc"가 나온 것은 MqttClient의 코드에서 해당 토픽을 구독하도록 했기 때문입니다.)
await managedClient.SubscribeAsync(new MqttTopicFilter { Topic = "xyz", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
await managedClient.SubscribeAsync(new MqttTopicFilter { Topic = "abc", QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce });
아울러 토픽에 메시지를 전송할 수 있고,
c:\temp> curl --basic -u admin:public -X POST "http://localhost:8081/api/v4/mqtt/publish" -d "{\"topic\":\"abc\",\"payload\":\"Hello World\",\"qos\":1,\"retain\":false,\"clientid\":\"MyMqttClient3\"}"
{"code":0}
특정 클라이언트에 토픽을 구독시키는 것도 가능합니다. 아래는 "test1", "test2"라는 새로운 토픽을 현재 연결된 MyMqttClient에 구독시키고 있습니다.
c:\temp> curl --basic -u admin:public -X POST "http://localhost:8081/api/v4/mqtt/subscribe" -d "{\"topics\":\"test1,test2\",\"qos\":1,\"clientid\":\"MyMqttClient\"}"
{"code":0}
확인은 publish API로 실행하면,
C:\temp> curl --basic -u admin:public -X POST "http://localhost:8081/api/v4/mqtt/publish" -d "{\"topic\":\"test1\",\"payload\":\"Hello World\",\"qos\":1,\"retain\":false,\"clientid\":\"MyMqttClient3\"}"
{"code":0}
MqttClient 화면에 ">> RECEIVED: test1"의 출력으로 알 수 있습니다.
당연히, 토픽 구독을 해제하는 것도 가능합니다.
curl --basic -u admin:public -X POST "http://localhost:8081/api/v4/mqtt/unsubscribe" -d "{\"topic\":\"test2\",\"qos\":1,\"clientid\":\"MyMqttClient\"}"
curl --basic -u admin:public -X POST "http://localhost:8081/api/v4/mqtt/unsubscribe" -d "{\"topic\":\"test1\",\"qos\":1,\"clientid\":\"MyMqttClient\"}"
REST API를 보면 사용자 계정으로 조회하는 것도 볼 수 있습니다.
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/clients/username/{username}"
위의 명령어는 해당 사용자 계정으로 실행 중인 모든 클라이언트를 열거하는데요, 이를 실습하기 위해서는 MqttClient의 코드에서 "Credentials" 속성을 다음과 같이 부여해 실행해야 합니다.
options.ClientOptions = new MqttClientOptions()
{
ClientId = "MyMqttClient",
Credentials = new RandomPassword(),
ChannelOptions = new MqttClientTcpOptions
{
Server = "localhost",
Port = 1883,
}
};
public class RandomPassword : IMqttClientCredentials
{
public byte[] Password => Guid.NewGuid().ToByteArray();
public string Username => "the_test_user";
}
위와 같이 변경한 MqttClient를 실행해 broker 측으로 연결하면 이제 다음과 같은 결과를 볼 수 있습니다.
c:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/clients/username/the_test_user"
{"data":[{"recv_cnt":9,"heap_size":987,"recv_pkt":9,"connected_at":"2021-06-04 14:21:44","node":"emqx@127.0.0.1","send_oct":22,"max_subscriptions":0,"send_msg":0,"reductions":77899,"clean_start":true,"mqueue_dropped":0,"mqueue_len":0,"expiry_interval":0,"keepalive":15,"recv_oct":112,"is_bridge":false,"send_pkt":7,"created_at":"2021-06-04 14:21:44","inflight":0,"mailbox_len":0,"max_mqueue":1000,"port":5254,"zone":"external","awaiting_rel":0,"recv_msg":3,"mountpoint":"undefined","proto_ver":4,"proto_name":"MQTT","max_inflight":32,"subscriptions_cnt":2,"clientid":"MyMqttClient","username":"the_test_user","max_awaiting_rel":100,"connected":true,"send_cnt":7,"ip_address":"127.0.0.1"}],"code":0}
acl_cache도 조회 및 삭제할 수 있다고 하는데, 아직 이에 대한 MqttClient 측에서의 사용법은 모르겠습니다. ^^
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/clients/MyMqttClient/acl_cache"
curl --basic -u admin:public -X DELETE "http://localhost:8081/api/v4/clients/MyMqttClient/acl_cache"
curl --basic -u admin:public -X DELETE "http://localhost:8081/api/v4/acl-cache"
route도 있다는데 아직 이것도 개념을 모르니 실행만 해봤습니다. (route 조회와 topic 조회의 차이점을 모르겠습니다.)
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/routes"
{"meta":{"page":1,"limit":10000,"count":2},"data":[{"topic":"abc","node":"emqx@127.0.0.1"},{"topic":"xyz","node":"emqx@127.0.0.1"}],"code":0}
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/routes/xyz"
{"data":[{"topic":"xyz","node":"emqx@127.0.0.1"}],"code":0}
알아본 김에 기타 여러 가지 명령어도 보겠습니다. 보니까, plugins도 지원하는 것 같고,
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/plugins"
{"data":[{"plugins":[{"type":"auth","name":"emqx_auth_http","description":"EMQ X Authentication/ACL with HTTP API","active":false},{"type":"auth","name":"emqx_auth_jwt","description":"EMQ X Authentication with JWT","active":false},{"type":"auth","name":"emqx_auth_ldap","description":"EMQ X Authentication/ACL with LDAP","active":false},{"type":"auth","name":"emqx_auth_mnesia","description":"EMQ X Authentication with Mnesia","active":false},{"type":"auth","name":"emqx_auth_mongo","description":"EMQ X Authentication/ACL with MongoDB","active":false},{"type":"auth","name":"emqx_auth_mysql","description":"EMQ X Authentication/ACL with MySQL","active":false},{"type":"auth","name":"emqx_auth_pgsql","description":"EMQ X Authentication/ACL with PostgreSQL","active":false},{"type":"auth","name":"emqx_auth_redis","description":"EMQ X Authentication/ACL with Redis","active":false},{"type":"bridge","name":"emqx_bridge_mqtt","description":"EMQ X Bridge to MQTT Broker","active":false},{"type":"protocol","name":"emqx_coap","description":"EMQ X CoAP Gateway","active":false},{"type":"feature","name":"emqx_dashboard","description":"EMQ X Web Dashboard","active":true},{"type":"feature","name":"emqx_exhook","description":"EMQ X Extension for Hook","active":false},{"type":"feature","name":"emqx_exproto","description":"EMQ X Extension for Protocol","active":false},{"type":"feature","name":"emqx_lua_hook","description":"EMQ X Lua Hooks","active":false},{"type":"protocol","name":"emqx_lwm2m","description":"EMQ X LwM2M Gateway","active":false},{"type":"feature","name":"emqx_management","description":"EMQ X Management API and CLI","active":true},{"type":"feature","name":"emqx_prometheus","description":"Prometheus for EMQ X","active":false},{"type":"feature","name":"emqx_psk_file","description":"EMQX PSK Plugin from File","active":false},{"type":"feature","name":"emqx_recon","description":"EMQ X Recon Plugin","active":true},{"type":"feature","name":"emqx_retainer","description":"EMQ X Retainer","active":true},{"type":"feature","name":"emqx_rule_engine","description":"EMQ X Rule Engine","active":true},{"type":"feature","name":"emqx_sasl","description":"EMQ X SASL","active":false},{"type":"protocol","name":"emqx_sn","description":"EMQ X MQTT-SN Plugin","active":false},{"type":"protocol","name":"emqx_stomp","description":"EMQ X Stomp Protocol Plugin","active":false},{"type":"feature","name":"emqx_telemetry","description":"EMQ X Telemetry","active":true},{"type":"feature","name":"emqx_web_hook","description":"EMQ X WebHook Plugin","active":false}],"node":"emqx@127.0.0.1"}],"code":0}
"name" 필드로 특정 plugin을 로드/언로드하는 것이 가능합니다.
C:\temp> curl --basic -u admin:public -X PUT "http://localhost:8081/api/v4/nodes/emqx@127.0.0.1/plugins/emqx_auth_jwt/load"
{"code":0}
C:\temp> curl --basic -u admin:public -X PUT "http://localhost:8081/api/v4/nodes/emqx@127.0.0.1/plugins/emqx_auth_jwt/unload"
{"code":0}
클러스터 내의 통계 수치와 상태 정보를 각각 metrics와 stats로 구할 수 있고,
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/metrics"
{"data":[{"node":"emqx@127.0.0.1","metrics":{"actions.exception":0,"packets.publish.error":0,"packets.publish.received":13,"packets.subscribe.error":0,"packets.pubrel.sent":0,"packets.connack.error":0,"messages.acked":3,"packets.pubcomp.received":0,"delivery.dropped.queue_full":0,"packets.puback.sent":5,"client.disconnected":11,"messages.publish":20,"messages.dropped":11,"packets.suback.sent":7,"packets.subscribe.received":7,"packets.pubcomp.inuse":0,"messages.delivered":9,"packets.pubcomp.missed":0,"session.resumed":0,"packets.unsuback.sent":2,"actions.retry":0,"delivery.dropped.qos0_msg":0,"packets.auth.sent":0,"messages.forward":0,"client.authenticate":15,"packets.subscribe.auth_error":0,"packets.pubrec.received":0,"client.connected":15,"messages.qos0.received":8,"messages.qos2.received":0,"messages.sent":9,"rules.matched":0,"delivery.dropped":0,"client.connect":15,"packets.pingresp.sent":643,"packets.received":686,"client.auth.failure":0,"session.discarded":0,"messages.qos1.sent":3,"packets.puback.received":3,"delivery.dropped.too_large":0,"packets.disconnect.sent":0,"packets.publish.auth_error":0,"messages.retained":312,"packets.sent":681,"packets.unsubscribe.error":0,"actions.taken":0,"packets.pubrec.inuse":0,"packets.publish.inuse":0,"client.subscribe":7,"messages.received":20,"packets.connack.sent":15,"delivery.dropped.expired":0,"packets.publish.sent":9,"delivery.dropped.no_local":0,"session.terminated":11,"client.check_acl":21,"packets.unsubscribe.received":2,"packets.pubrel.missed":0,"packets.puback.inuse":0,"bytes.received":2097,"session.takeovered":0,"messages.dropped.no_subscribers":11,"packets.pingreq.received":643,"packets.pubrec.sent":0,"actions.error":0,"bytes.sent":1550,"packets.auth.received":0,"session.created":15,"messages.qos0.sent":6,"messages.qos1.received":12,"packets.connack.auth_error":0,"packets.pubcomp.sent":0,"client.connack":15,"client.auth.success":0,"packets.publish.dropped":0,"client.auth.ignore":0,"packets.pubrec.missed":0,"messages.qos2.sent":0,"client.unsubscribe":2,"packets.disconnect.received":3,"actions.success":0,"packets.pubrel.received":0,"messages.dropped.expired":0,"client.auth.anonymous":15,"messages.delayed":0,"packets.connect.received":15,"packets.puback.missed":0}}],"code":0}
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/stats"
{"data":[{"stats":{"topics.max":4,"topics.count":2,"subscriptions.shared.max":0,"subscriptions.shared.count":0,"subscriptions.max":4,"subscriptions.count":2,"subscribers.max":4,"subscribers.count":2,"suboptions.max":4,"suboptions.count":2,"sessions.max":2,"sessions.count":2,"rules.max":0,"rules.count":0,"routes.max":4,"routes.count":2,"retained.max":3,"retained.count":3,"resources.max":0,"resources.count":0,"connections.max":2,"connections.count":2,"channels.max":2,"channels.count":2,"actions.max":5,"actions.count":5},"node":"emqx@127.0.0.1"}],"code":0}
알람 기능도 있는 듯하고,
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/alarms/present"
Not found.
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/alarms/history"
Not found.
blacklist 등의 관리 기능도 있습니다.
curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/banned"
{"meta":{"page":1,"limit":10000,"count":0},"data":[],"code":0}
curl --basic -u admin:public -X POST "http://localhost:8081/api/v4/banned" -d "{\"who\":\"MyMqttClient2\",\"as\":\"clientid\"}"
Internal Error
curl -i --basic -u admin:public -X DELETE "http://localhost:8081/api/v4/banned/clientid/MyMqttClient2"
대단하군요. ^^ 이런 것들을 일일이 MQTTnet 라이브러리를 이용해 구현하는 것이 귀찮을 수 있겠다는 생각이 들 정도로 잘해놨습니다. 게다가 web_hook까지 제공하는 것 같습니다.
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4/resource_types/web_hook"
{"data":{"title":{"zh":"WebHook","en":"WebHook"},"provider":"emqx_web_hook","params":{"verify":{"type":"boolean","title":{"zh":"校验服务器证书","en":"Verify Server Certfile"},"order":8,"description":{"zh":"是 否校验服务器证书。 默认客户端不会去校验服务器的证书,如果需要校验,请设置成true。","en":"Whether to verify the server certificate. By default, the client will not verify the server's certificate. If verification is required, please set it to true."},"default":false},"url":{"type":"string","title":{"zh":"请求 URL","en":"Request URL"},"required":true,"order":1,"format":"url","description":{"zh":"用于接收 Webhook 请求的服务器的 URL。","en":"The URL of the server that will receive the Webhook requests."}},"server_name_indication":{"type":"string","title":{"zh":"服务器名称指示","en":"Server Name Indication"},"order":9,"description":{"zh":"指定用于对端证书验证时使用的主机名,或者设置为 disable 以关闭此项验证。","en":"Specify the hostname used for peer certificate verification, or set to disable to turn off this verification."}},"request_timeout":{"type":"string","title":{"zh":"请求超时时间时间","en":"Request Timeout"},"order":3,"description":{"zh":"请求超时时间","en":"Request Timeout In Seconds"},"default":"5s"},"pool_size":{"type":"number","title":{"zh":"连接池大小","en":"Pool Size"},"order":4,"description":{"zh":"连接池大小","en":"Connection Pool"},"default":8},"keyfile":{"type":"file","title":{"zh":"SSL Key","en":"SSL Key"},"order":6,"description":{"zh":"SSL 私钥","en":"Your ssl keyfile"},"default":""},"connect_timeout":{"type":"string","title":{"zh":"连接超时时间","en":"Connect Timeout"},"order":2,"description":{"zh":"连接超时时间","en":"Connect Timeout In Seconds"},"default":"5s"},"certfile":{"type":"file","title":{"zh":"SSL Cert","en":"SSL Cert"},"order":7,"description":{"zh":"SSL 证书","en":"Your ssl certfile"},"default":""},"cacertfile":{"type":"file","title":{"zh":"CA 证书文件","en":"CA Certificate File"},"order":5,"description":{"zh":"CA 证书文件","en":"CA Certificate file"},"default":""}},"name":"web_hook","description":{"zh":"WebHook","en":"WebHook"}},"code":0}
뜬금없이 ^^ 리소스 이름에 중국어 문자가 나오는데요, EMQX라는 회사 자체가 중국계 인물들로 이뤄진 스타트업으로 보입니다.
About / Company
; https://www.emqx.io/about
암튼, 결국 MQTT broker를 혹시나 저런 규모로 만들 생각이라면 그냥 이미 저렇게 만들어 둔 서비스를 사용하는 것도 나쁘지 않은 선택으로 보입니다. 그 외에, 자신만의 소프트웨어에 간단하게 구현할 목적이라면 MQTTnet 라이브러리를 통해 만드는 것이 좋겠고!
이 글을 실습하면서, "Bad Request" 오류가 발생한다면?
c:\temp> url -i --basic -u admin:public -X POST "http://localhost:8081/api/v4/mqtt/publish" -d '{"topic":"abc","payload":"Hello World","qos":1,"retain":false,"clientid":"MyMqttClient"}'
HTTP/1.1 400 Bad Request
content-length: 11
content-type: text/plain
date: Fri, 04 Jun 2021 05:36:30 GMT
server: Cowboy
Bad Request
다음의 글에 정리한,
curl로 호출할 때 발생하는 오류 정리
; https://www.sysnet.pe.kr/2/0/11426
내용에 따라 윈도우에서는 json 텍스트를 다음과 같이 다뤄야 합니다.
'{"topic":"abc","payload":"Hello World","qos":1,"retain":false,"clientid":"MyMqttClient"}'
==>
"{\"topic\":\"abc\",\"payload\":\"Hello World\",\"qos\":1,\"retain\":false,\"clientid\":\"MyMqttClient\"}"
마지막으로, 아래는 EMQ X Broker가 제공하는 모든 API들의 endpoint와, 리소스 타입들입니다.
C:\temp> curl --basic -u admin:public -X GET "http://localhost:8081/api/v4" 2> nul | json_pp
{
"data": [
{
"path": "/acl/clientid",
"name": "list_clientid",
"method": "GET",
"descr": "List available mnesia in the cluster"
},
{
"path": "/acl/username",
"name": "list_username",
"method": "GET",
"descr": "List available mnesia in the cluster"
},
{
"path": "/acl/$all",
"name": "list_all",
"method": "GET",
"descr": "List available mnesia in the cluster"
},
{
"path": "/acl/clientid/:clientid",
"name": "lookup_clientid",
"method": "GET",
"descr": "Lookup mnesia in the cluster"
},
{
"path": "/acl/username/:username",
"name": "lookup_username",
"method": "GET",
"descr": "Lookup mnesia in the cluster"
},
{
"path": "/acl",
"name": "add",
"method": "POST",
"descr": "Add mnesia in the cluster"
},
{
"path": "/acl/clientid/:clientid/topic/:topic",
"name": "delete_clientid",
"method": "DELETE",
"descr": "Delete mnesia in the cluster"
},
{
"path": "/acl/username/:username/topic/:topic",
"name": "delete_username",
"method": "DELETE",
"descr": "Delete mnesia in the cluster"
},
{
"path": "/acl/$all/topic/:topic",
"name": "delete_all",
"method": "DELETE",
"descr": "Delete mnesia in the cluster"
},
{
"path": "/auth_clientid",
"name": "list_clientid",
"method": "GET",
"descr": "List available clientid in the cluster"
},
{
"path": "/auth_clientid/:clientid",
"name": "lookup_clientid",
"method": "GET",
"descr": "Lookup clientid in the cluster"
},
{
"path": "/auth_clientid",
"name": "add_clientid",
"method": "POST",
"descr": "Add clientid in the cluster"
},
{
"path": "/auth_clientid/:clientid",
"name": "update_clientid",
"method": "PUT",
"descr": "Update clientid in the cluster"
},
{
"path": "/auth_clientid/:clientid",
"name": "delete_clientid",
"method": "DELETE",
"descr": "Delete clientid in the cluster"
},
{
"path": "/auth_username",
"name": "list_username",
"method": "GET",
"descr": "List available username in the cluster"
},
{
"path": "/auth_username/:username",
"name": "lookup_username",
"method": "GET",
"descr": "Lookup username in the cluster"
},
{
"path": "/auth_username",
"name": "add_username",
"method": "POST",
"descr": "Add username in the cluster"
},
{
"path": "/auth_username/:username",
"name": "update_username",
"method": "PUT",
"descr": "Update username in the cluster"
},
{
"path": "/auth_username/:username",
"name": "delete_username",
"method": "DELETE",
"descr": "Delete username in the cluster"
},
{
"path": "/auth",
"name": "auth_user",
"method": "POST",
"descr": "Authenticate an user"
},
{
"path": "/users/",
"name": "create_user",
"method": "POST",
"descr": "Create an user"
},
{
"path": "/users/",
"name": "list_users",
"method": "GET",
"descr": "List users"
},
{
"path": "/users/:name",
"name": "update_user",
"method": "PUT",
"descr": "Update an user"
},
{
"path": "/users/:name",
"name": "delete_user",
"method": "DELETE",
"descr": "Delete an user"
},
{
"path": "/change_pwd/:username",
"name": "change_pwd",
"method": "PUT",
"descr": "Change password for an user"
},
{
"path": "/acl-cache",
"name": "clean_acl_cache_all",
"method": "DELETE",
"descr": "Clean acl cache on all nodes"
},
{
"path": "nodes/:node/acl-cache",
"name": "clean_acl_cache_node",
"method": "DELETE",
"descr": "Clean acl cache on specific node"
},
{
"path": "/alarms",
"name": "list_all_alarms",
"method": "GET",
"descr": "List all alarms in the cluster"
},
{
"path": "nodes/:node/alarms",
"name": "list_node_alarms",
"method": "GET",
"descr": "List all alarms on a node"
},
{
"path": "/alarms/activated",
"name": "list_all_activated_alarms",
"method": "GET",
"descr": "List all activated alarm in the cluster"
},
{
"path": "nodes/:node/alarms/activated",
"name": "list_node_activated_alarms",
"method": "GET",
"descr": "List all activated alarm on a node"
},
{
"path": "/alarms/deactivated",
"name": "list_all_deactivated_alarms",
"method": "GET",
"descr": "List all deactivated alarm in the cluster"
},
{
"path": "nodes/:node/alarms/deactivated",
"name": "list_node_deactivated_alarms",
"method": "GET",
"descr": "List all deactivated alarm on a node"
},
{
"path": "/alarms/deactivated",
"name": "deactivate_alarm",
"method": "POST",
"descr": "Delete the special alarm on a node"
},
{
"path": "/alarms/deactivated",
"name": "delete_all_deactivated_alarms",
"method": "DELETE",
"descr": "Delete all deactivated alarm in the cluster"
},
{
"path": "nodes/:node/alarms/deactivated",
"name": "delete_node_deactivated_alarms",
"method": "DELETE",
"descr": "Delete all deactivated alarm on a node"
},
{
"path": "/banned/",
"name": "list_banned",
"method": "GET",
"descr": "List banned"
},
{
"path": "/banned/",
"name": "create_banned",
"method": "POST",
"descr": "Create banned"
},
{
"path": "/banned/:who",
"name": "delete_banned",
"method": "DELETE",
"descr": "Delete banned"
},
{
"path": "/brokers/",
"name": "list_brokers",
"method": "GET",
"descr": "A list of brokers in the cluster"
},
{
"path": "/brokers/:node",
"name": "get_broker",
"method": "GET",
"descr": "Get broker info of a node"
},
{
"path": "/clients/",
"name": "list_clients",
"method": "GET",
"descr": "A list of clients on current node"
},
{
"path": "nodes/:node/clients/",
"name": "list_node_clients",
"method": "GET",
"descr": "A list of clients on specified node"
},
{
"path": "/clients/:clientid",
"name": "lookup_client",
"method": "GET",
"descr": "Lookup a client in the cluster"
},
{
"path": "nodes/:node/clients/:clientid",
"name": "lookup_node_client",
"method": "GET",
"descr": "Lookup a client on the node"
},
{
"path": "/clients/username/:username",
"name": "lookup_client_via_username",
"method": "GET",
"descr": "Lookup a client via username in the cluster"
},
{
"path": "/nodes/:node/clients/username/:username",
"name": "lookup_node_client_via_username",
"method": "GET",
"descr": "Lookup a client via username on the node "
},
{
"path": "/clients/:clientid",
"name": "kickout_client",
"method": "DELETE",
"descr": "Kick out the client in the cluster"
},
{
"path": "/clients/:clientid/acl_cache",
"name": "clean_acl_cache",
"method": "DELETE",
"descr": "Clear the ACL cache of a specified client in the cluster"
},
{
"path": "/clients/:clientid/acl_cache",
"name": "list_acl_cache",
"method": "GET",
"descr": "List the ACL cache of a specified client in the cluster"
},
{
"path": "/clients/:clientid/ratelimit",
"name": "set_ratelimit_policy",
"method": "POST",
"descr": "Set the client ratelimit policy"
},
{
"path": "/clients/:clientid/ratelimit",
"name": "clean_ratelimit",
"method": "DELETE",
"descr": "Clear the ratelimit policy"
},
{
"path": "/clients/:clientid/quota",
"name": "set_quota_policy",
"method": "POST",
"descr": "Set the client quota policy"
},
{
"path": "/clients/:clientid/quota",
"name": "clean_quota",
"method": "DELETE",
"descr": "Clear the quota policy"
},
{
"path": "/data/export",
"name": "export",
"method": "POST",
"descr": "Export data"
},
{
"path": "/data/export",
"name": "list_exported",
"method": "GET",
"descr": "List exported file"
},
{
"path": "/data/import",
"name": "import",
"method": "POST",
"descr": "Import data"
},
{
"path": "/data/file/:filename",
"name": "download",
"method": "GET",
"descr": "Download data file to local"
},
{
"path": "/data/file",
"name": "upload",
"method": "POST",
"descr": "Upload data file from local"
},
{
"path": "/data/file/:filename",
"name": "delete",
"method": "DELETE",
"descr": "Delete data file"
},
{
"path": "/listeners/",
"name": "list_listeners",
"method": "GET",
"descr": "A list of listeners in the cluster"
},
{
"path": "/nodes/:node/listeners",
"name": "list_node_listeners",
"method": "GET",
"descr": "A list of listeners on the node"
},
{
"path": "/listeners/:identifier/restart",
"name": "restart_listener",
"method": "PUT",
"descr": "Restart a listener in the cluster"
},
{
"path": "/nodes/:node/listeners/:identifier/restart",
"name": "restart_node_listener",
"method": "PUT",
"descr": "Restart a listener on a node"
},
{
"path": "/metrics",
"name": "list_all_metrics",
"method": "GET",
"descr": "A list of metrics of all nodes in the cluster"
},
{
"path": "/nodes/:node/metrics",
"name": "list_node_metrics",
"method": "GET",
"descr": "A list of metrics of a node"
},
{
"path": "/nodes/",
"name": "list_nodes",
"method": "GET",
"descr": "A list of nodes in the cluster"
},
{
"path": "/nodes/:node",
"name": "get_node",
"method": "GET",
"descr": "Lookup a node in the cluster"
},
{
"path": "/plugins/",
"name": "list_all_plugins",
"method": "GET",
"descr": "List all plugins in the cluster"
},
{
"path": "/nodes/:node/plugins/",
"name": "list_node_plugins",
"method": "GET",
"descr": "List all plugins on a node"
},
{
"path": "/nodes/:node/plugins/:plugin/load",
"name": "load_node_plugin",
"method": "PUT",
"descr": "Load a plugin"
},
{
"path": "/nodes/:node/plugins/:plugin/unload",
"name": "unload_node_plugin",
"method": "PUT",
"descr": "Unload a plugin"
},
{
"path": "/nodes/:node/plugins/:plugin/reload",
"name": "reload_node_plugin",
"method": "PUT",
"descr": "Reload a plugin"
},
{
"path": "/plugins/:plugin/unload",
"name": "unload_plugin",
"method": "PUT",
"descr": "Unload a plugin in the cluster"
},
{
"path": "/plugins/:plugin/reload",
"name": "reload_plugin",
"method": "PUT",
"descr": "Reload a plugin in the cluster"
},
{
"path": "/mqtt/subscribe",
"name": "mqtt_subscribe",
"method": "POST",
"descr": "Subscribe a topic"
},
{
"path": "/mqtt/publish",
"name": "mqtt_publish",
"method": "POST",
"descr": "Publish a MQTT message"
},
{
"path": "/mqtt/unsubscribe",
"name": "mqtt_unsubscribe",
"method": "POST",
"descr": "Unsubscribe a topic"
},
{
"path": "/mqtt/subscribe_batch",
"name": "mqtt_subscribe_batch",
"method": "POST",
"descr": "Batch subscribes topics"
},
{
"path": "/mqtt/publish_batch",
"name": "mqtt_publish_batch",
"method": "POST",
"descr": "Batch publish MQTT messages"
},
{
"path": "/mqtt/unsubscribe_batch",
"name": "mqtt_unsubscribe_batch",
"method": "POST",
"descr": "Batch unsubscribes topics"
},
{
"path": "/routes/",
"name": "list_routes",
"method": "GET",
"descr": "List routes"
},
{
"path": "/routes/:topic",
"name": "lookup_routes",
"method": "GET",
"descr": "Lookup routes to a topic"
},
{
"path": "/stats/",
"name": "list_stats",
"method": "GET",
"descr": "A list of stats of all nodes in the cluster"
},
{
"path": "/nodes/:node/stats/",
"name": "lookup_node_stats",
"method": "GET",
"descr": "A list of stats of a node"
},
{
"path": "/subscriptions/",
"name": "list_subscriptions",
"method": "GET",
"descr": "A list of subscriptions in the cluster"
},
{
"path": "/nodes/:node/subscriptions/",
"name": "list_node_subscriptions",
"method": "GET",
"descr": "A list of subscriptions on a node"
},
{
"path": "/subscriptions/:clientid",
"name": "lookup_client_subscriptions",
"method": "GET",
"descr": "A list of subscriptions of a client"
},
{
"path": "/nodes/:node/subscriptions/:clientid",
"name": "lookup_client_subscriptions_with_node",
"method": "GET",
"descr": "A list of subscriptions of a client on the node"
},
{
"path": "/emqx_prometheus",
"name": "stats",
"method": "GET",
"descr": "Get emqx all stats info"
},
{
"path": "/rules/",
"name": "create_rule",
"method": "POST",
"descr": "Create a rule"
},
{
"path": "/rules/:id",
"name": "update_rule",
"method": "PUT",
"descr": "Update a rule"
},
{
"path": "/rules/",
"name": "list_rules",
"method": "GET",
"descr": "A list of all rules"
},
{
"path": "/rules/:id",
"name": "show_rule",
"method": "GET",
"descr": "Show a rule"
},
{
"path": "/rules/:id",
"name": "delete_rule",
"method": "DELETE",
"descr": "Delete a rule"
},
{
"path": "/actions/",
"name": "list_actions",
"method": "GET",
"descr": "A list of all actions"
},
{
"path": "/actions/:name",
"name": "show_action",
"method": "GET",
"descr": "Show an action"
},
{
"path": "/resources/",
"name": "list_resources",
"method": "GET",
"descr": "A list of all resources"
},
{
"path": "/resources/",
"name": "create_resource",
"method": "POST",
"descr": "Create a resource"
},
{
"path": "/resources/:id",
"name": "update_resource",
"method": "PUT",
"descr": "Update a resource"
},
{
"path": "/resources/:id",
"name": "show_resource",
"method": "GET",
"descr": "Show a resource"
},
{
"path": "/resource_status/:id",
"name": "get_resource_status",
"method": "GET",
"descr": "Get status of a resource"
},
{
"path": "/resources/:id",
"name": "start_resource",
"method": "POST",
"descr": "Start a resource"
},
{
"path": "/resources/:id",
"name": "delete_resource",
"method": "DELETE",
"descr": "Delete a resource"
},
{
"path": "/resource_types/",
"name": "list_resource_types",
"method": "GET",
"descr": "List all resource types"
},
{
"path": "/resource_types/:name",
"name": "show_resource_type",
"method": "GET",
"descr": "Show a resource type"
},
{
"path": "/resource_types/:type/resources",
"name": "list_resources_by_type",
"method": "GET",
"descr": "List all resources of a resource type"
},
{
"path": "/rule_events/",
"name": "list_events",
"method": "GET",
"descr": "List all events with detailed info"
},
{
"path": "/sasl",
"name": "add",
"method": "POST",
"descr": "Add authentication information"
},
{
"path": "/sasl",
"name": "delete",
"method": "DELETE",
"descr": "Delete authentication information"
},
{
"path": "/sasl",
"name": "update",
"method": "PUT",
"descr": "Update authentication information"
},
{
"path": "/sasl",
"name": "get",
"method": "GET",
"descr": "Get authentication information"
},
{
"path": "/telemetry/status",
"name": "enable_telemetry",
"method": "PUT",
"descr": "Enable or disbale telemetry"
},
{
"path": "/telemetry/status",
"name": "get_telemetry_status",
"method": "GET",
"descr": "Get telemetry status"
},
{
"path": "/telemetry/data",
"name": "get_telemetry_data",
"method": "GET",
"descr": "Get reported telemetry data"
},
{
"path": "/topic-metrics",
"name": "list_all_topic_metrics",
"method": "GET",
"descr": "A list of all topic metrics of all nodes in the cluster"
},
{
"path": "/topic-metrics/:topic",
"name": "list_topic_metrics",
"method": "GET",
"descr": "A list of specfied topic metrics of all nodes in the cluster"
},
{
"path": "/topic-metrics",
"name": "register_topic_metrics",
"method": "POST",
"descr": "Register topic metrics"
},
{
"path": "/topic-metrics",
"name": "unregister_all_topic_metrics",
"method": "DELETE",
"descr": "Unregister all topic metrics"
},
{
"path": "/topic-metrics/:topic",
"name": "unregister_topic_metrics",
"method": "DELETE",
"descr": "Unregister topic metrics"
},
{
"path": "/modules/",
"name": "list_all_modules",
"method": "GET",
"descr": "List all modules in the cluster"
},
{
"path": "/nodes/:node/modules/",
"name": "list_node_modules",
"method": "GET",
"descr": "List all modules on a node"
},
{
"path": "/nodes/:node/modules/:module/load",
"name": "load_node_module",
"method": "PUT",
"descr": "Load a module"
},
{
"path": "/nodes/:node/modules/:module/unload",
"name": "unload_node_module",
"method": "PUT",
"descr": "Unload a module"
},
{
"path": "/nodes/:node/modules/:module/reload",
"name": "reload_node_module",
"method": "PUT",
"descr": "Reload a module"
},
{
"path": "/modules/:module/load",
"name": "load_module",
"method": "PUT",
"descr": "load a module in the cluster"
},
{
"path": "/modules/:module/unload",
"name": "unload_module",
"method": "PUT",
"descr": "Unload a module in the cluster"
},
{
"path": "/modules/:module/reload",
"name": "reload_module",
"method": "PUT",
"descr": "Reload a module in the cluster"
}
],
"code": 0
}
C:\temp> curl --basic -u admin:public "http://localhost:8081/api/v4/resource_types" 2> nul | json_pp
{
"data": [
{
"title": {
"zh": "EMQX Bridge",
"en": "EMQX Bridge"
},
"provider": "emqx_bridge_mqtt",
"params": {
"reconnect_interval": {
"type": "string",
"title": {
"zh": "重连间隔",
"en": "Reconnect Interval"
},
"required": false,
"order": 4,
"description": {
"zh": "重连间隔",
"en": "Reconnect Interval of bridge"
},
"default": "30s"
},
"pool_size": {
"type": "number",
"title": {
"zh": "连接池大小",
"en": "Pool Size"
},
"required": true,
"order": 3,
"description": {
"zh": "连接池大小",
"en": "MQTT/RPC Connection Pool Size"
},
"default": 8
},
"mountpoint": {
"type": "string",
"title": {
"zh": "桥接挂载点",
"en": "Bridge MountPoint"
},
"required": false,
"order": 2,
"description": {
"zh": "桥接主题的挂载点
示例: 本地节点向 `topic1` 发消息,远程桥接节点的主题会变换为 `bridge/aws/${node}/topic1`",
"en": "MountPoint for bridge topic
Example: The topic of messages sent to `topic1` on local node will be transformed to `bridge/aws/${node}/topic1`"
},
"default": "bridge/emqx/${node}/"
},
"disk_cache": {
"type": "string",
"title": {
"zh": "磁盘缓存",
"en": "Disk Cache"
},
"required": false,
"order": 6,
"enum": [
"on",
"off"
],
"description": {
"zh": "当桥接断开时用于控制是否将消息缓存到本地磁盘队列上",
"en": "The flag which determines whether messages can be cached on local disk when bridge is disconnected"
},
"default": "off"
},
"batch_size": {
"type": "number",
"title": {
"zh": "批处理大小",
"en": "Batch Size"
},
"required": false,
"order": 5,
"description": {
"zh": "批处理大小",
"en": "Batch Size"
},
"default": 32
},
"address": {
"type": "string",
"title": {
"zh": "EMQ X 节点名称",
"en": "EMQ X Node Name"
},
"required": true,
"order": 1,
"description": {
"zh": "远程 EMQ X 节点名称 ",
"en": "EMQ X Remote Node Name"
},
"default": "emqx2@127.0.0.1"
}
},
"name": "bridge_rpc",
"description": {
"zh": "EMQ X RPC 消息桥接",
"en": "EMQ X RPC Bridge"
}
},
{
"title": {
"zh": "MQTT Bridge",
"en": "MQTT Bridge"
},
"provider": "emqx_bridge_mqtt",
"params": {
"username": {
"type": "string",
"title": {
"zh": "用户名",
"en": "Username"
},
"required": false,
"order": 5,
"description": {
"zh": "连接远程 Broker 的用户名",
"en": "Username for connecting to remote MQTT Broker"
},
"default": ""
},
"ssl": {
"type": "boolean",
"title": {
"zh": "开启SSL链接",
"en": "Enable SSL"
},
"order": 14,
"description": {
"zh": "是否开启 SSL",
"en": "Enable SSL or not"
},
"default": false
},
"retry_interval": {
"type": "string",
"title": {
"zh": "重传间隔",
"en": "Retry interval"
},
"required": false,
"order": 12,
"description": {
"zh": "消息重传间隔",
"en": "Retry interval for bridge QoS1 message delivering"
},
"default": "20s"
},
"reconnect_interval": {
"type": "string",
"title": {
"zh": "重连间隔",
"en": "Reconnect Interval"
},
"required": false,
"order": 11,
"description": {
"zh": "重连间隔",
"en": "Reconnect interval of bridge:
"
},
"default": "30s"
},
"proto_ver": {
"type": "string",
"title": {
"zh": "协议版本",
"en": "Protocol Version"
},
"required": false,
"order": 9,
"enum": [
"mqttv3",
"mqttv4",
"mqttv5"
],
"description": {
"zh": "MQTT 协议版本",
"en": "MQTTT Protocol version"
},
"default": "mqttv4"
},
"pool_size": {
"type": "number",
"title": {
"zh": "连接池大小",
"en": "Pool Size"
},
"required": true,
"order": 2,
"description": {
"zh": "连接池大小",
"en": "MQTT Connection Pool Size"
},
"default": 8
},
"password": {
"type": "password",
"title": {
"zh": "密码",
"en": "Password"
},
"required": false,
"order": 6,
"description": {
"zh": "连接远程 Broker 的密码",
"en": "Password for connecting to remote MQTT Broker"
},
"default": ""
},
"mountpoint": {
"type": "string",
"title": {
"zh": "桥接挂载点",
"en": "Bridge MountPoint"
},
"required": false,
"order": 7,
"description": {
"zh": "桥接主题的挂载点:
示例: 本地节点向 `topic1` 发消息,远程桥接节点的主题会变换为 `bridge/aws/${node}/topic1`",
"en": "MountPoint for bridge topic:
Example: The topic of messages sent to `topic1` on local node will be transformed to `bridge/aws/${node}/topic1`"
},
"default": "bridge/aws/${node}/"
},
"keyfile": {
"type": "file",
"title": {
"zh": "SSL 密钥文件",
"en": "SSL Keyfile"
},
"required": false,
"order": 17,
"description": {
"zh": "客户端密钥路径",
"en": "The file path of the client keyfile"
},
"default": "etc/certs/client-key.pem"
},
"keepalive": {
"type": "string",
"title": {
"zh": "心跳间隔",
"en": "Keepalive"
},
"required": false,
"order": 10,
"description": {
"zh": "心跳间隔",
"en": "Keepalive"
},
"default": "60s"
},
"disk_cache": {
"type": "string",
"title": {
"zh": "磁盘缓存",
"en": "Disk Cache"
},
"required": false,
"order": 8,
"enum": [
"on",
"off"
],
"description": {
"zh": "当桥接断开时用于控制是否将消息缓存到本地磁盘队列上",
"en": "The flag which determines whether messages can be cached on local disk when bridge is disconnected"
},
"default": "off"
},
"clientid": {
"type": "string",
"title": {
"zh": "客户端 Id",
"en": "ClientId"
},
"required": true,
"order": 3,
"description": {
"zh": "连接远程 Broker 的 ClientId",
"en": "ClientId for connecting to remote MQTT broker"
},
"default": "client"
},
"ciphers": {
"type": "string",
"title": {
"zh": "SSL 加密算法",
"en": "SSL Ciphers"
},
"required": false,
"order": 18,
"description": {
"zh": "SSL 加密算法",
"en": "SSL Ciphers"
},
"default": "ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA"
},
"certfile": {
"type": "file",
"title": {
"zh": "SSL 客户端证书",
"en": "SSL Certfile"
},
"required": false,
"order": 16,
"description": {
"zh": "客户端证书路径",
"en": "The file path of the client certfile"
},
"default": "etc/certs/client-cert.pem"
},
"cacertfile": {
"type": "file",
"title": {
"zh": "CA 证书",
"en": "CA certificates"
},
"required": false,
"order": 15,
"description": {
"zh": "CA 证书路径",
"en": "The file path of the CA certificates"
},
"default": "etc/certs/cacert.pem"
},
"bridge_mode": {
"type": "boolean",
"title": {
"zh": "桥接模式",
"en": "Bridge Mode"
},
"required": false,
"order": 13,
"description": {
"zh": "MQTT 连接是否为桥接模式",
"en": "Bridge mode for MQTT bridge connection"
},
"default": false
},
"append": {
"type": "boolean",
"title": {
"zh": "附加 GUID",
"en": "Append GUID"
},
"required": false,
"order": 4,
"description": {
"zh": "是否将GUID附加到 MQTT ClientId 后",
"en": "Append GUID to MQTT ClientId?"
},
"default": true
},
"address": {
"type": "string",
"title": {
"zh": "远程 broker 地址",
"en": " Broker Address"
},
"required": true,
"order": 1,
"description": {
"zh": "远程 MQTT Broker 的地址",
"en": "The MQTT Remote Address"
},
"default": "127.0.0.1:1883"
}
},
"name": "bridge_mqtt",
"description": {
"zh": "MQTT 消息桥接",
"en": "MQTT Message Bridge"
}
},
{
"title": {
"zh": "WebHook",
"en": "WebHook"
},
"provider": "emqx_web_hook",
"params": {
"verify": {
"type": "boolean",
"title": {
"zh": "校验服务器证书",
"en": "Verify Server Certfile"
},
"order": 8,
"description": {
"zh": "是否校验服务器证书。 默认客户端不会去校验服务器的证书,如果需要校验,请设置成true。",
"en": "Whether to verify the server certificate. By default, the client will not verify the server's certificate. If verification is required, please set it to true."
},
"default": false
},
"url": {
"type": "string",
"title": {
"zh": "请求 URL",
"en": "Request URL"
},
"required": true,
"order": 1,
"format": "url",
"description": {
"zh": "用于接收 Webhook 请求的服务器的 URL。",
"en": "The URL of the server that will receive the Webhook requests."
}
},
"server_name_indication": {
"type": "string",
"title": {
"zh": "服务器名称指示",
"en": "Server Name Indication"
},
"order": 9,
"description": {
"zh": "指定用于对端证书验证时使用的主机名,或者设置为 disable 以关闭此项验证。",
"en": "Specify the hostname used for peer certificate verification, or set to disable to turn off this verification."
}
},
"request_timeout": {
"type": "string",
"title": {
"zh": "请求超时时间时间",
"en": "Request Timeout"
},
"order": 3,
"description": {
"zh": "请求超时时间",
"en": "Request Timeout In Seconds"
},
"default": "5s"
},
"pool_size": {
"type": "number",
"title": {
"zh": "连接池大小",
"en": "Pool Size"
},
"order": 4,
"description": {
"zh": "连接池大小",
"en": "Connection Pool"
},
"default": 8
},
"keyfile": {
"type": "file",
"title": {
"zh": "SSL Key",
"en": "SSL Key"
},
"order": 6,
"description": {
"zh": "SSL 私钥",
"en": "Your ssl keyfile"
},
"default": ""
},
"connect_timeout": {
"type": "string",
"title": {
"zh": "连接超时时间",
"en": "Connect Timeout"
},
"order": 2,
"description": {
"zh": "连接超时时间",
"en": "Connect Timeout In Seconds"
},
"default": "5s"
},
"certfile": {
"type": "file",
"title": {
"zh": "SSL Cert",
"en": "SSL Cert"
},
"order": 7,
"description": {
"zh": "SSL 证书",
"en": "Your ssl certfile"
},
"default": ""
},
"cacertfile": {
"type": "file",
"title": {
"zh": "CA 证书文件",
"en": "CA Certificate File"
},
"order": 5,
"description": {
"zh": "CA 证书文件",
"en": "CA Certificate file"
},
"default": ""
}
},
"name": "web_hook",
"description": {
"zh": "WebHook",
"en": "WebHook"
}
}
],
"code": 0
}
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]