Current section
Files
Jump to
Current section
Files
lib/orchid/runner_hooks/core.ex
defmodule Orchid.Runner.Hooks.Core do
@behaviour Orchid.Runner.Hook
alias Orchid.Param
@spec call(Orchid.Runner.Context.t(), function()) ::
{:ok, Orchid.Step.output()} | {:error, term()}
def call(ctx, _next) do
# 构造 Reporter
reporter_fn = fn progress, payload ->
:telemetry.execute(
[:orchid, :step, :progress],
%{progress: progress},
Map.merge(ctx.telemetry_meta, %{payload: payload})
)
end
# 注入资源
final_opts =
ctx.step_default_opts
|> Keyword.merge(ctx.recipe_opts)
|> Keyword.put(:__reporter__, reporter_fn)
case run_step(ctx.step_implementation, ctx.inputs, final_opts) do
{:ok, raw_output} ->
renamed = align_output_names(raw_output, ctx.out_keys)
{:ok, renamed}
other ->
other
end
end
## 囊括单体、列表元组
# 单体 + 单体
defp align_output_names(%Param{} = param, out_key) when is_atom(out_key) do
%{param | name: out_key}
end
defp align_output_names(%Param{} = param, [out_key]) when is_atom(out_key) do
%{param | name: out_key}
end
defp align_output_names([%Param{} = param], out_key) when not is_tuple(out_key) do
%{param | name: out_key}
end
# 列表 + 列表
defp align_output_names(params, out_keys) when is_list(params) and not is_tuple(out_keys) do
keys = List.wrap(out_keys)
Enum.zip_with(params, keys, fn param, key -> %{param | name: key} end)
end
# 包含元组
defp align_output_names(param, out_key) when is_tuple(param) and is_tuple(out_key) do
align_output_names(Tuple.to_list(param), Tuple.to_list(out_key))
end
defp align_output_names(param, out_key) when is_tuple(param) do
align_output_names(Tuple.to_list(param), out_key)
end
defp align_output_names(param, out_key) when is_tuple(out_key) do
align_output_names(param, Tuple.to_list(out_key))
end
defp run_step(impl, inputs, opts) when is_atom(impl) do
if Code.ensure_loaded?(impl) and function_exported?(impl, :run, 2) do
impl.run(inputs, opts)
else
{:error, {:invalid_step_implementation, impl}}
end
end
defp run_step(run_fun, inputs, opts) when is_function(run_fun, 2) do
run_fun.(inputs, opts)
end
defp run_step(_, _, _), do: {:error, :invalid_step_implementation}
end