Deploy and presence stub

This commit is contained in:
Chris McCord 2021-11-16 11:58:22 -05:00
parent 1a68db73f3
commit 364b0659e1
24 changed files with 332 additions and 55 deletions

2
.dockerignore Normal file
View file

@ -0,0 +1,2 @@
priv/uploads
deps/

98
Dockerfile Normal file
View file

@ -0,0 +1,98 @@
# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian instead of
# Alpine to avoid DNS resolution issues in production.
#
# https://hub.docker.com/r/hexpm/elixir/tags?page=1&name=ubuntu
# https://hub.docker.com/_/ubuntu?tab=tags
#
#
# This file is based on these images:
#
# - https://hub.docker.com/r/hexpm/elixir/tags - for the build image
# - https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye-20210902-slim - for the release image
# - https://pkgs.org/ - resource for finding needed packages
# - Ex: hexpm/elixir:1.12.3-erlang-24.1.4-debian-bullseye-20210902-slim
#
ARG BUILDER_IMAGE="hexpm/elixir:1.12.3-erlang-24.1.4-debian-bullseye-20210902-slim"
ARG RUNNER_IMAGE="debian:bullseye-20210902-slim"
FROM ${BUILDER_IMAGE} as builder
# install build dependencies
RUN apt-get update -y && apt-get install -y build-essential git \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
# prepare build dir
WORKDIR /app
# install hex + rebar
RUN mix local.hex --force && \
mix local.rebar --force
# set build ENV
ENV MIX_ENV="prod"
# install mix dependencies
COPY mix.exs mix.lock ./
RUN mix deps.get --only $MIX_ENV
RUN mkdir config
# copy compile-time config files before we compile dependencies
# to ensure any relevant config change will trigger the dependencies
# to be re-compiled.
COPY config/config.exs config/${MIX_ENV}.exs config/
RUN mix deps.compile
COPY priv priv
# note: if your project uses a tool like https://purgecss.com/,
# which customizes asset compilation based on what it finds in
# your Elixir templates, you will need to move the asset compilation
# step down so that `lib` is available.
COPY assets assets
# For Phoenix 1.6 and later, compile assets using esbuild
RUN mix assets.deploy
# For Phoenix versions earlier than 1.6, compile assets npm
# RUN cd assets && yarn install && yarn run webpack --mode production
# RUN mix phx.digest
# Compile the release
COPY lib lib
RUN mix compile
# Changes to config/runtime.exs don't require recompiling the code
COPY config/runtime.exs config/
COPY rel rel
RUN mix release
# start a new build stage so that the final image will only contain
# the compiled release and other runtime necessities
FROM ${RUNNER_IMAGE}
RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
WORKDIR "/app"
RUN chown nobody /app
# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/prod/rel ./
USER nobody
# Create a symlink to the application directory by extracting the directory name. This is required
# since the release directory will be named after the application, and we don't know that name.
RUN set -eux; \
ln -nfs /app/$(basename *)/bin/$(basename *) /app/entry
CMD /app/entry start

View file

@ -5,10 +5,12 @@ Play music together with Phoenix LiveView!
Visit [todo]() to try it out, or run locally:
* Create a [Github OAuth app](https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app)
* Export your GitHub client ID and secret:
- Set the app homepage to `http://localhost:4000` and `Authorization callback URL` to `http://localhost:4000/oauth/callbacks/github`
- After completing the form, click "Generate a new client secret" to obtain your API secret
* Export your GitHub Client ID and secret:
export LIVE_BEATS_GITHUB_CLIENT_ID="..."
export LIVE_BEATS_GITHUB_CLIENT_SECRET="..."
export LIVE_BEATS_GITHUB_CLIENT_ID="..."
export LIVE_BEATS_GITHUB_CLIENT_SECRET="..."
* Install dependencies with `mix deps.get`
* Create and migrate your database with `mix ecto.setup`

View file

@ -1,7 +1,7 @@
import "phoenix_html"
import {Socket} from "phoenix"
import {LiveSocket} from "./phoenix_live_view"
// import {LiveSocket} from "phoenix_live_view"
// import {LiveSocket} from "./phoenix_live_view"
import {LiveSocket} from "phoenix_live_view"
import topbar from "../vendor/topbar"
let nowSeconds = () => Math.round(Date.now() / 1000)
@ -33,8 +33,10 @@ Hooks.AudioPlayer = {
let enableAudio = () => {
if(this.player.src){
document.removeEventListener("click", enableAudio)
this.player.play().catch(error => null)
this.player.pause()
if(this.player.readyState === 0){
this.player.play().catch(error => null)
this.player.pause()
}
}
}
document.addEventListener("click", enableAudio)

View file

@ -14,9 +14,11 @@ if config_env() == :prod do
For example: ecto://USER:PASS@HOST/DATABASE
"""
ipv6? = !!System.get_env("IPV6")
config :live_beats, LiveBeats.Repo,
# ssl: true,
# socket_options: [:inet6],
socket_options: if(ipv6?, do: [:inet6], else: []),
url: database_url,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
@ -27,7 +29,11 @@ if config_env() == :prod do
You can generate one by calling: mix phx.gen.secret
"""
app_name = System.fetch_env!("FLY_APP_NAME")
host = System.get_env("URL_HOST") || "example.com"
config :live_beats, LiveBeatsWeb.Endpoint,
url: [host: host, port: 80],
http: [
# Enable IPv6 and bind on all interfaces.
# Set it to {0, 0, 0, 0, 0, 0, 0, 1} for local network only access.
@ -36,33 +42,18 @@ if config_env() == :prod do
ip: {0, 0, 0, 0, 0, 0, 0, 0},
port: String.to_integer(System.get_env("PORT") || "4000")
],
secret_key_base: secret_key_base
check_origin: ["//#{host}"],
secret_key_base: secret_key_base,
server: true
# ## Using releases
#
# If you are doing OTP releases, you need to instruct Phoenix
# to start each relevant endpoint:
#
# config :live_beats, LiveBeatsWeb.Endpoint, server: true
#
# Then you can assemble a release by calling `mix release`.
# See `mix help release` for more information.
config :live_beats, :file_host, %{
scheme: "http",
host: host,
port: 80
}
# ## Configuring the mailer
#
# In production you need to configure the mailer to use a different adapter.
# Also, you may need to configure the Swoosh API client of your choice if you
# are not using SMTP. Here is an example of the configuration:
#
# config :live_beats, LiveBeats.Mailer,
# adapter: Swoosh.Adapters.Mailgun,
# api_key: System.get_env("MAILGUN_API_KEY"),
# domain: System.get_env("MAILGUN_DOMAIN")
#
# For this example you need include a HTTP client required by Swoosh API client.
# Swoosh supports Hackney and Finch out of the box:
#
# config :swoosh, :api_client, Swoosh.ApiClient.Hackney
#
# See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details.
config :live_beats, :github, %{
client_id: System.fetch_env!("LIVE_BEATS_GITHUB_CLIENT_ID"),
client_secret: System.fetch_env!("LIVE_BEATS_GITHUB_CLIENT_SECRET"),
}
end

42
fly.toml Normal file
View file

@ -0,0 +1,42 @@
app = "livebeats"
kill_signal = "SIGTERM"
kill_timeout = 5
processes = []
[deploy]
release_command = "/app/entry eval LiveBeats.Release.migrate"
[env]
IPV6 = 1
URL_HOST = "livebeats.fly.dev"
[experimental]
allowed_public_ports = []
auto_rollback = true
[[services]]
http_checks = []
internal_port = 4000
processes = ["app"]
protocol = "tcp"
script_checks = []
[services.concurrency]
hard_limit = 25
soft_limit = 20
type = "connections"
[[services.ports]]
handlers = ["http"]
port = 80
[[services.ports]]
handlers = ["tls", "http"]
port = 443
[[services.tcp_checks]]
grace_period = "30s" # allow some time for startup
interval = "15s"
restart_limit = 0
timeout = "2s"

View file

@ -12,6 +12,8 @@ defmodule LiveBeats.Accounts.User do
field :role, :string, default: "subscriber"
field :profile_tagline, :string
field :active_profile_user_id, :id
field :avatar_url, :string
field :external_homepage_url, :string
has_many :identities, Identity
@ -22,7 +24,7 @@ defmodule LiveBeats.Accounts.User do
A user changeset for github registration.
"""
def github_registration_changeset(info, primary_email, emails, token) do
%{"login" => username} = info
%{"login" => username, "avatar_url" => avatar_url, "html_url" => external_homepage_url} = info
identity_changeset =
Identity.github_registration_changeset(info, primary_email, emails, token)
@ -31,11 +33,13 @@ defmodule LiveBeats.Accounts.User do
params = %{
"username" => username,
"email" => primary_email,
"name" => get_change(identity_changeset, :provider_name)
"name" => get_change(identity_changeset, :provider_name),
"avatar_url" => avatar_url,
"external_homepage_url" => external_homepage_url
}
%User{}
|> cast(params, [:email, :name, :username])
|> cast(params, [:email, :name, :username, :avatar_url, :external_homepage_url])
|> validate_required([:email, :name, :username])
|> validate_username()
|> validate_email()

View file

@ -203,7 +203,7 @@ defmodule LiveBeats.MediaLibrary do
where: s.status in [:playing],
limit: ^Keyword.fetch!(opts, :limit),
order_by: [desc: s.updated_at],
select: struct(u, [:id, :username, :profile_tagline])
select: struct(u, [:id, :username, :profile_tagline, :avatar_url, :external_homepage_url])
)
|> Repo.all()
|> Enum.map(&get_profile!/1)
@ -214,7 +214,13 @@ defmodule LiveBeats.MediaLibrary do
end
def get_profile!(%Accounts.User{} = user) do
%Profile{user_id: user.id, username: user.username, tagline: user.profile_tagline}
%Profile{
user_id: user.id,
username: user.username,
tagline: user.profile_tagline,
avatar_url: user.avatar_url,
external_homepage_url: user.external_homepage_url
}
end
def owns_profile?(%Accounts.User{} = user, %Profile{} = profile) do

View file

@ -1,3 +1,3 @@
defmodule LiveBeats.MediaLibrary.Profile do
defstruct user_id: nil, username: nil, tagline: nil
defstruct user_id: nil, username: nil, tagline: nil, avatar_url: nil, external_homepage_url: nil
end

28
lib/live_beats/release.ex Normal file
View file

@ -0,0 +1,28 @@
defmodule LiveBeats.Release do
@moduledoc """
Used for executing DB release tasks when run in production without Mix
installed.
"""
@app :live_beats
def migrate do
load_app()
for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
end
end
def rollback(repo, version) do
load_app()
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
end
defp repos do
Application.fetch_env!(@app, :ecto_repos)
end
defp load_app do
Application.load(@app)
end
end

View file

@ -0,0 +1,34 @@
defmodule LiveBeatsWeb.Presence do
@moduledoc """
Provides presence tracking to channels and processes.
See the [`Phoenix.Presence`](http://hexdocs.pm/phoenix/Phoenix.Presence.html)
docs for more details.
"""
use Phoenix.Presence, otp_app: :live_beats,
pubsub_server: LiveBeats.PubSub
import Phoenix.LiveView.Helpers
import LiveBeatsWeb.LiveHelpers
def listening_now(assigns) do
~H"""
<!-- users -->
<div class="px-4 mt-6 sm:px-6 lg:px-8">
<h2 class="text-gray-500 text-xs font-medium uppercase tracking-wide">Who's Here</h2>
<ul role="list" class="grid grid-cols-1 gap-4 sm:gap-4 sm:grid-cols-2 xl:grid-cols-5 mt-3" x-max="1">
<%= for presence <- @presences do %>
<li class="relative col-span-1 flex shadow-sm rounded-md overflow-hidden">
<.link redirect_to={profile_path(presence)} class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-md truncate">
<img class="w-10 h-10 flex-shrink-0 flex items-center justify-center rounded-l-md bg-purple-600" src={presence.avatar_url} alt="">
<div class="flex-1 flex items-center justify-between text-gray-900 text-sm font-medium hover:text-gray-600 pl-3">
<%= render_slot(@title, presence) %>
</div>
</.link>
</li>
<% end %>
</ul>
</div>
"""
end
end

View file

@ -70,7 +70,7 @@ defmodule LiveBeatsWeb.UserAuth do
conn
|> renew_session()
|> redirect(to: "/")
|> redirect(to: Routes.sign_in_path(conn, :index))
end
@doc """

View file

@ -95,7 +95,7 @@ defmodule LiveBeatsWeb.LiveHelpers do
assigns =
assigns
|> assign_new(:outlined, fn -> false end)
|> assign_new(:class, fn -> "w-4 h-4" end)
|> assign_new(:class, fn -> "w-4 h-4 inline-block" end)
~H"""
<%= if @outlined do %>

View file

@ -12,7 +12,7 @@ defmodule LiveBeatsWeb.SignInLive do
<p class="mt-2 text-center text-sm text-gray-600">
Or
<a href="#" class="font-medium text-indigo-600 hover:text-indigo-500">
start your 14-day free trial
listen now without signing in (TODO)
</a>
</p>
</div>

View file

@ -2,13 +2,20 @@ defmodule LiveBeatsWeb.SongLive.Index do
use LiveBeatsWeb, :live_view
alias LiveBeats.{Accounts, MediaLibrary, MP3Stat}
alias LiveBeatsWeb.LayoutComponent
alias LiveBeatsWeb.{LayoutComponent, Presence}
alias LiveBeatsWeb.SongLive.{SongRowComponent, UploadFormComponent}
def render(assigns) do
~H"""
<.title_bar>
<%= @profile.tagline %> <%= if @owns_profile? do %>(you)<% end %>
<div>
<div class="block">
<%= @profile.tagline %> <%= if @owns_profile? do %>(you)<% end %>
</div>
<.link href={@profile.external_homepage_url} _target="blank" class="block text-sm text-gray-600">
<.icon name={:code}/> <span class=""><%= url_text(@profile.external_homepage_url) %></span>
</.link>
</div>
<:actions>
<%= if @active_profile_id == @profile.user_id do %>
@ -32,6 +39,11 @@ defmodule LiveBeatsWeb.SongLive.Index do
</:actions>
</.title_bar>
<Presence.listening_now presences={@presences}>
<:abbrev let={user}><%= String.first(user.username) %></:abbrev>
<:title let={user}><%= user.username %></:title>
</Presence.listening_now>
<%= for song <- if(@owns_profile?, do: @songs, else: []), id = "delete-modal-#{song.id}" do %>
<.modal
id={id}
@ -89,6 +101,7 @@ defmodule LiveBeatsWeb.SongLive.Index do
owns_profile?: MediaLibrary.owns_profile?(current_user, profile)
)
|> list_songs()
|> assign_presences()
{:ok, socket, temporary_assigns: [songs: []]}
end
@ -216,4 +229,15 @@ defmodule LiveBeatsWeb.SongLive.Index do
defp list_songs(socket) do
assign(socket, songs: MediaLibrary.list_profile_songs(socket.assigns.profile, 50))
end
defp assign_presences(socket) do
# TODO
assign(socket, presences: Accounts.list_users(limit: 10))
end
defp url_text(nil), do: ""
defp url_text(url_str) do
uri = URI.parse(url_str)
uri.host <> uri.path
end
end

View file

@ -124,7 +124,7 @@
>
<span class="sr-only">Open user menu</span>
<img class="h-8 w-8 rounded-full"
src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
src={@current_user.avatar_url}
alt="">
</button>
</div>

View file

@ -74,7 +74,7 @@ defmodule LiveBeatsWeb.LayoutView do
<span class="flex w-full justify-between items-center">
<span class="flex min-w-0 items-center justify-between space-x-3">
<img class="w-10 h-10 bg-gray-300 rounded-full flex-shrink-0"
src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=3&amp;w=256&amp;h=256&amp;q=80"
src={@current_user.avatar_url}
alt="">
<span class="flex-1 flex flex-col min-w-0">
<span class="text-gray-900 text-sm font-medium truncate"><%= @current_user.name %></span>

10
mix.exs
View file

@ -39,8 +39,8 @@ defmodule LiveBeats.MixProject do
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 3.0"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, path: "~/oss/phoenix_live_view", override: true},
# {:phoenix_live_view, github: "phoenixframework/phoenix_live_view", branch: "cm-sticky-live-render", override: true},
# {:phoenix_live_view, path: "~/oss/phoenix_live_view", override: true},
{:phoenix_live_view, github: "phoenixframework/phoenix_live_view", branch: "cm-sticky-live-render", override: true},
{:floki, ">= 0.30.0", only: :test},
{:phoenix_live_dashboard, "~> 0.5"},
{:esbuild, "~> 0.2", runtime: Mix.env() == :dev},
@ -51,7 +51,8 @@ defmodule LiveBeats.MixProject do
{:jason, "~> 1.2"},
{:plug_cowboy, "~> 2.5"},
{:mint, "~> 1.0"},
{:heroicons, "~> 0.2.2"}
{:heroicons, "~> 0.2.2"},
{:castore, "~> 0.1.13"}
]
end
@ -63,12 +64,11 @@ defmodule LiveBeats.MixProject do
# See the documentation for `Mix` for more info on aliases.
defp aliases do
[
setup: ["deps.get", "ecto.setup", "cmd --cd assets npm install"],
setup: ["deps.get", "ecto.setup"],
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
"assets.deploy": [
"cmd --cd assets npm run deploy",
"esbuild default --minify",
"phx.digest"
]

View file

@ -1,5 +1,5 @@
%{
"castore": {:hex, :castore, "0.1.11", "c0665858e0e1c3e8c27178e73dffea699a5b28eb72239a3b2642d208e8594914", [:mix], [], "hexpm", "91b009ba61973b532b84f7c09ce441cba7aa15cb8b006cf06c6f4bba18220081"},
"castore": {:hex, :castore, "0.1.13", "ccf3ab251ffaebc4319f41d788ce59a6ab3f42b6c27e598ad838ffecee0b04f9", [:mix], [], "hexpm", "a14a7eecfec7e20385493dbb92b0d12c5d77ecfd6307de10102d58c94e8c49c0"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
@ -25,7 +25,7 @@
"phoenix_html": {:hex, :phoenix_html, "3.1.0", "0b499df05aad27160d697a9362f0e89fa0e24d3c7a9065c2bd9d38b4d1416c09", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0c0a98a2cefa63433657983a2a594c7dee5927e4391e0f1bfd3a151d1def33fc"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.5.0", "3282d8646e1bfc1ef1218f508d9fcefd48cf47f9081b7667bd9b281b688a49cf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.6", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.16.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "609740be43de94ae0abd2c4300ff0356a6e8a9487bf340e69967643a59fa7ec8"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"},
"phoenix_live_view": {:git, "https://github.com/phoenixframework/phoenix_live_view.git", "fba1ff66483c20d1c163ee9cd3aa74024d196f17", [branch: "cm-sticky-live-render"]},
"phoenix_live_view": {:git, "https://github.com/phoenixframework/phoenix_live_view.git", "0cb64f7b6082dc07e488d5547a35c32f8af18650", [branch: "cm-sticky-live-render"]},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
"phoenix_view": {:hex, :phoenix_view, "1.0.0", "fea71ecaaed71178b26dd65c401607de5ec22e2e9ef141389c721b3f3d4d8011", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "82be3e2516f5633220246e2e58181282c71640dab7afc04f70ad94253025db0c"},
"plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"},

View file

@ -0,0 +1,10 @@
defmodule LiveBeats.Repo.Migrations.AddAvatarUrlToUsers do
use Ecto.Migration
def change do
alter table(:users) do
add :avatar_url, :string
add :external_homepage_url, :string
end
end
end

6
rel/env.bat.eex Normal file
View file

@ -0,0 +1,6 @@
@echo off
rem Set the release to work across nodes. If using the long name format like
rem the one below (my_app@127.0.0.1), you need to also uncomment the
rem RELEASE_DISTRIBUTION variable below. Must be "sname", "name" or "none".
rem set RELEASE_DISTRIBUTION=name
rem set RELEASE_NODE=<%= @release.name %>@127.0.0.1

6
rel/env.sh.eex Normal file
View file

@ -0,0 +1,6 @@
#!/bin/sh
ip=$(grep fly-local-6pn /etc/hosts | cut -f 1)
export RELEASE_DISTRIBUTION=name
export RELEASE_NODE=$FLY_APP_NAME@$ip
export ELIXIR_ERL_OPTIONS="-proto_dist inet6_tcp"

11
rel/remote.vm.args.eex Normal file
View file

@ -0,0 +1,11 @@
## Customize flags given to the VM: https://erlang.org/doc/man/erl.html
## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here
## Number of dirty schedulers doing IO work (file, sockets, and others)
##+SDio 5
## Increase number of concurrent ports/sockets
##+Q 65536
## Tweak GC to run more often
##-env ERL_FULLSWEEP_AFTER 10

11
rel/vm.args.eex Normal file
View file

@ -0,0 +1,11 @@
## Customize flags given to the VM: https://erlang.org/doc/man/erl.html
## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here
## Number of dirty schedulers doing IO work (file, sockets, and others)
##+SDio 5
## Increase number of concurrent ports/sockets
##+Q 65536
## Tweak GC to run more often
##-env ERL_FULLSWEEP_AFTER 10