aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMelonai <einebeere@gmail.com>2021-05-07 17:11:50 +0200
committerMelonai <einebeere@gmail.com>2021-05-07 17:11:50 +0200
commit88c0fbf10145ddd4ccd10ee432b4ca1aadd96a91 (patch)
tree33691a532f460dbdf8a0e7909b898c0b324eaa2f /lib
downloadrook-88c0fbf10145ddd4ccd10ee432b4ca1aadd96a91.tar.zst
rook-88c0fbf10145ddd4ccd10ee432b4ca1aadd96a91.zip
Initial structure
Diffstat (limited to 'lib')
-rw-r--r--lib/rook.ex9
-rw-r--r--lib/rook/application.ex32
-rw-r--r--lib/rook/utils/token.ex7
-rw-r--r--lib/rook_web.ex78
-rw-r--r--lib/rook_web/channels/user_socket.ex35
-rw-r--r--lib/rook_web/controllers/app_controller.ex21
-rw-r--r--lib/rook_web/controllers/home_controller.ex7
-rw-r--r--lib/rook_web/endpoint.ex47
-rw-r--r--lib/rook_web/router.ex28
-rw-r--r--lib/rook_web/telemetry.ex48
-rw-r--r--lib/rook_web/templates/app/entrypoint.html.eex5
-rw-r--r--lib/rook_web/templates/app/request.html.eex1
-rw-r--r--lib/rook_web/templates/app/share.html.eex1
-rw-r--r--lib/rook_web/templates/home/index.html.eex1
-rw-r--r--lib/rook_web/templates/layout/app.html.eex21
-rw-r--r--lib/rook_web/views/app_view.ex7
-rw-r--r--lib/rook_web/views/error_helpers.ex30
-rw-r--r--lib/rook_web/views/error_view.ex16
-rw-r--r--lib/rook_web/views/home_view.ex3
-rw-r--r--lib/rook_web/views/layout_view.ex3
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