emq.schema 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. %%-*- mode: erlang -*-
  2. %% EMQ config mapping
  3. %%--------------------------------------------------------------------
  4. %% Erlang Node
  5. %%--------------------------------------------------------------------
  6. %% @doc Erlang node name
  7. {mapping, "node.name", "vm_args.-name", [
  8. {default, "emqttd@127.0.0.1"}
  9. ]}.
  10. %% @doc Secret cookie for distributed erlang node
  11. {mapping, "node.cookie", "vm_args.-setcookie", [
  12. {default, "emqsecretcookie"}
  13. ]}.
  14. %% @doc SMP Support
  15. {mapping, "node.smp", "vm_args.-smp", [
  16. {default, auto},
  17. {datatype, {enum, [enable, auto, disable]}},
  18. hidden
  19. ]}.
  20. %% @doc Enable Kernel Poll
  21. {mapping, "node.kernel_poll", "vm_args.+K", [
  22. {default, on},
  23. {datatype, flag},
  24. hidden
  25. ]}.
  26. %% @doc More information at: http://erlang.org/doc/man/erl.html
  27. {mapping, "node.async_threads", "vm_args.+A", [
  28. {default, 64},
  29. {datatype, integer},
  30. {validators, ["range:0-1024"]}
  31. ]}.
  32. %% @doc Erlang Process Limit
  33. {mapping, "node.process_limit", "vm_args.+P", [
  34. {datatype, integer},
  35. {default, 256000},
  36. hidden
  37. ]}.
  38. %% Note: OTP R15 and earlier uses -env ERL_MAX_PORTS, R16+ uses +Q
  39. %% @doc The number of concurrent ports/sockets
  40. %% Valid range is 1024-134217727
  41. {mapping, "node.max_ports",
  42. cuttlefish:otp("R16", "vm_args.+Q", "vm_args.-env ERL_MAX_PORTS"), [
  43. {default, 262144},
  44. {datatype, integer},
  45. {validators, ["range4ports"]}
  46. ]}.
  47. {validator, "range4ports", "must be 1024 to 134217727",
  48. fun(X) -> X >= 1024 andalso X =< 134217727 end}.
  49. %% @doc http://www.erlang.org/doc/man/erl.html#%2bzdbbl
  50. {mapping, "node.dist_buffer_size", "vm_args.+zdbbl", [
  51. {datatype, bytesize},
  52. {commented, "32MB"},
  53. hidden,
  54. {validators, ["zdbbl_range"]}
  55. ]}.
  56. {translation, "vm_args.+zdbbl",
  57. fun(Conf) ->
  58. ZDBBL = cuttlefish:conf_get("node.dist_buffer_size", Conf, undefined),
  59. case ZDBBL of
  60. undefined -> undefined;
  61. X when is_integer(X) -> cuttlefish_util:ceiling(X / 1024); %% Bytes to Kilobytes;
  62. _ -> undefined
  63. end
  64. end
  65. }.
  66. {validator, "zdbbl_range", "must be between 1KB and 2097151KB",
  67. fun(ZDBBL) ->
  68. %% 2097151KB = 2147482624
  69. ZDBBL >= 1024 andalso ZDBBL =< 2147482624
  70. end
  71. }.
  72. %% @doc http://www.erlang.org/doc/man/erlang.html#system_flag-2
  73. {mapping, "node.fullsweep_after", "vm_args.-env ERL_FULLSWEEP_AFTER", [
  74. {default, 1000},
  75. {datatype, integer},
  76. hidden,
  77. {validators, ["positive_integer"]}
  78. ]}.
  79. {validator, "positive_integer", "must be a positive integer",
  80. fun(X) -> X >= 0 end}.
  81. %% Note: OTP R15 and earlier uses -env ERL_MAX_ETS_TABLES,
  82. %% R16+ uses +e
  83. %% @doc The ETS table limit
  84. {mapping, "node.max_ets_tables",
  85. cuttlefish:otp("R16", "vm_args.+e", "vm_args.-env ERL_MAX_ETS_TABLES"), [
  86. {default, 256000},
  87. {datatype, integer},
  88. hidden
  89. ]}.
  90. %% @doc Set the location of crash dumps
  91. {mapping, "node.crash_dump", "vm_args.-env ERL_CRASH_DUMP", [
  92. {default, "{{crash_dump}}"},
  93. {datatype, file},
  94. hidden
  95. ]}.
  96. %% @doc http://www.erlang.org/doc/man/kernel_app.html#net_ticktime
  97. {mapping, "node.dist_net_ticktime", "vm_args.-kernel net_ticktime", [
  98. {commented, 60},
  99. {datatype, integer},
  100. hidden
  101. ]}.
  102. %% @doc http://www.erlang.org/doc/man/kernel_app.html
  103. {mapping, "node.dist_listen_min", "kernel.inet_dist_listen_min", [
  104. {commented, 6000},
  105. {datatype, integer},
  106. hidden
  107. ]}.
  108. %% @see node.dist_listen_min
  109. {mapping, "node.dist_listen_max", "kernel.inet_dist_listen_max", [
  110. {commented, 6999},
  111. {datatype, integer},
  112. hidden
  113. ]}.
  114. %%--------------------------------------------------------------------
  115. %% Log
  116. %%--------------------------------------------------------------------
  117. {mapping, "log.console", "lager.handlers", [
  118. {default, file },
  119. {datatype, {enum, [off, file, console, both]}}
  120. ]}.
  121. {mapping, "log.console.level", "lager.handlers", [
  122. {default, info},
  123. {datatype, {enum, [debug, info, notice, warning, error, critical, alert, emergency, none]}}
  124. ]}.
  125. {mapping, "log.console.file", "lager.handlers", [
  126. {default, "log/console.log"},
  127. {datatype, file}
  128. ]}.
  129. {mapping, "log.error.file", "lager.handlers", [
  130. {default, "log/error.log"},
  131. {datatype, file}
  132. ]}.
  133. {mapping, "log.error.redirect", "lager.error_logger_redirect", [
  134. {default, on},
  135. {datatype, flag},
  136. hidden
  137. ]}.
  138. {mapping, "log.error.messages_per_second", "lager.error_logger_hwm", [
  139. {default, 1000},
  140. {datatype, integer},
  141. hidden
  142. ]}.
  143. {translation,
  144. "lager.handlers",
  145. fun(Conf) ->
  146. ErrorHandler = case cuttlefish:conf_get("log.error.file", Conf) of
  147. undefined -> [];
  148. ErrorFilename -> [{lager_file_backend, [{file, ErrorFilename},
  149. {level, error},
  150. {size, 10485760},
  151. {date, "$D0"},
  152. {count, 5}]}]
  153. end,
  154. ConsoleLogLevel = cuttlefish:conf_get("log.console.level", Conf),
  155. ConsoleLogFile = cuttlefish:conf_get("log.console.file", Conf),
  156. ConsoleHandler = {lager_console_backend, ConsoleLogLevel},
  157. ConsoleFileHandler = {lager_file_backend, [{file, ConsoleLogFile},
  158. {level, ConsoleLogLevel},
  159. {size, 10485760},
  160. {date, "$D0"},
  161. {count, 5}]},
  162. ConsoleHandlers = case cuttlefish:conf_get("log.console", Conf) of
  163. off -> [];
  164. file -> [ConsoleFileHandler];
  165. console -> [ConsoleHandler];
  166. both -> [ConsoleHandler, ConsoleFileHandler];
  167. _ -> []
  168. end,
  169. ConsoleHandlers ++ ErrorHandler
  170. end
  171. }.
  172. {mapping, "log.crash", "lager.crash_log", [
  173. {default, on},
  174. {datatype, flag}
  175. ]}.
  176. {mapping, "log.crash.file", "lager.crash_log", [
  177. {default, "log/crash.log"},
  178. {datatype, file}
  179. ]}.
  180. {translation,
  181. "lager.crash_log",
  182. fun(Conf) ->
  183. case cuttlefish:conf_get("log.crash", Conf) of
  184. false -> undefined;
  185. _ ->
  186. cuttlefish:conf_get("log.crash.file", Conf, "./log/crash.log")
  187. end
  188. end}.
  189. {mapping, "sasl", "sasl.sasl_error_logger", [
  190. {default, off},
  191. {datatype, flag},
  192. hidden
  193. ]}.
  194. %%--------------------------------------------------------------------
  195. %% MQTT Protocol
  196. %%--------------------------------------------------------------------
  197. %% @doc Set the Max ClientId Length Allowed.
  198. {mapping, "mqtt.max_clientid_len", "emqttd.protocol", [
  199. {default, 1024},
  200. {datatype, integer}
  201. ]}.
  202. %% @doc Max Packet Size Allowed, 64K by default.
  203. {mapping, "mqtt.max_packet_size", "emqttd.protocol", [
  204. {default, "64KB"},
  205. {datatype, bytesize}
  206. ]}.
  207. %% @doc Client Idle Timeout.
  208. {mapping, "mqtt.client_idle_timeout", "emqttd.protocol", [
  209. {default, 30},
  210. {datatype, integer}
  211. ]}.
  212. {translation, "emqttd.protocol", fun(Conf) ->
  213. [{max_clientid_len, cuttlefish:conf_get("mqtt.max_clientid_len", Conf)},
  214. {max_packet_size, cuttlefish:conf_get("mqtt.max_packet_size", Conf)},
  215. {client_idle_timeout, cuttlefish:conf_get("mqtt.client_idle_timeout", Conf)}]
  216. end}.
  217. %% @doc Allow Anonymous
  218. {mapping, "mqtt.allow_anonymous", "emqttd.allow_anonymous", [
  219. {default, false},
  220. {datatype, {enum, [true, false]}},
  221. hidden
  222. ]}.
  223. %% @doc Default ACL File
  224. {mapping, "mqtt.acl_file", "emqttd.acl_file", [
  225. {datatype, string},
  226. hidden
  227. ]}.
  228. %%--------------------------------------------------------------------
  229. %% MQTT Session
  230. %%--------------------------------------------------------------------
  231. %% @doc Max number of QoS 1 and 2 messages that can be “inflight” at one time.
  232. %% 0 means no limit
  233. {mapping, "mqtt.session.max_inflight", "emqttd.session", [
  234. {default, 100},
  235. {datatype, integer}
  236. ]}.
  237. %% @doc Retry interval for redelivering QoS1/2 messages.
  238. {mapping, "mqtt.session.retry_interval", "emqttd.session", [
  239. {default, 60},
  240. {datatype, integer}
  241. ]}.
  242. %% @doc Awaiting PUBREL Timeout
  243. {mapping, "mqtt.session.await_rel_timeout", "emqttd.session", [
  244. {default, 30},
  245. {datatype, integer}
  246. ]}.
  247. %% @doc Max Packets that Awaiting PUBREL, 0 means no limit
  248. {mapping, "mqtt.session.max_awaiting_rel", "emqttd.session", [
  249. {default, 0},
  250. {datatype, integer}
  251. ]}.
  252. %% @doc Statistics Collection Interval(seconds)
  253. {mapping, "mqtt.session.collect_interval", "emqttd.session", [
  254. {default, 0},
  255. {datatype, integer}
  256. ]}.
  257. %% @doc Session expired after...
  258. {mapping, "mqtt.session.expired_after", "emqttd.session", [
  259. {default, "2d"},
  260. {datatype, {duration, s}}
  261. ]}.
  262. {translation, "emqttd.session", fun(Conf) ->
  263. [{max_inflight, cuttlefish:conf_get("mqtt.session.max_inflight", Conf)},
  264. {retry_interval, cuttlefish:conf_get("mqtt.session.retry_interval", Conf)},
  265. {await_rel_timeout, cuttlefish:conf_get("mqtt.session.await_rel_timeout", Conf)},
  266. {max_awaiting_rel, cuttlefish:conf_get("mqtt.session.max_awaiting_rel", Conf)},
  267. {collect_interval, cuttlefish:conf_get("mqtt.session.collect_interval", Conf)},
  268. {expired_after, cuttlefish:conf_get("mqtt.session.expired_after", Conf)}]
  269. end}.
  270. %%--------------------------------------------------------------------
  271. %% MQTT Queue
  272. %%--------------------------------------------------------------------
  273. %% @doc Type: simple | priority
  274. {mapping, "mqtt.queue.type", "emqttd.queue", [
  275. {default, simple},
  276. {datatype, atom}
  277. ]}.
  278. %% @doc Topic Priority: 0~255, Default is 0
  279. {mapping, "mqtt.queue.priority", "emqttd.queue", [
  280. {default, ""},
  281. {datatype, string},
  282. hidden
  283. ]}.
  284. %% @doc Max queue length. Enqueued messages when persistent client disconnected, or inflight window is full.
  285. {mapping, "mqtt.queue.max_length", "emqttd.queue", [
  286. {default, infinity},
  287. {datatype, [atom, integer]}
  288. ]}.
  289. %% @doc Low-water mark of queued messages
  290. {mapping, "mqtt.queue.low_watermark", "emqttd.queue", [
  291. {default, "20%"},
  292. {datatype, string},
  293. hidden
  294. ]}.
  295. %% @doc High-water mark of queued messages
  296. {mapping, "mqtt.queue.high_watermark", "emqttd.queue", [
  297. {default, "60%"},
  298. {datatype, string},
  299. hidden
  300. ]}.
  301. %% @doc Queue Qos0 messages?
  302. {mapping, "mqtt.queue.qos0", "emqttd.queue", [
  303. {default, true},
  304. {datatype, {enum, [true, false]}}
  305. ]}.
  306. {translation, "emqttd.queue", fun(Conf) ->
  307. Parse = fun(S) ->
  308. {match, [N]} = re:run(S, "^([0-9]+)%$", [{capture, all_but_first, list}]),
  309. list_to_integer(N) / 100
  310. end,
  311. Opts = [{type, cuttlefish:conf_get("mqtt.queue.type", Conf, simple)},
  312. {max_length, cuttlefish:conf_get("mqtt.queue.max_length", Conf)},
  313. {low_watermark, Parse(cuttlefish:conf_get("mqtt.queue.low_watermark", Conf))},
  314. {high_watermark, Parse(cuttlefish:conf_get("mqtt.queue.high_watermark", Conf))},
  315. {queue_qos0, cuttlefish:conf_get("mqtt.queue.qos0", Conf)}],
  316. case cuttlefish:conf_get("mqtt.queue.priority", Conf) of
  317. undefined -> Opts;
  318. V -> [{priority,
  319. [begin [T, P] = string:tokens(S, "="),
  320. {T, list_to_integer(P)}
  321. end || S <- string:tokens(V, ",")]}|Opts]
  322. end
  323. end}.
  324. %%--------------------------------------------------------------------
  325. %% MQTT Broker
  326. %%--------------------------------------------------------------------
  327. {mapping, "mqtt.broker.sys_interval", "emqttd.broker_sys_interval", [
  328. {default, 60},
  329. {datatype, integer}
  330. ]}.
  331. %%--------------------------------------------------------------------
  332. %% MQTT PubSub
  333. %%--------------------------------------------------------------------
  334. {mapping, "mqtt.pubsub.pool_size", "emqttd.pubsub", [
  335. {default, 8},
  336. {datatype, integer}
  337. ]}.
  338. {mapping, "mqtt.pubsub.by_clientid", "emqttd.pubsub", [
  339. {default, true},
  340. {datatype, {enum, [true, false]}}
  341. ]}.
  342. {mapping, "mqtt.pubsub.async", "emqttd.pubsub", [
  343. {default, true},
  344. {datatype, {enum, [true, false]}},
  345. hidden
  346. ]}.
  347. {translation, "emqttd.pubsub", fun(Conf) ->
  348. [{pool_size, cuttlefish:conf_get("mqtt.pubsub.pool_size", Conf)},
  349. {by_clientid, cuttlefish:conf_get("mqtt.pubsub.by_clientid", Conf)},
  350. {async, cuttlefish:conf_get("mqtt.pubsub.async", Conf)}]
  351. end}.
  352. %%--------------------------------------------------------------------
  353. %% MQTT Bridge
  354. %%--------------------------------------------------------------------
  355. {mapping, "mqtt.bridge.max_queue_len", "emqttd.bridge", [
  356. {default, 10000},
  357. {datatype, integer}
  358. ]}.
  359. {mapping, "mqtt.bridge.ping_down_interval", "emqttd.bridge", [
  360. {default, 1},
  361. {datatype, integer}
  362. ]}.
  363. {translation, "emqttd.bridge", fun(Conf) ->
  364. [{max_queue_len, cuttlefish:conf_get("mqtt.bridge.max_queue_len", Conf)},
  365. {ping_down_interval, cuttlefish:conf_get("mqtt.bridge.ping_down_interval", Conf)}]
  366. end}.
  367. %%-------------------------------------------------------------------
  368. %% MQTT Plugins
  369. %%-------------------------------------------------------------------
  370. {mapping, "mqtt.plugins.etc_dir", "emqttd.plugins_etc_dir", [
  371. {datatype, string}
  372. ]}.
  373. {mapping, "mqtt.plugins.loaded_file", "emqttd.plugins_loaded_file", [
  374. {datatype, string}
  375. ]}.
  376. %%--------------------------------------------------------------------
  377. %% MQTT Listeners
  378. %%--------------------------------------------------------------------
  379. {mapping, "mqtt.listener.tcp", "emqttd.listeners", [
  380. {default, 1883},
  381. {datatype, [integer, ip]}
  382. ]}.
  383. {mapping, "mqtt.listener.tcp.acceptors", "emqttd.listeners", [
  384. {default, 8},
  385. {datatype, integer}
  386. ]}.
  387. {mapping, "mqtt.listener.tcp.max_clients", "emqttd.listeners", [
  388. {default, 1024},
  389. {datatype, integer}
  390. ]}.
  391. {mapping, "mqtt.listener.tcp.rate_limit", "emqttd.listeners", [
  392. {default, undefined},
  393. {datatype, string},
  394. hidden
  395. ]}.
  396. {mapping, "mqtt.listener.tcp.backlog", "emqttd.listeners", [
  397. {default, 1024},
  398. {datatype, integer}
  399. ]}.
  400. {mapping, "mqtt.listener.tcp.recbuf", "emqttd.listeners", [
  401. {datatype, integer},
  402. hidden
  403. ]}.
  404. {mapping, "mqtt.listener.tcp.sndbuf", "emqttd.listeners", [
  405. {datatype, integer},
  406. hidden
  407. ]}.
  408. {mapping, "mqtt.listener.tcp.buffer", "emqttd.listeners", [
  409. {datatype, integer},
  410. hidden
  411. ]}.
  412. {mapping, "mqtt.listener.tcp.nodelay", "emqttd.listeners", [
  413. {datatype, {enum, [true, false]}},
  414. hidden
  415. ]}.
  416. {mapping, "mqtt.listener.ssl", "emqttd.listeners", [
  417. {default, 8883},
  418. {datatype, [integer, ip]}
  419. ]}.
  420. {mapping, "mqtt.listener.ssl.acceptors", "emqttd.listeners", [
  421. {default, 8},
  422. {datatype, integer}
  423. ]}.
  424. {mapping, "mqtt.listener.ssl.max_clients", "emqttd.listeners", [
  425. {default, 512},
  426. {datatype, integer}
  427. ]}.
  428. {mapping, "mqtt.listener.ssl.rate_limit", "emqttd.listeners", [
  429. {datatype, string}
  430. ]}.
  431. {mapping, "mqtt.listener.ssl.handshake_timeout", "emqttd.listeners", [
  432. {default, 15},
  433. {datatype, integer}
  434. ]}.
  435. {mapping, "mqtt.listener.ssl.keyfile", "emqttd.listeners", [
  436. {datatype, string}
  437. ]}.
  438. {mapping, "mqtt.listener.ssl.certfile", "emqttd.listeners", [
  439. {datatype, string}
  440. ]}.
  441. {mapping, "mqtt.listener.ssl.cacertfile", "emqttd.listeners", [
  442. {datatype, string}
  443. ]}.
  444. {mapping, "mqtt.listener.ssl.verify", "emqttd.listeners", [
  445. {datatype, string}
  446. ]}.
  447. {mapping, "mqtt.listener.ssl.failed_if_no_peer_cert", "emqttd.listeners", [
  448. {datatype, {enum, [true, false]}}
  449. ]}.
  450. {mapping, "mqtt.listener.http", "emqttd.listeners", [
  451. {default, 8883},
  452. {datatype, [integer, ip]}
  453. ]}.
  454. {mapping, "mqtt.listener.http.acceptors", "emqttd.listeners", [
  455. {default, 8},
  456. {datatype, integer}
  457. ]}.
  458. {mapping, "mqtt.listener.http.max_clients", "emqttd.listeners", [
  459. {default, 64},
  460. {datatype, integer}
  461. ]}.
  462. {mapping, "mqtt.listener.https", "emqttd.listeners", [
  463. {default, undefined},
  464. {datatype, [integer, ip]},
  465. hidden
  466. ]}.
  467. {mapping, "mqtt.listener.https.acceptors", "emqttd.listeners", [
  468. {default, 8},
  469. {datatype, integer}
  470. ]}.
  471. {mapping, "mqtt.listener.https.max_clients", "emqttd.listeners", [
  472. {default, 64},
  473. {datatype, integer}
  474. ]}.
  475. {mapping, "mqtt.listener.https.handshake_timeout", "emqttd.listeners", [
  476. {default, 15},
  477. {datatype, integer}
  478. ]}.
  479. {mapping, "mqtt.listener.https.keyfile", "emqttd.listeners", [
  480. {datatype, string}
  481. ]}.
  482. {mapping, "mqtt.listener.https.certfile", "emqttd.listeners", [
  483. {datatype, string}
  484. ]}.
  485. {mapping, "mqtt.listener.https.cacertfile", "emqttd.listeners", [
  486. {datatype, string}
  487. ]}.
  488. {mapping, "mqtt.listener.https.verify", "emqttd.listeners", [
  489. {datatype, string}
  490. ]}.
  491. {mapping, "mqtt.listener.https.failed_if_no_peer_cert", "emqttd.listeners", [
  492. {datatype, {enum, [true, false]}}
  493. ]}.
  494. {translation, "emqttd.listeners", fun(Conf) ->
  495. Filter = fun(Opts) -> [{K, V} || {K, V} <- Opts, V =/= undefined] end,
  496. LisOpts = fun(Prefix) ->
  497. Filter([{acceptors, cuttlefish:conf_get(Prefix ++ ".acceptors", Conf)},
  498. {max_clients, cuttlefish:conf_get(Prefix ++ ".max_clients", Conf)},
  499. {rate_limt, cuttlefish:conf_get(Prefix ++ ".rate_limit", Conf, undefined)}])
  500. end,
  501. TcpOpts = fun(Prefix) ->
  502. Filter([{backlog, cuttlefish:conf_get(Prefix ++ ".backlog", Conf, undefined)},
  503. {recbuf, cuttlefish:conf_get(Prefix ++ ".recbuf", Conf, undefined)},
  504. {sndbuf, cuttlefish:conf_get(Prefix ++ ".sndbuf", Conf, undefined)},
  505. {buffer, cuttlefish:conf_get(Prefix ++ ".buffer", Conf, undefined)},
  506. {nodelay, cuttlefish:conf_get(Prefix ++ ".nodelay", Conf, true)}])
  507. end,
  508. SslOpts = fun(Prefix) ->
  509. Filter([{handshake_timeout, cuttlefish:conf_get(Prefix ++ ".handshake_timeout", Conf)},
  510. {keyfile, cuttlefish:conf_get(Prefix ++ ".keyfile", Conf, undefined)},
  511. {certfile, cuttlefish:conf_get(Prefix ++ ".certfile", Conf, undefined)},
  512. {cacertfile, cuttlefish:conf_get(Prefix ++ ".cacertfile", Conf, undefined)},
  513. {verify, cuttlefish:conf_get(Prefix ++ ".verify_peer", Conf, undefined)},
  514. {failed_if_no_peer_cert, cuttlefish:conf_get(Prefix ++ "failed_if_no_peer_cert", Conf, undefined)}])
  515. end,
  516. Listeners = fun(Name) when is_atom(Name) ->
  517. Key = "mqtt.listener." ++ atom_to_list(Name),
  518. case cuttlefish:conf_get(Key, Conf, undefined) of
  519. undefined ->
  520. [];
  521. Port ->
  522. ConnOpts = Filter([{rate_limit, cuttlefish:conf_get(Key ++ ".rate_limit", Conf, undefined)}]),
  523. Opts = [{connopts, ConnOpts}, {sockopts, TcpOpts(Key)} | LisOpts(Key)],
  524. [{Name, Port, case Name =:= ssl orelse Name =:= https of
  525. true -> [{ssl, SslOpts(Key)} | Opts];
  526. false -> Opts
  527. end}]
  528. end
  529. end,
  530. lists:append([Listeners(tcp), Listeners(ssl), Listeners(http), Listeners(https)])
  531. end}.
  532. %%--------------------------------------------------------------------
  533. %% MQTT Modules
  534. %%--------------------------------------------------------------------
  535. {mapping, "mqtt.module.retainer", "emqttd.modules", [
  536. {default, on},
  537. {datatype, flag}
  538. ]}.
  539. {mapping, "mqtt.module.retainer.storage_type", "emqttd.modules", [
  540. {default, ram},
  541. {datatype, {enum, [disc, ram]}}
  542. ]}.
  543. {mapping, "mqtt.module.retainer.max_message_num", "emqttd.modules", [
  544. {default, 100000},
  545. {datatype, integer}
  546. ]}.
  547. {mapping, "mqtt.module.retainer.max_payload_size", "emqttd.modules", [
  548. {default, "64KB"},
  549. {datatype, bytesize}
  550. ]}.
  551. {mapping, "mqtt.module.retainer.expired_after", "emqttd.modules", [
  552. {default, 0},
  553. {datatype, integer}
  554. ]}.
  555. {mapping, "mqtt.module.presence", "emqttd.modules", [
  556. {default, on},
  557. {datatype, flag}
  558. ]}.
  559. {mapping, "mqtt.module.presence.qos", "emqttd.modules", [
  560. {default, 0},
  561. {datatype, integer},
  562. {validators, ["range:0-2"]}
  563. ]}.
  564. {mapping, "mqtt.module.subscription", "emqttd.modules", [
  565. {default, off},
  566. {datatype, flag}
  567. ]}.
  568. {mapping, "mqtt.module.subscription.topics", "emqttd.modules", [
  569. {default, undefined},
  570. {datatype, string}
  571. ]}.
  572. {translation, "emqttd.modules", fun(Conf) ->
  573. WithMod = fun(Name, OptsF) ->
  574. Key = "mqtt.module." ++ atom_to_list(Name),
  575. case cuttlefish:conf_get(Key, Conf, false) of
  576. true -> [{Name, OptsF(Key)}];
  577. false -> []
  578. end
  579. end,
  580. RetainOpts = fun(Prefix) ->
  581. [{storage_type, cuttlefish:conf_get(Prefix ++ ".storage_type", Conf, ram)},
  582. {max_message_num, cuttlefish:conf_get(Prefix ++ ".max_message_num", Conf, undefined)},
  583. {max_payload_size, cuttlefish:conf_get(Prefix ++ ".max_payload_size", Conf, undefined)},
  584. {expired_after, cuttlefish:conf_get(Prefix ++ ".expired_after", Conf, 0)}]
  585. end,
  586. PresOpts = fun(Prefix) ->
  587. [{qos, cuttlefish:conf_get(Prefix ++ ".qos", Conf, 0)}]
  588. end,
  589. ParseFun = fun(undefined) -> [];
  590. (Topics) -> [begin
  591. [Topic, Qos] = string:tokens(S, "="),
  592. {list_to_binary(Topic), list_to_integer(Qos)}
  593. end || S <- string:tokens(Topics, ",")]
  594. end,
  595. SubOpts = fun(Prefix) -> [{topics, ParseFun(cuttlefish:conf_get(Prefix ++ ".topics", Conf))}] end,
  596. lists:append([WithMod(retainer, RetainOpts), WithMod(presence, PresOpts), WithMod(subscription, SubOpts)])
  597. end}.
  598. %%--------------------------------------------------------------------
  599. %% System Monitor
  600. %%--------------------------------------------------------------------
  601. %% @doc Long GC, don't monitor in production mode for:
  602. %% https://github.com/erlang/otp/blob/feb45017da36be78d4c5784d758ede619fa7bfd3/erts/emulator/beam/erl_gc.c#L421
  603. {mapping, "sysmon.long_gc", "emqttd.sysmon", [
  604. {default, false},
  605. {datatype, {enum, [true, false]}}
  606. ]}.
  607. %% @doc Long Schedule(ms)
  608. {mapping, "sysmon.long_schedule", "emqttd.sysmon", [
  609. {default, 1000},
  610. {datatype, integer}
  611. ]}.
  612. %% @doc Large Heap
  613. {mapping, "sysmon.large_heap", "emqttd.sysmon", [
  614. {default, "8MB"},
  615. {datatype, bytesize}
  616. ]}.
  617. %% @doc Monitor Busy Port
  618. {mapping, "sysmon.busy_port", "emqttd.sysmon", [
  619. {default, false},
  620. {datatype, {enum, [true, false]}}
  621. ]}.
  622. %% @doc Monitor Busy Dist Port
  623. {mapping, "sysmon.busy_dist_port", "emqttd.sysmon", [
  624. {default, true},
  625. {datatype, {enum, [true, false]}}
  626. ]}.
  627. {translation, "emqttd.sysmon", fun(Conf) ->
  628. [{long_gc, cuttlefish:conf_get("sysmon.long_gc", Conf)},
  629. {long_schedule, cuttlefish:conf_get("sysmon.long_schedule", Conf)},
  630. {large_heap, cuttlefish:conf_get("sysmon.large_heap", Conf)},
  631. {busy_port, cuttlefish:conf_get("sysmon.busy_port", Conf)},
  632. {busy_dist_port, cuttlefish:conf_get("sysmon.busy_dist_port", Conf)}]
  633. end}.