Packages
avrora
0.29.0
0.30.2
0.30.1
0.30.0
0.29.2
0.29.1
0.29.0
0.28.0
0.27.0
0.26.0
0.25.0
0.24.2
0.24.1
0.24.0
0.23.0
0.22.0
0.21.1
0.21.0
0.20.0
0.19.0
0.18.1
0.18.0
0.17.0
0.16.0
0.15.0
0.14.1
0.14.0
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.1
0.8.0
0.7.1
0.7.0
0.6.0
0.5.1
0.5.0
0.4.0
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.1-beta
0.1.0-beta
An Elixir library for working with Avro messages conveniently. It supports local schema files and Confluent® schema registry.
Current section
Files
Jump to
Current section
Files
lib/avrora/client.ex
defmodule Avrora.Client do
@moduledoc """
Generates client module with isolated memory storage.
## Examples
defmodule MyClient do
use Avrora.Client,
schemas_path: Path.expand("./priv/schemas"),
registry_url: "https://registry.io"
end
It will expose `Avrora.Encoder` module functions and make `MyClient` module
identical to `Avrora` module, but isolated from it.
To start using `MyClient` follow the [Start cache process](README.md#start-cache-process),
add it to your supervision tree
children = [
MyClient
]
Supervisor.start_link(children, strategy: :one_for_one)
or start the process manually
{:ok, pid} = MyClient.start_link()
"""
# NOTE: Modules below contain usage of some other modules which should be defined
# under the private client module, for instance, `Avrora.Config` could be
# defined as `MyClient.Config`. Hence they are listed together with some
# aliases.
@modules ~w(
encoder
resolver
avro_schema_store
avro_decoder_options
schema/encoder
codec/plain
codec/schema_registry
codec/object_container_file
storage/file
storage/memory
storage/registry
utils/registrar
)
@aliases ~w(
Codec
Config
Resolver
Schema.Encoder
AvroDecoderOptions
Codec.Plain
Codec.SchemaRegistry
Codec.ObjectContainerFile
Storage.Registry
Storage.File
)
defp personalize(definition, module: module) do
definition = Regex.replace(~r/defmodule Avrora\./, definition, "defmodule ")
~r/alias Avrora\.([\w\.]+)(, as: [\w\.]+)?/
|> Regex.scan(definition)
|> Enum.reject(fn [_, modl | _] -> !Enum.member?(@aliases, modl) end)
|> Enum.reduce(definition, fn [alis, modl | as], defn ->
Regex.replace(~r/#{alis}(?=[[:cntrl:]])/, defn, "alias #{module}.#{modl}#{as}")
end)
end
defp generate!(definition, file: file) do
case Code.string_to_quoted(definition, file: file) do
{:ok, quoted} ->
quoted
{:error, {line, error, token}} ->
raise "error #{error} on line #{line} caused by #{inspect(token)}"
end
end
defmacro __using__(opts) do
module = __CALLER__.module |> Module.split() |> Enum.join(".")
modules =
@modules
|> Enum.map(fn name ->
file = Path.expand("./#{name}.ex", __DIR__)
file
|> File.read!()
|> personalize(module: module)
|> generate!(file: file)
end)
config =
quote do
defmodule Config do
@dialyzer {:no_match, [schemas_path: 0]}
@moduledoc false
@opts unquote(opts)
@otp_app Keyword.get(@opts, :otp_app)
def registry_url, do: get(@opts, :registry_url, nil)
def registry_auth, do: get(@opts, :registry_auth, nil)
def registry_user_agent, do: get(@opts, :registry_user_agent, "Avrora/#{version()} Elixir")
def registry_ssl_cacerts, do: get(@opts, :registry_ssl_cacerts, nil)
def registry_schemas_autoreg, do: get(@opts, :registry_schemas_autoreg, true)
def convert_null_values, do: get(@opts, :convert_null_values, true)
def convert_map_to_proplist, do: get(@opts, :convert_map_to_proplist, false)
def names_cache_ttl, do: get(@opts, :names_cache_ttl, :infinity)
def decoder_hook, do: get(@opts, :decoder_hook, fn _, _, data, fun -> fun.(data) end)
def file_storage, do: unquote(:"Elixir.#{module}.Storage.File")
def memory_storage, do: unquote(:"Elixir.#{module}.Storage.Memory")
def registry_storage, do: unquote(:"Elixir.#{module}.Storage.Registry")
def http_client, do: Avrora.HTTPClient
def ets_lib, do: :"Elixir.#{unquote(module)}.AvroSchemaStore"
defp version, do: Application.spec(:avrora, :vsn)
if is_nil(@otp_app) do
def self, do: __MODULE__
def schemas_path, do: Path.expand(get(@opts, :schemas_path, "./priv/schemas"))
def registry_ssl_cacert_path, do: nil
defp get(opts, key, default), do: Keyword.get(opts, key, default)
else
def self, do: get(@opts, :config, __MODULE__)
def schemas_path, do: Application.app_dir(@otp_app, get(@opts, :schemas_path, "./priv/schemas"))
def registry_ssl_cacert_path, do: Path.expand(get(@opts, :registry_ssl_cacert_path, nil))
defp get(opts, key, default) do
app_opts = Application.get_env(@otp_app, unquote(:"Elixir.#{module}"), [])
Keyword.get_lazy(app_opts, key, fn ->
Keyword.get(opts, key, default)
end)
end
end
end
end
quote location: :keep do
unquote(modules)
unquote(config)
use Supervisor
defdelegate decode(payload), to: unquote(:"Elixir.#{module}.Encoder")
defdelegate encode(payload, opts), to: unquote(:"Elixir.#{module}.Encoder")
defdelegate decode(payload, opts), to: unquote(:"Elixir.#{module}.Encoder")
defdelegate decode_plain(payload, opts), to: unquote(:"Elixir.#{module}.Encoder")
defdelegate encode_plain(payload, opts), to: unquote(:"Elixir.#{module}.Encoder")
defdelegate extract_schema(payload), to: unquote(:"Elixir.#{module}.Encoder")
def start_link(opts \\ []), do: Supervisor.start_link(__MODULE__, opts, name: __MODULE__)
@impl true
def init(_state \\ []) do
children = [
unquote(:"Elixir.#{module}.AvroSchemaStore"),
unquote(:"Elixir.#{module}.Storage.Memory")
]
Supervisor.init(children, strategy: :one_for_all)
end
end
end
end