BeepBeep + ewgi

1 view
Skip to first unread message

Dmitrii Dimandt

unread,
Jul 17, 2009, 5:10:54 PM7/17/09
to ew...@googlegroups.com
В общем, вести с полей.

1. Я полностью перевел beepbeep на ewgi. То
есть на входе у него ewgi_context и на выходе
— тоже

2. Я реализовал джангоподобный middleware stack

Но залить на GitHub не могу, потому что http://groups.google.com/group/ewgi/browse_fr
m/thread/c28995f6ef58bb94


Но пока расскажу.


Теперь *_web.erl может (должен?) выглядеть
так:

========= *_web.erl =========

start(Options) ->
Loop = fun (Req) ->
?MODULE:loop(Req)
end,
mochiweb_http:start([{name, ?MODULE}, {loop, Loop} | Options]).

stop() ->
mochiweb_http:stop(?MODULE).

loop(Req) ->
Mod = ewgi_mochiweb:new(beepbeep:loop([
beepbeep_session,
beep_web_dispatch,
{another_module, [with, options]}
beepbeep
])),
Mod:run(Req).

========= end of file =========

И т.п.

Сам миддлварь обязан реализовать run/2
или run/3 по такому принципу:

========= middleware_example.erl =========

%% Ctx - это ewgi_context
%% App — это функция, принимающая на вход
ewgi_context.
%% Эта функция просто вызовет
следующий модуль в цепочке

run(Ctx, App) ->
Ctx1 = модифицированный_запрос_Ctx,
Ctx2 = App(Ctx1),
Ctx3 = модифицированый_ответ_Ctx2,
Ctx3.

run(Ctx, App, Options) ->
то же самое, только с опциями для
самого модуля.

========= end of file =========


Middleware stack реализован очень просто:

========= beepbeep_mw.erl =========

stack(Ctx, []) ->
Ctx;
stack(Ctx, [Middleware|T]) ->
F = fun(C) ->
stack(C, T)
end,
run(Middleware, Ctx, F).

run(Module, Ctx, F) when is_atom(Module) ->
Module:run(Ctx, F);

run({Module}, Ctx, F) ->
Module:run(Ctx, F);

run({Module, Options}, Ctx, F) ->
Module:run(Ctx, F, Options).

========= end of file =========

Таким образом,
stack(Ctx, [
beepbeep_session,
beep_web_dispatch,
{another_module, [with, options]}
beepbeep
]).
просто позволит миддлварям вызывать
себя по цепочке.


ПРИМЕР РЕЛЬНОЙ МИДДЛВАРИ

Если вы обратите внимание на http://beepbeep.dmitriid.com/ru
-RU/documentation/hooks/ и http://beepbeep.dmitriid.com/ru-RU/documentation/innards
/ , то увидите там выбивающийся из общей
картины хук *_web:preprocess/1

Этот хук появился по одной простой
причине: мне хотелось, чтобы на сайте
BeepBeep'а в урле обязтельно
присутствовала локаль. Из-за этого
пришлось врезать еще один хук, который
переписывал Env до его попадания в
собственно BeepBeep.

В новой версии этот хук уйдет прочь,
потому что он может быть легко заменен
благородной миддлварью :)

Эта благородная мидлварь в нашем
случае будет называться beep_web_dispatch и
располагаться сразу за миддлварью
сессии

========= beep_web.erl =========

start(Options) ->
Loop = fun (Req) ->
?MODULE:loop(Req)
end,
mochiweb_http:start([{name, ?MODULE}, {loop, Loop} | Options]).

stop() ->
mochiweb_http:stop(?MODULE).

loop(Req) ->
Mod = ewgi_mochiweb:new(beepbeep:loop([
beepbeep_session,
beep_web_dispatch,
beepbeep
])),
Mod:run(Req).

========= end of file =========


========= beep_web_dispatch.erl =========

run({ewgi_context, Request, _} = Ctx, App) ->
PathInfo = string:tokens(ewgi_api:path_info(Ctx), "/"),
Path = list_to_binary(PathInfo),

Session = ewgi_api:find_data("beep.session_id", Ctx),
SessionData = beepbeep_session_server:get_session_data(Session),

Language = case proplists:get_value("language", SessionData) of
undefined ->
"en-US";
Any ->
Any
end,

beepbeep_session_server:set_session_data(Session, "language",
Language),
case Path of
<<>> ->
%% если локали нет,
перенаправляем пользователя
{ewgi_context, Request, {ewgi_response, {302,
"Temporary redirect"}, [{"Location", "/" ++ Language ++ "/"}], "",
undefined}};
<<A,B,$-,C,D>> ->
%% язык мы получили в URL'е,
устанавливаем его
beepbeep_session_server:set_session_data(Session,
"language", [A,B,$-,C,D]),
Ctx1 = ewgi_api:path_info("/", Ctx),
Ctx2 = ewgi_api:store_data("beep_web.language", [A,B,
$-,C,D], Ctx1),
App(Ctx2);
<<A,B,$-,C,D,Rest/binary>> ->
beepbeep_session_server:set_session_data(Session,
"language", [A,B,$-,C,D]),
Ctx1 = ewgi_api:path_info("/" ++
string:join(tl(PathInfo), "/"), Ctx),
Ctx2 = ewgi_api:store_data("beep_web.language", [A,B,
$-,C,D], Ctx1),
App(Ctx2);
_ ->
%% локали все так же нет,
перенаправляем
{ewgi_context, Request, {ewgi_response, {302,
"Temporary redirect"}, [{"Location", "/"++Language++"/" ++
string:join(PathInfo, "/")}], "", undefined}}
end.

========= end of file =========

В общем, где-то так :) Ура, товарищи :)

Dmitrii Dimandt

unread,
Jul 17, 2009, 5:13:38 PM7/17/09
to ewgi
Sorry for this post, it was intended for erlang-russian group :)
Reply all
Reply to author
Forward
0 new messages