diff options
| author | Melonai <einebeere@gmail.com> | 2021-05-07 17:11:50 +0200 |
|---|---|---|
| committer | Melonai <einebeere@gmail.com> | 2021-05-07 17:11:50 +0200 |
| commit | 88c0fbf10145ddd4ccd10ee432b4ca1aadd96a91 (patch) | |
| tree | 33691a532f460dbdf8a0e7909b898c0b324eaa2f /lib | |
| download | rook-88c0fbf10145ddd4ccd10ee432b4ca1aadd96a91.tar.zst rook-88c0fbf10145ddd4ccd10ee432b4ca1aadd96a91.zip | |
Initial structure
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/rook.ex | 9 | ||||
| -rw-r--r-- | lib/rook/application.ex | 32 | ||||
| -rw-r--r-- | lib/rook/utils/token.ex | 7 | ||||
| -rw-r--r-- | lib/rook_web.ex | 78 | ||||
| -rw-r--r-- | lib/rook_web/channels/user_socket.ex | 35 | ||||
| -rw-r--r-- | lib/rook_web/controllers/app_controller.ex | 21 | ||||
| -rw-r--r-- | lib/rook_web/controllers/home_controller.ex | 7 | ||||
| -rw-r--r-- | lib/rook_web/endpoint.ex | 47 | ||||
| -rw-r--r-- | lib/rook_web/router.ex | 28 | ||||
| -rw-r--r-- | lib/rook_web/telemetry.ex | 48 | ||||
| -rw-r--r-- | lib/rook_web/templates/app/entrypoint.html.eex | 5 | ||||
| -rw-r--r-- | lib/rook_web/templates/app/request.html.eex | 1 | ||||
| -rw-r--r-- | lib/rook_web/templates/app/share.html.eex | 1 | ||||
| -rw-r--r-- | lib/rook_web/templates/home/index.html.eex | 1 | ||||
| -rw-r--r-- | lib/rook_web/templates/layout/app.html.eex | 21 | ||||
| -rw-r--r-- | lib/rook_web/views/app_view.ex | 7 | ||||
| -rw-r--r-- | lib/rook_web/views/error_helpers.ex | 30 | ||||
| -rw-r--r-- | lib/rook_web/views/error_view.ex | 16 | ||||
| -rw-r--r-- | lib/rook_web/views/home_view.ex | 3 | ||||
| -rw-r--r-- | lib/rook_web/views/layout_view.ex | 3 |
20 files changed, 400 insertions, 0 deletions
diff --git a/lib/rook.ex b/lib/rook.ex new file mode 100644 index 0000000..9bc30ab --- /dev/null +++ b/lib/rook.ex @@ -0,0 +1,9 @@ +defmodule Rook do + @moduledoc """ + Rook keeps the contexts that define your domain + and business logic. + + Contexts are also responsible for managing your data, regardless + if it comes from the database, an external API or others. + """ +end diff --git a/lib/rook/application.ex b/lib/rook/application.ex new file mode 100644 index 0000000..71fdf24 --- /dev/null +++ b/lib/rook/application.ex @@ -0,0 +1,32 @@ +defmodule Rook.Application do + # See https://hexdocs.pm/elixir/Application.html + # for more information on OTP Applications + @moduledoc false + + use Application + + def start(_type, _args) do + children = [ + # Start the Telemetry supervisor + RookWeb.Telemetry, + # Start the PubSub system + {Phoenix.PubSub, name: Rook.PubSub}, + # Start the Endpoint (http/https) + RookWeb.Endpoint + # Start a worker by calling: Rook.Worker.start_link(arg) + # {Rook.Worker, arg} + ] + + # See https://hexdocs.pm/elixir/Supervisor.html + # for other strategies and supported options + opts = [strategy: :one_for_one, name: Rook.Supervisor] + Supervisor.start_link(children, opts) + end + + # Tell Phoenix to update the endpoint configuration + # whenever the application is updated. + def config_change(changed, _new, removed) do + RookWeb.Endpoint.config_change(changed, removed) + :ok + end +end diff --git a/lib/rook/utils/token.ex b/lib/rook/utils/token.ex new file mode 100644 index 0000000..344789b --- /dev/null +++ b/lib/rook/utils/token.ex @@ -0,0 +1,7 @@ +defmodule Rook.Utils.Token do + @alphabet "abcdefghijklmnopqrstuvw0123456789" + + def token() do + Nanoid.generate(21, @alphabet) + end +end diff --git a/lib/rook_web.ex b/lib/rook_web.ex new file mode 100644 index 0000000..5b96dc8 --- /dev/null +++ b/lib/rook_web.ex @@ -0,0 +1,78 @@ +defmodule RookWeb do + @moduledoc """ + The entrypoint for defining your web interface, such + as controllers, views, channels and so on. + + This can be used in your application as: + + use RookWeb, :controller + use RookWeb, :view + + The definitions below will be executed for every view, + controller, etc, so keep them short and clean, focused + on imports, uses and aliases. + + Do NOT define functions inside the quoted expressions + below. Instead, define any helper function in modules + and import those modules here. + """ + + def controller do + quote do + use Phoenix.Controller, namespace: RookWeb + + import Plug.Conn + alias RookWeb.Router.Helpers, as: Routes + end + end + + def view do + quote do + use Phoenix.View, + root: "lib/rook_web/templates", + namespace: RookWeb + + # Import convenience functions from controllers + import Phoenix.Controller, + only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1] + + # Include shared imports and aliases for views + unquote(view_helpers()) + end + end + + def router do + quote do + use Phoenix.Router + + import Plug.Conn + import Phoenix.Controller + end + end + + def channel do + quote do + use Phoenix.Channel + end + end + + defp view_helpers do + quote do + # Use all HTML functionality (forms, tags, etc) + use Phoenix.HTML + + # Import basic rendering functionality (render, render_layout, etc) + import Phoenix.View + + import RookWeb.ErrorHelpers + alias RookWeb.Router.Helpers, as: Routes + end + end + + @doc """ + When used, dispatch to the appropriate controller/view/etc. + """ + defmacro __using__(which) when is_atom(which) do + apply(__MODULE__, which, []) + end +end diff --git a/lib/rook_web/channels/user_socket.ex b/lib/rook_web/channels/user_socket.ex new file mode 100644 index 0000000..66637af --- /dev/null +++ b/lib/rook_web/channels/user_socket.ex @@ -0,0 +1,35 @@ +defmodule RookWeb.UserSocket do + use Phoenix.Socket + + ## Channels + # channel "room:*", RookWeb.RoomChannel + + # Socket params are passed from the client and can + # be used to verify and authenticate a user. After + # verification, you can put default assigns into + # the socket that will be set for all channels, ie + # + # {:ok, assign(socket, :user_id, verified_user_id)} + # + # To deny connection, return `:error`. + # + # See `Phoenix.Token` documentation for examples in + # performing token verification on connect. + @impl true + def connect(_params, socket, _connect_info) do + {:ok, socket} + end + + # Socket id's are topics that allow you to identify all sockets for a given user: + # + # def id(socket), do: "user_socket:#{socket.assigns.user_id}" + # + # Would allow you to broadcast a "disconnect" event and terminate + # all active sockets and channels for a given user: + # + # RookWeb.Endpoint.broadcast("user_socket:#{user.id}", "disconnect", %{}) + # + # Returning `nil` makes this socket anonymous. + @impl true + def id(_socket), do: nil +end diff --git a/lib/rook_web/controllers/app_controller.ex b/lib/rook_web/controllers/app_controller.ex new file mode 100644 index 0000000..4c36fda --- /dev/null +++ b/lib/rook_web/controllers/app_controller.ex @@ -0,0 +1,21 @@ +defmodule RookWeb.AppController do + use RookWeb, :controller + + plug :add_token + + def share(conn, _params) do + render(conn, "share.html") + end + + def request(conn, _params) do + render(conn, "request.html") + end + + defp add_token(conn, _params) do + if conn.assigns[:token] do + conn + else + assign(conn, :token, Rook.Utils.Token.token()) + end + end +end diff --git a/lib/rook_web/controllers/home_controller.ex b/lib/rook_web/controllers/home_controller.ex new file mode 100644 index 0000000..c87814d --- /dev/null +++ b/lib/rook_web/controllers/home_controller.ex @@ -0,0 +1,7 @@ +defmodule RookWeb.HomeController do + use RookWeb, :controller + + def index(conn, _params) do + render(conn, "index.html") + end +end diff --git a/lib/rook_web/endpoint.ex b/lib/rook_web/endpoint.ex new file mode 100644 index 0000000..dd847f7 --- /dev/null +++ b/lib/rook_web/endpoint.ex @@ -0,0 +1,47 @@ +defmodule RookWeb.Endpoint do + use Phoenix.Endpoint, otp_app: :rook + + # The session will be stored in the cookie and signed, + # this means its contents can be read but not tampered with. + # Set :encryption_salt if you would also like to encrypt it. + @session_options [ + store: :cookie, + key: "_rook_key", + signing_salt: "IVge2MOv" + ] + + socket "/socket", RookWeb.UserSocket, + websocket: true, + longpoll: false + + # Serve at "/" the static files from "priv/static" directory. + # + # You should set gzip to true if you are running phx.digest + # when deploying your static files in production. + plug Plug.Static, + at: "/", + from: :rook, + gzip: false, + only: ~w(css fonts images js favicon.ico robots.txt) + + # Code reloading can be explicitly enabled under the + # :code_reloader configuration of your endpoint. + if code_reloading? do + socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket + plug Phoenix.LiveReloader + plug Phoenix.CodeReloader + end + + plug Plug.RequestId + plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint] + + plug Plug.Parsers, + parsers: [:urlencoded, :multipart, :json], + pass: ["*/*"], + json_decoder: Phoenix.json_library() + + plug Plug.MethodOverride + plug Plug.Head + plug Plug.Session, @session_options + plug RookWeb.Router +end diff --git a/lib/rook_web/router.ex b/lib/rook_web/router.ex new file mode 100644 index 0000000..298d722 --- /dev/null +++ b/lib/rook_web/router.ex @@ -0,0 +1,28 @@ +defmodule RookWeb.Router do + use RookWeb, :router + + pipeline :browser do + plug :accepts, ["html"] + plug :fetch_session + plug :fetch_flash + plug :protect_from_forgery + plug :put_secure_browser_headers + end + + pipeline :api do + plug :accepts, ["json"] + end + + scope "/", RookWeb do + pipe_through :browser + + get "/", HomeController, :index + get "/share", AppController, :share + get "/:token", AppController, :request + end + + # Other scopes may use custom stacks. + # scope "/api", RookWeb do + # pipe_through :api + # end +end diff --git a/lib/rook_web/telemetry.ex b/lib/rook_web/telemetry.ex new file mode 100644 index 0000000..24b502b --- /dev/null +++ b/lib/rook_web/telemetry.ex @@ -0,0 +1,48 @@ +defmodule RookWeb.Telemetry do + use Supervisor + import Telemetry.Metrics + + def start_link(arg) do + Supervisor.start_link(__MODULE__, arg, name: __MODULE__) + end + + @impl true + def init(_arg) do + children = [ + # Telemetry poller will execute the given period measurements + # every 10_000ms. Learn more here: https://hexdocs.pm/telemetry_metrics + {:telemetry_poller, measurements: periodic_measurements(), period: 10_000} + # Add reporters as children of your supervision tree. + # {Telemetry.Metrics.ConsoleReporter, metrics: metrics()} + ] + + Supervisor.init(children, strategy: :one_for_one) + end + + def metrics do + [ + # Phoenix Metrics + summary("phoenix.endpoint.stop.duration", + unit: {:native, :millisecond} + ), + summary("phoenix.router_dispatch.stop.duration", + tags: [:route], + unit: {:native, :millisecond} + ), + + # VM Metrics + summary("vm.memory.total", unit: {:byte, :kilobyte}), + summary("vm.total_run_queue_lengths.total"), + summary("vm.total_run_queue_lengths.cpu"), + summary("vm.total_run_queue_lengths.io") + ] + end + + defp periodic_measurements do + [ + # A module, function and arguments to be invoked periodically. + # This function must call :telemetry.execute/3 and a metric must be added above. + # {RookWeb, :count_users, []} + ] + end +end diff --git a/lib/rook_web/templates/app/entrypoint.html.eex b/lib/rook_web/templates/app/entrypoint.html.eex new file mode 100644 index 0000000..bc7e84a --- /dev/null +++ b/lib/rook_web/templates/app/entrypoint.html.eex @@ -0,0 +1,5 @@ +<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/#{@entrypoint}.css") %>"/> +<script defer type="text/javascript" src="<%= Routes.static_path(@conn, "/js/#{@entrypoint}.js") %>"></script> +<script>window.token = "<%= @token %>";</script> + +<div id="app"></div> diff --git a/lib/rook_web/templates/app/request.html.eex b/lib/rook_web/templates/app/request.html.eex new file mode 100644 index 0000000..c09a843 --- /dev/null +++ b/lib/rook_web/templates/app/request.html.eex @@ -0,0 +1 @@ +<%= render_app(@conn, @token, "request") %> diff --git a/lib/rook_web/templates/app/share.html.eex b/lib/rook_web/templates/app/share.html.eex new file mode 100644 index 0000000..d72b2c4 --- /dev/null +++ b/lib/rook_web/templates/app/share.html.eex @@ -0,0 +1 @@ +<%= render_app(@conn, @token, "share") %> diff --git a/lib/rook_web/templates/home/index.html.eex b/lib/rook_web/templates/home/index.html.eex new file mode 100644 index 0000000..9152474 --- /dev/null +++ b/lib/rook_web/templates/home/index.html.eex @@ -0,0 +1 @@ +<p>Hi! Welcome to Walmart.</p> diff --git a/lib/rook_web/templates/layout/app.html.eex b/lib/rook_web/templates/layout/app.html.eex new file mode 100644 index 0000000..d651e23 --- /dev/null +++ b/lib/rook_web/templates/layout/app.html.eex @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"/> + <meta http-equiv="X-UA-Compatible" content="IE=edge"/> + <meta name="viewport" content="width=device-width, initial-scale=1.0"/> + <title>Rook</title> + <link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/> + </head> + <body> + <header> + <section class="container"> + Rook + </header> + <main role="main" class="container"> + <p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p> + <p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p> + <%= @inner_content %> + </main> + </body> +</html> diff --git a/lib/rook_web/views/app_view.ex b/lib/rook_web/views/app_view.ex new file mode 100644 index 0000000..66c7f6a --- /dev/null +++ b/lib/rook_web/views/app_view.ex @@ -0,0 +1,7 @@ +defmodule RookWeb.AppView do + use RookWeb, :view + + def render_app(conn, token, entrypoint) do + render("entrypoint.html", conn: conn, token: token, entrypoint: entrypoint) + end +end diff --git a/lib/rook_web/views/error_helpers.ex b/lib/rook_web/views/error_helpers.ex new file mode 100644 index 0000000..a905b5e --- /dev/null +++ b/lib/rook_web/views/error_helpers.ex @@ -0,0 +1,30 @@ +defmodule RookWeb.ErrorHelpers do + @moduledoc """ + Conveniences for translating and building error messages. + """ + + use Phoenix.HTML + + @doc """ + Generates tag for inlined form input errors. + """ + def error_tag(form, field) do + Enum.map(Keyword.get_values(form.errors, field), fn error -> + content_tag(:span, translate_error(error), + class: "invalid-feedback", + phx_feedback_for: input_name(form, field) + ) + end) + end + + @doc """ + Translates an error message. + """ + def translate_error({msg, opts}) do + # Because the error messages we show in our forms and APIs + # are defined inside Ecto, we need to translate them dynamically. + Enum.reduce(opts, msg, fn {key, value}, acc -> + String.replace(acc, "%{#{key}}", to_string(value)) + end) + end +end diff --git a/lib/rook_web/views/error_view.ex b/lib/rook_web/views/error_view.ex new file mode 100644 index 0000000..6ffc93d --- /dev/null +++ b/lib/rook_web/views/error_view.ex @@ -0,0 +1,16 @@ +defmodule RookWeb.ErrorView do + use RookWeb, :view + + # If you want to customize a particular status code + # for a certain format, you may uncomment below. + # def render("500.html", _assigns) do + # "Internal Server Error" + # end + + # By default, Phoenix returns the status message from + # the template name. For example, "404.html" becomes + # "Not Found". + def template_not_found(template, _assigns) do + Phoenix.Controller.status_message_from_template(template) + end +end diff --git a/lib/rook_web/views/home_view.ex b/lib/rook_web/views/home_view.ex new file mode 100644 index 0000000..700ea71 --- /dev/null +++ b/lib/rook_web/views/home_view.ex @@ -0,0 +1,3 @@ +defmodule RookWeb.HomeView do + use RookWeb, :view +end diff --git a/lib/rook_web/views/layout_view.ex b/lib/rook_web/views/layout_view.ex new file mode 100644 index 0000000..19d121f --- /dev/null +++ b/lib/rook_web/views/layout_view.ex @@ -0,0 +1,3 @@ +defmodule RookWeb.LayoutView do + use RookWeb, :view +end |
