Skip to content
This repository has been archived by the owner on Oct 22, 2021. It is now read-only.

Commit

Permalink
hook up POST to webmachine.
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert Newson committed Mar 9, 2011
1 parent bf10221 commit 8e7a8b9
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 49 deletions.
38 changes: 16 additions & 22 deletions src/monic_file.erl
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,9 @@ load_main_items(Tid, Fd, {_, Location}=Hints) ->
add_item(Size, Fun, #state{tid=Tid, index_fd=IndexFd, main_fd=MainFd,
next_key=Key, next_location=Location}) ->
Cookie = monic_utils:new_cookie(),
Flags = <<0:16>>,
Version = 1,
Header = #header{key=Key, cookie=Cookie, size=Size, version=Version, flags=0},
Header = #header{key=Key, cookie=Cookie, size=Size, version=Version, flags=Flags},
case monic_utils:pwrite_header(MainFd, Location, Header) of
ok ->
case copy_in(MainFd, Fun, Location + ?HEADER_SIZE, Size) of
Expand All @@ -184,7 +185,7 @@ add_item(Size, Fun, #state{tid=Tid, index_fd=IndexFd, main_fd=MainFd,
case file:datasync(MainFd) of
ok ->
monic_utils:write_index(IndexFd,
#index{key=Key,location=Location,size=Size,version=Version,flags=0}
#index{key=Key,location=Location,size=Size,version=Version,flags=Flags}
),
ets:insert(Tid, {Key, Location, Size, Version}),
{ok, Key, Cookie};
Expand All @@ -204,27 +205,20 @@ add_item(Size, Fun, #state{tid=Tid, index_fd=IndexFd, main_fd=MainFd,
copy_in(Fd, Fun, Location, Remaining) ->
copy_in(Fd, Fun, Location, Remaining, crypto:sha_init()).

copy_in(_Fd, _Fun, _Location, 0, Sha) ->
copy_in(_Fd, done, _Location, 0, Sha) ->
{ok, crypto:sha_final(Sha)};
copy_in(Fd, Fun, Location, Remaining, Sha) ->
case Fun(?BUFFER_SIZE) of
{ok, Bin} ->
Size = iolist_size(Bin),
case Size =< Remaining of
true ->
case file:pwrite(Fd, Location, Bin) of
ok ->
copy_in(Fd, Fun, Location + Size,
Remaining - Size,
crypto:sha_update(Sha, Bin));
Else ->
Else
end;
false ->
{error, overflow}
end;
Else ->
Else
copy_in(_Fd, done, _Location, _Remaining, _Sha) ->
{error, underflow};
copy_in(Fd, Fun, Location, Remaining, Sha) ->
{Bin, Next} = Fun(),
Size = iolist_size(Bin),
case Size =< Remaining of
true ->
file:pwrite(Fd, Location, Bin),
copy_in(Fd, Next, Location + Size, Remaining - Size,
crypto:sha_update(Sha, Bin));
false ->
{error, overflow}
end.

copy_out(_Fd, _Fun, _Location, 0) ->
Expand Down
81 changes: 66 additions & 15 deletions src/monic_file_resource.erl
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,43 @@
allowed_methods/2,
content_types_accepted/2,
content_types_provided/2,
create_path/2,
delete_resource/2,
is_conflict/2,
resource_exists/2]).

-export([from_json/2, to_json/2]).
-import(monic_utils, [path/2, exists/2]).
post_is_create/2,
resource_exists/2,
valid_entity_length/2]).
-export([show_file/2, create_file/2, add_item/2]).

-include_lib("webmachine/include/webmachine.hrl").
-define(BUFFER_SIZE, 64*1024).

allowed_methods(ReqData, Context) ->
{['DELETE', 'GET', 'PUT'], ReqData, Context}.
{['DELETE', 'GET', 'PUT', 'POST'], ReqData, Context}.

content_types_accepted(ReqData, Context) ->
{[{"application/json", from_json}], ReqData, Context}.
case wrq:method(ReqData) of
'PUT' ->
{[{"application/json", create_file}], ReqData, Context};
'POST' ->
CT = case wrq:get_req_header("Content-Type", ReqData) of
undefined -> "application/octet-stream";
Other -> Other
end,
{[{CT, add_item}], ReqData, Context}
end.

content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
{[{"application/json", show_file}], ReqData, Context}.

create_path(ReqData, Context) ->
File = wrq:path_info(file, ReqData),
Key = 1, %% TODO increment.
Cookie = crypto:rand_uniform(1, 1 bsl 32),
{io_lib:format("/~s/~B/~B", [File, Key, Cookie]), ReqData, Context}.

delete_resource(ReqData, Context) ->
case file:delete(path(ReqData, Context)) of
case file:delete(monic_utils:path(ReqData, Context)) of
ok ->
{true, ReqData, Context};
_ ->
Expand All @@ -47,15 +64,49 @@ init(ConfigProps) ->
{ok, ConfigProps}.

is_conflict(ReqData, Context) ->
{exists(ReqData, Context), ReqData, Context}.
{monic_utils:exists(ReqData, Context), ReqData, Context}.

post_is_create(ReqData, Context) ->
{true, ReqData, Context}.

resource_exists(ReqData, Context) ->
{exists(ReqData, Context), ReqData, Context}.
{monic_utils:exists(ReqData, Context), ReqData, Context}.

from_json(ReqData, Context) ->
ok = file:write_file(path(ReqData, Context), <<>>, [exclusive]),
{true, ReqData, Context}.

to_json(ReqData, Context) ->
valid_entity_length(ReqData, Context) ->
Valid = case wrq:method(ReqData) of
'POST' ->
wrq:get_req_header("Content-Length", ReqData) /= undefined;
_ ->
true
end,
{Valid, ReqData, Context}.

%% private functions

show_file(ReqData, Context) ->
{"{\"ok\": true}", ReqData, Context}.

create_file(ReqData, Context) ->
case file:write_file(monic_utils:path(ReqData, Context), <<>>, [exclusive]) of
ok -> {true, ReqData, Context};
_ -> {false, ReqData, Context}
end.

add_item(ReqData, Context) ->
case monic_file:open(monic_utils:path(ReqData, Context)) of
{ok, Pid} ->
try
Size = list_to_integer(wrq:get_req_header("Content-Length", ReqData)),
StreamBody = fun() -> wrq:stream_req_body(ReqData, ?BUFFER_SIZE) end,
case monic_file:add(Pid, Size, StreamBody) of
{ok, Key, Cookie} ->
{true, ReqData, Context};
_ ->
{false, ReqData, Context}
end
after
monic_file:close(Pid)
end;
_ ->
{false, ReqData, Context}
end.
8 changes: 4 additions & 4 deletions src/monic_utils.erl
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ exists(ReqData, Context) ->
pwrite_header(Fd, Location, #header{key=Key,cookie=Cookie,size=Size,
version=Version,flags=Flags}) ->
Bin = <<?ITEM_HEADER_MAGIC:32/integer, Key:64/integer, Cookie:32/integer,
Size:64/integer, Version:16/integer, Flags:16/integer>>,
Size:64/integer, Version:16/integer, Flags:16/bitstring>>,
file:pwrite(Fd, Location, Bin).

pread_header(Fd, Location) ->
case file:pread(Fd, Location, ?HEADER_SIZE) of
{ok, <<?ITEM_HEADER_MAGIC:32/integer, Key:64/integer, Cookie:32/integer,
Size:64/integer, Version:16/integer, Flags:16/integer>>} ->
Size:64/integer, Version:16/integer, Flags:16/bitstring>>} ->
{ok, #header{key=Key,cookie=Cookie,size=Size,version=Version,flags=Flags}};
{ok, _} ->
{error, invalid_header};
Expand All @@ -65,13 +65,13 @@ pread_footer(Fd, Location) ->

write_index(Fd, #index{key=Key,location=Location,size=Size,version=Version,flags=Flags}) ->
Bin = <<Key:64/integer, Location:64/integer, Size:64/integer,
Version:16/integer, Flags:16/integer>>,
Version:16/integer, Flags:16/bitstring>>,
file:write(Fd, Bin).

read_index(Fd) ->
case file:read(Fd, ?INDEX_SIZE) of
{ok, <<Key:64/integer, Location:64/integer, Size:64/integer,
Version:16/integer, Flags:16/integer>>} ->
Version:16/integer, Flags:16/bitstring>>} ->
{ok, #index{key=Key,location=Location,size=Size,
version=Version,flags=Flags}};
{ok, _} ->
Expand Down
21 changes: 13 additions & 8 deletions test/monic_file_test.erl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ all_test_() ->
[fun add/1,
fun add_read/1,
fun add_multi/1,
fun overflow/1
fun overflow/1,
fun underflow/1
]}.

setup() ->
Expand All @@ -36,18 +37,22 @@ cleanup(Pid) ->
monic_file:close(Pid).

add(Pid) ->
?_assertMatch({ok, 0, _}, monic_file:add(Pid, 3, fun(_Max) -> {ok, <<"123">>} end)).
?_assertMatch({ok, 0, _}, monic_file:add(Pid, 3, fun() -> {<<"123">>, done} end)).

add_read(Pid) ->
{ok, Key, Cookie} = monic_file:add(Pid, 3, fun(_Max) -> {ok, <<"123">>} end),
{ok, Key, Cookie} = monic_file:add(Pid, 3, fun() -> {<<"123">>, done} end),
?_assertEqual(ok, monic_file:read(Pid, Key, Cookie, fun({ok, <<"123">>}) -> ok end)).

add_multi(Pid) ->
[?_assertMatch({ok, 0, _}, monic_file:add(Pid, 3, fun(_Max) -> {ok, <<"123">>} end)),
?_assertMatch({ok, 1, _}, monic_file:add(Pid, 3, fun(_Max) -> {ok, <<"456">>} end)),
?_assertMatch({ok, 2, _}, monic_file:add(Pid, 3, fun(_Max) -> {ok, <<"789">>} end)),
?_assertMatch({ok, 3, _}, monic_file:add(Pid, 3, fun(_Max) -> {ok, <<"abc">>} end))].
[?_assertMatch({ok, 0, _}, monic_file:add(Pid, 3, fun() -> {<<"123">>, done} end)),
?_assertMatch({ok, 1, _}, monic_file:add(Pid, 3, fun() -> {<<"456">>, done} end)),
?_assertMatch({ok, 2, _}, monic_file:add(Pid, 3, fun() -> {<<"789">>, done} end)),
?_assertMatch({ok, 3, _}, monic_file:add(Pid, 3, fun() -> {<<"abc">>, done} end))].

overflow(Pid) ->
Res = monic_file:add(Pid, 3, fun(_Max) -> {ok, <<"1234">>} end),
Res = monic_file:add(Pid, 3, fun() -> {<<"1234">>, done} end),
?_assertEqual({error, overflow}, Res).

underflow(Pid) ->
Res = monic_file:add(Pid, 3, fun() -> {<<"12">>, done} end),
?_assertEqual({error, underflow}, Res).

0 comments on commit 8e7a8b9

Please sign in to comment.