Current section
Files
Jump to
Current section
Files
lib/vik_web/controllers/shard_controller.ex
defmodule VikWeb.ShardController do
@moduledoc false
use VikWeb, :controller
alias Vik.Repo
alias Vik.Store
alias Vik.Shard
alias Vik.Result
alias Vik.PubSub
import Structo
plug :put_content_type
def execute(conn, ~m{slug}s = params) do
case Repo.get_by(Shard, slug: slug) do
%Shard{} = shard -> try_execute(conn, params, shard)
nil -> raise Vik.ShardNotFound, slug
end
end
defp try_execute(conn, params, shard) do
case find_callable(shard) do
{mod, [{f, 2}]} -> apply(mod, f, [conn, []])
{mod, [{f, 3}]} -> apply(mod, f, [conn, params, []])
nil -> raise Vik.ShardNotExposed, shard
end
rescue
e ->
Vik.Logger.exception(e, __STACKTRACE__)
PubSub.broadcast(shard.slug, {:exception, e})
reraise e, __STACKTRACE__
end
defp find_callable(~m{:Shard, slug}) do
case Store.fetch(slug) do
{:ok, data} -> extract_spec(data)
:error -> raise Vik.ShardNotAlive, slug
end
end
defp extract_spec(~m{:Result, module}) do
if function_exported?(module, :__call__, 0) do
{module, module.__call__()}
end
end
# The shard can of course override this, but we need
# to make sure we at least set the header. Otherwise,
# the browser will assume application/ocet-stream, which
# is almost never desired behaviour. JSON is a sane default.
defp put_content_type(conn, _opts) do
put_resp_content_type(conn, "application/json")
end
end