lib/plug/refresh_component_access_token.ex

if Code.ensure_loaded?(Plug) do
  defmodule WeChat.Plug.RefreshComponentAccessToken do
    @moduledoc false

    use Plug.Builder
    require Logger

    def call(conn, opts) do
      conn = conn |> super(opts) |> fetch_query_params()
      adapter_storage = opts[:adapter_storage]
      body = conn.body_params

      result =
        try do
          case refresh_if_expired(body, adapter_storage) do
            {:ok, token} ->
              %{
                "access_token" => token.access_token,
                "expires_in" => token.expires_in,
                "timestamp" => token.timestamp
              }

            {:error, %WeChat.Error{} = error} ->
              Logger.error(
                "fetch access token occurs an error: #{inspect(error)} with body params: #{inspect(body)}"
              )

              error
          end
        rescue
          error in WeChat.Error ->
            error
        end

      conn
      |> put_resp_content_type("application/json")
      |> send_resp(200, Jason.encode!(result))
      |> halt()
    end

    defp refresh_if_expired(%{"appid" => appid, "access_token" => access_token}, adapter_storage) do
      comp_adapter_storage = adapter_storage[:component]

      case WeChat.Component.fetch_component_access_token(appid, comp_adapter_storage) do
        {:ok, %{access_token: ^access_token}} ->
          adapter_storage.refresh_component_access_token(appid, access_token, nil)

        token ->
          token
      end
    end

    defp refresh_if_expired(_, _) do
      {:error, %WeChat.Error{reason: "invalid_request"}}
    end
  end
end