Created
July 17, 2024 04:03
-
-
Save sb8244/0cea9b7ace4a65dd316245c38261c584 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule SuperWeb.Plug.AssetNotFound do | |
import Plug.Conn | |
alias Plug.Conn | |
def init(opts) do | |
%{ | |
at: Keyword.fetch!(opts, :at) |> Plug.Router.Utils.split(), | |
only: {Keyword.fetch!(opts, :only), []} | |
} | |
end | |
def call(conn = %Conn{}, %{at: at, only: only_rules}) do | |
segments = subset(at, conn.path_info) | |
asset_path? = allowed?(only_rules, segments) | |
if asset_path? do | |
# Give a second for servers to boot and hopefully help timeline | |
Process.sleep(Process.get({__MODULE__, :delay}, 1000)) | |
conn | |
|> maybe_replay() | |
|> send_resp(404, "Asset not found") | |
|> halt() | |
else | |
conn | |
end | |
end | |
defp maybe_replay(conn) do | |
case get_next_replay_amount(conn) do | |
:do_not_replay -> conn | |
num -> put_resp_header(conn, "fly-replay", "elsewhere=true;state=replays_#{num}") | |
end | |
end | |
# Taken from Plug.Static | |
defp subset([h | expected], [h | actual]), do: subset(expected, actual) | |
defp subset([], actual), do: actual | |
defp subset(_, _), do: [] | |
# Taken from Plug.Static, `:only` option needs put into this tuple format even though not used now | |
defp allowed?(_only_rules, []), do: false | |
defp allowed?({[], []}, _list), do: true | |
defp allowed?({full, prefix}, [h | _]) do | |
h in full or (prefix != [] and match?({0, _}, :binary.match(h, prefix))) | |
end | |
defp get_next_replay_amount(conn) do | |
next_num = | |
with [header] <- get_req_header(conn, "fly-replay-src"), | |
[_, "replays_" <> str_num] <- Regex.run(~r/(?:^|;)state=([^;]*)/, header), | |
{num, ""} <- Integer.parse(str_num) do | |
num + 1 | |
else | |
_ -> 1 | |
end | |
# Number of replays starts at 0 (header not included), so < is used | |
if next_num < number_of_machines() do | |
next_num | |
else | |
:do_not_replay | |
end | |
end | |
defp number_of_machines do | |
query = Application.get_env(:super, :dns_cluster_query) | |
if query do | |
length(:inet_res.lookup(~c"#{query}", :in, :aaaa)) | |
else | |
Process.get({__MODULE__, :number_of_machines}, 0) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment