У нас есть модуль-обертка, который реализует все обратные вызовы Webgear и передает их в реальный модуль реализации, если они реализованы там. Этот модуль может иметь специальные реализации для определенных частей или даже включать новые обратные вызовы в модулях, использующих его. По сути, этот модуль является ресурсом-оберткой для всех ваших других ресурсов.
Во-первых, ваша карта отправки будет выглядеть следующим образом:
[{"/some/path", webgear_wrapper, {actual_resource, ["Some", extra, "Args"]}}].
Для этого вам необходимо выяснить, какие обратные вызовы реализует ваш фактический модуль реализации:
-record(context, {module, context, exports}).
init({Mod, Args}) ->
{ok, Context} = Mod:init(Args),
{ok, #context{module = Mod, context = Context, exports = exports(Mod)}}.
exports(Mod) ->
dict:from_list(Mod:module_info(exports)).
Это инициализирует базовый ресурс Webgear, который имеет информацию о реальном модуле обратного вызова в своем состоянии.
Затем для каждого обратного вызова к ресурсу-оболочке (который вы должны реализовать, если хотите, чтобы ваши модули реализации могли его использовать), вы увидите, реализована ли эта функция, и обработаете ее там используя эту функцию:
call(#context{module = Mod, context = Cxt, exports = Exports},
Func, Req, Default) ->
case dict:is_key(Func, Exports) of
true -> Mod:Func(Req, Cxt);
false -> {Default, Req, Cxt}
end.
Функция call/4
, например, используется в модуле оболочки следующим образом:
malformed_request(Req, Cxt) ->
% false here is the default value to return if the callback is missing
{Res, NewReq, NewCxt} = call(Cxt, malformed_request, Req, false),
% Now we must update the state accordingly
{Res, NewReq, Cxt#context{context = NewCxt}}.
Это хорошо работает в нашем проекте, где все ресурсы имеют общую логику (реализованную в таком модуле-обертке). Хотя производительность не очень сильно оценивалась, но накладные расходы должны быть довольно небольшими (один анализ dict и один дополнительный вызов модуля, а также некоторые записи).