# Copyright(c) 2015-2018 ACCESS CO., LTD. All rights reserved. use Croma defmodule Antikythera.GearApplication.ErrorHandler do @moduledoc """ Helper module for gear's custom error handler. To customize HTTP responses returned on errors, gear must implement an error handler module which - is named `YourGear.Controller.Error`, and - defines the following functions: - Mandatory error handlers - `error/2` - `no_route/1` - `bad_request/1` - Optional error handlers (when your gear uses websocket) - `ws_too_many_connections/1` This module generates `YourGear.error_handler_module/0` function, which is called by antikythera when handling errors. """ alias Antikythera.GearName alias AntikytheraCore.GearModule @all_handlers [ error: 2, no_route: 1, bad_request: 1, ] @doc false defun find_error_handler_module(gear_name :: v[GearName.t]) :: nil | module do mod = GearModule.error_handler_unsafe(gear_name) # during compilation of gear, allowed to call unsafe function try do exported_funs = mod.module_info(:exports) not_defined_handlers = Enum.reject(@all_handlers, &(&1 in exported_funs)) if Enum.empty?(not_defined_handlers) do mod else IO.puts(""" [antikythera] warning: #{mod} exists but some of the error handlers are not defined: #{inspect(not_defined_handlers)}; [antikythera] #{mod} is not eligible for a custom error handler module. """) nil end rescue UndefinedFunctionError -> nil # module not defined end end defmacro __using__(_) do quote do # Assuming that module attribute `@gear_name` is defined in the __CALLER__'s context @error_handler_module Antikythera.GearApplication.ErrorHandler.find_error_handler_module(@gear_name) defun error_handler_module() :: nil | module do @error_handler_module end end end end