summaryrefslogtreecommitdiff
path: root/src/frontend.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend.erl')
-rw-r--r--src/frontend.erl130
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)}.