78 lines
2.1 KiB
Elixir
78 lines
2.1 KiB
Elixir
defmodule ZoeyscomputerWeb.DiscordHandler do
|
|
require Logger
|
|
alias ElixirSense.Log
|
|
alias ExAws.S3
|
|
import Plug.Conn
|
|
import Mogrify
|
|
|
|
def init(opts), do: opts
|
|
|
|
@discord_patterns [
|
|
~r/^Mozilla\/5\.0 \(compatible; Discordbot\//,
|
|
# Discord's specific Mac client pattern
|
|
~r/^Mozilla\/5\.0 \(Macintosh; Intel Mac OS X [0-9_.]+; rv:[0-9.]+\) Gecko\/20100101 Firefox\/[0-9.]+$/
|
|
]
|
|
|
|
def call(%{path_info: ["images", _id | _]} = conn, _opts) do
|
|
user_agent = List.first(get_req_header(conn, "user-agent"))
|
|
request_id = Logger.metadata()[:request_id]
|
|
|
|
Logger.info(
|
|
"Processing image request:\n user_agent: #{user_agent}\n request_id: #{request_id}"
|
|
)
|
|
|
|
Logger.info("Is discord request: #{is_discord_request?(user_agent)}")
|
|
|
|
cond do
|
|
is_discord_request?(user_agent) -> handle_discord(conn)
|
|
true -> conn
|
|
end
|
|
end
|
|
|
|
def call(conn, _opts), do: conn
|
|
|
|
defp is_discord_request?(nil), do: false
|
|
|
|
defp is_discord_request?(user_agent) do
|
|
Enum.any?(@discord_patterns, fn pattern ->
|
|
Regex.match?(pattern, user_agent)
|
|
end)
|
|
end
|
|
|
|
defp handle_discord(%{path_info: ["images", id]} = conn) do
|
|
case download_from_s3("imgs", id) do
|
|
{:ok, image_binary, content_type} ->
|
|
conn
|
|
|> put_resp_content_type(content_type)
|
|
# Optional: Add caching
|
|
|> put_resp_header("cache-control", "public, max-age=86400")
|
|
|> send_resp(200, image_binary)
|
|
|> halt()
|
|
|
|
{:error, reason} ->
|
|
IO.inspect(reason)
|
|
|
|
conn
|
|
|> put_resp_content_type("text/plain")
|
|
|> send_resp(500, "Failed to retrieve image")
|
|
|> halt()
|
|
end
|
|
end
|
|
|
|
defp download_from_s3(bucket, key) do
|
|
case S3.get_object(bucket, "uploads/#{key}.png") |> ExAws.request() do
|
|
{:ok, %{body: image_binary}} ->
|
|
local_path = "/tmp/#{key}.png"
|
|
File.write!(local_path, image_binary)
|
|
|
|
image = open(local_path) |> format("webp") |> save()
|
|
|
|
{:ok, file_binary} = File.read(image.path)
|
|
|
|
{:ok, file_binary, "image/webp"}
|
|
|
|
error ->
|
|
error
|
|
end
|
|
end
|
|
end
|