Microsoft MVP성태의 닷넷 이야기
개발 환경 구성: 577. MQTT - emqx.io 서비스 소개 [링크 복사], [링크+제목 복사],
조회: 10341
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 

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 }




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]







[최초 등록일: ]
[최종 수정일: 7/15/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 31  32  33  34  35  36  37  38  39  40  41  42  43  [44]  45  ...
NoWriterDateCnt.TitleFile(s)
12537정성태2/11/202111171.NET Framework: 1022. UI 요소의 접근은 반드시 그 UI를 만든 스레드에서! - 두 번째 이야기 [2]
12536정성태2/9/202110140개발 환경 구성: 542. BDP(Bandwidth-delay product)와 TCP Receive Window
12535정성태2/9/20219248개발 환경 구성: 541. Wireshark로 확인하는 LSO(Large Send Offload), RSC(Receive Segment Coalescing) 옵션
12534정성태2/8/20219821개발 환경 구성: 540. Wireshark + C/C++로 확인하는 TCP 연결에서의 closesocket 동작 [1]파일 다운로드1
12533정성태2/8/20219477개발 환경 구성: 539. Wireshark + C/C++로 확인하는 TCP 연결에서의 shutdown 동작파일 다운로드1
12532정성태2/6/20219972개발 환경 구성: 538. Wireshark + C#으로 확인하는 ReceiveBufferSize(SO_RCVBUF), SendBufferSize(SO_SNDBUF) [3]
12531정성태2/5/20218982개발 환경 구성: 537. Wireshark + C#으로 확인하는 PSH flag와 Nagle 알고리듬파일 다운로드1
12530정성태2/4/202113169개발 환경 구성: 536. Wireshark + C#으로 확인하는 TCP 통신의 Receive Window
12529정성태2/4/202110212개발 환경 구성: 535. Wireshark + C#으로 확인하는 TCP 통신의 MIN RTO [1]
12528정성태2/1/20219616개발 환경 구성: 534. Wireshark + C#으로 확인하는 TCP 통신의 MSS(Maximum Segment Size) - 윈도우 환경
12527정성태2/1/20219832개발 환경 구성: 533. Wireshark + C#으로 확인하는 TCP 통신의 MSS(Maximum Segment Size) - 리눅스 환경파일 다운로드1
12526정성태2/1/20217686개발 환경 구성: 532. Azure Devops의 파이프라인 빌드 시 snk 파일 다루는 방법 - Secure file
12525정성태2/1/20217397개발 환경 구성: 531. Azure Devops - 파이프라인 실행 시 빌드 이벤트를 생략하는 방법
12524정성태1/31/20218507개발 환경 구성: 530. 기존 github 프로젝트를 Azure Devops의 빌드 Pipeline에 연결하는 방법 [1]
12523정성태1/31/20218556개발 환경 구성: 529. 기존 github 프로젝트를 Azure Devops의 Board에 연결하는 방법
12522정성태1/31/202110061개발 환경 구성: 528. 오라클 클라우드의 리눅스 VM - 9000 MTU Jumbo Frame 테스트
12521정성태1/31/202110005개발 환경 구성: 527. 이더넷(Ethernet) 환경의 TCP 통신에서 MSS(Maximum Segment Size) 확인 [1]
12520정성태1/30/20218570개발 환경 구성: 526. 오라클 클라우드의 VM에 ping ICMP 여는 방법
12519정성태1/30/20217609개발 환경 구성: 525. 오라클 클라우드의 VM을 외부에서 접근하기 위해 포트 여는 방법
12518정성태1/30/202125065Linux: 37. Ubuntu에 Wireshark 설치 [2]
12517정성태1/30/202112701Linux: 36. 윈도우 클라이언트에서 X2Go를 이용한 원격 리눅스의 GUI 접속 - 우분투 20.04
12516정성태1/29/20219339Windows: 188. Windows - TCP default template 설정 방법
12515정성태1/28/202110593웹: 41. Microsoft Edge - localhost에 대해 http 접근 시 무조건 https로 바뀌는 문제 [3]
12514정성태1/28/202110854.NET Framework: 1021. C# - 일렉트론 닷넷(Electron.NET) 소개 [1]파일 다운로드1
12513정성태1/28/20218904오류 유형: 698. electronize - User Profile 디렉터리에 공백 문자가 있는 경우 빌드가 실패하는 문제 [1]
12512정성태1/28/20218673오류 유형: 697. The program can't start because VCRUNTIME140.dll is missing from your computer. Try reinstalling the program to fix this problem.
... 31  32  33  34  35  36  37  38  39  40  41  42  43  [44]  45  ...