--- /dev/null
+# Used by "mix format"
+[
+ inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
+]
--- /dev/null
+# The directory Mix will write compiled artifacts to.
+/_build/
+
+# If you run "mix test --cover", coverage assets end up here.
+/cover/
+
+# The directory Mix downloads your dependencies sources to.
+/deps/
+
+# Where third-party dependencies like ExDoc output generated docs.
+/doc/
+
+# Ignore .fetch files in case you like to edit your project deps locally.
+/.fetch
+
+# If the VM crashes, it generates a dump, let's ignore it too.
+erl_crash.dump
+
+# Also ignore archive artifacts (built via "mix archive.build").
+*.ez
+
+# Ignore package tarball (built via "mix hex.build").
+dns_phrases-*.tar
+
+# Temporary files, for example, from tests.
+/tmp/
--- /dev/null
+# DnsPhrases
+
+**TODO: Add description**
+
+## Installation
+
+If [available in Hex](https://hex.pm/docs/publish), the package can be installed
+by adding `dns_phrases` to your list of dependencies in `mix.exs`:
+
+```elixir
+def deps do
+ [
+ {:dns_phrases, "~> 0.1.0"}
+ ]
+end
+```
+
+Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
+and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
+be found at <https://hexdocs.pm/dns_phrases>.
+
--- /dev/null
+defmodule DnsPhrases do
+ @moduledoc """
+ Documentation for `DnsPhrases`.
+ """
+
+ @doc """
+ Hello world.
+
+ ## Examples
+
+ iex> DnsPhrases.hello()
+ :world
+
+ """
+ def hello do
+ :world
+ end
+end
--- /dev/null
+defmodule DnsPhrases.Application do
+ # See https://hexdocs.pm/elixir/Application.html
+ # for more information on OTP Applications
+ @moduledoc false
+
+ use Application
+
+ @impl true
+ def start(_type, _args) do
+ children = [
+ # TODO: Fetch the port from command line
+ {DnsPhrases.Server, [listen_port: 3069]}
+ ]
+
+ # See https://hexdocs.pm/elixir/Supervisor.html
+ # for other strategies and supported options
+ opts = [strategy: :one_for_one, name: DnsPhrases.Supervisor]
+ Supervisor.start_link(children, opts)
+ end
+end
--- /dev/null
+defmodule DnsPhrases.Server do
+ use GenServer
+
+ defmodule State do
+ defstruct([:socket])
+ end
+
+ def start_link(opts) do
+ listen_port = Keyword.fetch!(opts, :listen_port)
+ GenServer.start_link(__MODULE__, listen_port, opts)
+ end
+
+ @impl GenServer
+ def init(listen_port) do
+ {:ok, socket} = :gen_udp.open(listen_port, mode: :binary, active: true)
+ {:ok, %State{socket: socket}}
+ end
+
+ @impl GenServer
+ def handle_info(
+ {:udp, socket, _ip, _port, data},
+ %State{socket: socket} = state
+ ) do
+ # TODO 1: Fetch random phrase
+ # TODO 2: Assemble DNS response as a TXT record containing the frame
+ # TODO 3: Reply to our client
+ {:noreply, state}
+ end
+end
--- /dev/null
+defmodule DnsPhrases.MixProject do
+ use Mix.Project
+
+ def project do
+ [
+ app: :dns_phrases,
+ version: "0.1.0",
+ elixir: "~> 1.17",
+ start_permanent: Mix.env() == :prod,
+ deps: deps()
+ ]
+ end
+
+ # Run "mix help compile.app" to learn about applications.
+ def application do
+ [
+ extra_applications: [:logger],
+ mod: {DnsPhrases.Application, []}
+ ]
+ end
+
+ # Run "mix help deps" to learn about dependencies.
+ defp deps do
+ [
+ # {:dep_from_hexpm, "~> 0.3.0"},
+ # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
+ ]
+ end
+end
--- /dev/null
+defmodule DnsPhrasesTest do
+ use ExUnit.Case
+ doctest DnsPhrases
+
+ test "greets the world" do
+ assert DnsPhrases.hello() == :world
+ end
+end
--- /dev/null
+ExUnit.start()