%%% Copyright (c) 2014-2015, NORDUnet A/S. %%% See LICENSE for licensing information. %%% @doc Storage node API -module(storage). %% API (URL) -export([request/4]). -define(APPURL_PLOP_STORAGE, "plop/v1/storage"). request(post, ?APPURL_PLOP_STORAGE, "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_entry_sync(TreeLeafHash, LogEntry), ok = storagedb:add(TreeLeafHash), success({[{result, <<"ok">>}]}) end; request(post, ?APPURL_PLOP_STORAGE, "entrycommitted", Input) -> case (catch mochijson2:decode(Input)) of {error, E} -> html("entrycommitted: bad input:", E); {struct, PropList} -> EntryHash = base64:decode(proplists:get_value(<<"entryhash">>, PropList)), LeafHash = base64:decode(proplists:get_value(<<"treeleafhash">>, PropList)), db:add_entryhash(LeafHash, EntryHash), db:commit_entryhash(), success({[{result, <<"ok">>}]}) end; request(get, ?APPURL_PLOP_STORAGE, "fetchnewentries", _Input) -> {LastIndexOrZero, LastHash} = storagedb:lastverifiednewentry(), LastVerifiedAndNewHashes = storagedb:fetchnewhashes(LastIndexOrZero), NewHashes = case {LastHash, LastVerifiedAndNewHashes} of {none, LastVerifiedAndNewHashes} -> LastVerifiedAndNewHashes; {Hash1, [Hash2|Rest]} when Hash1 == Hash2 -> Rest; _ -> exit({internalerror, "Incorrect lastverifiedentry"}) end, Entries = lists:map(fun(LeafHash) -> base64:encode(LeafHash) end, NewHashes), success({[{result, <<"ok">>}, {entries, Entries}]}); request(get, ?APPURL_PLOP_STORAGE, "getentry", Query) -> Hashes = [base64:decode(Value) || {Key, Value} <- Query, Key == "hash"], Entries = lists:map(fun(LeafHash) -> {[{hash, base64:encode(LeafHash)}, {entry, base64:encode(case db:entry_for_leafhash(LeafHash) of noentry -> <<>>; Entry -> Entry end)}]} end, Hashes), success({[{result, <<"ok">>}, {entries, Entries}]}). %% Private functions. html(Text, Input) -> {400, [{"Content-Type", "text/html"}], io_lib:format( "

~n" ++ "~s~n" ++ "~p~n" ++ "~n", [Text, Input])}. success(Data) -> {200, [{"Content-Type", "text/json"}], mochijson2:encode(Data)}.