Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update template to demonstrate custom configuration #31

Merged
merged 1 commit into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ jobs:
fail-fast: false
matrix:
otp:
- 25.3.2-2
- 26.2.5-2
elixir:
- 1.14.5
- 1.15.7
os:
- ubuntu22.04

container: "ghcr.io/emqx/emqx-builder/5.2-3:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os }}"
container: "ghcr.io/emqx/emqx-builder/5.3-8:${{ matrix.elixir }}-${{ matrix.otp }}-${{ matrix.os }}"

steps:
- name: Checkout
Expand Down
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
erlang 25.3.2
elixir 1.14.5-otp-25
erlang 26.2.5-2
elixir 1.15.7-otp-26
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Example EMQX Elixir Plugin Template

An example Mix project that can be used to build an EMQX 5.0.0 plugin.
An example Mix project that can be used to build an EMQX 5.7.0 plugin.

## Quickstart

Expand Down Expand Up @@ -33,3 +33,18 @@ An example Mix project that can be used to build an EMQX 5.0.0 plugin.
topic: "topic"
}
```

## Custom configuration schema

EMQX 5.7.0 introduced the Avro configuration schema feature which allows plugins to define their own config schema to be used and managed. In order to use this feature:

- Be sure to use EMQX 5.7.0 or newer;
- Rename and edit the following files:
- `priv/config.hocon.example` -> `priv/config.hocon`
- `priv/config_i18n.json.example` -> `priv/config_i18n.json`
- `priv/config_schema.avsc.example` -> `priv/config_schema.avsc`
- Refer to `priv/config_schema.avsc.enterprise.example` if using EMQX Enterprise
Edition.
- Set `:with_config_schema?` to `true` under the `emqx_plugin_opts` release config in
`mix.exs`.
- Add `:emqx_plugins` as a dependency by uncommenting the line containing `emqx_dep.(:emqx_plugins)` in `mix.exs`'s dependencies.
21 changes: 17 additions & 4 deletions lib/elixir_plugin_template.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
defmodule ElixirPluginTemplate do
use GenServer

require Logger

@moduledoc """
A dummy example server
"""
Expand All @@ -20,6 +22,15 @@ defmodule ElixirPluginTemplate do

@impl GenServer
def init(_) do
## If your plugin defines a custom configuration schema, you may access it with
## `:emqx_plugins.get_config`.
## Ex:
# this_app = Application.get_application(__MODULE__)
# with {:ok, vsn} <- :application.get_key(this_app, :vsn),
# app_vsn = IO.iodata_to_binary([to_string(this_app), "-", vsn]),
# {:ok, %{"hostname" => hostname, "port" => port}} <- :emqx_plugins.get_config(app_vsn) do
# Logger.warning("using server #{hostname}:#{port}")
# end
{:ok, %{pings: 0}}
end

Expand All @@ -30,10 +41,12 @@ defmodule ElixirPluginTemplate do
end

@impl GenServer
def handle_cast({:log, msg}, state) do
msg
|> :emqx_message.to_map()
|> IO.inspect(label: :emqx_msg)
def handle_cast({:log, _msg}, state) do
## Do stuff here.
## Ex:
# msg
# |> :emqx_message.to_map()
# |> tap(&Logger.debug/1)

{:noreply, state}
end
Expand Down
51 changes: 30 additions & 21 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,20 @@ defmodule ElixirPluginTemplate.MixProject do
repo: "https://github.com/emqx/emqx-elixir-plugin-template",
functionality: ["Demo"],
compatibility: %{
emqx: "~> 5.0"
emqx: "~> 5.7.0"
},
description: "This is a demo plugin"
},
emqx_plugin_opts: [
include_src?: true,
exclude_elixir?: false
## Set this to `false` if your EMQX installation does not already ship with
## Elixir.
exclude_elixir?: true,
## Set`:with_config_schema?` to `true` if your application uses its own Avro
## configuration.
## See `priv/config.hocon.example`, `config_i18n.json.example`, and
## `priv/config_schema.avsc{.enterprise,}.example` files for examples.
with_config_schema?: false
]
]
]
Expand Down Expand Up @@ -174,6 +181,7 @@ defmodule ElixirPluginTemplate.MixProject do
end

defp make_plugin_release_json(release, lib_dirs) do
with_config_schema? = get_in(release.options, [:emqx_plugin_opts, :with_config_schema?])
extra_info = %{
name: release.name,
rel_vsn: release.version,
Expand All @@ -182,7 +190,8 @@ defmodule ElixirPluginTemplate.MixProject do
git_commit_or_build_date: get_date(),
metadata_vsn: @emqx_metadata_vsn,
built_on_otp_release: System.otp_release(),
built_on_elixir_release: System.version()
built_on_elixir_release: System.version(),
with_config_schema: with_config_schema?
}

release.options[:emqx_plugin_info]
Expand Down Expand Up @@ -225,33 +234,33 @@ defmodule ElixirPluginTemplate.MixProject do

# Run "mix help deps" to learn about dependencies.
defp deps do
# emqx v5.7.0
emqx_ref = "d885ac3dd8626fb6ad3d246db279c922e4eb5a0c"
emqx_dep = fn app ->
{app,
git: "https://github.com/emqx/emqx",
ref: emqx_ref,
sparse: "apps/#{app}",
override: true,
runtime: false}
end
[
# This is just for building the tarball. Remove `runtime:
# false` if your application depends on this lib.
{:jason, "~> 1.3", runtime: false},
# If your plugin depends on emqx, you may include it here. Be
# sure to use `runtime: false`.
{:emqx,
git: "https://github.com/emqx/emqx",
ref: "7b3ce3cbc740af4707f5bef5aee499f1e9842ac9",
sparse: "apps/emqx",
runtime: false},
{:emqx_utils,
git: "https://github.com/emqx/emqx",
ref: "7b3ce3cbc740af4707f5bef5aee499f1e9842ac9",
sparse: "apps/emqx_utils",
runtime: false,
override: true},
{:emqx_durable_storage,
git: "https://github.com/emqx/emqx",
ref: "7b3ce3cbc740af4707f5bef5aee499f1e9842ac9",
sparse: "apps/emqx_durable_storage",
runtime: false,
override: true,
app: false},
emqx_dep.(:emqx),
emqx_dep.(:emqx_ctl),
emqx_dep.(:emqx_utils),
emqx_dep.(:emqx_durable_storage),
## Uncomment the `:emqx_plugins` line if your application uses custom configuration
## schema:
# emqx_dep.(:emqx_plugins),
# temporarily needed due to clashing dependencies of
# dependencies of emqx.
{:cowlib, "2.8.0", override: true, runtime: false},
{:jiffy, github: "emqx/jiffy", tag: "1.0.6", override: true, runtime: false},
# These are dependencies for your plugin
{:hallux, "~> 1.2"}
]
Expand Down
31 changes: 18 additions & 13 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,33 +1,38 @@
%{
"aten": {:hex, :aten, "0.6.0", "7a57b275a6daf515ac3683fb9853e280b4d0dcdd74292fd66ac4a01c8694f8c7", [:rebar3], [], "hexpm", "5f39a164206ae3f211ef5880b1f7819415686436e3229d30b6a058564fbaa168"},
"bcrypt": {:git, "https://github.com/emqx/erlang-bcrypt.git", "dc2ba66acf2332c111362d01137746eefecc5e90", [tag: "0.6.0"]},
"cowboy": {:git, "https://github.com/emqx/cowboy", "f4a05678e3e66633d4e3c25bc390c02b8996918e", [tag: "2.9.2"]},
"cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm", "79f954a7021b302186a950a32869dbc185523d99d3e44ce430cd1f3289f41ed4"},
"eetcd": {:git, "https://github.com/zhongwencool/eetcd", "69d50aca98247953ee8a3ff58423a693f8318d90", [tag: "v0.3.4"]},
"ekka": {:git, "https://github.com/emqx/ekka", "2912b6938ae4562f0ac3a96c7075de464524dcd6", [tag: "0.15.14"]},
"emqx": {:git, "https://github.com/emqx/emqx", "7b3ce3cbc740af4707f5bef5aee499f1e9842ac9", [ref: "7b3ce3cbc740af4707f5bef5aee499f1e9842ac9", sparse: "apps/emqx"]},
"emqx_durable_storage": {:git, "https://github.com/emqx/emqx", "7b3ce3cbc740af4707f5bef5aee499f1e9842ac9", [ref: "7b3ce3cbc740af4707f5bef5aee499f1e9842ac9", sparse: "apps/emqx_durable_storage"]},
"ekka": {:git, "https://github.com/emqx/ekka", "27840afe2f0d9e04e63a3a73cc18be449443908b", [tag: "0.19.3"]},
"emqx": {:git, "https://github.com/emqx/emqx", "d885ac3dd8626fb6ad3d246db279c922e4eb5a0c", [ref: "d885ac3dd8626fb6ad3d246db279c922e4eb5a0c", sparse: "apps/emqx"]},
"emqx_ctl": {:git, "https://github.com/emqx/emqx", "d885ac3dd8626fb6ad3d246db279c922e4eb5a0c", [ref: "d885ac3dd8626fb6ad3d246db279c922e4eb5a0c", sparse: "apps/emqx_ctl"]},
"emqx_durable_storage": {:git, "https://github.com/emqx/emqx", "d885ac3dd8626fb6ad3d246db279c922e4eb5a0c", [ref: "d885ac3dd8626fb6ad3d246db279c922e4eb5a0c", sparse: "apps/emqx_durable_storage"]},
"emqx_http_lib": {:git, "https://github.com/emqx/emqx_http_lib.git", "6adc836747d346635066801e38c60de4f7f6fe20", [tag: "0.5.3"]},
"emqx_utils": {:git, "https://github.com/emqx/emqx", "7b3ce3cbc740af4707f5bef5aee499f1e9842ac9", [ref: "7b3ce3cbc740af4707f5bef5aee499f1e9842ac9", sparse: "apps/emqx_utils"]},
"esockd": {:git, "https://github.com/emqx/esockd", "04e20992b3be10d453adc3da503c625b5f452531", [tag: "5.9.7"]},
"gen_rpc": {:git, "https://github.com/emqx/gen_rpc", "f1029663e632ab03c1ab7d66b12bce4cbea7e6e6", [tag: "3.1.0"]},
"emqx_utils": {:git, "https://github.com/emqx/emqx", "d885ac3dd8626fb6ad3d246db279c922e4eb5a0c", [ref: "d885ac3dd8626fb6ad3d246db279c922e4eb5a0c", sparse: "apps/emqx_utils"]},
"esockd": {:git, "https://github.com/emqx/esockd", "313713eff1ecaf4d5c9e6d575ebd1b5f4e14e9c5", [tag: "5.11.2"]},
"gen_batch_server": {:hex, :gen_batch_server, "0.8.8", "7840a1fa63ee1effc83e8a91d22664847a2ba1192d30eafffd914acb51578068", [:rebar3], [], "hexpm", "c3e6a1a2a0fb62aee631a98cfa0fd8903e9562422cbf72043953e2fb1d203017"},
"gen_rpc": {:git, "https://github.com/emqx/gen_rpc", "3251f41065786945580be7f0eadeb4246d3b256a", [tag: "3.3.1"]},
"getopt": {:hex, :getopt, "1.0.1", "c73a9fa687b217f2ff79f68a3b637711bb1936e712b521d8ce466b29cbf7808a", [:rebar3], [], "hexpm", "53e1ab83b9ceb65c9672d3e7a35b8092e9bdc9b3ee80721471a161c10c59959c"},
"gproc": {:git, "https://github.com/emqx/gproc", "21a5995812498969bb5e47b520b47ea7c514f16b", [tag: "0.9.0.1"]},
"gun": {:hex, :gun, "1.3.3", "cf8b51beb36c22b9c8df1921e3f2bc4d2b1f68b49ad4fbc64e91875aa14e16b4", [:rebar3], [{:cowlib, "~> 2.7.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "3106ce167f9c9723f849e4fb54ea4a4d814e3996ae243a1c828b256e749041e0"},
"hallux": {:hex, :hallux, "1.2.0", "0d26c4f4db8a988683c5a2fadd0c02807e72e26c09d2a57b2ee670fff8397c75", [:mix], [], "hexpm", "6d19ea15b2603bfbf584b6b016abb97c9512b2fad6f55d4f2933061bdce9e86b"},
"hocon": {:git, "https://github.com/emqx/hocon.git", "de7428d83cb048556ba49ca30867c7fd0948d06b", [tag: "0.39.16"]},
"hocon": {:git, "https://github.com/emqx/hocon.git", "a796199f672b2ff8f0286b9af70513d00fc4ccb9", [tag: "0.42.2"]},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"jiffy": {:git, "https://github.com/emqx/jiffy", "baa1f4e750ae3c5c9e54f9c2e52280b7fc24a8d9", [tag: "1.0.5"]},
"jiffy": {:git, "https://github.com/emqx/jiffy.git", "8727c771d56978cf121316b2d88761467b151420", [tag: "1.0.6"]},
"lc": {:git, "https://github.com/emqx/lc.git", "ef76ab213f78f5efcc49a30ae3b41822c6db1ba0", [tag: "0.3.2"]},
"mnesia_rocksdb": {:git, "https://github.com/emqx/mnesia_rocksdb", "99d9193778d0fa545b722369319ab0c76a544ceb", [tag: "0.1.14"]},
"mria": {:git, "https://github.com/emqx/mria", "efda2264d5f634c6ea387341151d9f2a3a5bd417", [tag: "0.6.3"]},
"mnesia_rocksdb": {:git, "https://github.com/emqx/mnesia_rocksdb", "6ae456e536b8cb8f3ffa33bbe57dc90484eb1479", [tag: "0.1.15"]},
"mria": {:git, "https://github.com/emqx/mria", "21c5954ff4db050be651d37e753f882d3b707813", [tag: "0.8.6"]},
"optvar": {:git, "https://github.com/emqx/optvar", "2331bbff4ddce7d9dc64698936a9d158174f3315", [tag: "1.0.5"]},
"pbkdf2": {:git, "https://github.com/emqx/erlang-pbkdf2.git", "45d9981209ea07a83a58cf85aaf8236457da4342", [tag: "2.0.4"]},
"quicer": {:git, "https://github.com/emqx/quic.git", "ef73617d0f10f0f30f3aa77eb4a2f6ae071a2e29", [tag: "0.0.9"]},
"quicer": {:git, "https://github.com/emqx/quic.git", "69de6f1c81629e3dbee32a9eea4aed3b5455b7b6", [tag: "0.0.313"]},
"ra": {:hex, :ra, "2.7.3", "e2d98860f13e671388bbb8cae740f61c0df7d7589c1d59e556cdac491eff9c77", [:rebar3], [{:aten, "0.6.0", [hex: :aten, repo: "hexpm", optional: false]}, {:gen_batch_server, "0.8.8", [hex: :gen_batch_server, repo: "hexpm", optional: false]}, {:seshat, "0.6.0", [hex: :seshat, repo: "hexpm", optional: false]}], "hexpm", "6f2b912a779f4efa4deea762b65192ed6e87111c7d98cbbe8a29576964739147"},
"ranch": {:git, "https://github.com/emqx/ranch", "d3d6420b190b4ed084b3a5db82c35a3eeae75212", [tag: "1.8.1-emqx"]},
"recon": {:git, "https://github.com/ferd/recon", "f7b6c08e6e9e2219db58bfb012c58c178822e01e", [tag: "2.5.1"]},
"replayq": {:git, "https://github.com/emqx/replayq", "1d389ac552eb6952ce515298ef60284df659e617", [tag: "0.3.6"]},
"rocksdb": {:git, "https://github.com/emqx/erlang-rocksdb.git", "5c08f88b045b2b09a474c2f1ee894fb2740bcdae", [tag: "1.8.0-emqx-1"]},
"rocksdb": {:git, "https://github.com/emqx/erlang-rocksdb.git", "27226d982f5f74965190672bbca5e348a9d9ea94", [tag: "1.8.0-emqx-2"]},
"seshat": {:hex, :seshat, "0.6.0", "3172eb1d7a2a4f66108cd6933a4e465aff80f84aa90ed83f047b92f636123ccd", [:rebar3], [], "hexpm", "7cef700f92831dd7cae6a6dd223ccc55ac88ecce0631ee9ab0f2b5fb70e79b90"},
"sext": {:hex, :sext, "1.8.0", "90a95b889f5c781b70bbcf44278b763148e313c376b60d87ce664cb1c1dd29b5", [:rebar3], [], "hexpm", "bc6016cb8690baf677eacacfe6e7cadfec8dc7e286cbbed762f6cd55b0678e73"},
"snabbkaffe": {:git, "https://github.com/kafka4beam/snabbkaffe.git", "732ac2c9f2daff1d5c2fe4bd225037d5820095a0", [tag: "1.0.8"]},
"snabbkaffe": {:git, "https://github.com/kafka4beam/snabbkaffe.git", "b59298334ed349556f63405d1353184c63c66534", [tag: "1.0.10"]},
"typerefl": {:git, "https://github.com/ieQu1/typerefl.git", "310b82ff02f96207c519b9556491433b6ea02d01", [tag: "0.9.1"]},
}
20 changes: 20 additions & 0 deletions priv/config.hocon.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## This is a demo config in HOCON format
## The same format used by EMQX since 5.0

hostname = "localhost"
port = 3306

connectionOptions = [
{
optionName = "autoReconnect"
optionType = "string"
optionValue = "true"
}
]

auth {
username = "admin"
password {
string = "Public123"
}
}
74 changes: 74 additions & 0 deletions priv/config_i18n.json.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"$hostname_label": {
"zh": "主机名",
"en": "Hostname"
},
"$hostname_desc": {
"zh": "主机名是一个标识符,用于识别网络上的设备。主机名通常是一个域名,例如:www.example.com。",
"en": "The hostname is an identifier used to identify devices on a network. The hostname is usually a domain name, such as www.example.com."
},
"$hostname_validate": {
"zh": "主机名必须是一个有效的域名。",
"en": "The hostname must be a valid domain name."
},
"$port_label": {
"zh": "端口",
"en": "Port"
},
"$port_desc": {
"zh": "端口是一个数字,用于标识网络上的服务。常见的端口有:80(HTTP)、443(HTTPS)、21(FTP)。",
"en": "The port is a number used to identify services on a network. Common ports include: 80 (HTTP), 443 (HTTPS), 21 (FTP)."
},
"$port_range_validate": {
"zh": "端口必须在 1 到 65535 之间。",
"en": "The port must be between 1 and 65535."
},
"$connection_options_label": {
"en": "Connection Options",
"zh": "连接选项"
},
"$connection_options_desc": {
"en": "A list of additional options for the database connection.",
"zh": "数据库连接的附加选项列表。"
},
"$username_label": {
"en": "Username",
"zh": "用户名"
},
"$username_desc": {
"zh": "连接数据库的用户名",
"en": "The username used to connect to the database."
},
"$password_label": {
"en": "Password",
"zh": "密码"
},
"$password_desc": {
"en": "The password used to connect to the database.",
"zh": "连接数据库的密码。"
},
"$password_length_validate": {
"en": "The password must be at least 8 characters long.",
"zh": "密码长度必须至少为 8 个字符。"
},
"$password_validate": {
"en": "The password must contain at least one uppercase letter, one lowercase letter, one number, and one special character.",
"zh": "密码必须包含至少一个大写字母、一个小写字母、一个数字和一个特殊字符。"
},
"$option_name_label": {
"en": "Option Name",
"zh": "选项名称"
},
"$option_name_desc": {
"en": "The name of the connection option.",
"zh": "连接选项的名称。"
},
"$option_value_label": {
"en": "Option Value",
"zh": "选项值"
},
"$option_value_desc": {
"en": "The value of the connection option.",
"zh": "连接选项的值。"
}
}
Loading