diff options
Diffstat (limited to 'src/frontend.erl')
-rw-r--r-- | src/frontend.erl | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/src/frontend.erl b/src/frontend.erl new file mode 100644 index 0000000..9c69517 --- /dev/null +++ b/src/frontend.erl @@ -0,0 +1,130 @@ +%%% Copyright (c) 2014, NORDUnet A/S. +%%% See LICENSE for licensing information. + +%%% @doc Frontend node API + +-module(frontend). +%% API (URL) +-export([request/3]). + +request(post, "ct/frontend/sendentry", Input) -> + case (catch mochijson2:decode(Input)) of + {error, E} -> + html("sendentry: bad input:", E); + {struct, PropList} -> + LogEntry = base64:decode(proplists:get_value(<<"entry">>, PropList)), + TreeLeafHash = base64:decode(proplists:get_value(<<"treeleafhash">>, PropList)), + + ok = db:add(TreeLeafHash, LogEntry), + success({[{result, <<"ok">>}]}) + end; + +request(post, "ct/frontend/sendlog", Input) -> + case (catch mochijson2:decode(Input)) of + {error, E} -> + html("sendentry: bad input:", E); + {struct, PropList} -> + Start = proplists:get_value(<<"start">>, PropList), + Hashes = lists:map(fun (S) -> base64:decode(S) end, proplists:get_value(<<"hashes">>, PropList)), + + Indices = lists:seq(Start, Start + length(Hashes) - 1), + lists:foreach(fun ({Hash, Index}) -> + ok = db:add_index(Hash, Index) + end, lists:zip(Hashes, Indices)), + success({[{result, <<"ok">>}]}) + end; + +request(post, "ct/frontend/sendsth", Input) -> + case (catch mochijson2:decode(Input)) of + {error, E} -> + html("sendentry: bad input:", E); + {struct, PropList} -> + OldSize = db:size(), + Treesize = proplists:get_value(<<"tree_size">>, PropList), + Indexsize = db:indexsize(), + + if + Treesize < OldSize -> + html("Size is older than current size", OldSize); + Treesize == OldSize -> + success({[{result, <<"ok">>}]}); + Treesize > Indexsize -> + html("Has too few entries", Indexsize); + true -> + NewEntries = db:leafhash_for_indices(OldSize, Treesize - 1), + lager:debug("old size: ~p new size: ~p entries: ~p", + [OldSize, Treesize, NewEntries]), + + Errors = check_entries(NewEntries, OldSize, Treesize - 1), + + case Errors of + [] -> + ok = db:set_treesize(Treesize), + ht:reset_tree([db:size() - 1]), + success({[{result, <<"ok">>}]}); + _ -> + html("Database not complete", Errors) + end + end + end; + +request(get, "ct/frontend/currentposition", _Query) -> + Size = db:size(), + success({[{result, <<"ok">>}, + {position, Size}]}); + +request(get, "ct/frontend/missingentries", _Query) -> + Size = db:size(), + Missing = fetchmissingentries(Size), + lager:debug("missingentries: ~p", [Missing]), + success({[{result, <<"ok">>}, + {entries, lists:map(fun (Entry) -> base64:encode(Entry) end, + Missing)}]}). +check_entries(Entries, Start, End) -> + lists:foldl(fun ({Hash, Index}, Acc) -> + case check_entry(Hash, Index) of + ok -> + Acc; + Error -> + [Error | Acc] + end + end, [], lists:zip(Entries, lists:seq(Start, End))). + +check_entry(Hash, Index) -> + case db:get_by_leaf_hash(Hash) of + notfound -> + {notfound, Index}; + _ -> + ok + end. + +fetchmissingentries(Index) -> + lists:reverse(fetchmissingentries(Index, [])). + +fetchmissingentries(Index, Acc) -> + lager:debug("index ~p", [Index]), + case db:leafhash_for_index(Index) of + noentry -> + Acc; + Hash -> + case db:entry_for_leafhash(Hash) of + noentry -> + lager:debug("didn't find hash ~p", [Hash]), + fetchmissingentries(Index + 1, [Hash | Acc]); + _ -> + fetchmissingentries(Index + 1, Acc) + end + end. + + +%% Private functions. +html(Text, Input) -> + {400, [{"Content-Type", "text/html"}], + io_lib:format( + "<html><body><p>~n" ++ + "~s~n" ++ + "~p~n" ++ + "</body></html>~n", [Text, Input])}. + +success(Data) -> + {200, [{"Content-Type", "text/json"}], mochijson2:encode(Data)}. |