caching works correctly
This commit is contained in:
parent
a942d79869
commit
673bc3ae52
120
src/fd_cache.erl
Normal file
120
src/fd_cache.erl
Normal file
@ -0,0 +1,120 @@
|
||||
% @doc storing map #{cookie := Context}
|
||||
-module(fd_cache).
|
||||
|
||||
-behavior(gen_server).
|
||||
|
||||
-export([
|
||||
start_link/0,
|
||||
query/1, set/2, unset/1,
|
||||
%%---
|
||||
%% everything below here runs in process context
|
||||
%%--
|
||||
%% gen_server callbacks
|
||||
init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||
code_change/3, terminate/2
|
||||
]).
|
||||
|
||||
-include("$zx_include/zx_logger.hrl").
|
||||
|
||||
-type context() :: wfc_eval_context:context().
|
||||
|
||||
-record(s,
|
||||
{cookies = #{} :: #{Cookie :: binary() := context()}}).
|
||||
% -type state() :: #s{}.
|
||||
|
||||
|
||||
%%--------------------------------
|
||||
%% api (runs in context of caller)
|
||||
%%--------------------------------
|
||||
|
||||
-spec start_link() -> {ok, pid()} | {error, term()}.
|
||||
start_link() ->
|
||||
gen_server:start_link({local, ?MODULE}, ?MODULE, none, []).
|
||||
|
||||
|
||||
|
||||
-spec query(Cookie) -> {ok, Context} | error
|
||||
when Cookie :: binary(),
|
||||
Context :: context().
|
||||
|
||||
query(Cookie) ->
|
||||
gen_server:call(?MODULE, {query, Cookie}).
|
||||
|
||||
|
||||
|
||||
-spec set(Cookie, Context) -> ok
|
||||
when Cookie :: binary(),
|
||||
Context :: context().
|
||||
|
||||
set(Cookie, Context) ->
|
||||
gen_server:cast(?MODULE, {set, Cookie, Context}).
|
||||
|
||||
|
||||
-spec unset(Cookie) -> ok
|
||||
when Cookie :: binary().
|
||||
|
||||
unset(Cookie) ->
|
||||
gen_server:cast(?MODULE, {unset, Cookie}).
|
||||
|
||||
|
||||
%%----------------------
|
||||
%% gen-server bs
|
||||
%%----------------------
|
||||
|
||||
|
||||
|
||||
init(none) ->
|
||||
log(info, "starting fd_cache"),
|
||||
InitState = #s{},
|
||||
{ok, InitState}.
|
||||
|
||||
|
||||
handle_call({query, Cookie}, _, State) ->
|
||||
Result = do_query(Cookie, State),
|
||||
{reply, Result, State};
|
||||
handle_call(Unexpected, From, State) ->
|
||||
tell("~tp: unexpected call from ~tp: ~tp", [?MODULE, Unexpected, From]),
|
||||
{noreply, State}.
|
||||
|
||||
|
||||
handle_cast({set, Cookie, Context}, State) ->
|
||||
NewState = do_set(Cookie, Context, State),
|
||||
{noreply, NewState};
|
||||
handle_cast({unset, Cookie}, State) ->
|
||||
NewState = do_unset(Cookie, State),
|
||||
{noreply, NewState};
|
||||
handle_cast(Unexpected, State) ->
|
||||
tell("~tp: unexpected cast: ~tp", [?MODULE, Unexpected]),
|
||||
{noreply, State}.
|
||||
|
||||
|
||||
handle_info(Unexpected, State) ->
|
||||
tell("~tp: unexpected info: ~tp", [?MODULE, Unexpected]),
|
||||
{noreply, State}.
|
||||
|
||||
|
||||
code_change(_, State, _) ->
|
||||
{ok, State}.
|
||||
|
||||
terminate(_, _) ->
|
||||
ok.
|
||||
|
||||
|
||||
%%---------------------
|
||||
%% doers
|
||||
%%---------------------
|
||||
|
||||
do_set(Cookie, Context, State = #s{cookies = Cookies}) ->
|
||||
NewCookies = maps:put(Cookie, Context, Cookies),
|
||||
NewState = State#s{cookies = NewCookies},
|
||||
NewState.
|
||||
|
||||
|
||||
do_unset(Cookie, State = #s{cookies = Cookies}) ->
|
||||
NewCookies = maps:remove(Cookie, Cookies),
|
||||
NewState = State#s{cookies = NewCookies},
|
||||
NewState.
|
||||
|
||||
|
||||
do_query(Cookie, _State = #s{cookies = Cookies}) ->
|
||||
maps:find(Cookie, Cookies).
|
||||
@ -263,34 +263,52 @@ default_css(Sock) ->
|
||||
http_err(Sock, 500)
|
||||
end.
|
||||
|
||||
wfcin(Sock, #request{enctype = json, body = #{"wfcin" := Input}}) ->
|
||||
wfcin(Sock, #request{enctype = json,
|
||||
cookies = Cookies,
|
||||
body = #{"wfcin" := Input}}) ->
|
||||
tell("wfcin good request: ~tp", [Input]),
|
||||
RespObj =
|
||||
{Cookie, Ctx0} = ctx(Cookies),
|
||||
{RespObj, NewCtx} =
|
||||
%% FIXME: this should really be a new process
|
||||
try
|
||||
case wfc_read:expr(Input) of
|
||||
%% FIXME support multiple expressions
|
||||
{ok, Expr, _Rest} ->
|
||||
case wfc_eval:eval(Expr, wfc_eval_context:default()) of
|
||||
{ok, noop, _NewContext} -> jsgud("<noop>");
|
||||
{ok, Sentence, _NewContext} -> jsgud(wfc_pp:sentence(Sentence));
|
||||
{error, Message} -> jsbad(Message)
|
||||
case wfc_eval:eval(Expr, Ctx0) of
|
||||
{ok, noop, Ctx1} -> {jsgud("<noop>"), Ctx1};
|
||||
{ok, Sentence, Ctx1} -> {jsgud(wfc_pp:sentence(Sentence)), Ctx1};
|
||||
{error, Message} -> {jsbad(Message), Ctx0}
|
||||
end;
|
||||
{error, Message} ->
|
||||
jsbad(Message)
|
||||
{jsbad(Message), Ctx0}
|
||||
end
|
||||
catch
|
||||
error:E:S ->
|
||||
ErrorMessage = unicode:characters_to_list(io_lib:format("parser crashed: ~p:~p", [E, S])),
|
||||
jsbad(ErrorMessage)
|
||||
{jsbad(ErrorMessage), Ctx0}
|
||||
end,
|
||||
% update cache with new context
|
||||
ok = fd_cache:set(Cookie, NewCtx),
|
||||
Body = zj:encode(RespObj),
|
||||
Response = #response{headers = [{"content-type", "application/json"}],
|
||||
Response = #response{headers = [{"content-type", "application/json"},
|
||||
{"set-cookie", ["wfc=", Cookie]}],
|
||||
body = Body},
|
||||
respond(Sock, Response);
|
||||
wfcin(Sock, Request) ->
|
||||
tell("wfcin: bad request: ~tp", [Request]),
|
||||
http_err(Sock, 400).
|
||||
|
||||
|
||||
ctx(#{<<"wfc">> := Cookie}) ->
|
||||
case fd_cache:query(Cookie) of
|
||||
{ok, Context} -> {Cookie, Context};
|
||||
error -> {Cookie, wfc_eval_context:default()}
|
||||
end;
|
||||
ctx(_) ->
|
||||
{new_cookie(), wfc_eval_context:default()}.
|
||||
|
||||
new_cookie() ->
|
||||
binary:encode_hex(crypto:strong_rand_bytes(8)).
|
||||
|
||||
jsgud(X) ->
|
||||
#{"ok" => true,
|
||||
"result" => X}.
|
||||
|
||||
@ -42,5 +42,11 @@ init([]) ->
|
||||
5000,
|
||||
supervisor,
|
||||
[fd_clients]},
|
||||
Children = [Clients],
|
||||
Cache = {fd_cache,
|
||||
{fd_cache, start_link, []},
|
||||
permanent,
|
||||
5000,
|
||||
worker,
|
||||
[fd_cache]},
|
||||
Children = [Clients, Cache],
|
||||
{ok, {RestartStrategy, Children}}.
|
||||
|
||||
@ -59,6 +59,11 @@ eval_sexp(Args = [{snowflake, <<"define">>}, {pattern, Pat}, Expr], Ctx0) ->
|
||||
Error ->
|
||||
Error
|
||||
end;
|
||||
eval_sexp(_Args = [{snowflake, <<"undefine">>}, {pattern, Pat}], Ctx0) ->
|
||||
case wfc_eval_context:undefine(Pat, Ctx0) of
|
||||
{ok, NewContext} -> {ok, noop, NewContext};
|
||||
Error -> Error
|
||||
end;
|
||||
eval_sexp([{snowflake, SF} | Args], Ctx0) ->
|
||||
% first evaluate the arguments individually
|
||||
case eval_sexp_args(Args, Ctx0, []) of
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
default/0,
|
||||
default_snowflakes/0,
|
||||
define/3,
|
||||
undefine/2,
|
||||
resolve_pattern/2,
|
||||
resolve_snowflake/2
|
||||
]).
|
||||
@ -33,6 +34,7 @@ default() ->
|
||||
default_snowflakes() ->
|
||||
#{<<"and">> => fun wfc:mul/1,
|
||||
<<"xor">> => fun wfc:add/1,
|
||||
<<"implies">> => fun snf_implies/1,
|
||||
<<"ior">> =>
|
||||
fun IOR([S1 | Rest]) ->
|
||||
case IOR(Rest) of
|
||||
@ -46,10 +48,6 @@ default_snowflakes() ->
|
||||
fun ([S]) -> {ok, sf_not(S)};
|
||||
(Bad) -> {error, wfc_utils:str("not/1: wrong number of arguments: ~p", [Bad])}
|
||||
end,
|
||||
<<"implies">> =>
|
||||
fun ([A, B]) -> {ok, sf_implies(A, B)};
|
||||
(Bad) -> {error, wfc_utils:str("implies/2: wrong number of arguments: ~p", [Bad])}
|
||||
end,
|
||||
<<"impliedby">> =>
|
||||
fun ([A, B]) -> {ok, sf_impliedby(A, B)};
|
||||
(Bad) -> {error, wfc_utils:str("impliedby/2: wrong number of arguments: ~p", [Bad])}
|
||||
@ -60,6 +58,10 @@ default_snowflakes() ->
|
||||
end
|
||||
}.
|
||||
|
||||
snf_implies([A, B]) -> {ok, sf_implies(A, B)};
|
||||
snf_implies(Bad) -> {error, wfc_utils:str("implies/2: wrong number of arguments: ~p", [Bad])}.
|
||||
|
||||
|
||||
sf_ior(A, B) ->
|
||||
wfc_sftt:appl_ttf(fun ttf_ior/2, [A, B]).
|
||||
|
||||
@ -93,14 +95,18 @@ define(Pat, Sentence, Ctx = #ctx{patterns = OldPatterns}) ->
|
||||
NewPatterns = maps:put(Pat, Sentence, OldPatterns),
|
||||
{ok, Ctx#ctx{patterns = NewPatterns}}.
|
||||
|
||||
undefine(Pat, Ctx = #ctx{patterns = OldPatterns}) ->
|
||||
NewPatterns = maps:remove(Pat, OldPatterns),
|
||||
{ok, Ctx#ctx{patterns = NewPatterns}}.
|
||||
|
||||
resolve_pattern(Pat, Ctx = #ctx{patterns = Patterns}) ->
|
||||
case maps:find(Pat, Patterns) of
|
||||
error -> {error, wfc_utils:str("wfc_eval_context:resolve_pattern: not found: ~w; context: ~w", [Pat, Ctx])};
|
||||
error -> {error, wfc_utils:str("wfc_eval_context:resolve_pattern: not found: ~s; context: ~w", [Pat, Ctx])};
|
||||
Result -> Result
|
||||
end.
|
||||
|
||||
resolve_snowflake(SF, Ctx = #ctx{snowflakes = Snowflakes}) ->
|
||||
case maps:find(SF, Snowflakes) of
|
||||
error -> {error, wfc_utils:str("wfc_eval_context:resolve_snowflake: not found: ~w; context: ~w", [SF, Ctx])};
|
||||
error -> {error, wfc_utils:str("wfc_eval_context:resolve_snowflake: not found: ~s; context: ~w", [SF, Ctx])};
|
||||
Result -> Result
|
||||
end.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user