diff --git a/README.md b/README.md index b77ac74..c9554dc 100644 --- a/README.md +++ b/README.md @@ -47,9 +47,9 @@ Erlazure requires OTP version R16+. ## Starting an instance of erlazure -Start an instance of erlazure by calling ```erlazure:start/2``` where **Account** is Storage account name and **Key** is Storage account key. +Start an instance of erlazure by calling `erlazure:new/2` where **Account** is Storage account name and **Key** is Storage account key. ```erlang -{ok, Pid} = erlazure:start(Account, Key) +{ok, State} = erlazure:new(Account, Key) ``` Account and Key are strings. @@ -60,39 +60,30 @@ Account and Key are strings. Account = "devstoreaccount1". Key = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==". %% Mind the trailing slash at the end of the endpoint. -{ok, Pid} = erlazure:start(#{account => Account, key => Key, endpoint => "http://127.0.0.1:10000/"}) +{ok, State} = erlazure:new(#{account => Account, key => Key, endpoint => "http://127.0.0.1:10000/"}) ``` ## Calling Azure services -Almost each azure services request has three corresponding functions in ```erlazure``` module, the first has minimal set of parameters, the second has additionaly list of ```Options``` and the third has additionaly ```Timeout``` parameter. +Almost each azure services request has three corresponding functions in ```erlazure``` module, the first has minimal set of parameters, the second has additionaly list of ```Options```. ```Options``` as the name states is list of options supported by this azure services request, each options is tuple ```{OptionName, OptionValue}``` where ```OptionName``` is atom and ```OptionValue``` can be of any type, option is passed either as a header or as a query string parameter. -```Timeout``` is number of milliseconds to wait for a reply from erlazure, infinity value is not supported. Note, that this is gen_server call timeout and isn't http request timeout (it's set to infinity by default) or azure service request timeout (you can specify it by sending option ```{timeout, _Timeout}```). By default timeout is set to 30 seconds. - For a list of supported options for each azure service request please consult msdn documentation. ## Examples ### Upload block blob ``` -{ok, Pid} = erlazure:start("storage", "2o4b4tHpoWifLU+BlyzsIG1VtlO9LgBRFyl1qLw/+w9/ZszSxKGIK8JYac/UEJp5r8HKgiOiG8YTqGS9otAYWA=="), +{ok, State} = erlazure:new("storage", "2o4b4tHpoWifLU+BlyzsIG1VtlO9LgBRFyl1qLw/+w9/ZszSxKGIK8JYac/UEJp5r8HKgiOiG8YTqGS9otAYWA=="), {ok, Binary} = file:read("/path/to/some/small/file"), -{ok, created} = erlazure:put_block_blob(Pid, "uploads", "test_upload.file", Binary). -``` -### Upload block blob with timeout set -Uploads block blob and waits no longer than 15 seconds for erlazure to finish the upload -``` -{ok, Pid} = erlazure:start("storage", "2o4b4tHpoWifLU+BlyzsIG1VtlO9LgBRFyl1qLw/+w9/ZszSxKGIK8JYac/UEJp5r8HKgiOiG8YTqGS9otAYWA=="), -{ok, Binary} = file:read("/path/to/some/other/file"), -{ok, created} = erlazure:put_block_blob(Pid, "uploads", "test_upload2.file", Binary, [], 15000). +{ok, created} = erlazure:put_block_blob(State, "uploads", "test_upload.file", Binary). ``` ### Get 20 messages from a queue Retrieves max 20 messages from a queue ``` -{ok, Pid} = erlazure:start("storage", "2o4b4tHpoWifLU+BlyzsIG1VtlO9LgBRFyl1qLw/+w9/ZszSxKGIK8JYac/UEJp5r8HKgiOiG8YTqGS9otAYWA=="), -{ok, Messages} = erlazure:get_messages(Pid, "test_queue", [{num_of_messages, 20}]). +{ok, State} = erlazure:new("storage", "2o4b4tHpoWifLU+BlyzsIG1VtlO9LgBRFyl1qLw/+w9/ZszSxKGIK8JYac/UEJp5r8HKgiOiG8YTqGS9otAYWA=="), +{ok, Messages} = erlazure:get_messages(State, "test_queue", [{num_of_messages, 20}]). ``` ## License diff --git a/src/erlazure.erl b/src/erlazure.erl index 55857f8..414eb17 100644 --- a/src/erlazure.erl +++ b/src/erlazure.erl @@ -35,53 +35,47 @@ -include("../include/erlazure.hrl"). -define(json_content_type, "application/json"). --define(gen_server_call_default_timeout, 30000). - --behaviour(gen_server). %% API --export([start/1, start/2]). +-export([new/1, new/2]). %% Queue API --export([list_queues/1, list_queues/2, list_queues/3]). --export([set_queue_acl/3, set_queue_acl/4, set_queue_acl/5]). --export([get_queue_acl/2, get_queue_acl/3, get_queue_acl/4]). --export([create_queue/2, create_queue/3, create_queue/4]). --export([delete_queue/2, delete_queue/3, delete_queue/4]). --export([put_message/3, put_message/4, put_message/5]). --export([get_messages/2, get_messages/3, get_messages/4]). --export([peek_messages/2, peek_messages/3, peek_messages/4]). --export([delete_message/4, delete_message/5, delete_message/6]). --export([clear_messages/2, clear_messages/3, clear_messages/4]). --export([update_message/4, update_message/5, update_message/6]). +-export([list_queues/1, list_queues/2]). +-export([set_queue_acl/3, set_queue_acl/4]). +-export([get_queue_acl/2, get_queue_acl/3]). +-export([create_queue/2, create_queue/3]). +-export([delete_queue/2, delete_queue/3]). +-export([put_message/3, put_message/4]). +-export([get_messages/2, get_messages/3]). +-export([peek_messages/2, peek_messages/3]). +-export([delete_message/4, delete_message/5]). +-export([clear_messages/2, clear_messages/3]). +-export([update_message/4, update_message/5]). %% Blob API --export([list_containers/1, list_containers/2, list_containers/3]). --export([create_container/2, create_container/3, create_container/4]). --export([delete_container/2, delete_container/3, delete_container/4]). --export([lease_container/3, lease_container/4, lease_container/5]). --export([list_blobs/2, list_blobs/3, list_blobs/4]). --export([put_block_blob/4, put_block_blob/5, put_block_blob/6]). --export([put_append_blob/3, put_append_blob/4, put_append_blob/5]). --export([append_block/4, append_block/5, append_block/6]). --export([put_page_blob/4, put_page_blob/5, put_page_blob/6]). --export([get_blob/3, get_blob/4, get_blob/5]). --export([snapshot_blob/3, snapshot_blob/4, snapshot_blob/5]). --export([copy_blob/4, copy_blob/5, copy_blob/6]). --export([delete_blob/3, delete_blob/4, delete_blob/5]). --export([put_block/5, put_block/6, put_block/7]). --export([put_block_list/4, put_block_list/5, put_block_list/6]). --export([get_block_list/3, get_block_list/4, get_block_list/5]). --export([acquire_blob_lease/4, acquire_blob_lease/5, acquire_blob_lease/7]). +-export([list_containers/1, list_containers/2]). +-export([create_container/2, create_container/3]). +-export([delete_container/2, delete_container/3]). +-export([lease_container/3, lease_container/4]). +-export([list_blobs/2, list_blobs/3]). +-export([put_block_blob/4, put_block_blob/5]). +-export([put_append_blob/3, put_append_blob/4]). +-export([append_block/4, append_block/5]). +-export([put_page_blob/4, put_page_blob/5]). +-export([get_blob/3, get_blob/4]). +-export([snapshot_blob/3, snapshot_blob/4]). +-export([copy_blob/4, copy_blob/5]). +-export([delete_blob/3, delete_blob/4]). +-export([put_block/5, put_block/6]). +-export([put_block_list/4, put_block_list/5]). +-export([get_block_list/3, get_block_list/4]). +-export([acquire_blob_lease/4, acquire_blob_lease/5, acquire_blob_lease/6]). %% Table API --export([list_tables/1, list_tables/3, new_table/2, delete_table/2]). +-export([list_tables/1, list_tables/2, new_table/2, delete_table/2]). %% Host API --export([get_host/3, get_host/4]). - -%% gen_server callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-export([get_host/3]). -type init_opts() :: #{ account := string(), @@ -93,267 +87,17 @@ }. -record(state, { account = "", key = "", options = #{}, param_specs = [] }). +-type state() :: #state{}. + +-export_types([state/0]). %%==================================================================== %% API %%==================================================================== --spec start(init_opts()) -> gen_server:start_ret(). -start(InitOpts0) -> +-spec new(init_opts()) -> {ok, state()}. +new(InitOpts0) -> InitOpts = ensure_wrapped_key(InitOpts0), - gen_server:start_link(?MODULE, InitOpts, []). - --spec start(string(), string()) -> {ok, pid()}. -start(Account, Key) -> - start(#{account => Account, key => Key}). - -%%==================================================================== -%% Queue -%%==================================================================== - --spec list_queues(pid()) -> enum_parse_result(queue()). -list_queues(Pid) -> - list_queues(Pid, []). - --spec list_queues(pid(), common_opts()) -> enum_parse_result(queue()). -list_queues(Pid, Options) -> - list_queues(Pid, Options, ?gen_server_call_default_timeout). - --spec list_queues(pid(), common_opts(), pos_integer()) -> enum_parse_result(queue()). -list_queues(Pid, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {list_queues, Options}, Timeout). - --type queue_acl_opts() :: req_param_timeout() | req_param_clientrequestid(). --spec set_queue_acl(pid(), string(), signed_id()) -> {ok, created}. -set_queue_acl(Pid, Queue, SignedId=#signed_id{}) -> - set_queue_acl(Pid, Queue, SignedId, []). - --spec set_queue_acl(pid(), string(), signed_id(), list(queue_acl_opts())) -> {ok, created}. -set_queue_acl(Pid, Queue, SignedId=#signed_id{}, Options) -> - set_queue_acl(Pid, Queue, SignedId, Options, ?gen_server_call_default_timeout). - --spec set_queue_acl(pid(), string(), signed_id(), list(queue_acl_opts()), pos_integer()) -> {ok, created}. -set_queue_acl(Pid, Queue, SignedId=#signed_id{}, Options, Timeout) when is_list(Options); is_integer(Timeout)-> - gen_server:call(Pid, {set_queue_acl, Queue, SignedId, Options}, Timeout). - --spec get_queue_acl(pid(), string()) -> {ok, no_acl} | {ok, signed_id()}. -get_queue_acl(Pid, Queue) -> - get_queue_acl(Pid, Queue, []). - --spec get_queue_acl(pid(), string(), list(queue_acl_opts())) -> {ok, no_acl} | {ok, signed_id()}. -get_queue_acl(Pid, Queue, Options) -> - get_queue_acl(Pid, Queue, Options, ?gen_server_call_default_timeout). - --spec get_queue_acl(pid(), string(), list(queue_acl_opts()), pos_integer()) -> {ok, no_acl} | {ok, signed_id()}. -get_queue_acl(Pid, Queue, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {get_queue_acl, Queue, Options}, Timeout). - --spec create_queue(pid(), string()) -> created_response() | already_created_response(). -create_queue(Pid, Queue) -> - create_queue(Pid, Queue, []). -create_queue(Pid, Queue, Options) -> - create_queue(Pid, Queue, Options, ?gen_server_call_default_timeout). -create_queue(Pid, Queue, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {create_queue, Queue, Options}, Timeout). - -delete_queue(Pid, Queue) -> - delete_queue(Pid, Queue, []). -delete_queue(Pid, Queue, Options) -> - delete_queue(Pid, Queue, Options, ?gen_server_call_default_timeout). -delete_queue(Pid, Queue, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {delete_queue, Queue, Options}, Timeout). - -put_message(Pid, Queue, Message) -> - put_message(Pid, Queue, Message, []). -put_message(Pid, Queue, Message, Options) -> - put_message(Pid, Queue, Message, Options, ?gen_server_call_default_timeout). -put_message(Pid, Queue, Message, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {put_message, Queue, Message, Options}, Timeout). - -get_messages(Pid, Queue) -> - get_messages(Pid, Queue, []). -get_messages(Pid, Queue, Options) -> - get_messages(Pid, Queue, Options, ?gen_server_call_default_timeout). -get_messages(Pid, Queue, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {get_messages, Queue, Options}, Timeout). - -peek_messages(Pid, Queue) -> - peek_messages(Pid, Queue, []). -peek_messages(Pid, Queue, Options) -> - peek_messages(Pid, Queue, Options, ?gen_server_call_default_timeout). -peek_messages(Pid, Queue, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {peek_messages, Queue, Options}, Timeout). - -delete_message(Pid, Queue, MessageId, PopReceipt) -> - delete_message(Pid, Queue, MessageId, PopReceipt, []). -delete_message(Pid, Queue, MessageId, PopReceipt, Options) -> - delete_message(Pid, Queue, MessageId, PopReceipt, Options, ?gen_server_call_default_timeout). -delete_message(Pid, Queue, MessageId, PopReceipt, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {delete_message, Queue, MessageId, PopReceipt, Options}, Timeout). - -clear_messages(Pid, Queue) -> - clear_messages(Pid, Queue, []). -clear_messages(Pid, Queue, Options) -> - clear_messages(Pid, Queue, Options, ?gen_server_call_default_timeout). -clear_messages(Pid, Queue, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {clear_messages, Queue, Options}, Timeout). - -update_message(Pid, Queue, UpdatedMessage=#queue_message{}, VisibilityTimeout) -> - update_message(Pid, Queue, UpdatedMessage, VisibilityTimeout, []). -update_message(Pid, Queue, UpdatedMessage=#queue_message{}, VisibilityTimeout, Options) -> - update_message(Pid, Queue, UpdatedMessage, VisibilityTimeout, Options, ?gen_server_call_default_timeout). -update_message(Pid, Queue, UpdatedMessage=#queue_message{}, VisibilityTimeout, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {update_message, Queue, UpdatedMessage, VisibilityTimeout, Options}, Timeout). - -%%==================================================================== -%% Blob -%%==================================================================== - -list_containers(Pid) -> - list_containers(Pid, []). -list_containers(Pid, Options) -> - list_containers(Pid, Options, ?gen_server_call_default_timeout). -list_containers(Pid, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {list_containers, Options}, Timeout). - -create_container(Pid, Name) -> - create_container(Pid, Name, []). -create_container(Pid, Name, Options) -> - create_container(Pid, Name, Options, ?gen_server_call_default_timeout). -create_container(Pid, Name, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {create_container, Name, Options}, Timeout). - -delete_container(Pid, Name) -> - delete_container(Pid, Name, []). -delete_container(Pid, Name, Options) -> - delete_container(Pid, Name, Options, ?gen_server_call_default_timeout). -delete_container(Pid, Name, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {delete_container, Name, Options}, Timeout). - -put_block_blob(Pid, Container, Name, Data) -> - put_block_blob(Pid, Container, Name, Data, []). -put_block_blob(Pid, Container, Name, Data, Options) -> - put_block_blob(Pid, Container, Name, Data, Options, ?gen_server_call_default_timeout). -put_block_blob(Pid, Container, Name, Data, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {put_blob, Container, Name, block_blob, Data, Options}, Timeout). - -put_page_blob(Pid, Container, Name, ContentLength) -> - put_page_blob(Pid, Container, Name, ContentLength, []). -put_page_blob(Pid, Container, Name, ContentLength, Options) -> - put_page_blob(Pid, Container, Name, ContentLength, Options, ?gen_server_call_default_timeout). -put_page_blob(Pid, Container, Name, ContentLength, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {put_blob, Container, Name, page_blob, ContentLength, Options}, Timeout). - -put_append_blob(Pid, Container, Name) -> - put_append_blob(Pid, Container, Name, []). -put_append_blob(Pid, Container, Name, Options) -> - put_append_blob(Pid, Container, Name, Options, ?gen_server_call_default_timeout). -put_append_blob(Pid, Container, Name, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {put_blob, Container, Name, append_blob, Options}, Timeout). - -append_block(Pid, Container, Name, Data) -> - append_block(Pid, Container, Name, Data, []). -append_block(Pid, Container, Name, Data, Options) -> - append_block(Pid, Container, Name, Data, Options, ?gen_server_call_default_timeout). -append_block(Pid, Container, Name, Data, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {append_block, Container, Name, Data, Options}, Timeout). - -list_blobs(Pid, Container) -> - list_blobs(Pid, Container, []). -list_blobs(Pid, Container, Options) -> - list_blobs(Pid, Container, Options, ?gen_server_call_default_timeout). -list_blobs(Pid, Container, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {list_blobs, Container, Options}, Timeout). - -get_blob(Pid, Container, Blob) -> - get_blob(Pid, Container, Blob, []). -get_blob(Pid, Container, Blob, Options) -> - get_blob(Pid, Container, Blob, Options, ?gen_server_call_default_timeout). -get_blob(Pid, Container, Blob, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {get_blob, Container, Blob, Options}, Timeout). - -snapshot_blob(Pid, Container, Blob) -> - snapshot_blob(Pid, Container, Blob, []). -snapshot_blob(Pid, Container, Blob, Options) -> - snapshot_blob(Pid, Container, Blob, Options, ?gen_server_call_default_timeout). -snapshot_blob(Pid, Container, Blob, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {snapshot_blob, Container, Blob, Options}, Timeout). - -copy_blob(Pid, Container, Blob, Source) -> - copy_blob(Pid, Container, Blob, Source, []). -copy_blob(Pid, Container, Blob, Source, Options) -> - copy_blob(Pid, Container, Blob, Source, Options, ?gen_server_call_default_timeout). -copy_blob(Pid, Container, Blob, Source, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {copy_blob, Container, Blob, Source, Options}, Timeout). - -delete_blob(Pid, Container, Blob) -> - delete_blob(Pid, Container, Blob, []). -delete_blob(Pid, Container, Blob, Options) -> - delete_blob(Pid, Container, Blob, Options, ?gen_server_call_default_timeout). -delete_blob(Pid, Container, Blob, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {delete_blob, Container, Blob, Options}, Timeout). - -put_block(Pid, Container, Blob, BlockId, BlockContent) -> - put_block(Pid, Container, Blob, BlockId, BlockContent, []). -put_block(Pid, Container, Blob, BlockId, BlockContent, Options) -> - put_block(Pid, Container, Blob, BlockId, BlockContent, Options, ?gen_server_call_default_timeout). -put_block(Pid, Container, Blob, BlockId, BlockContent, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {put_block, Container, Blob, BlockId, BlockContent, Options}, Timeout). - -put_block_list(Pid, Container, Blob, BlockRefs) -> - put_block_list(Pid, Container, Blob, BlockRefs, []). -put_block_list(Pid, Container, Blob, BlockRefs, Options) -> - put_block_list(Pid, Container, Blob, BlockRefs, Options, ?gen_server_call_default_timeout). -put_block_list(Pid, Container, Blob, BlockRefs, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {put_block_list, Container, Blob, BlockRefs, Options}, Timeout). - -get_block_list(Pid, Container, Blob) -> - get_block_list(Pid, Container, Blob, []). -get_block_list(Pid, Container, Blob, Options) -> - get_block_list(Pid, Container, Blob, Options, ?gen_server_call_default_timeout). -get_block_list(Pid, Container, Blob, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {get_block_list, Container, Blob, Options}, Timeout). - -acquire_blob_lease(Pid, Container, Blob, Duration) -> - acquire_blob_lease(Pid, Container, Blob, Duration, []). -acquire_blob_lease(Pid, Container, Blob, Duration, Options) -> - acquire_blob_lease(Pid, Container, Blob, "", Duration, Options, ?gen_server_call_default_timeout). -acquire_blob_lease(Pid, Container, Blob, ProposedId, Duration, Options, Timeout) when is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {acquire_blob_lease, Container, Blob, ProposedId, Duration, Options}, Timeout). - -lease_container(Pid, Name, Mode) -> - lease_container(Pid, Name, Mode, []). -lease_container(Pid, Name, Mode, Options) -> - lease_container(Pid, Name, Mode, Options, ?gen_server_call_default_timeout). -lease_container(Pid, Name, Mode, Options, Timeout) when is_atom(Mode); is_list(Options); is_integer(Timeout) -> - gen_server:call(Pid, {lease_container, Name, Mode, Options}, Timeout). - -%%==================================================================== -%% Table -%%==================================================================== - -list_tables(Pid) -> - list_tables(Pid, [], ?gen_server_call_default_timeout). -list_tables(Pid, Options, Timeout) when is_list(Options); is_integer(Timeout)-> - gen_server:call(Pid, {list_tables, Options}, Timeout). - -new_table(Pid, TableName) when is_list(TableName) -> - new_table(Pid, list_to_binary(TableName)); - -new_table(Pid, TableName) when is_binary(TableName) -> - gen_server:call(Pid, {new_table, TableName}). - -delete_table(Pid, TableName) when is_binary(TableName) -> - delete_table(Pid, binary_to_list(TableName)); - -delete_table(Pid, TableName) when is_list(TableName) -> - gen_server:call(Pid, {delete_table, TableName}). - -%%==================================================================== -%% gen_server callbacks -%%==================================================================== - -init(InitOpts) -> #{ account := Account , key := Key } = InitOpts, @@ -363,18 +107,34 @@ init(InitOpts) -> options = StateOpts, param_specs = get_req_param_specs() }}. -% List queues -handle_call({list_queues, Options}, _From, State) -> +-spec new(string(), string()) -> {ok, state()}. +new(Account, Key) -> + new(#{account => Account, key => Key}). + +%%==================================================================== +%% Queue +%%==================================================================== + +-spec list_queues(state()) -> enum_parse_result(queue()). +list_queues(State) -> + list_queues(State, []). + +-spec list_queues(state(), common_opts()) -> enum_parse_result(queue()). +list_queues(State, Options) when is_list(Options) -> ServiceContext = new_service_context(?queue_service, State), ReqOptions = [{params, [{comp, list}] ++ Options}], ReqContext = new_req_context(?queue_service, ReqOptions, State), {?http_ok, Body} = execute_request(ServiceContext, ReqContext), - ParseResult = erlazure_queue:parse_queue_list(Body), - {reply, ParseResult, State}; + erlazure_queue:parse_queue_list(Body). + +-type queue_acl_opts() :: req_param_timeout() | req_param_clientrequestid(). +-spec set_queue_acl(state(), string(), signed_id()) -> {ok, created}. +set_queue_acl(State, Queue, SignedId=#signed_id{}) -> + set_queue_acl(State, Queue, SignedId, []). -% Set queue acl -handle_call({set_queue_acl, Queue, SignedId=#signed_id{}, Options}, _From, State) -> +-spec set_queue_acl(state(), string(), signed_id(), list(queue_acl_opts())) -> {ok, created}. +set_queue_acl(State, Queue, SignedId=#signed_id{}, Options) when is_list(Options)-> ServiceContext = new_service_context(?queue_service, State), ReqOptions = [{method, put}, {path, string:to_lower(Queue)}, @@ -383,21 +143,26 @@ handle_call({set_queue_acl, Queue, SignedId=#signed_id{}, Options}, _From, State ReqContext = new_req_context(?queue_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_no_content, created); + return_response(Code, Body, ?http_no_content, created). -% Get queue acl -handle_call({get_queue_acl, Queue, Options}, _From, State) -> +-spec get_queue_acl(state(), string()) -> {ok, no_acl} | {ok, signed_id()}. +get_queue_acl(State, Queue) -> + get_queue_acl(State, Queue, []). + +-spec get_queue_acl(state(), string(), list(queue_acl_opts())) -> {ok, no_acl} | {ok, signed_id()}. +get_queue_acl(State, Queue, Options) when is_list(Options) -> ServiceContext = new_service_context(?queue_service, State), ReqOptions = [{path, string:to_lower(Queue)}, {params, [{comp, acl}] ++ Options}], ReqContext = new_req_context(?queue_service, ReqOptions, State), {?http_ok, Body} = execute_request(ServiceContext, ReqContext), - ParseResult = erlazure_queue:parse_queue_acl_response(Body), - {reply, ParseResult, State}; + erlazure_queue:parse_queue_acl_response(Body). -% Create queue -handle_call({create_queue, Queue, Options}, _From, State) -> +-spec create_queue(state(), string()) -> created_response() | already_created_response(). +create_queue(State, Queue) -> + create_queue(State, Queue, []). +create_queue(State, Queue, Options) when is_list(Options) -> ServiceContext = new_service_context(?queue_service, State), ReqOptions = [{method, put}, {path, string:to_lower(Queue)}, @@ -407,13 +172,14 @@ handle_call({create_queue, Queue, Options}, _From, State) -> {Code, _Body} = execute_request(ServiceContext, ReqContext), case Code of ?http_created -> - {reply, {ok, created}, State}; + {ok, created}; ?http_no_content -> - {reply, {error, already_created}, State} - end; + {error, already_created} + end. -% Delete queue -handle_call({delete_queue, Queue, Options}, _From, State) -> +delete_queue(State, Queue) -> + delete_queue(State, Queue, []). +delete_queue(State, Queue, Options) when is_list(Options) -> ServiceContext = new_service_context(?queue_service, State), ReqOptions = [{method, delete}, {path, string:to_lower(Queue)}, @@ -421,10 +187,11 @@ handle_call({delete_queue, Queue, Options}, _From, State) -> ReqContext = new_req_context(?queue_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_no_content, deleted); + return_response(Code, Body, ?http_no_content, deleted). -% Add message to a queue -handle_call({put_message, Queue, Message, Options}, _From, State) -> +put_message(State, Queue, Message) -> + put_message(State, Queue, Message, []). +put_message(State, Queue, Message, Options) when is_list(Options) -> ServiceContext = new_service_context(?queue_service, State), ReqOptions = [{method, post}, {path, lists:concat([string:to_lower(Queue), "/messages"])}, @@ -433,30 +200,33 @@ handle_call({put_message, Queue, Message, Options}, _From, State) -> ReqContext = new_req_context(?queue_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_created, created); + return_response(Code, Body, ?http_created, created). -% Get messages from the queue -handle_call({get_messages, Queue, Options}, _From, State) -> +get_messages(State, Queue) -> + get_messages(State, Queue, []). +get_messages(State, Queue, Options) when is_list(Options) -> ServiceContext = new_service_context(?queue_service, State), ReqOptions = [{path, string:to_lower(Queue) ++ "/messages"}, {params, Options}], ReqContext = new_req_context(?queue_service, ReqOptions, State), {?http_ok, Body} = execute_request(ServiceContext, ReqContext), - {reply, erlazure_queue:parse_queue_messages_list(Body), State}; + erlazure_queue:parse_queue_messages_list(Body). -% Peek messages from the queue -handle_call({peek_messages, Queue, Options}, _From, State) -> +peek_messages(State, Queue) -> + peek_messages(State, Queue, []). +peek_messages(State, Queue, Options) when is_list(Options) -> ServiceContext = new_service_context(?queue_service, State), ReqOptions = [{path, string:to_lower(Queue) ++ "/messages"}, {params, [{peek_only, true}] ++ Options}], ReqContext = new_req_context(?queue_service, ReqOptions, State), {?http_ok, Body} = execute_request(ServiceContext, ReqContext), - {reply, erlazure_queue:parse_queue_messages_list(Body), State}; + erlazure_queue:parse_queue_messages_list(Body). -% Delete message from the queue -handle_call({delete_message, Queue, MessageId, PopReceipt, Options}, _From, State) -> +delete_message(State, Queue, MessageId, PopReceipt) -> + delete_message(State, Queue, MessageId, PopReceipt, []). +delete_message(State, Queue, MessageId, PopReceipt, Options) when is_list(Options) -> ServiceContext = new_service_context(?queue_service, State), ReqOptions = [{method, delete}, {path, lists:concat([string:to_lower(Queue), "/messages/", MessageId])}, @@ -464,10 +234,11 @@ handle_call({delete_message, Queue, MessageId, PopReceipt, Options}, _From, Stat ReqContext = new_req_context(?queue_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_no_content, deleted); + return_response(Code, Body, ?http_no_content, deleted). -% Delete all messages from the queue -handle_call({clear_messages, Queue, Options}, _From, State) -> +clear_messages(State, Queue) -> + clear_messages(State, Queue, []). +clear_messages(State, Queue, Options) when is_list(Options) -> ServiceContext = new_service_context(?queue_service, State), ReqOptions = [{method, delete}, {path, string:to_lower(Queue) ++ "/messages"}, @@ -475,10 +246,11 @@ handle_call({clear_messages, Queue, Options}, _From, State) -> ReqContext = new_req_context(?queue_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_no_content, deleted); + return_response(Code, Body, ?http_no_content, deleted). -% Update a message in the queue -handle_call({update_message, Queue, UpdatedMessage=#queue_message{}, VisibilityTimeout, Options}, _From, State) -> +update_message(State, Queue, UpdatedMessage=#queue_message{}, VisibilityTimeout) -> + update_message(State, Queue, UpdatedMessage, VisibilityTimeout, []). +update_message(State, Queue, UpdatedMessage=#queue_message{}, VisibilityTimeout, Options) when is_list(Options) -> ServiceContext = new_service_context(?queue_service, State), Params = [{pop_receipt, UpdatedMessage#queue_message.pop_receipt}, {message_visibility_timeout, integer_to_list(VisibilityTimeout)}], @@ -489,10 +261,15 @@ handle_call({update_message, Queue, UpdatedMessage=#queue_message{}, VisibilityT ReqContext = new_req_context(?queue_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_no_content, updated); + return_response(Code, Body, ?http_no_content, updated). + +%%==================================================================== +%% Blob +%%==================================================================== -% List containers -handle_call({list_containers, Options}, _From, State) -> +list_containers(State) -> + list_containers(State, []). +list_containers(State, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), ReqOptions = [{params, [{comp, list}] ++ Options}], ReqContext = new_req_context(?blob_service, ReqOptions, State), @@ -500,13 +277,14 @@ handle_call({list_containers, Options}, _From, State) -> case execute_request(ServiceContext, ReqContext) of {?http_ok, Body} -> {ok, Containers} = erlazure_blob:parse_container_list(Body), - {reply, Containers, State}; + Containers; {error, _} = Error -> - {reply, Error, State} - end; + Error + end. -% Create a container -handle_call({create_container, Name, Options}, _From, State) -> +create_container(State, Name) -> + create_container(State, Name, []). +create_container(State, Name, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), ReqOptions = [{method, put}, {path, Name}, @@ -514,12 +292,13 @@ handle_call({create_container, Name, Options}, _From, State) -> ReqContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), case Code of - ?http_created -> {reply, {ok, created}, State}; - _ -> {reply, {error, Body}, State} - end; + ?http_created -> {ok, created}; + _ -> {error, Body} + end. -% Delete container -handle_call({delete_container, Name, Options}, _From, State) -> +delete_container(State, Name) -> + delete_container(State, Name, []). +delete_container(State, Name, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), ReqOptions = [{method, delete}, {path, Name}, @@ -527,42 +306,16 @@ handle_call({delete_container, Name, Options}, _From, State) -> RequestContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, RequestContext), - return_response(Code, Body, State, ?http_accepted, deleted); + return_response(Code, Body, ?http_accepted, deleted). -% Lease a container -handle_call({lease_container, Name, Mode, Options}, _From, State) -> - ServiceContext = new_service_context(?blob_service, State), - Params = [{comp, lease}, - {res_type, container}, - {lease_action, Mode}], - ReqOptions = [{method, put}, - {path, Name}, - {params, Params ++ Options}], - ReqContext = new_req_context(?blob_service, ReqOptions, State), - - {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_accepted, deleted); - -% List blobs -handle_call({list_blobs, Name, Options}, _From, State) -> - ServiceContext = new_service_context(?blob_service, State), - Params = [{comp, list}, - {res_type, container}], - ReqOptions = [{path, Name}, - {params, Params ++ Options}], - ReqContext = new_req_context(?blob_service, ReqOptions, State), - - {?http_ok, Body} = execute_request(ServiceContext, ReqContext), - {ok, Blobs} = erlazure_blob:parse_blob_list(Body), - {reply, Blobs, State}; - -% Put block blob -handle_call({put_blob, Container, Name, Type = block_blob, Data, Options}, _From, State) -> +put_block_blob(State, Container, Name, Data) -> + put_block_blob(State, Container, Name, Data, []). +put_block_blob(State, Container, Name, Data, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), ReqOptions = [{method, put}, {path, lists:concat([Container, "/", Name])}, {body, Data}, - {params, [{blob_type, Type}] ++ Options}], + {params, [{blob_type, block_blob}] ++ Options}], ReqContext = new_req_context(?blob_service, ReqOptions, State), ReqContext1 = case proplists:get_value(content_type, Options) of undefined -> ReqContext#req_context{ content_type = "application/octet-stream" }; @@ -570,12 +323,13 @@ handle_call({put_blob, Container, Name, Type = block_blob, Data, Options}, _From end, {Code, Body} = execute_request(ServiceContext, ReqContext1), - return_response(Code, Body, State, ?http_created, created); + return_response(Code, Body, ?http_created, created). -% Put page blob -handle_call({put_blob, Container, Name, Type = page_blob, ContentLength, Options}, _From, State) -> +put_page_blob(State, Container, Name, ContentLength) -> + put_page_blob(State, Container, Name, ContentLength, []). +put_page_blob(State, Container, Name, ContentLength, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), - Params = [{blob_type, Type}, + Params = [{blob_type, page_blob}, {blob_content_length, ContentLength}], ReqOptions = [{method, put}, {path, lists:concat([Container, "/", Name])}, @@ -583,12 +337,13 @@ handle_call({put_blob, Container, Name, Type = page_blob, ContentLength, Options ReqContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_created, created); + return_response(Code, Body, ?http_created, created). -% Put append blob -handle_call({put_blob, Container, Name, Type = append_blob, Options}, _From, State) -> +put_append_blob(State, Container, Name) -> + put_append_blob(State, Container, Name, []). +put_append_blob(State, Container, Name, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), - Params = [{blob_type, Type}], + Params = [{blob_type, append_blob}], ReqOptions = [{method, put}, {path, lists:concat([Container, "/", Name])}, {params, Params ++ Options}], @@ -599,10 +354,11 @@ handle_call({put_blob, Container, Name, Type = append_blob, Options}, _From, Sta end, {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_created, created); + return_response(Code, Body, ?http_created, created). -% Append block -handle_call({append_block, Container, Name, Data, Options}, _From, State) -> +append_block(State, Container, Name, Data) -> + append_block(State, Container, Name, Data, []). +append_block(State, Container, Name, Data, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), Params = [{comp, "appendblock"}], ReqOptions = [{method, put}, @@ -612,10 +368,25 @@ handle_call({append_block, Container, Name, Data, Options}, _From, State) -> ReqContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_created, appended); + return_response(Code, Body, ?http_created, appended). + +list_blobs(State, Container) -> + list_blobs(State, Container, []). +list_blobs(State, Container, Options) when is_list(Options) -> + ServiceContext = new_service_context(?blob_service, State), + Params = [{comp, list}, + {res_type, container}], + ReqOptions = [{path, Container}, + {params, Params ++ Options}], + ReqContext = new_req_context(?blob_service, ReqOptions, State), + + {?http_ok, Body} = execute_request(ServiceContext, ReqContext), + {ok, Blobs} = erlazure_blob:parse_blob_list(Body), + Blobs. -% Get blob -handle_call({get_blob, Container, Blob, Options}, _From, State) -> +get_blob(State, Container, Blob) -> + get_blob(State, Container, Blob, []). +get_blob(State, Container, Blob, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), ReqOptions = [{path, lists:concat([Container, "/", Blob])}, {params, Options}], @@ -624,14 +395,15 @@ handle_call({get_blob, Container, Blob, Options}, _From, State) -> {Code, Body} = execute_request(ServiceContext, ReqContext), case Code of ?http_ok -> - {reply, {ok, Body}, State}; + {ok, Body}; ?http_partial_content-> - {reply, {ok, Body}, State}; - _ -> {reply, {error, Body}, State} - end; + {ok, Body}; + _ -> {error, Body} + end. -% Snapshot blob -handle_call({snapshot_blob, Container, Blob, Options}, _From, State) -> +snapshot_blob(State, Container, Blob) -> + snapshot_blob(State, Container, Blob, []). +snapshot_blob(State, Container, Blob, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), ReqOptions = [{method, put}, {path, lists:concat([Container, "/", Blob])}, @@ -639,10 +411,11 @@ handle_call({snapshot_blob, Container, Blob, Options}, _From, State) -> ReqContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_created, created); + return_response(Code, Body, ?http_created, created). -% Copy blob -handle_call({copy_blob, Container, Blob, Source, Options}, _From, State) -> +copy_blob(State, Container, Blob, Source) -> + copy_blob(State, Container, Blob, Source, []). +copy_blob(State, Container, Blob, Source, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), ReqOptions = [{method, put}, {path, lists:concat([Container, "/", Blob])}, @@ -650,10 +423,11 @@ handle_call({copy_blob, Container, Blob, Source, Options}, _From, State) -> ReqContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_accepted, created); + return_response(Code, Body, ?http_accepted, created). -% Delete blob -handle_call({delete_blob, Container, Blob, Options}, _From, State) -> +delete_blob(State, Container, Blob) -> + delete_blob(State, Container, Blob, []). +delete_blob(State, Container, Blob, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), ReqOptions = [{method, delete}, {path, lists:concat([Container, "/", Blob])}, @@ -661,24 +435,26 @@ handle_call({delete_blob, Container, Blob, Options}, _From, State) -> ReqContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_accepted, deleted); + return_response(Code, Body, ?http_accepted, deleted). -% Put block -handle_call({put_block, Container, Blob, BlockId, Content, Options}, _From, State) -> +put_block(State, Container, Blob, BlockId, BlockContent) -> + put_block(State, Container, Blob, BlockId, BlockContent, []). +put_block(State, Container, Blob, BlockId, BlockContent, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), Params = [{comp, block}, {blob_block_id, uri_string:quote(base64:encode_to_string(BlockId))}], ReqOptions = [{method, put}, {path, lists:concat([Container, "/", Blob])}, - {body, Content}, + {body, BlockContent}, {params, Params ++ Options}], ReqContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_created, created); + return_response(Code, Body, ?http_created, created). -% Put block list -handle_call({put_block_list, Container, Blob, BlockRefs, Options0}, _From, State) -> +put_block_list(State, Container, Blob, BlockRefs) -> + put_block_list(State, Container, Blob, BlockRefs, []). +put_block_list(State, Container, Blob, BlockRefs, Options0) when is_list(Options0) -> ServiceContext = new_service_context(?blob_service, State), {ExtraReqOpts, Options} = proplist_take(req_opts, Options0, []), ReqOptions = [{method, put}, @@ -688,10 +464,11 @@ handle_call({put_block_list, Container, Blob, BlockRefs, Options0}, _From, State ReqContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_created, created); + return_response(Code, Body, ?http_created, created). -% Get block list -handle_call({get_block_list, Container, Blob, Options}, _From, State) -> +get_block_list(State, Container, Blob) -> + get_block_list(State, Container, Blob, []). +get_block_list(State, Container, Blob, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), ReqOptions = [{path, lists:concat([Container, "/", Blob])}, {params, [{comp, "blocklist"}] ++ Options}], @@ -699,10 +476,13 @@ handle_call({get_block_list, Container, Blob, Options}, _From, State) -> {?http_ok, Body} = execute_request(ServiceContext, ReqContext), {ok, BlockList} = erlazure_blob:parse_block_list(Body), - {reply, BlockList, State}; + BlockList. -% Acquire blob lease -handle_call({acquire_blob_lease, Container, Blob, ProposedId, Duration, Options}, _From, State) -> +acquire_blob_lease(State, Container, Blob, Duration) -> + acquire_blob_lease(State, Container, Blob, Duration, []). +acquire_blob_lease(State, Container, Blob, Duration, Options) -> + acquire_blob_lease(State, Container, Blob, "", Duration, Options). +acquire_blob_lease(State, Container, Blob, ProposedId, Duration, Options) when is_list(Options) -> ServiceContext = new_service_context(?blob_service, State), Params = [{lease_action, acquire}, @@ -716,20 +496,42 @@ handle_call({acquire_blob_lease, Container, Blob, ProposedId, Duration, Options} ReqContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), - return_response(Code, Body, State, ?http_created, acquired); + return_response(Code, Body, ?http_created, acquired). -% List tables -handle_call({list_tables, Options}, _From, State) -> +lease_container(State, Name, Mode) -> + lease_container(State, Name, Mode, []). +lease_container(State, Name, Mode, Options) when is_atom(Mode), is_list(Options) -> + ServiceContext = new_service_context(?blob_service, State), + Params = [{comp, lease}, + {res_type, container}, + {lease_action, Mode}], + ReqOptions = [{method, put}, + {path, Name}, + {params, Params ++ Options}], + ReqContext = new_req_context(?blob_service, ReqOptions, State), + + {Code, Body} = execute_request(ServiceContext, ReqContext), + return_response(Code, Body, ?http_accepted, deleted). + +%%==================================================================== +%% Table +%%==================================================================== + +list_tables(State) -> + list_tables(State, []). +list_tables(State, Options) when is_list(Options) -> ServiceContext = new_service_context(?table_service, State), ReqOptions = [{path, "Tables"}, {params, Options}], ReqContext = new_req_context(?table_service, ReqOptions, State), {?http_ok, Body} = execute_request(ServiceContext, ReqContext), - {reply, {ok, erlazure_table:parse_table_list(Body)}, State}; + {ok, erlazure_table:parse_table_list(Body)}. -% New tables -handle_call({new_table, TableName}, _From, State) -> +new_table(State, TableName) when is_list(TableName) -> + new_table(State, list_to_binary(TableName)); + +new_table(State, TableName) when is_binary(TableName) -> ServiceContext = new_service_context(?table_service, State), ReqOptions = [{path, "Tables"}, {method, post}, @@ -737,40 +539,24 @@ handle_call({new_table, TableName}, _From, State) -> ReqContext = new_req_context(?table_service, ReqOptions, State), ReqContext1 = ReqContext#req_context{ content_type = ?json_content_type }, {Code, Body} = execute_request(ServiceContext, ReqContext1), - return_response(Code, Body, State, ?http_created, created); + return_response(Code, Body, ?http_created, created). -% Get host -handle_call({get_host, Service, Domain}, _From, State) -> - Account = State#state.account, - Host = lists:concat([Account, ".", erlang:atom_to_list(Service), Domain]), - {reply, Host, State}; +delete_table(State, TableName) when is_binary(TableName) -> + delete_table(State, binary_to_list(TableName)); -% Delete table -handle_call({delete_table, TableName}, _From, State) -> +delete_table(State, TableName) when is_list(TableName) -> ServiceContext = new_service_context(?table_service, State), ReqOptions = [{path, io:format("Tables('~s')", [TableName])}, {method, delete}], ReqContext = new_req_context(?table_service, ReqOptions, State), {?http_no_content, _} = execute_request(ServiceContext, ReqContext), - {reply, {ok, deleted}, State}. - -handle_cast(_Msg, State) -> - {noreply, State}. - -handle_info(_Info, State) -> - {noreply, State}. - -terminate(_Reason, _State) -> - ok. - -code_change(_OldVer, State, _Extra) -> - {ok, State}. + {ok, deleted}. %%-------------------------------------------------------------------- %% Private functions %%-------------------------------------------------------------------- --spec execute_request(service_context(), req_context()) -> {non_neg_integer(), binary()}. +-spec execute_request(service_context(), req_context()) -> {non_neg_integer(), binary()} | {error, any()}. execute_request(ServiceContext = #service_context{}, ReqContext = #req_context{}) -> DateHeader = if (ServiceContext#service_context.service =:= ?table_service) -> {"Date", httpd_util:rfc1123_date()}; @@ -891,18 +677,19 @@ build_uri_base(Service, #state{account = Account}) -> get_host(Service, Account) -> lists:concat([Account, ".", erlang:atom_to_list(Service), ".core.windows.net"]). -get_host(Pid, Service, []) -> + +get_host(State, Service, []) -> Domain = ".core.windows.net", - Timeout = ?gen_server_call_default_timeout, - get_host(Pid, Service, Domain, Timeout); -get_host(Pid, Service, Timeout) when is_integer(Timeout) -> + do_get_host(State, Service, Domain); +get_host(State, Service, Timeout) when is_integer(Timeout) -> Domain = ".core.windows.net", - get_host(Pid, Service, Domain, Timeout); -get_host(Pid, Service, Domain) when is_list(Domain) -> - Timeout = ?gen_server_call_default_timeout, - get_host(Pid, Service, Domain, Timeout). -get_host(Pid, Service, Domain, Timeout) when is_list(Domain), is_integer(Timeout) -> - gen_server:call(Pid, {get_host, Service, Domain}, Timeout). + do_get_host(State, Service, Domain); +get_host(State, Service, Domain) when is_list(Domain) -> + do_get_host(State, Service, Domain). + +do_get_host(State, Service, Domain) when is_list(Domain), is_atom(Service) -> + Account = State#state.account, + lists:concat([Account, ".", atom_to_list(Service), Domain]). -spec canonicalize_headers([string()]) -> string(). canonicalize_headers(Headers) -> @@ -1052,12 +839,12 @@ get_req_common_param_specs() -> #param_spec{ id = ?req_param_include, type = uri, name = "include" }, #param_spec{ id = ?req_param_marker, type = uri, name = "marker" }]. -return_response(Code, Body, State, ExpectedResponseCode, SuccessAtom) -> +return_response(Code, Body, ExpectedResponseCode, SuccessAtom) -> case Code of ExpectedResponseCode -> - {reply, {ok, SuccessAtom}, State}; + {ok, SuccessAtom}; _ -> - {reply, {error, Body}, State} + {error, Body} end. -spec parse_init_opts(init_opts()) -> state_opts(). diff --git a/src/erlazure_blob.erl b/src/erlazure_blob.erl index 61008d7..681b41b 100644 --- a/src/erlazure_blob.erl +++ b/src/erlazure_blob.erl @@ -38,7 +38,7 @@ -export([parse_container_list/1, parse_blob_list/1, get_request_body/1, parse_block_list/1, get_request_param_specs/0, parse_blob_response/1]). --spec parse_container_list(string()) -> {error, bad_response} | {[blob_container()], list()}. +-spec parse_container_list(string() | binary()) -> {error, bad_response} | {ok, {[blob_container()], list()}}. parse_container_list(Response) -> ParserSpec = #enum_parser_spec { rootKey = 'Containers', elementKey = 'Container', diff --git a/test/erlazure_SUITE.erl b/test/erlazure_SUITE.erl index 604fba3..6f9018f 100644 --- a/test/erlazure_SUITE.erl +++ b/test/erlazure_SUITE.erl @@ -73,17 +73,17 @@ end_per_testcase(_TestCase, Config) -> %% Helper fns %%------------------------------------------------------------------------------ -start(Config) -> +new(Config) -> Endpoint = ?config(endpoint, Config), - {ok, Pid} = erlazure:start(#{account => ?ACCOUNT, key => ?KEY, endpoint => Endpoint}), - Pid. + {ok, State} = erlazure:new(#{account => ?ACCOUNT, key => ?KEY, endpoint => Endpoint}), + State. delete_all_containers(Config) -> - Pid = start(Config), - {Containers, _} = erlazure:list_containers(Pid), + State = new(Config), + {Containers, _} = erlazure:list_containers(State), lists:foreach( fun(#blob_container{name = Name}) -> - {ok, deleted} = erlazure:delete_container(Pid, Name) + {ok, deleted} = erlazure:delete_container(State, Name) end, Containers). @@ -98,118 +98,118 @@ container_name(Name) -> %% Basic smoke test for basic blob storage operations. t_blob_storage_smoke_test(Config) -> Endpoint = ?config(endpoint, Config), - {ok, Pid} = erlazure:start(#{account => ?ACCOUNT, key => ?KEY, endpoint => Endpoint}), + {ok, State} = erlazure:new(#{account => ?ACCOUNT, key => ?KEY, endpoint => Endpoint}), %% Create a container Container = container_name(?FUNCTION_NAME), - ?assertMatch({[], _}, erlazure:list_containers(Pid)), - ?assertMatch({ok, created}, erlazure:create_container(Pid, Container)), + ?assertMatch({[], _}, erlazure:list_containers(State)), + ?assertMatch({ok, created}, erlazure:create_container(State, Container)), %% Upload some blobs - ?assertMatch({ok, created}, erlazure:put_block_blob(Pid, Container, "blob1", <<"1">>)), - ?assertMatch({ok, created}, erlazure:put_block_blob(Pid, Container, "blob2", <<"2">>)), + ?assertMatch({ok, created}, erlazure:put_block_blob(State, Container, "blob1", <<"1">>)), + ?assertMatch({ok, created}, erlazure:put_block_blob(State, Container, "blob2", <<"2">>)), ?assertMatch({[#cloud_blob{name = "blob1"}, #cloud_blob{name = "blob2"}], _}, - erlazure:list_blobs(Pid, Container)), + erlazure:list_blobs(State, Container)), %% Read back data - ?assertMatch({ok, <<"1">>}, erlazure:get_blob(Pid, Container, "blob1")), - ?assertMatch({ok, <<"2">>}, erlazure:get_blob(Pid, Container, "blob2")), + ?assertMatch({ok, <<"1">>}, erlazure:get_blob(State, Container, "blob1")), + ?assertMatch({ok, <<"2">>}, erlazure:get_blob(State, Container, "blob2")), %% Delete blob - ?assertMatch({ok, deleted}, erlazure:delete_blob(Pid, Container, "blob1")), + ?assertMatch({ok, deleted}, erlazure:delete_blob(State, Container, "blob1")), ?assertMatch({[#cloud_blob{name = "blob2"}], _}, - erlazure:list_blobs(Pid, Container)), + erlazure:list_blobs(State, Container)), %% Delete container - ?assertMatch({ok, deleted}, erlazure:delete_container(Pid, Container)), + ?assertMatch({ok, deleted}, erlazure:delete_container(State, Container)), ok. %% Basic smoke test to check that we can pass already wrapped keys to `erlazure:start`. t_blob_storage_wrapped_key(Config) -> Endpoint = ?config(endpoint, Config), - {ok, Pid} = erlazure:start(#{account => ?ACCOUNT, key => ?KEY, endpoint => Endpoint}), - ?assertMatch({[], _}, erlazure:list_containers(Pid)), + {ok, State} = erlazure:new(#{account => ?ACCOUNT, key => ?KEY, endpoint => Endpoint}), + ?assertMatch({[], _}, erlazure:list_containers(State)), ok. %% Basic smoke test for append blob storage operations. t_append_blob_smoke_test(Config) -> Endpoint = ?config(endpoint, Config), - {ok, Pid} = erlazure:start(#{account => ?ACCOUNT, key => ?KEY, endpoint => Endpoint}), + {ok, State} = erlazure:new(#{account => ?ACCOUNT, key => ?KEY, endpoint => Endpoint}), %% Create a container Container = container_name(?FUNCTION_NAME), - ?assertMatch({[], _}, erlazure:list_containers(Pid)), - ?assertMatch({ok, created}, erlazure:create_container(Pid, Container)), + ?assertMatch({[], _}, erlazure:list_containers(State)), + ?assertMatch({ok, created}, erlazure:create_container(State, Container)), %% Upload some blobs Opts = [{content_type, "text/csv"}], - ?assertMatch({ok, created}, erlazure:put_append_blob(Pid, Container, "blob1", Opts)), - ?assertMatch({ok, appended}, erlazure:append_block(Pid, Container, "blob1", <<"1">>)), - ?assertMatch({ok, appended}, erlazure:append_block(Pid, Container, "blob1", <<"\n">>)), - ?assertMatch({ok, appended}, erlazure:append_block(Pid, Container, "blob1", <<"2">>)), - ListedBlobs = erlazure:list_blobs(Pid, Container), + ?assertMatch({ok, created}, erlazure:put_append_blob(State, Container, "blob1", Opts)), + ?assertMatch({ok, appended}, erlazure:append_block(State, Container, "blob1", <<"1">>)), + ?assertMatch({ok, appended}, erlazure:append_block(State, Container, "blob1", <<"\n">>)), + ?assertMatch({ok, appended}, erlazure:append_block(State, Container, "blob1", <<"2">>)), + ListedBlobs = erlazure:list_blobs(State, Container), ?assertMatch({[#cloud_blob{name = "blob1"}], _}, ListedBlobs), {[#cloud_blob{name = "blob1", properties = BlobProps}], _} = ListedBlobs, ?assertMatch(#{content_type := "text/csv"}, maps:from_list(BlobProps)), %% Read back data - ?assertMatch({ok, <<"1\n2">>}, erlazure:get_blob(Pid, Container, "blob1")), + ?assertMatch({ok, <<"1\n2">>}, erlazure:get_blob(State, Container, "blob1")), %% Delete blob - ?assertMatch({ok, deleted}, erlazure:delete_blob(Pid, Container, "blob1")), - ?assertMatch({[], _}, erlazure:list_blobs(Pid, Container)), + ?assertMatch({ok, deleted}, erlazure:delete_blob(State, Container, "blob1")), + ?assertMatch({[], _}, erlazure:list_blobs(State, Container)), %% Delete container - ?assertMatch({ok, deleted}, erlazure:delete_container(Pid, Container)), + ?assertMatch({ok, deleted}, erlazure:delete_container(State, Container)), ok. %% Test error handling when endpoint is unavailable t_blob_failure_to_connect(_Config) -> BadEndpoint = "http://127.0.0.2:65535/", - {ok, Pid} = erlazure:start(#{account => ?ACCOUNT, key => ?KEY, endpoint => BadEndpoint}), - ?assertMatch({error, {failed_connect, _}}, erlazure:list_containers(Pid)), - ?assertMatch({error, {failed_connect, _}}, erlazure:create_container(Pid, "c")), - ?assertMatch({error, {failed_connect, _}}, erlazure:delete_container(Pid, "c")), - ?assertMatch({error, {failed_connect, _}}, erlazure:put_append_blob(Pid, "c", "b1")), - ?assertMatch({error, {failed_connect, _}}, erlazure:put_block_blob(Pid, "c", "b1", <<"a">>)), - ?assertMatch({error, {failed_connect, _}}, erlazure:append_block(Pid, "c", "b1", <<"a">>)), - ?assertMatch({error, {failed_connect, _}}, erlazure:get_blob(Pid, "c", "b1")), + {ok, State} = erlazure:new(#{account => ?ACCOUNT, key => ?KEY, endpoint => BadEndpoint}), + ?assertMatch({error, {failed_connect, _}}, erlazure:list_containers(State)), + ?assertMatch({error, {failed_connect, _}}, erlazure:create_container(State, "c")), + ?assertMatch({error, {failed_connect, _}}, erlazure:delete_container(State, "c")), + ?assertMatch({error, {failed_connect, _}}, erlazure:put_append_blob(State, "c", "b1")), + ?assertMatch({error, {failed_connect, _}}, erlazure:put_block_blob(State, "c", "b1", <<"a">>)), + ?assertMatch({error, {failed_connect, _}}, erlazure:append_block(State, "c", "b1", <<"a">>)), + ?assertMatch({error, {failed_connect, _}}, erlazure:get_blob(State, "c", "b1")), ok. %% Basic smoke test for block blob storage operations. t_put_block(Config) -> Endpoint = ?config(endpoint, Config), - {ok, Pid} = erlazure:start(#{account => ?ACCOUNT, key => ?KEY, endpoint => Endpoint}), + {ok, State} = erlazure:new(#{account => ?ACCOUNT, key => ?KEY, endpoint => Endpoint}), %% Create a container Container = container_name(?FUNCTION_NAME), - ?assertMatch({[], _}, erlazure:list_containers(Pid)), - ?assertMatch({ok, created}, erlazure:create_container(Pid, Container)), + ?assertMatch({[], _}, erlazure:list_containers(State)), + ?assertMatch({ok, created}, erlazure:create_container(State, Container)), %% Upload some blocks. Note: this content-type will be overwritten later by `put_block_list'. Opts1 = [{content_type, "application/json"}], BlobName = "blob1", - ?assertMatch({ok, created}, erlazure:put_block_blob(Pid, Container, BlobName, <<"0">>, Opts1)), + ?assertMatch({ok, created}, erlazure:put_block_blob(State, Container, BlobName, <<"0">>, Opts1)), %% Note: this short name is important for this test. It'll produce a base64 string %% that's padded. That padding must be URL-encoded when sending the request, but not %% when generating the string to sign. BlockId1 = <<"blo1">>, - ?assertMatch({ok, created}, erlazure:put_block(Pid, Container, BlobName, BlockId1, <<"a">>)), + ?assertMatch({ok, created}, erlazure:put_block(State, Container, BlobName, BlockId1, <<"a">>)), %% Testing iolists BlockId2 = <<"blo2">>, - ?assertMatch({ok, created}, erlazure:put_block(Pid, Container, BlobName, BlockId2, [<<"\n">>, ["b", [$\n]]])), + ?assertMatch({ok, created}, erlazure:put_block(State, Container, BlobName, BlockId2, [<<"\n">>, ["b", [$\n]]])), %% Not yet committed. Contains only the data from the blob creation. - ?assertMatch({ok, <<"0">>}, erlazure:get_blob(Pid, Container, BlobName)), + ?assertMatch({ok, <<"0">>}, erlazure:get_blob(State, Container, BlobName)), %% Committing BlockList1 = [{BlockId1, latest}], - ?assertMatch({ok, created}, erlazure:put_block_list(Pid, Container, BlobName, BlockList1)), + ?assertMatch({ok, created}, erlazure:put_block_list(State, Container, BlobName, BlockList1)), %% Committed only first block. Initial data was lost, as it was not in the block list. - ?assertMatch({ok, <<"a">>}, erlazure:get_blob(Pid, Container, BlobName)), + ?assertMatch({ok, <<"a">>}, erlazure:get_blob(State, Container, BlobName)), %% Block 2 was dropped after committing. - ?assertMatch({[#blob_block{id = "blo1"}], _}, erlazure:get_block_list(Pid, Container, BlobName)), + ?assertMatch({[#blob_block{id = "blo1"}], _}, erlazure:get_block_list(State, Container, BlobName)), BlockId3 = <<"blo3">>, - ?assertMatch({ok, created}, erlazure:put_block(Pid, Container, BlobName, BlockId3, [<<"\n">>, ["b", [$\n]]])), + ?assertMatch({ok, created}, erlazure:put_block(State, Container, BlobName, BlockId3, [<<"\n">>, ["b", [$\n]]])), %% Commit both blocks Opts2 = [{req_opts, [{headers, [{"x-ms-blob-content-type", "text/csv"}]}]}], BlockList2 = [{BlockId1, committed}, {BlockId3, uncommitted}], - ?assertMatch({ok, created}, erlazure:put_block_list(Pid, Container, BlobName, BlockList2, Opts2)), - ?assertMatch({ok, <<"a\nb\n">>}, erlazure:get_blob(Pid, Container, BlobName)), + ?assertMatch({ok, created}, erlazure:put_block_list(State, Container, BlobName, BlockList2, Opts2)), + ?assertMatch({ok, <<"a\nb\n">>}, erlazure:get_blob(State, Container, BlobName)), %% Check content type. - ListedBlobs = erlazure:list_blobs(Pid, Container), + ListedBlobs = erlazure:list_blobs(State, Container), ?assertMatch({[#cloud_blob{name = "blob1"}], _}, ListedBlobs), {[#cloud_blob{name = "blob1", properties = Props}], _} = ListedBlobs, %% Content-type from `put_block_list' prevails. ?assertMatch(#{content_type := "text/csv"}, maps:from_list(Props)), %% Delete container - ?assertMatch({ok, deleted}, erlazure:delete_container(Pid, Container)), + ?assertMatch({ok, deleted}, erlazure:delete_container(State, Container)), ok. diff --git a/test/erlazure_queue_cloud_tests.erl b/test/erlazure_queue_cloud_tests.erl index 1b023cf..082879f 100644 --- a/test/erlazure_queue_cloud_tests.erl +++ b/test/erlazure_queue_cloud_tests.erl @@ -123,55 +123,55 @@ peek_messages_test_() -> fun peek_messages/1}. start() -> - {ok, Pid} = erlazure:start(?account_name, ?account_key), + {ok, State} = erlazure:new(?account_name, ?account_key), UniqueQueueName = get_queue_unique_name(), - {Pid, UniqueQueueName}. + {State, UniqueQueueName}. start_create() -> - {ok, Pid} = erlazure:start(?account_name, ?account_key), + {ok, State} = erlazure:new(?account_name, ?account_key), UniqueQueueName = get_queue_unique_name(), - {ok, created} = erlazure:create_queue(Pid, UniqueQueueName), - {Pid, UniqueQueueName}. + {ok, created} = erlazure:create_queue(State, UniqueQueueName), + {State, UniqueQueueName}. -stop({Pid, QueueName}) -> - erlazure:delete_queue(Pid, QueueName). +stop({State, QueueName}) -> + erlazure:delete_queue(State, QueueName). -create_queue({Pid, QueueName}) -> - Response = erlazure:create_queue(Pid, QueueName), +create_queue({State, QueueName}) -> + Response = erlazure:create_queue(State, QueueName), ?_assertMatch({ok, created}, Response). -create_queue_duplicate_name({Pid, QueueName}) -> - Response = erlazure:create_queue(Pid, QueueName), +create_queue_duplicate_name({State, QueueName}) -> + Response = erlazure:create_queue(State, QueueName), ?_assertMatch({error, already_created}, Response). -list_queues({Pid, QueueName}) -> +list_queues({State, QueueName}) -> LowerQueueName = string:to_lower(QueueName), - {ok, {Queues, _Metadata}} = erlazure:list_queues(Pid), + {ok, {Queues, _Metadata}} = erlazure:list_queues(State), Queue = lists:keyfind(LowerQueueName, 2, Queues), ?_assertMatch(#queue { name = LowerQueueName }, Queue). -delete_queue({Pid, QueueName}) -> - Response = erlazure:delete_queue(Pid, QueueName), +delete_queue({State, QueueName}) -> + Response = erlazure:delete_queue(State, QueueName), ?_assertMatch({ok, deleted}, Response). -delete_queue_twice({Pid, QueueName}) -> - {ok, deleted} = erlazure:delete_queue(Pid, QueueName), - Response = erlazure:delete_queue(Pid, QueueName), +delete_queue_twice({State, QueueName}) -> + {ok, deleted} = erlazure:delete_queue(State, QueueName), + Response = erlazure:delete_queue(State, QueueName), ?_assertMatch({ok, deleted}, Response). -set_queue_acl({Pid, QueueName}) -> +set_queue_acl({State, QueueName}) -> SignedId = get_queue_test_acl(), - Response = erlazure:set_queue_acl(Pid, QueueName, SignedId), + Response = erlazure:set_queue_acl(State, QueueName, SignedId), ?_assertMatch({ok, created}, Response). -get_queue_empty_acl({Pid, QueueName}) -> - Response = erlazure:get_queue_acl(Pid, QueueName), +get_queue_empty_acl({State, QueueName}) -> + Response = erlazure:get_queue_acl(State, QueueName), ?_assertMatch({ok, no_acl}, Response). -get_queue_acl({Pid, QueueName}) -> +get_queue_acl({State, QueueName}) -> SignedId = get_queue_test_acl(), - {ok, created} = erlazure:set_queue_acl(Pid, QueueName, SignedId), - {ok, Response} = erlazure:get_queue_acl(Pid, QueueName), + {ok, created} = erlazure:set_queue_acl(State, QueueName, SignedId), + {ok, Response} = erlazure:get_queue_acl(State, QueueName), Id = SignedId#signed_id.id, Start = string:left(SignedId#signed_id.access_policy#access_policy.start, 19), @@ -183,41 +183,41 @@ get_queue_acl({Pid, QueueName}) -> ?_assertMatch([], string:tokens(Response#signed_id.access_policy#access_policy.permission, Permission))]. -put_message({Pid, QueueName}) -> - Response = erlazure:put_message(Pid, QueueName, "test message"), +put_message({State, QueueName}) -> + Response = erlazure:put_message(State, QueueName, "test message"), ?_assertMatch({ok, created}, Response). -get_message({Pid, QueueName}) -> - {ok, created} = erlazure:put_message(Pid, QueueName, "test message"), - Response = erlazure:get_messages(Pid, QueueName), +get_message({State, QueueName}) -> + {ok, created} = erlazure:put_message(State, QueueName, "test message"), + Response = erlazure:get_messages(State, QueueName), ?_assertMatch({ok, [#queue_message { text = "test message"}]}, Response). -get_messages({Pid, QueueName}) -> - {ok, created} = erlazure:put_message(Pid, QueueName, "test message1"), - {ok, created} = erlazure:put_message(Pid, QueueName, "test message2"), - {ok, created} = erlazure:put_message(Pid, QueueName, "test message3"), - {ok, Messages} = erlazure:get_messages(Pid, QueueName, [{num_of_messages, 32}]), +get_messages({State, QueueName}) -> + {ok, created} = erlazure:put_message(State, QueueName, "test message1"), + {ok, created} = erlazure:put_message(State, QueueName, "test message2"), + {ok, created} = erlazure:put_message(State, QueueName, "test message3"), + {ok, Messages} = erlazure:get_messages(State, QueueName, [{num_of_messages, 32}]), ?_assertEqual(3, lists:flatlength(Messages)). -get_messages_removes_from_queue({Pid, QueueName}) -> - {ok, created} = erlazure:put_message(Pid, QueueName, "test message1"), - {ok, created} = erlazure:put_message(Pid, QueueName, "test message2"), - {ok, created} = erlazure:put_message(Pid, QueueName, "test message3"), - {ok, _Messages} = erlazure:get_messages(Pid, QueueName, [{num_of_messages, 32}]), - {ok, Messages} = erlazure:get_messages(Pid, QueueName, [{num_of_messages, 32}]), +get_messages_removes_from_queue({State, QueueName}) -> + {ok, created} = erlazure:put_message(State, QueueName, "test message1"), + {ok, created} = erlazure:put_message(State, QueueName, "test message2"), + {ok, created} = erlazure:put_message(State, QueueName, "test message3"), + {ok, _Messages} = erlazure:get_messages(State, QueueName, [{num_of_messages, 32}]), + {ok, Messages} = erlazure:get_messages(State, QueueName, [{num_of_messages, 32}]), ?_assertMatch([], Messages). -peek_message({Pid, QueueName}) -> - {ok, created} = erlazure:put_message(Pid, QueueName, "test message 1"), - {ok, created} = erlazure:put_message(Pid, QueueName, "test message 2"), - Response = erlazure:peek_messages(Pid, QueueName), +peek_message({State, QueueName}) -> + {ok, created} = erlazure:put_message(State, QueueName, "test message 1"), + {ok, created} = erlazure:put_message(State, QueueName, "test message 2"), + Response = erlazure:peek_messages(State, QueueName), ?_assertMatch({ok, [#queue_message { text = "test message 1" }]}, Response). -peek_messages({Pid, QueueName}) -> - {ok, created} = erlazure:put_message(Pid, QueueName, "test message 1"), - {ok, created} = erlazure:put_message(Pid, QueueName, "test message 2"), - {ok, created} = erlazure:put_message(Pid, QueueName, "test message 3"), - {ok, Messages} = erlazure:peek_messages(Pid, QueueName, [{num_of_messages, 32}]), +peek_messages({State, QueueName}) -> + {ok, created} = erlazure:put_message(State, QueueName, "test message 1"), + {ok, created} = erlazure:put_message(State, QueueName, "test message 2"), + {ok, created} = erlazure:put_message(State, QueueName, "test message 3"), + {ok, Messages} = erlazure:peek_messages(State, QueueName, [{num_of_messages, 32}]), ?_assertEqual(3, lists:flatlength(Messages)). get_queue_unique_name() -> @@ -236,4 +236,4 @@ get_queue_test_acl() -> expiry = erlazure_utils:iso_8601_fmt(Expiry), permission = "raup" }, #signed_id { id = "12345678901234567890123456789012", - access_policy = AccessPolicy }. \ No newline at end of file + access_policy = AccessPolicy }.