feat(s3): separate concepts to make app reusable in bridges
This commit is contained in:
parent
a5266f68ec
commit
4ff04ab1f3
|
@ -69,11 +69,9 @@
|
||||||
-spec start_export(options(), transfer(), filemeta()) ->
|
-spec start_export(options(), transfer(), filemeta()) ->
|
||||||
{ok, export_st()} | {error, term()}.
|
{ok, export_st()} | {error, term()}.
|
||||||
start_export(_Options, Transfer, Filemeta) ->
|
start_export(_Options, Transfer, Filemeta) ->
|
||||||
Options = #{
|
Key = s3_key(Transfer, Filemeta),
|
||||||
key => s3_key(Transfer, Filemeta),
|
UploadOpts = #{headers => s3_headers(Transfer, Filemeta)},
|
||||||
headers => s3_headers(Transfer, Filemeta)
|
case emqx_s3:start_uploader(?S3_PROFILE_ID, Key, UploadOpts) of
|
||||||
},
|
|
||||||
case emqx_s3:start_uploader(?S3_PROFILE_ID, Options) of
|
|
||||||
{ok, Pid} ->
|
{ok, Pid} ->
|
||||||
true = erlang:link(Pid),
|
true = erlang:link(Pid),
|
||||||
{ok, #{filemeta => Filemeta, pid => Pid}};
|
{ok, #{filemeta => Filemeta, pid => Pid}};
|
||||||
|
@ -180,22 +178,24 @@ list_pages(Client, Marker, Limit, Acc) ->
|
||||||
ListOptions = [{marker, Marker} || Marker =/= undefined],
|
ListOptions = [{marker, Marker} || Marker =/= undefined],
|
||||||
case list_key_info(Client, [{max_keys, MaxKeys} | ListOptions]) of
|
case list_key_info(Client, [{max_keys, MaxKeys} | ListOptions]) of
|
||||||
{ok, {Exports, NextMarker}} ->
|
{ok, {Exports, NextMarker}} ->
|
||||||
list_accumulate(Client, Limit, NextMarker, [Exports | Acc]);
|
Left = update_limit(Limit, Exports),
|
||||||
|
NextAcc = [Exports | Acc],
|
||||||
|
case NextMarker of
|
||||||
|
undefined ->
|
||||||
|
{ok, {flatten_pages(NextAcc), undefined}};
|
||||||
|
_ when Left =< 0 ->
|
||||||
|
{ok, {flatten_pages(NextAcc), NextMarker}};
|
||||||
|
_ ->
|
||||||
|
list_pages(Client, NextMarker, Left, NextAcc)
|
||||||
|
end;
|
||||||
{error, _Reason} = Error ->
|
{error, _Reason} = Error ->
|
||||||
Error
|
Error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
list_accumulate(_Client, _Limit, undefined, Acc) ->
|
update_limit(undefined, _Exports) ->
|
||||||
{ok, {flatten_pages(Acc), undefined}};
|
undefined;
|
||||||
list_accumulate(Client, undefined, Marker, Acc) ->
|
update_limit(Limit, Exports) ->
|
||||||
list_pages(Client, Marker, undefined, Acc);
|
Limit - length(Exports).
|
||||||
list_accumulate(Client, Limit, Marker, Acc = [Exports | _]) ->
|
|
||||||
case Limit - length(Exports) of
|
|
||||||
0 ->
|
|
||||||
{ok, {flatten_pages(Acc), Marker}};
|
|
||||||
Left ->
|
|
||||||
list_pages(Client, Marker, Left, Acc)
|
|
||||||
end.
|
|
||||||
|
|
||||||
flatten_pages(Pages) ->
|
flatten_pages(Pages) ->
|
||||||
lists:append(lists:reverse(Pages)).
|
lists:append(lists:reverse(Pages)).
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
start_profile/2,
|
start_profile/2,
|
||||||
stop_profile/1,
|
stop_profile/1,
|
||||||
update_profile/2,
|
update_profile/2,
|
||||||
start_uploader/2,
|
start_uploader/3,
|
||||||
with_client/2
|
with_client/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
-export_type([
|
-export_type([
|
||||||
profile_id/0,
|
profile_id/0,
|
||||||
profile_config/0,
|
profile_config/0,
|
||||||
|
transport_options/0,
|
||||||
acl/0
|
acl/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
@ -81,18 +82,18 @@ stop_profile(ProfileId) when ?IS_PROFILE_ID(ProfileId) ->
|
||||||
update_profile(ProfileId, ProfileConfig) when ?IS_PROFILE_ID(ProfileId) ->
|
update_profile(ProfileId, ProfileConfig) when ?IS_PROFILE_ID(ProfileId) ->
|
||||||
emqx_s3_profile_conf:update_config(ProfileId, ProfileConfig).
|
emqx_s3_profile_conf:update_config(ProfileId, ProfileConfig).
|
||||||
|
|
||||||
-spec start_uploader(profile_id(), emqx_s3_uploader:opts()) ->
|
-spec start_uploader(profile_id(), emqx_s3_client:key(), emqx_s3_client:upload_options()) ->
|
||||||
emqx_types:startlink_ret() | {error, profile_not_found}.
|
emqx_types:startlink_ret() | {error, profile_not_found}.
|
||||||
start_uploader(ProfileId, Opts) when ?IS_PROFILE_ID(ProfileId) ->
|
start_uploader(ProfileId, Key, Props) when ?IS_PROFILE_ID(ProfileId) ->
|
||||||
emqx_s3_profile_uploader_sup:start_uploader(ProfileId, Opts).
|
emqx_s3_profile_uploader_sup:start_uploader(ProfileId, Key, Props).
|
||||||
|
|
||||||
-spec with_client(profile_id(), fun((emqx_s3_client:client()) -> Result)) ->
|
-spec with_client(profile_id(), fun((emqx_s3_client:client()) -> Result)) ->
|
||||||
{error, profile_not_found} | Result.
|
{error, profile_not_found} | Result.
|
||||||
with_client(ProfileId, Fun) when is_function(Fun, 1) andalso ?IS_PROFILE_ID(ProfileId) ->
|
with_client(ProfileId, Fun) when is_function(Fun, 1) andalso ?IS_PROFILE_ID(ProfileId) ->
|
||||||
case emqx_s3_profile_conf:checkout_config(ProfileId) of
|
case emqx_s3_profile_conf:checkout_config(ProfileId) of
|
||||||
{ok, ClientConfig, _UploadConfig} ->
|
{Bucket, ClientConfig, _UploadOpts, _UploadConfig} ->
|
||||||
try
|
try
|
||||||
Fun(emqx_s3_client:create(ClientConfig))
|
Fun(emqx_s3_client:create(Bucket, ClientConfig))
|
||||||
after
|
after
|
||||||
emqx_s3_profile_conf:checkin_config(ProfileId)
|
emqx_s3_profile_conf:checkin_config(ProfileId)
|
||||||
end;
|
end;
|
||||||
|
|
|
@ -9,12 +9,11 @@
|
||||||
-include_lib("erlcloud/include/erlcloud_aws.hrl").
|
-include_lib("erlcloud/include/erlcloud_aws.hrl").
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
create/1,
|
create/2,
|
||||||
|
|
||||||
put_object/3,
|
put_object/3,
|
||||||
put_object/4,
|
put_object/4,
|
||||||
|
|
||||||
start_multipart/2,
|
|
||||||
start_multipart/3,
|
start_multipart/3,
|
||||||
upload_part/5,
|
upload_part/5,
|
||||||
complete_multipart/4,
|
complete_multipart/4,
|
||||||
|
@ -26,10 +25,15 @@
|
||||||
format_request/1
|
format_request/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
%% For connectors
|
||||||
|
-export([aws_config/1]).
|
||||||
|
|
||||||
-export_type([
|
-export_type([
|
||||||
client/0,
|
client/0,
|
||||||
headers/0,
|
headers/0,
|
||||||
|
bucket/0,
|
||||||
key/0,
|
key/0,
|
||||||
|
upload_options/0,
|
||||||
upload_id/0,
|
upload_id/0,
|
||||||
etag/0,
|
etag/0,
|
||||||
part_number/0,
|
part_number/0,
|
||||||
|
@ -39,18 +43,17 @@
|
||||||
-type headers() :: #{binary() | string() => iodata()}.
|
-type headers() :: #{binary() | string() => iodata()}.
|
||||||
-type erlcloud_headers() :: list({string(), iodata()}).
|
-type erlcloud_headers() :: list({string(), iodata()}).
|
||||||
|
|
||||||
|
-type bucket() :: string().
|
||||||
-type key() :: string().
|
-type key() :: string().
|
||||||
-type part_number() :: non_neg_integer().
|
-type part_number() :: non_neg_integer().
|
||||||
-type upload_id() :: string().
|
-type upload_id() :: string().
|
||||||
-type etag() :: string().
|
-type etag() :: string().
|
||||||
-type http_pool() :: ehttpc:pool_name().
|
-type http_pool() :: ehttpc:pool_name().
|
||||||
-type pool_type() :: random | hash.
|
-type pool_type() :: random | hash.
|
||||||
-type upload_options() :: list({acl, emqx_s3:acl()}).
|
|
||||||
|
|
||||||
-opaque client() :: #{
|
-opaque client() :: #{
|
||||||
aws_config := aws_config(),
|
aws_config := aws_config(),
|
||||||
upload_options := upload_options(),
|
bucket := bucket(),
|
||||||
bucket := string(),
|
|
||||||
headers := erlcloud_headers(),
|
headers := erlcloud_headers(),
|
||||||
url_expire_time := non_neg_integer(),
|
url_expire_time := non_neg_integer(),
|
||||||
pool_type := pool_type()
|
pool_type := pool_type()
|
||||||
|
@ -60,9 +63,7 @@
|
||||||
scheme := string(),
|
scheme := string(),
|
||||||
host := string(),
|
host := string(),
|
||||||
port := part_number(),
|
port := part_number(),
|
||||||
bucket := string(),
|
|
||||||
headers := headers(),
|
headers := headers(),
|
||||||
acl := emqx_s3:acl() | undefined,
|
|
||||||
url_expire_time := pos_integer(),
|
url_expire_time := pos_integer(),
|
||||||
access_key_id := string() | undefined,
|
access_key_id := string() | undefined,
|
||||||
secret_access_key := emqx_secret:t(string()) | undefined,
|
secret_access_key := emqx_secret:t(string()) | undefined,
|
||||||
|
@ -72,6 +73,11 @@
|
||||||
max_retries := non_neg_integer() | undefined
|
max_retries := non_neg_integer() | undefined
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
-type upload_options() :: #{
|
||||||
|
acl => emqx_s3:acl() | undefined,
|
||||||
|
headers => headers()
|
||||||
|
}.
|
||||||
|
|
||||||
-type s3_options() :: proplists:proplist().
|
-type s3_options() :: proplists:proplist().
|
||||||
|
|
||||||
-define(DEFAULT_REQUEST_TIMEOUT, 30000).
|
-define(DEFAULT_REQUEST_TIMEOUT, 30000).
|
||||||
|
@ -81,12 +87,11 @@
|
||||||
%% API
|
%% API
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
-spec create(config()) -> client().
|
-spec create(bucket(), config()) -> client().
|
||||||
create(Config) ->
|
create(Bucket, Config) ->
|
||||||
#{
|
#{
|
||||||
aws_config => aws_config(Config),
|
aws_config => aws_config(Config),
|
||||||
upload_options => upload_options(Config),
|
bucket => Bucket,
|
||||||
bucket => maps:get(bucket, Config),
|
|
||||||
url_expire_time => maps:get(url_expire_time, Config),
|
url_expire_time => maps:get(url_expire_time, Config),
|
||||||
headers => headers(Config),
|
headers => headers(Config),
|
||||||
pool_type => maps:get(pool_type, Config)
|
pool_type => maps:get(pool_type, Config)
|
||||||
|
@ -94,17 +99,19 @@ create(Config) ->
|
||||||
|
|
||||||
-spec put_object(client(), key(), iodata()) -> ok_or_error(term()).
|
-spec put_object(client(), key(), iodata()) -> ok_or_error(term()).
|
||||||
put_object(Client, Key, Value) ->
|
put_object(Client, Key, Value) ->
|
||||||
put_object(Client, #{}, Key, Value).
|
put_object(Client, Key, #{}, Value).
|
||||||
|
|
||||||
-spec put_object(client(), headers(), key(), iodata()) -> ok_or_error(term()).
|
-spec put_object(client(), key(), upload_options(), iodata()) -> ok_or_error(term()).
|
||||||
put_object(
|
put_object(
|
||||||
#{bucket := Bucket, upload_options := Options, headers := Headers, aws_config := AwsConfig},
|
#{bucket := Bucket, headers := BaseHeaders, aws_config := AwsConfig},
|
||||||
SpecialHeaders,
|
|
||||||
Key,
|
Key,
|
||||||
Value
|
UploadOpts,
|
||||||
|
Content
|
||||||
) ->
|
) ->
|
||||||
AllHeaders = join_headers(Headers, SpecialHeaders),
|
ECKey = erlcloud_key(Key),
|
||||||
try erlcloud_s3:put_object(Bucket, erlcloud_key(Key), Value, Options, AllHeaders, AwsConfig) of
|
ECOpts = erlcloud_upload_options(UploadOpts),
|
||||||
|
Headers = join_headers(BaseHeaders, maps:get(headers, UploadOpts, undefined)),
|
||||||
|
try erlcloud_s3:put_object(Bucket, ECKey, Content, ECOpts, Headers, AwsConfig) of
|
||||||
Props when is_list(Props) ->
|
Props when is_list(Props) ->
|
||||||
ok
|
ok
|
||||||
catch
|
catch
|
||||||
|
@ -113,18 +120,16 @@ put_object(
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec start_multipart(client(), key()) -> ok_or_error(upload_id(), term()).
|
-spec start_multipart(client(), key(), upload_options()) -> ok_or_error(upload_id(), term()).
|
||||||
start_multipart(Client, Key) ->
|
|
||||||
start_multipart(Client, #{}, Key).
|
|
||||||
|
|
||||||
-spec start_multipart(client(), headers(), key()) -> ok_or_error(upload_id(), term()).
|
|
||||||
start_multipart(
|
start_multipart(
|
||||||
#{bucket := Bucket, upload_options := Options, headers := Headers, aws_config := AwsConfig},
|
#{bucket := Bucket, headers := BaseHeaders, aws_config := AwsConfig},
|
||||||
SpecialHeaders,
|
Key,
|
||||||
Key
|
UploadOpts
|
||||||
) ->
|
) ->
|
||||||
AllHeaders = join_headers(Headers, SpecialHeaders),
|
ECKey = erlcloud_key(Key),
|
||||||
case erlcloud_s3:start_multipart(Bucket, erlcloud_key(Key), Options, AllHeaders, AwsConfig) of
|
ECOpts = erlcloud_upload_options(UploadOpts),
|
||||||
|
Headers = join_headers(BaseHeaders, maps:get(headers, UploadOpts, undefined)),
|
||||||
|
case erlcloud_s3:start_multipart(Bucket, ECKey, ECOpts, Headers, AwsConfig) of
|
||||||
{ok, Props} ->
|
{ok, Props} ->
|
||||||
{ok, response_property('uploadId', Props)};
|
{ok, response_property('uploadId', Props)};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
|
@ -204,11 +209,11 @@ format(#{aws_config := AwsConfig} = Client) ->
|
||||||
%% Internal functions
|
%% Internal functions
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
upload_options(#{acl := Acl}) when Acl =/= undefined ->
|
erlcloud_upload_options(#{acl := Acl}) when Acl =/= undefined ->
|
||||||
[
|
[
|
||||||
{acl, Acl}
|
{acl, Acl}
|
||||||
];
|
];
|
||||||
upload_options(#{}) ->
|
erlcloud_upload_options(#{}) ->
|
||||||
[].
|
[].
|
||||||
|
|
||||||
headers(#{headers := Headers}) ->
|
headers(#{headers := Headers}) ->
|
||||||
|
@ -401,6 +406,8 @@ headers_ehttpc_to_erlcloud_response(EhttpcHeaders) ->
|
||||||
headers_erlcloud_request_to_ehttpc(ErlcloudHeaders) ->
|
headers_erlcloud_request_to_ehttpc(ErlcloudHeaders) ->
|
||||||
[{to_binary(K), V} || {K, V} <- ErlcloudHeaders].
|
[{to_binary(K), V} || {K, V} <- ErlcloudHeaders].
|
||||||
|
|
||||||
|
join_headers(ErlcloudHeaders, undefined) ->
|
||||||
|
ErlcloudHeaders;
|
||||||
join_headers(ErlcloudHeaders, UserSpecialHeaders) ->
|
join_headers(ErlcloudHeaders, UserSpecialHeaders) ->
|
||||||
ErlcloudHeaders ++ headers_user_to_erlcloud_request(UserSpecialHeaders).
|
ErlcloudHeaders ++ headers_user_to_erlcloud_request(UserSpecialHeaders).
|
||||||
|
|
||||||
|
|
|
@ -37,13 +37,25 @@
|
||||||
code_change/3
|
code_change/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% For test purposes
|
%% For connectors
|
||||||
-export([
|
-export([
|
||||||
client_config/2,
|
client_config/2,
|
||||||
|
http_config/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
%% For test purposes
|
||||||
|
-export([
|
||||||
start_http_pool/2,
|
start_http_pool/2,
|
||||||
id/1
|
id/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
-type config_checkout() :: {
|
||||||
|
emqx_s3_client:bucket(),
|
||||||
|
emqx_s3_client:config(),
|
||||||
|
emqx_s3_client:upload_options(),
|
||||||
|
emqx_s3_uploader:config()
|
||||||
|
}.
|
||||||
|
|
||||||
-define(DEFAULT_CALL_TIMEOUT, 5000).
|
-define(DEFAULT_CALL_TIMEOUT, 5000).
|
||||||
|
|
||||||
-define(DEFAULT_HTTP_POOL_TIMEOUT, 60000).
|
-define(DEFAULT_HTTP_POOL_TIMEOUT, 60000).
|
||||||
|
@ -78,12 +90,12 @@ update_config(ProfileId, ProfileConfig, Timeout) ->
|
||||||
?SAFE_CALL_VIA_GPROC(ProfileId, {update_config, ProfileConfig}, Timeout).
|
?SAFE_CALL_VIA_GPROC(ProfileId, {update_config, ProfileConfig}, Timeout).
|
||||||
|
|
||||||
-spec checkout_config(emqx_s3:profile_id()) ->
|
-spec checkout_config(emqx_s3:profile_id()) ->
|
||||||
{ok, emqx_s3_client:config(), emqx_s3_uploader:config()} | {error, profile_not_found}.
|
config_checkout() | {error, profile_not_found}.
|
||||||
checkout_config(ProfileId) ->
|
checkout_config(ProfileId) ->
|
||||||
checkout_config(ProfileId, ?DEFAULT_CALL_TIMEOUT).
|
checkout_config(ProfileId, ?DEFAULT_CALL_TIMEOUT).
|
||||||
|
|
||||||
-spec checkout_config(emqx_s3:profile_id(), timeout()) ->
|
-spec checkout_config(emqx_s3:profile_id(), timeout()) ->
|
||||||
{ok, emqx_s3_client:config(), emqx_s3_uploader:config()} | {error, profile_not_found}.
|
config_checkout() | {error, profile_not_found}.
|
||||||
checkout_config(ProfileId, Timeout) ->
|
checkout_config(ProfileId, Timeout) ->
|
||||||
?SAFE_CALL_VIA_GPROC(ProfileId, {checkout_config, self()}, Timeout).
|
?SAFE_CALL_VIA_GPROC(ProfileId, {checkout_config, self()}, Timeout).
|
||||||
|
|
||||||
|
@ -108,6 +120,8 @@ init([ProfileId, ProfileConfig]) ->
|
||||||
{ok, #{
|
{ok, #{
|
||||||
profile_id => ProfileId,
|
profile_id => ProfileId,
|
||||||
profile_config => ProfileConfig,
|
profile_config => ProfileConfig,
|
||||||
|
bucket => bucket(ProfileConfig),
|
||||||
|
upload_options => upload_options(ProfileConfig),
|
||||||
client_config => client_config(ProfileConfig, PoolName),
|
client_config => client_config(ProfileConfig, PoolName),
|
||||||
uploader_config => uploader_config(ProfileConfig),
|
uploader_config => uploader_config(ProfileConfig),
|
||||||
pool_name => PoolName,
|
pool_name => PoolName,
|
||||||
|
@ -128,12 +142,14 @@ handle_call(
|
||||||
{checkout_config, Pid},
|
{checkout_config, Pid},
|
||||||
_From,
|
_From,
|
||||||
#{
|
#{
|
||||||
|
bucket := Bucket,
|
||||||
|
upload_options := Options,
|
||||||
client_config := ClientConfig,
|
client_config := ClientConfig,
|
||||||
uploader_config := UploaderConfig
|
uploader_config := UploaderConfig
|
||||||
} = State
|
} = State
|
||||||
) ->
|
) ->
|
||||||
ok = register_client(Pid, State),
|
ok = register_client(Pid, State),
|
||||||
{reply, {ok, ClientConfig, UploaderConfig}, State};
|
{reply, {Bucket, ClientConfig, Options, UploaderConfig}, State};
|
||||||
handle_call({checkin_config, Pid}, _From, State) ->
|
handle_call({checkin_config, Pid}, _From, State) ->
|
||||||
ok = unregister_client(Pid, State),
|
ok = unregister_client(Pid, State),
|
||||||
{reply, ok, State};
|
{reply, ok, State};
|
||||||
|
@ -146,6 +162,8 @@ handle_call(
|
||||||
{ok, PoolName} ->
|
{ok, PoolName} ->
|
||||||
NewState = State#{
|
NewState = State#{
|
||||||
profile_config => NewProfileConfig,
|
profile_config => NewProfileConfig,
|
||||||
|
bucket => bucket(NewProfileConfig),
|
||||||
|
upload_options => upload_options(NewProfileConfig),
|
||||||
client_config => client_config(NewProfileConfig, PoolName),
|
client_config => client_config(NewProfileConfig, PoolName),
|
||||||
uploader_config => uploader_config(NewProfileConfig),
|
uploader_config => uploader_config(NewProfileConfig),
|
||||||
http_pool_timeout => http_pool_timeout(NewProfileConfig),
|
http_pool_timeout => http_pool_timeout(NewProfileConfig),
|
||||||
|
@ -198,8 +216,6 @@ client_config(ProfileConfig, PoolName) ->
|
||||||
port => maps:get(port, ProfileConfig),
|
port => maps:get(port, ProfileConfig),
|
||||||
url_expire_time => maps:get(url_expire_time, ProfileConfig),
|
url_expire_time => maps:get(url_expire_time, ProfileConfig),
|
||||||
headers => maps:get(headers, HTTPOpts, #{}),
|
headers => maps:get(headers, HTTPOpts, #{}),
|
||||||
acl => maps:get(acl, ProfileConfig, undefined),
|
|
||||||
bucket => maps:get(bucket, ProfileConfig),
|
|
||||||
access_key_id => maps:get(access_key_id, ProfileConfig, undefined),
|
access_key_id => maps:get(access_key_id, ProfileConfig, undefined),
|
||||||
secret_access_key => maps:get(secret_access_key, ProfileConfig, undefined),
|
secret_access_key => maps:get(secret_access_key, ProfileConfig, undefined),
|
||||||
request_timeout => maps:get(request_timeout, HTTPOpts, undefined),
|
request_timeout => maps:get(request_timeout, HTTPOpts, undefined),
|
||||||
|
@ -214,6 +230,12 @@ uploader_config(#{max_part_size := MaxPartSize, min_part_size := MinPartSize} =
|
||||||
max_part_size => MaxPartSize
|
max_part_size => MaxPartSize
|
||||||
}.
|
}.
|
||||||
|
|
||||||
|
bucket(ProfileConfig) ->
|
||||||
|
maps:get(bucket, ProfileConfig).
|
||||||
|
|
||||||
|
upload_options(ProfileConfig) ->
|
||||||
|
#{acl => maps:get(acl, ProfileConfig, undefined)}.
|
||||||
|
|
||||||
scheme(#{ssl := #{enable := true}}) -> "https://";
|
scheme(#{ssl := #{enable := true}}) -> "https://";
|
||||||
scheme(_TransportOpts) -> "http://".
|
scheme(_TransportOpts) -> "http://".
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
start_link/1,
|
start_link/1,
|
||||||
child_spec/1,
|
child_spec/1,
|
||||||
id/1,
|
id/1,
|
||||||
start_uploader/2
|
start_uploader/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([init/1]).
|
-export([init/1]).
|
||||||
|
@ -43,10 +43,10 @@ child_spec(ProfileId) ->
|
||||||
id(ProfileId) ->
|
id(ProfileId) ->
|
||||||
{?MODULE, ProfileId}.
|
{?MODULE, ProfileId}.
|
||||||
|
|
||||||
-spec start_uploader(emqx_s3:profile_id(), emqx_s3_uploader:opts()) ->
|
-spec start_uploader(emqx_s3:profile_id(), emqx_s3_client:key(), emqx_s3_client:upload_options()) ->
|
||||||
emqx_types:startlink_ret() | {error, profile_not_found}.
|
emqx_types:startlink_ret() | {error, profile_not_found}.
|
||||||
start_uploader(ProfileId, Opts) ->
|
start_uploader(ProfileId, Key, UploadOpts) ->
|
||||||
try supervisor:start_child(?VIA_GPROC(id(ProfileId)), [Opts]) of
|
try supervisor:start_child(?VIA_GPROC(id(ProfileId)), [Key, UploadOpts]) of
|
||||||
Result -> Result
|
Result -> Result
|
||||||
catch
|
catch
|
||||||
exit:{noproc, _} -> {error, profile_not_found}
|
exit:{noproc, _} -> {error, profile_not_found}
|
||||||
|
|
|
@ -23,6 +23,13 @@ tags() ->
|
||||||
[<<"S3">>].
|
[<<"S3">>].
|
||||||
|
|
||||||
fields(s3) ->
|
fields(s3) ->
|
||||||
|
lists:append([
|
||||||
|
fields(s3_client),
|
||||||
|
fields(s3_uploader),
|
||||||
|
fields(s3_url_options),
|
||||||
|
props_with([bucket, acl], fields(s3_upload))
|
||||||
|
]);
|
||||||
|
fields(s3_client) ->
|
||||||
[
|
[
|
||||||
{access_key_id,
|
{access_key_id,
|
||||||
mk(
|
mk(
|
||||||
|
@ -38,14 +45,6 @@ fields(s3) ->
|
||||||
desc => ?DESC("secret_access_key")
|
desc => ?DESC("secret_access_key")
|
||||||
}
|
}
|
||||||
)},
|
)},
|
||||||
{bucket,
|
|
||||||
mk(
|
|
||||||
string(),
|
|
||||||
#{
|
|
||||||
desc => ?DESC("bucket"),
|
|
||||||
required => true
|
|
||||||
}
|
|
||||||
)},
|
|
||||||
{host,
|
{host,
|
||||||
mk(
|
mk(
|
||||||
string(),
|
string(),
|
||||||
|
@ -62,16 +61,51 @@ fields(s3) ->
|
||||||
required => true
|
required => true
|
||||||
}
|
}
|
||||||
)},
|
)},
|
||||||
{url_expire_time,
|
{transport_options,
|
||||||
mk(
|
mk(
|
||||||
%% not used in a `receive ... after' block, just timestamp comparison
|
ref(?MODULE, transport_options),
|
||||||
emqx_schema:duration_s(),
|
|
||||||
#{
|
#{
|
||||||
default => <<"1h">>,
|
desc => ?DESC("transport_options"),
|
||||||
desc => ?DESC("url_expire_time"),
|
|
||||||
required => false
|
required => false
|
||||||
}
|
}
|
||||||
|
)}
|
||||||
|
];
|
||||||
|
fields(s3_upload) ->
|
||||||
|
[
|
||||||
|
{bucket,
|
||||||
|
mk(
|
||||||
|
string(),
|
||||||
|
#{
|
||||||
|
desc => ?DESC("bucket"),
|
||||||
|
required => true
|
||||||
|
}
|
||||||
)},
|
)},
|
||||||
|
{key,
|
||||||
|
mk(
|
||||||
|
string(),
|
||||||
|
#{
|
||||||
|
desc => ?DESC("key"),
|
||||||
|
required => true
|
||||||
|
}
|
||||||
|
)},
|
||||||
|
{acl,
|
||||||
|
mk(
|
||||||
|
hoconsc:enum([
|
||||||
|
private,
|
||||||
|
public_read,
|
||||||
|
public_read_write,
|
||||||
|
authenticated_read,
|
||||||
|
bucket_owner_read,
|
||||||
|
bucket_owner_full_control
|
||||||
|
]),
|
||||||
|
#{
|
||||||
|
desc => ?DESC("acl"),
|
||||||
|
required => false
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
];
|
||||||
|
fields(s3_uploader) ->
|
||||||
|
[
|
||||||
{min_part_size,
|
{min_part_size,
|
||||||
mk(
|
mk(
|
||||||
emqx_schema:bytesize(),
|
emqx_schema:bytesize(),
|
||||||
|
@ -91,27 +125,17 @@ fields(s3) ->
|
||||||
required => true,
|
required => true,
|
||||||
validator => fun part_size_validator/1
|
validator => fun part_size_validator/1
|
||||||
}
|
}
|
||||||
)},
|
)}
|
||||||
{acl,
|
];
|
||||||
|
fields(s3_url_options) ->
|
||||||
|
[
|
||||||
|
{url_expire_time,
|
||||||
mk(
|
mk(
|
||||||
hoconsc:enum([
|
%% not used in a `receive ... after' block, just timestamp comparison
|
||||||
private,
|
emqx_schema:duration_s(),
|
||||||
public_read,
|
|
||||||
public_read_write,
|
|
||||||
authenticated_read,
|
|
||||||
bucket_owner_read,
|
|
||||||
bucket_owner_full_control
|
|
||||||
]),
|
|
||||||
#{
|
#{
|
||||||
desc => ?DESC("acl"),
|
default => <<"1h">>,
|
||||||
required => false
|
desc => ?DESC("url_expire_time"),
|
||||||
}
|
|
||||||
)},
|
|
||||||
{transport_options,
|
|
||||||
mk(
|
|
||||||
ref(?MODULE, transport_options),
|
|
||||||
#{
|
|
||||||
desc => ?DESC("transport_options"),
|
|
||||||
required => false
|
required => false
|
||||||
}
|
}
|
||||||
)}
|
)}
|
||||||
|
@ -138,6 +162,10 @@ fields(transport_options) ->
|
||||||
|
|
||||||
desc(s3) ->
|
desc(s3) ->
|
||||||
"S3 connection options";
|
"S3 connection options";
|
||||||
|
desc(s3_client) ->
|
||||||
|
"S3 connection options";
|
||||||
|
desc(s3_upload) ->
|
||||||
|
"S3 upload options";
|
||||||
desc(transport_options) ->
|
desc(transport_options) ->
|
||||||
"Options for the HTTP transport layer used by the S3 client".
|
"Options for the HTTP transport layer used by the S3 client".
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
-behaviour(gen_statem).
|
-behaviour(gen_statem).
|
||||||
|
|
||||||
-export([
|
-export([
|
||||||
start_link/2,
|
start_link/3,
|
||||||
|
|
||||||
write/2,
|
write/2,
|
||||||
write/3,
|
write/3,
|
||||||
|
@ -33,30 +33,25 @@
|
||||||
format_status/2
|
format_status/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export_type([opts/0, config/0]).
|
-export_type([config/0]).
|
||||||
|
|
||||||
-type config() :: #{
|
-type config() :: #{
|
||||||
min_part_size => pos_integer(),
|
min_part_size => pos_integer(),
|
||||||
max_part_size => pos_integer()
|
max_part_size => pos_integer()
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-type opts() :: #{
|
|
||||||
key := string(),
|
|
||||||
headers => emqx_s3_client:headers()
|
|
||||||
}.
|
|
||||||
|
|
||||||
-type data() :: #{
|
-type data() :: #{
|
||||||
profile_id := emqx_s3:profile_id(),
|
profile_id => emqx_s3:profile_id(),
|
||||||
client := emqx_s3_client:client(),
|
client := emqx_s3_client:client(),
|
||||||
key := emqx_s3_client:key(),
|
key := emqx_s3_client:key(),
|
||||||
|
upload_opts := emqx_s3_client:upload_options(),
|
||||||
buffer := iodata(),
|
buffer := iodata(),
|
||||||
buffer_size := non_neg_integer(),
|
buffer_size := non_neg_integer(),
|
||||||
min_part_size := pos_integer(),
|
min_part_size := pos_integer(),
|
||||||
max_part_size := pos_integer(),
|
max_part_size := pos_integer(),
|
||||||
upload_id := undefined | emqx_s3_client:upload_id(),
|
upload_id := undefined | emqx_s3_client:upload_id(),
|
||||||
etags := [emqx_s3_client:etag()],
|
etags := [emqx_s3_client:etag()],
|
||||||
part_number := emqx_s3_client:part_number(),
|
part_number := emqx_s3_client:part_number()
|
||||||
headers := emqx_s3_client:headers()
|
|
||||||
}.
|
}.
|
||||||
|
|
||||||
%% 5MB
|
%% 5MB
|
||||||
|
@ -66,9 +61,10 @@
|
||||||
|
|
||||||
-define(DEFAULT_TIMEOUT, 30000).
|
-define(DEFAULT_TIMEOUT, 30000).
|
||||||
|
|
||||||
-spec start_link(emqx_s3:profile_id(), opts()) -> gen_statem:start_ret().
|
-spec start_link(emqx_s3:profile_id(), emqx_s3_client:key(), emqx_s3_client:upload_options()) ->
|
||||||
start_link(ProfileId, #{key := Key} = Opts) when is_list(Key) ->
|
gen_statem:start_ret().
|
||||||
gen_statem:start_link(?MODULE, [ProfileId, Opts], []).
|
start_link(ProfileId, Key, UploadOpts) when is_list(Key) ->
|
||||||
|
gen_statem:start_link(?MODULE, {profile, ProfileId, Key, UploadOpts}, []).
|
||||||
|
|
||||||
-spec write(pid(), iodata()) -> ok_or_error(term()).
|
-spec write(pid(), iodata()) -> ok_or_error(term()).
|
||||||
write(Pid, WriteData) ->
|
write(Pid, WriteData) ->
|
||||||
|
@ -105,19 +101,23 @@ shutdown(Pid) ->
|
||||||
|
|
||||||
callback_mode() -> handle_event_function.
|
callback_mode() -> handle_event_function.
|
||||||
|
|
||||||
init([ProfileId, #{key := Key} = Opts]) ->
|
init({profile, ProfileId, Key, UploadOpts}) ->
|
||||||
process_flag(trap_exit, true),
|
{Bucket, ClientConfig, BaseOpts, UploaderConfig} =
|
||||||
{ok, ClientConfig, UploaderConfig} = emqx_s3_profile_conf:checkout_config(ProfileId),
|
emqx_s3_profile_conf:checkout_config(ProfileId),
|
||||||
Client = client(ClientConfig),
|
Upload = #{
|
||||||
{ok, upload_not_started, #{
|
|
||||||
profile_id => ProfileId,
|
profile_id => ProfileId,
|
||||||
client => Client,
|
client => client(Bucket, ClientConfig),
|
||||||
headers => maps:get(headers, Opts, #{}),
|
|
||||||
key => Key,
|
key => Key,
|
||||||
|
upload_opts => maps:merge(BaseOpts, UploadOpts)
|
||||||
|
},
|
||||||
|
init({upload, UploaderConfig, Upload});
|
||||||
|
init({upload, Config, Upload}) ->
|
||||||
|
process_flag(trap_exit, true),
|
||||||
|
{ok, upload_not_started, Upload#{
|
||||||
buffer => [],
|
buffer => [],
|
||||||
buffer_size => 0,
|
buffer_size => 0,
|
||||||
min_part_size => maps:get(min_part_size, UploaderConfig, ?DEFAULT_MIN_PART_SIZE),
|
min_part_size => maps:get(min_part_size, Config, ?DEFAULT_MIN_PART_SIZE),
|
||||||
max_part_size => maps:get(max_part_size, UploaderConfig, ?DEFAULT_MAX_PART_SIZE),
|
max_part_size => maps:get(max_part_size, Config, ?DEFAULT_MAX_PART_SIZE),
|
||||||
upload_id => undefined,
|
upload_id => undefined,
|
||||||
etags => [],
|
etags => [],
|
||||||
part_number => 1
|
part_number => 1
|
||||||
|
@ -221,8 +221,8 @@ maybe_start_upload(#{buffer_size := BufferSize, min_part_size := MinPartSize} =
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec start_upload(data()) -> {started, data()} | {error, term()}.
|
-spec start_upload(data()) -> {started, data()} | {error, term()}.
|
||||||
start_upload(#{client := Client, key := Key, headers := Headers} = Data) ->
|
start_upload(#{client := Client, key := Key, upload_opts := UploadOpts} = Data) ->
|
||||||
case emqx_s3_client:start_multipart(Client, Headers, Key) of
|
case emqx_s3_client:start_multipart(Client, Key, UploadOpts) of
|
||||||
{ok, UploadId} ->
|
{ok, UploadId} ->
|
||||||
NewData = Data#{upload_id => UploadId},
|
NewData = Data#{upload_id => UploadId},
|
||||||
{started, NewData};
|
{started, NewData};
|
||||||
|
@ -274,12 +274,9 @@ complete_upload(
|
||||||
} = Data0
|
} = Data0
|
||||||
) ->
|
) ->
|
||||||
case upload_part(Data0) of
|
case upload_part(Data0) of
|
||||||
{ok, #{etags := ETags} = Data1} ->
|
{ok, #{etags := ETagsRev} = Data1} ->
|
||||||
case
|
ETags = lists:reverse(ETagsRev),
|
||||||
emqx_s3_client:complete_multipart(
|
case emqx_s3_client:complete_multipart(Client, Key, UploadId, ETags) of
|
||||||
Client, Key, UploadId, lists:reverse(ETags)
|
|
||||||
)
|
|
||||||
of
|
|
||||||
ok ->
|
ok ->
|
||||||
{ok, Data1};
|
{ok, Data1};
|
||||||
{error, _} = Error ->
|
{error, _} = Error ->
|
||||||
|
@ -309,11 +306,11 @@ put_object(
|
||||||
#{
|
#{
|
||||||
client := Client,
|
client := Client,
|
||||||
key := Key,
|
key := Key,
|
||||||
buffer := Buffer,
|
upload_opts := UploadOpts,
|
||||||
headers := Headers
|
buffer := Buffer
|
||||||
}
|
}
|
||||||
) ->
|
) ->
|
||||||
case emqx_s3_client:put_object(Client, Headers, Key, Buffer) of
|
case emqx_s3_client:put_object(Client, Key, UploadOpts, Buffer) of
|
||||||
ok ->
|
ok ->
|
||||||
ok;
|
ok;
|
||||||
{error, _} = Error ->
|
{error, _} = Error ->
|
||||||
|
@ -337,5 +334,5 @@ unwrap(WrappedData) ->
|
||||||
is_valid_part(WriteData, #{max_part_size := MaxPartSize, buffer_size := BufferSize}) ->
|
is_valid_part(WriteData, #{max_part_size := MaxPartSize, buffer_size := BufferSize}) ->
|
||||||
BufferSize + iolist_size(WriteData) =< MaxPartSize.
|
BufferSize + iolist_size(WriteData) =< MaxPartSize.
|
||||||
|
|
||||||
client(Config) ->
|
client(Bucket, Config) ->
|
||||||
emqx_s3_client:create(Config).
|
emqx_s3_client:create(Bucket, Config).
|
||||||
|
|
|
@ -79,7 +79,7 @@ t_multipart_upload(Config) ->
|
||||||
|
|
||||||
Client = client(Config),
|
Client = client(Config),
|
||||||
|
|
||||||
{ok, UploadId} = emqx_s3_client:start_multipart(Client, Key),
|
{ok, UploadId} = emqx_s3_client:start_multipart(Client, Key, #{}),
|
||||||
|
|
||||||
Data = data(6_000_000),
|
Data = data(6_000_000),
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ t_simple_put(Config) ->
|
||||||
|
|
||||||
Data = data(6_000_000),
|
Data = data(6_000_000),
|
||||||
|
|
||||||
ok = emqx_s3_client:put_object(Client, Key, Data).
|
ok = emqx_s3_client:put_object(Client, Key, #{acl => private}, Data).
|
||||||
|
|
||||||
t_list(Config) ->
|
t_list(Config) ->
|
||||||
Key = ?config(key, Config),
|
Key = ?config(key, Config),
|
||||||
|
@ -123,7 +123,7 @@ t_url(Config) ->
|
||||||
Key = ?config(key, Config),
|
Key = ?config(key, Config),
|
||||||
|
|
||||||
Client = client(Config),
|
Client = client(Config),
|
||||||
ok = emqx_s3_client:put_object(Client, Key, <<"data">>),
|
ok = emqx_s3_client:put_object(Client, Key, #{acl => public_read}, <<"data">>),
|
||||||
|
|
||||||
Url = emqx_s3_client:uri(Client, Key),
|
Url = emqx_s3_client:uri(Client, Key),
|
||||||
|
|
||||||
|
@ -135,20 +135,18 @@ t_url(Config) ->
|
||||||
t_no_acl(Config) ->
|
t_no_acl(Config) ->
|
||||||
Key = ?config(key, Config),
|
Key = ?config(key, Config),
|
||||||
|
|
||||||
ClientConfig = emqx_s3_profile_conf:client_config(
|
Client = client(Config),
|
||||||
profile_config(Config), ?config(ehttpc_pool_name, Config)
|
|
||||||
),
|
|
||||||
Client = emqx_s3_client:create(maps:without([acl], ClientConfig)),
|
|
||||||
|
|
||||||
ok = emqx_s3_client:put_object(Client, Key, <<"data">>).
|
ok = emqx_s3_client:put_object(Client, Key, #{}, <<"data">>).
|
||||||
|
|
||||||
t_extra_headers(Config0) ->
|
t_extra_headers(Config0) ->
|
||||||
Config = [{extra_headers, #{'Content-Type' => <<"application/json">>}} | Config0],
|
Config = [{extra_headers, #{'Content-Type' => <<"application/json">>}} | Config0],
|
||||||
Key = ?config(key, Config),
|
Key = ?config(key, Config),
|
||||||
|
|
||||||
Client = client(Config),
|
Client = client(Config),
|
||||||
|
Opts = #{acl => public_read},
|
||||||
Data = #{foo => bar},
|
Data = #{foo => bar},
|
||||||
ok = emqx_s3_client:put_object(Client, Key, emqx_utils_json:encode(Data)),
|
ok = emqx_s3_client:put_object(Client, Key, Opts, emqx_utils_json:encode(Data)),
|
||||||
|
|
||||||
Url = emqx_s3_client:uri(Client, Key),
|
Url = emqx_s3_client:uri(Client, Key),
|
||||||
|
|
||||||
|
@ -164,10 +162,11 @@ t_extra_headers(Config0) ->
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
client(Config) ->
|
client(Config) ->
|
||||||
|
Bucket = ?config(bucket, Config),
|
||||||
ClientConfig = emqx_s3_profile_conf:client_config(
|
ClientConfig = emqx_s3_profile_conf:client_config(
|
||||||
profile_config(Config), ?config(ehttpc_pool_name, Config)
|
profile_config(Config), ?config(ehttpc_pool_name, Config)
|
||||||
),
|
),
|
||||||
emqx_s3_client:create(ClientConfig).
|
emqx_s3_client:create(Bucket, ClientConfig).
|
||||||
|
|
||||||
profile_config(Config) ->
|
profile_config(Config) ->
|
||||||
ProfileConfig0 = emqx_s3_test_helpers:base_config(?config(conn_type, Config)),
|
ProfileConfig0 = emqx_s3_test_helpers:base_config(?config(conn_type, Config)),
|
||||||
|
@ -175,7 +174,6 @@ profile_config(Config) ->
|
||||||
fun inject_config/3,
|
fun inject_config/3,
|
||||||
ProfileConfig0,
|
ProfileConfig0,
|
||||||
#{
|
#{
|
||||||
bucket => ?config(bucket, Config),
|
|
||||||
[transport_options, pool_type] => ?config(pool_type, Config),
|
[transport_options, pool_type] => ?config(pool_type, Config),
|
||||||
[transport_options, headers] => ?config(extra_headers, Config)
|
[transport_options, headers] => ?config(extra_headers, Config)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ end_per_testcase(_TestCase, _Config) ->
|
||||||
t_regular_outdated_pool_cleanup(Config) ->
|
t_regular_outdated_pool_cleanup(Config) ->
|
||||||
_ = process_flag(trap_exit, true),
|
_ = process_flag(trap_exit, true),
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
[OldPool] = emqx_s3_profile_http_pools:all(profile_id()),
|
[OldPool] = emqx_s3_profile_http_pools:all(profile_id()),
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ t_timeout_pool_cleanup(Config) ->
|
||||||
|
|
||||||
%% Start uploader
|
%% Start uploader
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
ok = emqx_s3_uploader:write(Pid, <<"data">>),
|
ok = emqx_s3_uploader:write(Pid, <<"data">>),
|
||||||
|
|
||||||
[OldPool] = emqx_s3_profile_http_pools:all(profile_id()),
|
[OldPool] = emqx_s3_profile_http_pools:all(profile_id()),
|
||||||
|
|
|
@ -133,7 +133,7 @@ end_per_testcase(_TestCase, _Config) ->
|
||||||
|
|
||||||
t_happy_path_simple_put(Config) ->
|
t_happy_path_simple_put(Config) ->
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ t_happy_path_simple_put(Config) ->
|
||||||
|
|
||||||
t_happy_path_multi(Config) ->
|
t_happy_path_multi(Config) ->
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ t_signed_nonascii_url_download(_Config) ->
|
||||||
|
|
||||||
t_abort_multi(Config) ->
|
t_abort_multi(Config) ->
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ t_abort_multi(Config) ->
|
||||||
|
|
||||||
t_abort_simple_put(_Config) ->
|
t_abort_simple_put(_Config) ->
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -278,7 +278,7 @@ t_abort_simple_put(_Config) ->
|
||||||
t_config_switch(Config) ->
|
t_config_switch(Config) ->
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
OldBucket = ?config(bucket, Config),
|
OldBucket = ?config(bucket, Config),
|
||||||
{ok, Pid0} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid0} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
[Data0, Data1] = data($a, 6 * 1024 * 1024, 2),
|
[Data0, Data1] = data($a, 6 * 1024 * 1024, 2),
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ t_config_switch(Config) ->
|
||||||
),
|
),
|
||||||
|
|
||||||
%% Now check that new uploader uses new config
|
%% Now check that new uploader uses new config
|
||||||
{ok, Pid1} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid1} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
ok = emqx_s3_uploader:write(Pid1, Data0),
|
ok = emqx_s3_uploader:write(Pid1, Data0),
|
||||||
ok = emqx_s3_uploader:complete(Pid1),
|
ok = emqx_s3_uploader:complete(Pid1),
|
||||||
|
|
||||||
|
@ -318,7 +318,7 @@ t_config_switch(Config) ->
|
||||||
t_config_switch_http_settings(Config) ->
|
t_config_switch_http_settings(Config) ->
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
OldBucket = ?config(bucket, Config),
|
OldBucket = ?config(bucket, Config),
|
||||||
{ok, Pid0} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid0} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
[Data0, Data1] = data($a, 6 * 1024 * 1024, 2),
|
[Data0, Data1] = data($a, 6 * 1024 * 1024, 2),
|
||||||
|
|
||||||
|
@ -345,7 +345,7 @@ t_config_switch_http_settings(Config) ->
|
||||||
),
|
),
|
||||||
|
|
||||||
%% Now check that new uploader uses new config
|
%% Now check that new uploader uses new config
|
||||||
{ok, Pid1} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid1} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
ok = emqx_s3_uploader:write(Pid1, Data0),
|
ok = emqx_s3_uploader:write(Pid1, Data0),
|
||||||
ok = emqx_s3_uploader:complete(Pid1),
|
ok = emqx_s3_uploader:complete(Pid1),
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ t_start_multipart_error(Config) ->
|
||||||
_ = process_flag(trap_exit, true),
|
_ = process_flag(trap_exit, true),
|
||||||
|
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -386,7 +386,7 @@ t_upload_part_error(Config) ->
|
||||||
_ = process_flag(trap_exit, true),
|
_ = process_flag(trap_exit, true),
|
||||||
|
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ t_abort_multipart_error(Config) ->
|
||||||
_ = process_flag(trap_exit, true),
|
_ = process_flag(trap_exit, true),
|
||||||
|
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -442,7 +442,7 @@ t_complete_multipart_error(Config) ->
|
||||||
_ = process_flag(trap_exit, true),
|
_ = process_flag(trap_exit, true),
|
||||||
|
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -470,7 +470,7 @@ t_put_object_error(Config) ->
|
||||||
_ = process_flag(trap_exit, true),
|
_ = process_flag(trap_exit, true),
|
||||||
|
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -496,7 +496,7 @@ t_put_object_error(Config) ->
|
||||||
|
|
||||||
t_too_large(Config) ->
|
t_too_large(Config) ->
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -533,7 +533,7 @@ t_tls_error(Config) ->
|
||||||
),
|
),
|
||||||
ok = emqx_s3:update_profile(profile_id(), ProfileConfig),
|
ok = emqx_s3:update_profile(profile_id(), ProfileConfig),
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
@ -553,7 +553,7 @@ t_no_profile(_Config) ->
|
||||||
Key = emqx_s3_test_helpers:unique_key(),
|
Key = emqx_s3_test_helpers:unique_key(),
|
||||||
?assertMatch(
|
?assertMatch(
|
||||||
{error, profile_not_found},
|
{error, profile_not_found},
|
||||||
emqx_s3:start_uploader(<<"no-profile">>, #{key => Key})
|
emqx_s3:start_uploader(<<"no-profile">>, Key, #{})
|
||||||
).
|
).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
@ -572,7 +572,7 @@ list_objects(Config) ->
|
||||||
proplists:get_value(contents, Props).
|
proplists:get_value(contents, Props).
|
||||||
|
|
||||||
upload(Key, ChunkSize, ChunkCount) ->
|
upload(Key, ChunkSize, ChunkCount) ->
|
||||||
{ok, Pid} = emqx_s3:start_uploader(profile_id(), #{key => Key}),
|
{ok, Pid} = emqx_s3:start_uploader(profile_id(), Key, #{}),
|
||||||
|
|
||||||
_ = erlang:monitor(process, Pid),
|
_ = erlang:monitor(process, Pid),
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue