Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge remote-tracking branch 'refs/remotes/wagerlabs/master'

  • Loading branch information...
commit f1029228451128cc1bea8e20c0ad41df1235ec52 2 parents cf9e23a + 930177a
@gleber gleber authored
View
4 include/erlcloud.hrl
@@ -1,2 +1,2 @@
--type(proplist() :: [{atom(), term()}]).
--type(datetime() :: {{pos_integer(), 1..12, 1..31}, {0..23, 0..59, 0..60}}).
+-type proplist() :: proplists:proplist().
+-type datetime() :: {{pos_integer(), 1..12, 1..31}, {0..23, 0..59, 0..60}}.
View
1  include/erlcloud_aws.hrl
@@ -5,6 +5,7 @@
elb_host="elasticloadbalancing.amazonaws.com"::string(),
sqs_host="queue.amazonaws.com"::string(),
mturk_host="mechanicalturk.amazonaws.com"::string(),
+ mon_host="monitoring.amazonaws.com"::string(),
access_key_id::string(),
secret_access_key::string()
}).
View
70 include/erlcloud_mon.hrl
@@ -0,0 +1,70 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% File: erlcloud_mon.hrl
+%% Date: 18-Sep-2011
+%%
+%% @doc AWS CloudWatch erlang binding (the CLI SDK uses "mon_" prefix)
+%%
+%% @author Zvi Avraham <zvi-AT-nivertech-DOT-com>
+%% @copyright 2011 Zvi Avraham
+%% @end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%------------------------------------------------------------------------------
+%% @doc date time
+%% @end
+%%------------------------------------------------------------------------------
+%-type datetime() :: string().
+
+%%------------------------------------------------------------------------------
+%% @doc The unit of the metric.
+%% Valid Values: Seconds | Microseconds | Milliseconds
+%% | Bytes | Kilobytes | Megabytes | Gigabytes | Terabytes | Bits | Kilobits | Megabits | Gigabits | Terabits
+%% | Percent | Count | Bytes/Second | Kilobytes/Second | Megabytes/Second | Gigabytes/Second | Terabytes/Second
+%% | Bits/Second | Kilobits/Second | Megabits/Second | Gigabits/Second | Terabits/Second | Count/Second | None
+%% @end
+%%------------------------------------------------------------------------------
+-type unit() :: string().
+
+%%------------------------------------------------------------------------------
+%% @doc Dimension
+%% The Dimension data type further expands on the identity of a metric using a Name, Value pair.
+%% For examples that use one or more dimensions, see PutMetricData.
+%% @see[ http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/index.html?API_Dimension.html ]
+%% @end
+%%------------------------------------------------------------------------------
+-record(dimension, {
+ name ::string(), %% The name of the dimension. Length constraints: Minimum value of 1. Maximum value of 255.
+ value ::string() %% The value representing the dimension measurement. Length constraints: Minimum value of 1. Maximum value of 255.
+}).
+-type dimension() :: #dimension{}.
+
+%%------------------------------------------------------------------------------
+%% @doc StatisticSet
+%% @see[ http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/index.html?API_StatisticSet.html ]
+%% @end
+%%------------------------------------------------------------------------------
+-record(statistic_set, {
+ sample_count ::non_neg_integer(), %% The number of samples used for the statistic set.
+ maximum ::float(), %% The maximum value of the sample set.
+ minimum ::float(), %% The minimum value of the sample set.
+ sum ::float() %% The sum of values for the sample set.
+}).
+-type statistic_set() :: #statistic_set{}.
+
+%%------------------------------------------------------------------------------
+%% @doc MetricDatum
+%% @see[ http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/index.html?API_MetricDatum.html ]
+%% @end
+%%------------------------------------------------------------------------------
+-record(metric_datum, {
+ metric_name ::string(), %% The name of the metric.
+ %% Length constraints: Minimum value of 1. Maximum value of 255.
+ dimensions ::[dimension()], %% A list of dimensions associated with the metric.
+ %% Length constraints: Minimum of 0 item(s) in the list. Maximum of 10 item(s) in the list.
+ statistic_values::statistic_set(), %% A set of statistical values describing the metric.
+ timestamp ::datetime()|string(),%% The time stamp used for the metric. If not specified, the default value is set to the time the metric data was received.
+ unit ::unit(), %% The unit of the metric.
+ value ::float() %% The value for the metric.
+}).
+-type metric_datum() :: #metric_datum{}.
+
View
17 src/erlcloud.app.src
@@ -1,11 +1,18 @@
+%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
+%% ex: ts=4 sw=4 ft=erlang et
+
{application, erlcloud,
[{description, "Erlang cloud computing library"},
- {vsn, "0.3.0"},
- {modules, [erlcloud, erlcloud_aws, erlcloud_ec2, erlcloud_http,
- erlcloud_mturk, erlcloud_s3, erlcloud_sdb, erlcloud_sqs,
- erlcloud_elb, erlcloud_xml]},
+ {vsn, git},
{registered, []},
- {applications, [stdlib, kernel, sasl, crypto, ssl, xmerl, inets]},
+ {applications, [stdlib,
+ kernel,
+ sasl,
+ crypto,
+ ssl,
+ xmerl,
+ inets]},
+ {modules, []},
{env, []}
]
}.
View
11 src/erlcloud_aws.erl
@@ -6,6 +6,7 @@
aws_request_xml(Method, Host, Path, Params, AccessKeyID, SecretAccessKey) ->
Body = aws_request(Method, Host, Path, Params, AccessKeyID, SecretAccessKey),
+ %io:format("Body = ~p~n", [Body]),
element(1, xmerl_scan:string(Body)).
aws_request(Method, Host, Path, Params, AccessKeyID, SecretAccessKey) ->
@@ -28,10 +29,10 @@ aws_request(Method, Host, Path, Params, AccessKeyID, SecretAccessKey) ->
case Method of
get ->
Req = lists:flatten([URL, $?, Query]),
- io:format("Req: >~s<~n", [Req]),
- http:request(Req);
+ %io:format("Req: >~s<~n", [Req]),
+ httpc:request(Req);
_ ->
- http:request(Method,
+ httpc:request(Method,
{lists:flatten(URL), [], "application/x-www-form-urlencoded",
list_to_binary(Query)}, [], [])
end,
@@ -77,8 +78,8 @@ format_timestamp({{Yr, Mo, Da}, {H, M, S}}) ->
default_config() ->
case get(aws_config) of
undefined ->
- #aws_config{access_key_id=os:getenv("AMAZON_ACCESS_KEY_ID"),
- secret_access_key=os:getenv("AMAZON_SECRET_ACCESS_KEY")};
+ #aws_config{access_key_id=os:getenv("AWS_ACCESS_KEY_ID"),
+ secret_access_key=os:getenv("AWS_SECRET_ACCESS_KEY")};
Config ->
Config
end.
View
288 src/erlcloud_mon.erl
@@ -0,0 +1,288 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% File: erlcloud_mon.erl
+%% Date: 14-Sep-2011
+%%
+%% @doc AWS CloudWatch erlang binding (the CLI SDK uses "mon_" prefix)
+%%
+%% @author Zvi Avraham <zvi-AT-nivertech-DOT-com>
+%% @copyright 2011 Zvi Avraham
+%% @end
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-module(erlcloud_mon).
+
+-export([
+ list_metrics/4,
+ put_metric_data/2,
+ put_metric_data/5,
+ get_metric_statistics/8,
+ test/0,
+ test2/0
+]).
+
+-include("erlcloud.hrl").
+-include("erlcloud_aws.hrl").
+-include("erlcloud_mon.hrl").
+-include_lib("xmerl/include/xmerl.hrl").
+
+-import(erlcloud_xml, [get_text/1, get_text/2, get_text/3, get_bool/2, get_list/2, get_integer/2]).
+
+-define(XMLNS_MON, "http://monitoring.amazonaws.com/doc/2010-08-01/").
+-define(API_VERSION, "2010-08-01").
+
+-define(FMT(Fmt,Args), lists:flatten(io_lib:format((Fmt),(Args)))).
+
+%%------------------------------------------------------------------------------
+%% @doc CloudWatch API - ListMetrics
+%% @see [ http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/index.html?API_ListMetrics.html ]
+%%
+%% USAGE:
+%%
+%% erlcloud_mon:list_metrics("AWS/EC2", "NetworkIn", [{"InstanceType","m1.large"}], "").
+%% [[{metric_name,"NetworkIn"},
+%% {namespace,"AWS/EC2"},
+%% {dimensions,[[{name,"InstanceType"},{value,"m1.large"}]]}]]
+%%
+%% @end
+%%------------------------------------------------------------------------------
+-spec list_metrics(
+ Namespace ::string(),
+ MetricName ::string(),
+ DimensionFilter ::[{string(),string()}],
+ NextToken ::string()
+ ) -> term().
+
+list_metrics(
+ Namespace,
+ MetricName,
+ DimensionFilter,
+ NextToken
+ ) ->
+
+ Config = default_config(),
+ Params =
+ [{"Namespace", Namespace} || Namespace/=""]
+ ++
+ [{"MetricName", MetricName} || MetricName/=""]
+ ++
+ [{"NextToken", NextToken} || NextToken/=""]
+ ++
+ lists:flatten(
+ [begin
+ {Name, Value} = lists:nth(N, DimensionFilter),
+ [{?FMT("Dimensions.member.~b.Name", [N]), Name},
+ {?FMT("Dimensions.member.~b.Value", [N]), Value}]
+ end
+ || N<-lists:seq(1, length(DimensionFilter))]
+ ),
+
+ Doc = mon_query(Config, "ListMetrics", Params),
+ Members = xmerl_xpath:string("/ListMetricsResponse/ListMetricsResult/Metrics/member", Doc),
+ [extract_member(Member) || Member <- Members].
+
+extract_member(Node) ->
+ [
+ {metric_name, get_text("MetricName", Node)},
+ {namespace, get_text("Namespace", Node)},
+ {dimensions,
+ [extract_dimension(Item) || Item <- xmerl_xpath:string("Dimensions/member", Node)]
+ }
+ ].
+
+extract_dimension(Node) ->
+ [
+ {name, get_text("Name", Node)},
+ {value, get_text("Value", Node)}
+ ].
+
+%%------------------------------------------------------------------------------
+%% @doc CloudWatch API - PutMetricData
+%% @see [ http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/index.html?API_PutMetricData.html ]
+%%
+%% &MetricData.member.1.MetricName=buffers
+%% &MetricData.member.1.Unit=Bytes
+%% &MetricData.member.1.Value=231434333
+%% &MetricData.member.1.Dimensions.member.1.Name=InstanceID
+%% &MetricData.member.1.Dimensions.member.1.Value=i-aaba32d4
+%% &MetricData.member.1.Dimensions.member.2.Name=InstanceType
+%% &MetricData.member.1.Dimensions.member.2.Value=m1.small
+%% &MetricData.member.2.MetricName=latency
+%% &MetricData.member.2.Unit=Milliseconds
+%% &MetricData.member.2.Value=23
+%% &MetricData.member.2.Dimensions.member.1.Name=InstanceID
+%% &MetricData.member.2.Dimensions.member.1.Value=i-aaba32d4
+%% &MetricData.member.2.Dimensions.member.2.Name=InstanceType
+%% &MetricData.member.2.Dimensions.member.2.Value=m1.small
+%%
+%% @end
+%%------------------------------------------------------------------------------
+-spec put_metric_data(
+ Namespace ::string(),
+ MetricData ::[metric_datum()]
+ ) -> term().
+
+put_metric_data(Namespace, MetricData) ->
+ Config = default_config(),
+ Params =
+ [
+ {"Namespace", Namespace} |
+ lists:flatten(
+ [ params_metric_data(N,MD) || {N,MD} <- lists:zip(lists:seq(1,length(MetricData)), MetricData) ]
+ )
+ ],
+ mon_query(Config, "PutMetricData", Params).
+
+%%------------------------------------------------------------------------------
+-spec params_metric_data(NM::pos_integer(), MD::metric_datum()) -> [{string(),string()}].
+params_metric_data(NM,MD) ->
+ %% TODO - check case when both Value and statistics specified or both undefined
+ Prefix = ?FMT("MetricData.member.~b", [NM]),
+ lists:flatten(
+ [
+ [ {Prefix++".MetricName", MD#metric_datum.metric_name} ],
+ [ {Prefix++".Unit", MD#metric_datum.unit} || MD#metric_datum.unit=/=undefined ],
+ [ {Prefix++".Timestamp", format_timestamp(MD#metric_datum.timestamp)}|| MD#metric_datum.timestamp=/=undefined ],
+ [ {Prefix++".Value", float_to_list(MD#metric_datum.value)} || MD#metric_datum.value=/=undefined ],
+ [ params_stat(Prefix, MD#metric_datum.statistic_values) || MD#metric_datum.statistic_values=/=undefined ],
+ [ params_dimension(Prefix, ND, Dimension)
+ || {ND,Dimension} <- lists:zip(lists:seq(1, length(MD#metric_datum.dimensions)), MD#metric_datum.dimensions)
+ ]
+ ]
+ ).
+
+%%------------------------------------------------------------------------------
+%% @doc format datetime as Amazon timestamp
+%% @end
+%%------------------------------------------------------------------------------
+format_timestamp({{Yr, Mo, Da}, {H, M, S}} = Timestamp)
+ when is_integer(Yr), is_integer(Mo), is_integer(Da),
+ is_integer(H), is_integer(M), is_integer(S)
+ ->
+ erlcloud_aws:format_timestamp(Timestamp);
+
+format_timestamp(Timestamp) when is_list(Timestamp) ->
+ Timestamp.
+
+%%------------------------------------------------------------------------------
+-spec params_dimension(Prefix::string(), ND::pos_integer(), Dimension::dimension()) -> [{string(),string()}].
+params_dimension(Prefix, ND, Dimension) ->
+ DimPrefix = ?FMT("~s.Dimensions.member.~b", [Prefix, ND]),
+ [
+ {DimPrefix++".Name", Dimension#dimension.name},
+ {DimPrefix++".Value", Dimension#dimension.value}
+ ].
+
+%%------------------------------------------------------------------------------
+%% @doc format statistic value records to URI params
+%% @end
+%%------------------------------------------------------------------------------
+-spec params_stat(Prefix::string(), StatisticValues::statistic_set()) -> [{string(),string()}].
+params_stat(Prefix, StatisticValues) ->
+ [
+ {Prefix++".StatisticValues.Maximum", float_to_list(StatisticValues#statistic_set.maximum)},
+ {Prefix++".StatisticValues.Minimum", float_to_list(StatisticValues#statistic_set.maximum)},
+ {Prefix++".StatisticValues.Sum", float_to_list(StatisticValues#statistic_set.sum)},
+ {Prefix++".StatisticValues.SampleCount",integer_to_list(StatisticValues#statistic_set.sample_count)}
+ ].
+
+%%------------------------------------------------------------------------------
+%% @doc CloudWatch API - PutMetricData
+%% @see [ http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/index.html?API_PutMetricData.html ]
+%% @end
+%%------------------------------------------------------------------------------
+-spec put_metric_data(
+ Namespace ::string(),
+ MetricName ::string(),
+ Value ::string(),
+ Unit ::unit(),
+ Timestamp ::datetime()|string()
+ ) -> term().
+
+put_metric_data(Namespace, MetricName, Value, Unit, Timestamp) ->
+ Config = default_config(),
+ Params =
+ lists:flatten(
+ [
+ {"Namespace", Namespace},
+ {"MetricData.member.1.MetricName", MetricName},
+ {"MetricData.member.1.Value", Value},
+ [ {"MetricData.member.1.Unit", Unit} || Unit=/=undefined, Unit=/="" ],
+ [ {"MetricData.member.1.Timestamp", format_timestamp(Timestamp)} || Timestamp=/=undefined, Timestamp=/="" ]
+ ]
+ ),
+ mon_simple_query(Config, "PutMetricData", Params).
+
+%%------------------------------------------------------------------------------
+%% @doc CloudWatch API - GetMetricStatistics
+%% @see [ http://docs.amazonwebservices.com/AmazonCloudWatch/latest/APIReference/index.html?API_GetMetricStatistics.html ]
+%% @end
+%%------------------------------------------------------------------------------
+-spec get_metric_statistics(
+ Namespace ::string(),
+ MetricName ::string(),
+ StartTime ::string(),
+ EndTime ::string(),
+ Period ::pos_integer(),
+ Unit ::string(),
+ Statistics ::[string()],
+ Dimensions ::[string()]
+ ) -> term().
+
+get_metric_statistics(
+ Namespace,
+ MetricName,
+ StartTime,
+ EndTime,
+ Period,
+ Unit,
+ Statistics,
+ Dimensions
+ ) ->
+ todo.
+
+%%------------------------------------------------------------------------------
+mon_simple_query(Config, Action, Params) ->
+ mon_query(Config, Action, Params),
+ ok.
+
+mon_query(Config, Action, Params) ->
+ mon_query(Config, Action, Params, ?API_VERSION).
+
+mon_query(Config, Action, Params, ApiVersion) ->
+ QParams = [{"Action", Action}, {"Version", ApiVersion}|Params],
+ erlcloud_aws:aws_request_xml(get,
+ Config#aws_config.mon_host,
+ "/",
+ QParams,
+ Config#aws_config.access_key_id,
+ Config#aws_config.secret_access_key).
+
+default_config() -> erlcloud_aws:default_config().
+
+%%------------------------------------------------------------------------------
+%% tests
+%% TODO : convert into e-unit tests
+%%------------------------------------------------------------------------------
+test() ->
+ M1 = #metric_datum{
+ metric_name = "zvi",
+ dimensions = [],
+ statistic_values = undefined,
+ timestamp = undefined,
+ unit = "Count",
+ value = 10.0
+ },
+ M2 = #metric_datum{
+ metric_name = "zvi",
+ dimensions = [],
+ statistic_values = #statistic_set{minimum=18.0, maximum=21.4, sum=67.7, sample_count=15},
+ timestamp = undefined,
+ unit = "Count",
+ value = undefined
+ },
+ put_metric_data("my", [M1, M2]).
+ %put_metric_data("my", [M2]).
+
+test2() ->
+ put_metric_data("my", "zvi", "13", "Count", "").
+
View
2  src/erlcloud_mturk.erl
@@ -1608,7 +1608,7 @@ mturk_request(Config, Operation, Params) ->
URL = ["https://", Config#aws_config.mturk_host, "/"],
- Response = http:request(post,
+ Response = httpc:request(post,
{lists:flatten(URL), [], "application/x-www-form-urlencoded",
list_to_binary(erlcloud_http:make_query_string(QParams))}, [], []),
View
812 src/erlcloud_s3.erl
@@ -1,268 +1,306 @@
%% Amazon Simple Storage Service (S3)
-module(erlcloud_s3).
--export([
- create_bucket/1, create_bucket/2, create_bucket/3,
- delete_bucket/1, delete_bucket/2,
- get_bucket_attribute/2, get_bucket_attribute/3,
- list_buckets/0, list_buckets/1,
- set_bucket_attribute/3, set_bucket_attribute/4,
-
- list_objects/1, list_objects/2, list_objects/3,
- list_object_versions/1, list_object_versions/2, list_object_versions/3,
-
- copy_object/4, copy_object/5, copy_object/6,
- delete_object/2, delete_object/3,
- delete_object_version/3, delete_object_version/4,
- get_object/2, get_object/3,
- get_object_acl/2, get_object_acl/3, get_object_acl/4,
- get_object_torrent/2, get_object_torrent/3,
- get_object_metadata/2, get_object_metadata/3, get_object_metadata/4,
- put_object/3, put_object/4, put_object/5, put_object/6,
- set_object_acl/3, set_object_acl/4
-]).
+-export([new/2, new/3, configure/2, configure/3,
+ create_bucket/1, create_bucket/2, create_bucket/3,
+ delete_bucket/1, delete_bucket/2,
+ get_bucket_attribute/2, get_bucket_attribute/3,
+ list_buckets/0, list_buckets/1,
+ set_bucket_attribute/3, set_bucket_attribute/4,
+ list_objects/1, list_objects/2, list_objects/3,
+ list_object_versions/1, list_object_versions/2, list_object_versions/3,
+ copy_object/4, copy_object/5, copy_object/6,
+ delete_object/2, delete_object/3,
+ delete_object_version/3, delete_object_version/4,
+ get_object/2, get_object/3,
+ get_object_acl/2, get_object_acl/3, get_object_acl/4,
+ get_object_torrent/2, get_object_torrent/3,
+ get_object_metadata/2, get_object_metadata/3, get_object_metadata/4,
+ put_object/3, put_object/4, put_object/5, put_object/6,
+ set_object_acl/3, set_object_acl/4]).
-include("erlcloud.hrl").
-include("erlcloud_aws.hrl").
-include_lib("xmerl/include/xmerl.hrl").
--type(s3_bucket_attribute_name() :: acl | location | logging | request_payment | versioning).
--type(s3_bucket_acl() :: private | public_read | public_read_write | authenticated_read | bucket_owner_read | bucket_owner_full_control).
--type(s3_location_constraint() :: none | us_west_1 | eu).
+-spec new(string(), string()) -> aws_config().
+
+new(AccessKeyID, SecretAccessKey) ->
+ #aws_config{
+ access_key_id=AccessKeyID,
+ secret_access_key=SecretAccessKey
+ }.
+
+-spec new(string(), string(), string()) -> aws_config().
+
+new(AccessKeyID, SecretAccessKey, Host) ->
+ #aws_config{
+ access_key_id=AccessKeyID,
+ secret_access_key=SecretAccessKey,
+ ec2_host=Host
+ }.
+
+-spec configure(string(), string()) -> ok.
+
+configure(AccessKeyID, SecretAccessKey) ->
+ put(aws_config, new(AccessKeyID, SecretAccessKey)),
+ ok.
+
+-spec configure(string(), string(), string()) -> ok.
+
+configure(AccessKeyID, SecretAccessKey, Host) ->
+ put(aws_config, new(AccessKeyID, SecretAccessKey, Host)),
+ ok.
+
+-type s3_bucket_attribute_name() :: acl
+ | location
+ | logging
+ | request_payment
+ | versioning.
+
+-type s3_bucket_acl() :: private
+ | public_read
+ | public_read_write
+ | authenticated_read
+ | bucket_owner_read
+ | bucket_owner_full_control.
+
+-type s3_location_constraint() :: none
+ | us_west_1
+ | eu.
-define(XMLNS_S3, "http://s3.amazonaws.com/doc/2006-03-01/").
--spec copy_object/4 :: (string(), string(), string(), string()) -> proplist().
+-spec copy_object(string(), string(), string(), string()) -> proplist().
+
copy_object(DestBucketName, DestKeyName, SrcBucketName, SrcKeyName) ->
copy_object(DestBucketName, DestKeyName, SrcBucketName, SrcKeyName, []).
--spec copy_object/5 :: (string(), string(), string(), string(), proplist() | aws_config()) -> proplist().
+-spec copy_object(string(), string(), string(), string(), proplist() | aws_config()) -> proplist().
+
copy_object(DestBucketName, DestKeyName, SrcBucketName, SrcKeyName, Config)
when is_record(Config, aws_config) ->
copy_object(DestBucketName, DestKeyName, SrcBucketName, SrcKeyName, [], Config);
+
copy_object(DestBucketName, DestKeyName, SrcBucketName, SrcKeyName, Options) ->
copy_object(DestBucketName, DestKeyName, SrcBucketName, SrcKeyName,
Options, default_config()).
--spec copy_object/6 :: (string(), string(), string(), string(), proplist(), aws_config()) -> proplist().
+-spec copy_object(string(), string(), string(), string(), proplist(), aws_config()) -> proplist().
copy_object(DestBucketName, DestKeyName, SrcBucketName, SrcKeyName, Options, Config) ->
SrcVersion = case proplists:get_value(version_id, Options) of
- undefined -> "";
- VersionID -> ["?versionId=", VersionID]
- end,
- RequestHeaders = [
- {"x-amz-copy-source", [SrcBucketName, $/, SrcKeyName, SrcVersion]},
- {"x-amz-metadata-directive", proplists:get_value(metadata_directive, Options)},
- {"x-amz-copy-source-if-match", proplists:get_value(if_match, Options)},
- {"x-amz-copy-source-if-none-match", proplists:get_value(if_none_match, Options)},
- {"x-amz-copy-source-if-unmodified-since", proplists:get_value(if_unmodified_since, Options)},
- {"x-amz-copy-source-if-modified-since", proplists:get_value(if_modified_since, Options)},
- {"x-amz-acl", encode_acl(proplists:get_value(acl, Options))}
- ],
+ undefined -> "";
+ VersionID -> ["?versionId=", VersionID]
+ end,
+ RequestHeaders =
+ [{"x-amz-copy-source", [SrcBucketName, $/, SrcKeyName, SrcVersion]},
+ {"x-amz-metadata-directive", proplists:get_value(metadata_directive, Options)},
+ {"x-amz-copy-source-if-match", proplists:get_value(if_match, Options)},
+ {"x-amz-copy-source-if-none-match", proplists:get_value(if_none_match, Options)},
+ {"x-amz-copy-source-if-unmodified-since", proplists:get_value(if_unmodified_since, Options)},
+ {"x-amz-copy-source-if-modified-since", proplists:get_value(if_modified_since, Options)},
+ {"x-amz-acl", encode_acl(proplists:get_value(acl, Options))}],
{Headers, _Body} = s3_request(Config, put, DestBucketName, [$/|DestKeyName],
- "", [], <<>>, RequestHeaders),
- [
- {copy_source_version_id, proplists:get_value("x-amz-copy-source-version-id", Headers, "false")},
- {version_id, proplists:get_value("x-amz-version-id", Headers, "null")}
- ].
+ "", [], <<>>, RequestHeaders),
+ [{copy_source_version_id, proplists:get_value("x-amz-copy-source-version-id", Headers, "false")},
+ {version_id, proplists:get_value("x-amz-version-id", Headers, "null")}].
+
+-spec create_bucket(string()) -> ok.
--spec create_bucket/1 :: (string()) -> ok.
create_bucket(BucketName) ->
create_bucket(BucketName, private).
--spec create_bucket/2 :: (string(), s3_bucket_acl() | aws_config()) -> ok.
+-spec create_bucket(string(), s3_bucket_acl() | aws_config()) -> ok.
+
create_bucket(BucketName, Config)
when is_record(Config, aws_config) ->
create_bucket(BucketName, private, Config);
+
create_bucket(BucketName, ACL) ->
create_bucket(BucketName, ACL, none).
--spec create_bucket/3 :: (string(), s3_bucket_acl(), s3_location_constraint() | aws_config()) -> ok.
+-spec create_bucket(string(), s3_bucket_acl(), s3_location_constraint() | aws_config()) -> ok.
+
create_bucket(BucketName, ACL, Config)
when is_record(Config, aws_config) ->
create_bucket(BucketName, ACL, none, Config);
+
create_bucket(BucketName, ACL, LocationConstraint) ->
create_bucket(BucketName, ACL, LocationConstraint, default_config()).
--spec create_bucket/4 :: (string(), s3_bucket_acl(), s3_location_constraint(), aws_config()) -> ok.
+-spec create_bucket(string(), s3_bucket_acl(), s3_location_constraint(), aws_config()) -> ok.
+
create_bucket(BucketName, ACL, LocationConstraint, Config)
when is_list(BucketName), is_atom(ACL), is_atom(LocationConstraint) ->
Headers = case ACL of
- private -> []; %% private is the default
- _ -> [{"x-amz-acl", encode_acl(ACL)}]
- end,
+ private -> []; %% private is the default
+ _ -> [{"x-amz-acl", encode_acl(ACL)}]
+ end,
POSTData = case LocationConstraint of
- none -> <<>>;
- Location when Location =:= eu; Location =:= us_west_1 ->
- LocationName = case Location of eu -> "EU"; us_west_1 -> "us-west-1" end,
- XML = {'CreateBucketConfiguration', [{xmlns, ?XMLNS_S3}],
- [
- {'LocationConstraint', [LocationName]}
- ]
- },
- list_to_binary(xmerl:export_simple([XML], xmerl_xml))
- end,
+ none -> <<>>;
+ Location when Location =:= eu; Location =:= us_west_1 ->
+ LocationName = case Location of eu -> "EU"; us_west_1 -> "us-west-1" end,
+ XML = {'CreateBucketConfiguration', [{xmlns, ?XMLNS_S3}],
+ [{'LocationConstraint', [LocationName]}]},
+ list_to_binary(xmerl:export_simple([XML], xmerl_xml))
+ end,
s3_simple_request(Config, put, BucketName, "/", "", [], POSTData, Headers).
-encode_acl(undefined) -> undefined;
-encode_acl(private) -> "private";
-encode_acl(public_read) -> "public-read";
-encode_acl(public_read_write) -> "public-read-write";
-encode_acl(authenticated_read) -> "authenticated-read";
-encode_acl(bucket_owner_read) -> "bucket-owner-read";
+encode_acl(undefined) -> undefined;
+encode_acl(private) -> "private";
+encode_acl(public_read) -> "public-read";
+encode_acl(public_read_write) -> "public-read-write";
+encode_acl(authenticated_read) -> "authenticated-read";
+encode_acl(bucket_owner_read) -> "bucket-owner-read";
encode_acl(bucket_owner_full_control) -> "bucket-owner-full-control".
+-spec delete_bucket(string()) -> ok.
-
--spec delete_bucket/1 :: (string()) -> ok.
delete_bucket(BucketName) ->
delete_bucket(BucketName, default_config()).
--spec delete_bucket/2 :: (string(), aws_config()) -> ok.
+-spec delete_bucket(string(), aws_config()) -> ok.
+
delete_bucket(BucketName, Config)
when is_list(BucketName) ->
s3_simple_request(Config, delete, BucketName, "/", "", [], <<>>, []).
--spec delete_object/2 :: (string(), string()) -> proplist().
+-spec delete_object(string(), string()) -> proplist().
+
delete_object(BucketName, Key) ->
delete_object(BucketName, Key, default_config()).
--spec delete_object/3 :: (string(), string(), aws_config()) -> proplist().
+-spec delete_object(string(), string(), aws_config()) -> proplist().
+
delete_object(BucketName, Key, Config)
when is_list(BucketName), is_list(Key) ->
{Headers, _Body} = s3_request(Config, delete, BucketName, [$/|Key], "", [], <<>>, []),
- [
- {delete_marker, list_to_existing_atom(proplists:get_value("x-amz-delete-marker", Headers, "false"))},
- {version_id, proplists:get_value("x-amz-version-id", Headers, "null")}
- ].
+ Marker = proplists:get_value("x-amz-delete-marker", Headers, "false"),
+ Id = proplists:get_value("x-amz-version-id", Headers, "null"),
+ [{delete_marker, list_to_existing_atom(Marker)},
+ {version_id, Id}].
+
+-spec delete_object_version(string(), string(), string()) -> proplist().
--spec delete_object_version/3 :: (string(), string(), string()) -> proplist().
delete_object_version(BucketName, Key, Version) ->
delete_object_version(BucketName, Key, Version, default_config()).
--spec delete_object_version/4 :: (string(), string(), string(), aws_config()) -> proplist().
+-spec delete_object_version(string(), string(), string(), aws_config()) -> proplist().
+
delete_object_version(BucketName, Key, Version, Config)
- when is_list(BucketName), is_list(Key), is_list(Version)->
- {Headers, _Body} = s3_request(Config, delete, BucketName, [$/|Key], ["versionId=", Version], [], <<>>, []),
- [
- {delete_marker, list_to_existing_atom(proplists:get_value("x-amz-delete-marker", Headers, "false"))},
- {version_id, proplists:get_value("x-amz-version-id", Headers, "null")}
- ].
-
--spec list_buckets/0 :: () -> proplist().
+ when is_list(BucketName),
+ is_list(Key),
+ is_list(Version)->
+ {Headers, _Body} = s3_request(Config, delete, BucketName, [$/|Key],
+ ["versionId=", Version], [], <<>>, []),
+ Marker = proplists:get_value("x-amz-delete-marker", Headers, "false"),
+ Id = proplists:get_value("x-amz-version-id", Headers, "null"),
+ [{delete_marker, list_to_existing_atom(Marker)},
+ {version_id, Id}].
+
+-spec list_buckets() -> proplist().
+
list_buckets() ->
list_buckets(default_config()).
--spec list_buckets/1 :: (aws_config()) -> proplist().
+-spec list_buckets(aws_config()) -> proplist().
+
list_buckets(Config) ->
Doc = s3_xml_request(Config, get, "", "/", "", [], <<>>, []),
Buckets = [extract_bucket(Node) || Node <- xmerl_xpath:string("/*/Buckets/Bucket", Doc)],
[{buckets, Buckets}].
--spec list_objects/1 :: (string()) -> proplist().
+-spec list_objects(string()) -> proplist().
+
list_objects(BucketName) ->
list_objects(BucketName, []).
--spec list_objects/2 :: (string(), proplist() | aws_config()) -> proplist().
+-spec list_objects(string(), proplist() | aws_config()) -> proplist().
+
list_objects(BucketName, Config)
when is_record(Config, aws_config) ->
list_objects(BucketName, [], Config);
+
list_objects(BucketName, Options) ->
list_objects(BucketName, Options, default_config()).
--spec list_objects/3 :: (string(), proplist(), aws_config()) -> proplist().
+-spec list_objects(string(), proplist(), aws_config()) -> proplist().
+
list_objects(BucketName, Options, Config)
- when is_list(BucketName), is_list(Options) ->
- Params = [
- {"delimiter", proplists:get_value(delimiter, Options)},
- {"marker", proplists:get_value(marker, Options)},
- {"max-keys", proplists:get_value(max_keys, Options)},
- {"prefix", proplists:get_value(prefix, Options)}
- ],
+ when is_list(BucketName),
+ is_list(Options) ->
+ Params = [{"delimiter", proplists:get_value(delimiter, Options)},
+ {"marker", proplists:get_value(marker, Options)},
+ {"max-keys", proplists:get_value(max_keys, Options)},
+ {"prefix", proplists:get_value(prefix, Options)}],
Doc = s3_xml_request(Config, get, BucketName, "/", "", Params, <<>>, []),
- erlcloud_xml:decode(
- [
- {name, "Name", text},
- {prefix, "Prefix", text},
- {marker, "Marker", text},
- {delimiter, "Delimiter", text},
- {max_keys, "MaxKeys", integer},
- {is_truncated, "IsTruncated", boolean},
- {contents, "Contents", fun extract_contents/1}
- ],
- Doc
- ).
+ Attributes = [{name, "Name", text},
+ {prefix, "Prefix", text},
+ {marker, "Marker", text},
+ {delimiter, "Delimiter", text},
+ {max_keys, "MaxKeys", integer},
+ {is_truncated, "IsTruncated", boolean},
+ {contents, "Contents", fun extract_contents/1}],
+ erlcloud_xml:decode(Attributes, Doc).
extract_contents(Nodes) ->
- [erlcloud_xml:decode(
- [
- {key, "Key", text},
- {last_modified, "LastModified", time},
- {etag, "ETag", text},
- {size, "Size", integer},
- {storage_class, "StorageClass", text},
- {owner, "Owner", fun extract_user/1}
- ], Node) ||
- Node <- Nodes].
+ Attributes = [{key, "Key", text},
+ {last_modified, "LastModified", time},
+ {etag, "ETag", text},
+ {size, "Size", integer},
+ {storage_class, "StorageClass", text},
+ {owner, "Owner", fun extract_user/1}],
+ [erlcloud_xml:decode(Attributes, Node) || Node <- Nodes].
extract_user([Node]) ->
- erlcloud_xml:decode(
- [
- {id, "ID", text},
- {display_name, "DisplayName", optional_text}
- ],
- Node
- ).
-
--spec get_bucket_attribute/2 :: (string(), s3_bucket_attribute_name()) -> term().
+ Attributes = [{id, "ID", text},
+ {display_name, "DisplayName", optional_text}],
+ erlcloud_xml:decode(Attributes, Node).
+
+-spec get_bucket_attribute(string(), s3_bucket_attribute_name()) -> term().
+
get_bucket_attribute(BucketName, AttributeName) ->
get_bucket_attribute(BucketName, AttributeName, default_config()).
--spec get_bucket_attribute/3 :: (string(), s3_bucket_attribute_name(), aws_config()) -> term().
+-spec get_bucket_attribute(string(), s3_bucket_attribute_name(), aws_config()) -> term().
+
get_bucket_attribute(BucketName, AttributeName, Config)
when is_list(BucketName), is_atom(AttributeName) ->
Attr = case AttributeName of
- acl -> "acl";
- location -> "location";
- logging -> "logging";
- request_payment -> "requestPayment";
- versioning -> "versioning"
- end,
+ acl -> "acl";
+ location -> "location";
+ logging -> "logging";
+ request_payment -> "requestPayment";
+ versioning -> "versioning"
+ end,
Doc = s3_xml_request(Config, get, BucketName, "/", Attr, [], <<>>, []),
case AttributeName of
acl ->
- erlcloud_xml:decode(
- [
- {owner, "Owner", fun extract_user/1},
- {access_control_list, "AccessControlList/Grant", fun extract_acl/1}
- ],
- Doc
- );
+ Attributes = [{owner, "Owner", fun extract_user/1},
+ {access_control_list, "AccessControlList/Grant", fun extract_acl/1}],
+ erlcloud_xml:decode(Attributes, Doc);
location ->
erlcloud_xml:get_text("/LocationConstraint", Doc);
logging ->
case xmerl_xpath:string("/BucketLoggingStatus/LoggingEnabled", Doc) of
- [] -> {enabled, false};
+ [] ->
+ {enabled, false};
[LoggingEnabled] ->
- [{enabled, true}|erlcloud_xml:decode(
- [
- {target_bucket, "TargetBucket", text},
- {target_prefix, "TargetPrefix", text},
- {target_trants, "TargetGrants/Grant", fun extract_acl/1}
- ],
- LoggingEnabled
- )]
+ Attributes = [{target_bucket, "TargetBucket", text},
+ {target_prefix, "TargetPrefix", text},
+ {target_trants, "TargetGrants/Grant", fun extract_acl/1}],
+ [{enabled, true}|erlcloud_xml:decode(Attributes, LoggingEnabled)]
end;
request_payment ->
case erlcloud_xml:get_text("/RequestPaymentConfiguration/Payer", Doc) of
"Requester" -> requester;
- _ -> bucket_owner
+ _ -> bucket_owner
end;
versioning ->
case erlcloud_xml:get_text("/VersioningConfiguration/Status", Doc) of
- "Enabled" -> enabled;
+ "Enabled" -> enabled;
"Suspended" -> suspended;
- _ -> disabled
+ _ -> disabled
end
end.
@@ -270,334 +308,310 @@ extract_acl(ACL) ->
[extract_grant(Item) || Item <- ACL].
extract_grant(Node) ->
- [
- {grantee, extract_user(xmerl_xpath:string("Grantee", Node))},
- {permission, decode_permission(erlcloud_xml:get_text("Permission", Node))}
- ].
+ [{grantee, extract_user(xmerl_xpath:string("Grantee", Node))},
+ {permission, decode_permission(erlcloud_xml:get_text("Permission", Node))}].
encode_permission(full_control) -> "FULL_CONTROL";
-encode_permission(write) -> "WRITE";
-encode_permission(write_acp) -> "WRITE_ACP";
-encode_permission(read) -> "READ";
+encode_permission(write) -> "WRITE";
+encode_permission(write_acp) -> "WRITE_ACP";
+encode_permission(read) -> "READ";
encode_permission(read_acp) -> "READ_ACP".
decode_permission("FULL_CONTROL") -> full_control;
-decode_permission("WRITE") -> write;
-decode_permission("WRITE_ACP") -> write_acp;
-decode_permission("READ") -> read;
-decode_permission("READ_ACP") -> read_acp.
+decode_permission("WRITE") -> write;
+decode_permission("WRITE_ACP") -> write_acp;
+decode_permission("READ") -> read;
+decode_permission("READ_ACP") -> read_acp.
+
+-spec get_object(string(), string()) -> proplist().
--spec get_object/2 :: (string(), string()) -> proplist().
get_object(BucketName, Key) ->
get_object(BucketName, Key, []).
--spec get_object/3 :: (string(), string(), proplist() | aws_config()) -> proplist().
+-spec get_object(string(), string(), proplist() | aws_config()) -> proplist().
+
get_object(BucketName, Key, Config)
when is_record(Config, aws_config) ->
get_object(BucketName, Key, [], Config);
+
get_object(BucketName, Key, Options) ->
get_object(BucketName, Key, Options, default_config()).
--spec get_object/4 :: (string(), string(), proplist(), aws_config()) -> proplist().
+-spec get_object(string(), string(), proplist(), aws_config()) -> proplist().
+
get_object(BucketName, Key, Options, Config) ->
- RequestHeaders = [
- {"Range", proplists:get_value(range, Options)},
- {"If-Modified-Since", proplists:get_value(if_modified_since, Options)},
- {"If-Unmodified-Since", proplists:get_value(if_unmodified_since, Options)},
- {"If-Match", proplists:get_value(if_match, Options)},
- {"If-None-Match", proplists:get_value(if_none_match, Options)}
- ],
+ RequestHeaders = [{"Range", proplists:get_value(range, Options)},
+ {"If-Modified-Since", proplists:get_value(if_modified_since, Options)},
+ {"If-Unmodified-Since", proplists:get_value(if_unmodified_since, Options)},
+ {"If-Match", proplists:get_value(if_match, Options)},
+ {"If-None-Match", proplists:get_value(if_none_match, Options)}],
Subresource = case proplists:get_value(version_id, Options) of
- undefined -> "";
- Version -> ["versionId=", Version]
- end,
- {Headers, Body} = s3_request(Config, get, BucketName, [$/|Key], Subresource, [], <<>>,
- RequestHeaders),
- [
- {etag, proplists:get_value("etag", Headers)},
- {content_length, proplists:get_value("content-length", Headers)},
- {content_type, proplists:get_value("content-type", Headers)},
- {delete_marker, list_to_existing_atom(proplists:get_value("x-amz-delete-marker", Headers, "false"))},
- {version_id, proplists:get_value("x-amz-version-id", Headers, "null")},
- {content, list_to_binary(Body)}|
- extract_metadata(Headers)
- ].
-
--spec get_object_acl/2 :: (string(), string()) -> proplist().
+ undefined -> "";
+ Version -> ["versionId=", Version]
+ end,
+ {Headers, Body} = s3_request(Config, get, BucketName, [$/|Key], Subresource, [], <<>>, RequestHeaders),
+ [{etag, proplists:get_value("etag", Headers)},
+ {content_length, proplists:get_value("content-length", Headers)},
+ {content_type, proplists:get_value("content-type", Headers)},
+ {delete_marker, list_to_existing_atom(proplists:get_value("x-amz-delete-marker", Headers, "false"))},
+ {version_id, proplists:get_value("x-amz-version-id", Headers, "null")},
+ {content, list_to_binary(Body)}|
+ extract_metadata(Headers)].
+
+-spec get_object_acl(string(), string()) -> proplist().
+
get_object_acl(BucketName, Key) ->
get_object_acl(BucketName, Key, default_config()).
--spec get_object_acl/3 :: (string(), string(), proplist() | aws_config()) -> proplist().
+-spec get_object_acl(string(), string(), proplist() | aws_config()) -> proplist().
+
get_object_acl(BucketName, Key, Config)
when is_record(Config, aws_config) ->
get_object_acl(BucketName, Key, [], Config);
+
get_object_acl(BucketName, Key, Options) ->
get_object_acl(BucketName, Key, Options, default_config()).
--spec get_object_acl/4 :: (string(), string(), proplist(), aws_config()) -> proplist().
+-spec get_object_acl(string(), string(), proplist(), aws_config()) -> proplist().
+
get_object_acl(BucketName, Key, Options, Config)
when is_list(BucketName), is_list(Key), is_list(Options) ->
Subresource = case proplists:get_value(version_id, Options) of
- undefined -> "";
- Version -> ["&versionId=", Version]
- end,
+ undefined -> "";
+ Version -> ["&versionId=", Version]
+ end,
Doc = s3_xml_request(Config, get, BucketName, [$/|Key], "acl" ++ Subresource, [], <<>>, []),
- erlcloud_xml:decode(
- [
- {owner, "Owner", fun extract_user/1},
- {access_control_list, "AccessControlList/Grant", fun extract_acl/1}
- ],
- Doc
- ).
-
--spec get_object_metadata/2 :: (string(), string()) -> proplist().
+ Attributes = [{owner, "Owner", fun extract_user/1},
+ {access_control_list, "AccessControlList/Grant", fun extract_acl/1}],
+ erlcloud_xml:decode(Attributes, Doc).
+
+-spec get_object_metadata(string(), string()) -> proplist().
+
get_object_metadata(BucketName, Key) ->
get_object_metadata(BucketName, Key, []).
--spec get_object_metadata/3 :: (string(), string(), proplist() | aws_config()) -> proplist().
+-spec get_object_metadata(string(), string(), proplist() | aws_config()) -> proplist().
+
get_object_metadata(BucketName, Key, Config)
when is_record(Config, aws_config) ->
get_object_metadata(BucketName, Key, [], Config);
+
get_object_metadata(BucketName, Key, Options) ->
get_object_metadata(BucketName, Key, Options, default_config()).
--spec get_object_metadata/4 :: (string(), string(), proplist(), proplist() | aws_config()) -> proplist().
+-spec get_object_metadata(string(), string(), proplist(), proplist() | aws_config()) -> proplist().
+
get_object_metadata(BucketName, Key, Options, Config) ->
- RequestHeaders = [
- {"If-Modified-Since", proplists:get_value(if_modified_since, Options)},
- {"If-Unmodified-Since", proplists:get_value(if_unmodified_since, Options)},
- {"If-Match", proplists:get_value(if_match, Options)},
- {"If-None-Match", proplists:get_value(if_none_match, Options)}
- ],
+ RequestHeaders = [{"If-Modified-Since", proplists:get_value(if_modified_since, Options)},
+ {"If-Unmodified-Since", proplists:get_value(if_unmodified_since, Options)},
+ {"If-Match", proplists:get_value(if_match, Options)},
+ {"If-None-Match", proplists:get_value(if_none_match, Options)}],
Subresource = case proplists:get_value(version_id, Options) of
- undefined -> "";
- Version -> ["versionId=", Version]
- end,
- {Headers, _Body} = s3_request(Config, get, BucketName, [$/|Key], Subresource, [], <<>>,
- RequestHeaders),
- [
- {last_modified, proplists:get_value("last-modified", Headers)},
- {etag, proplists:get_value("etag", Headers)},
- {content_length, proplists:get_value("content-length", Headers)},
- {content_type, proplists:get_value("content-type", Headers)},
- {delete_marker, list_to_existing_atom(proplists:get_value("x-amz-delete-marker", Headers, "false"))},
- {version_id, proplists:get_value("x-amz-version-id", Headers, "false")}|
- extract_metadata(Headers)
- ].
+ undefined -> "";
+ Version -> ["versionId=", Version]
+ end,
+ {Headers, _Body} = s3_request(Config, get, BucketName, [$/|Key], Subresource, [], <<>>, RequestHeaders),
+ [{last_modified, proplists:get_value("last-modified", Headers)},
+ {etag, proplists:get_value("etag", Headers)},
+ {content_length, proplists:get_value("content-length", Headers)},
+ {content_type, proplists:get_value("content-type", Headers)},
+ {delete_marker, list_to_existing_atom(proplists:get_value("x-amz-delete-marker", Headers, "false"))},
+ {version_id, proplists:get_value("x-amz-version-id", Headers, "false")}|extract_metadata(Headers)].
extract_metadata(Headers) ->
[{Key, Value} || {["x-amz-meta-"|Key], Value} <- Headers].
--spec get_object_torrent/2 :: (string(), string()) -> proplist().
+-spec get_object_torrent(string(), string()) -> proplist().
+
get_object_torrent(BucketName, Key) ->
get_object_torrent(BucketName, Key, default_config()).
--spec get_object_torrent/3 :: (string(), string(), aws_config()) -> proplist().
+-spec get_object_torrent(string(), string(), aws_config()) -> proplist().
+
get_object_torrent(BucketName, Key, Config) ->
- {Headers, Body} = s3_request(Config, get, BucketName, [$/|Key], "torrent",
- [], <<>>, []),
- [
- {delete_marker, list_to_existing_atom(proplists:get_value("x-amz-delete-marker", Headers, "false"))},
- {version_id, proplists:get_value("x-amz-delete-marker", Headers, "false")},
- {torrent, list_to_binary(Body)}
- ].
-
--spec list_object_versions/1 :: (string()) -> proplist().
+ {Headers, Body} = s3_request(Config, get, BucketName, [$/|Key], "torrent", [], <<>>, []),
+ [{delete_marker, list_to_existing_atom(proplists:get_value("x-amz-delete-marker", Headers, "false"))},
+ {version_id, proplists:get_value("x-amz-delete-marker", Headers, "false")},
+ {torrent, list_to_binary(Body)}].
+
+-spec list_object_versions(string()) -> proplist().
+
list_object_versions(BucketName) ->
list_object_versions(BucketName, []).
--spec list_object_versions/2 :: (string(), proplist() | aws_config()) -> proplist().
+-spec list_object_versions(string(), proplist() | aws_config()) -> proplist().
+
list_object_versions(BucketName, Config)
when is_record(Config, aws_config) ->
list_object_versions(BucketName, [], Config);
+
list_object_versions(BucketName, Options) ->
list_object_versions(BucketName, Options, default_config()).
--spec list_object_versions/3 :: (string(), proplist(), aws_config()) -> proplist().
+-spec list_object_versions(string(), proplist(), aws_config()) -> proplist().
+
list_object_versions(BucketName, Options, Config)
when is_list(BucketName), is_list(Options) ->
- Params = [
- {"delimiter", proplists:get_value(delimiter, Options)},
- {"key-marker", proplists:get_value(key_marker, Options)},
- {"max-keys", proplists:get_value(max_keys, Options)},
- {"prefix", proplists:get_value(prefix, Options)},
- {"version-id-marker", proplists:get_value(version_id_marker, Options)}
- ],
+ Params = [{"delimiter", proplists:get_value(delimiter, Options)},
+ {"key-marker", proplists:get_value(key_marker, Options)},
+ {"max-keys", proplists:get_value(max_keys, Options)},
+ {"prefix", proplists:get_value(prefix, Options)},
+ {"version-id-marker", proplists:get_value(version_id_marker, Options)}],
Doc = s3_xml_request(Config, get, BucketName, "/", "versions", Params, <<>>, []),
- erlcloud_xml:decode(
- [
- {name, "Name", text},
- {prefix, "Prefix", text},
- {key_marker, "KeyMarker", text},
- {next_key_marker, "NextKeyMarker", optional_text},
- {version_id_marker, "VersionIdMarker", text},
- {next_version_id_marker, "NextVersionIdMarker", optional_text},
- {max_keys, "MaxKeys", integer},
- {is_truncated, "Istruncated", boolean},
- {versions, "Version", fun extract_versions/1},
- {delete_markers, "DeleteMarker", fun extract_delete_markers/1}
- ],
- Doc
- ).
+ Attributes = [{name, "Name", text},
+ {prefix, "Prefix", text},
+ {key_marker, "KeyMarker", text},
+ {next_key_marker, "NextKeyMarker", optional_text},
+ {version_id_marker, "VersionIdMarker", text},
+ {next_version_id_marker, "NextVersionIdMarker", optional_text},
+ {max_keys, "MaxKeys", integer},
+ {is_truncated, "Istruncated", boolean},
+ {versions, "Version", fun extract_versions/1},
+ {delete_markers, "DeleteMarker", fun extract_delete_markers/1}],
+ erlcloud_xml:decode(Attributes, Doc).
extract_versions(Nodes) ->
[extract_version(Node) || Node <- Nodes].
extract_version(Node) ->
- erlcloud_xml:decode(
- [
- {key, "Key", text},
- {version_id, "VersionId", text},
- {is_latest, "IsLatest", boolean},
- {etag, "ETag", text},
- {size, "Size", integer},
- {owner, "Owner", fun extract_user/1},
- {storage_class, "StorageClass", text}
- ],
- Node
- ).
+ Attributes = [{key, "Key", text},
+ {version_id, "VersionId", text},
+ {is_latest, "IsLatest", boolean},
+ {etag, "ETag", text},
+ {size, "Size", integer},
+ {owner, "Owner", fun extract_user/1},
+ {storage_class, "StorageClass", text}],
+ erlcloud_xml:decode(Attributes, Node).
extract_delete_markers(Nodes) ->
[extract_delete_marker(Node) || Node <- Nodes].
extract_delete_marker(Node) ->
- erlcloud_xml:decode(
- [
- {key, "Key", text},
- {version_id, "VersionId", text},
- {is_latest, "IsLatest", boolean},
- {owner, "Owner", fun extract_user/1}
- ],
- Node
- ).
+ Attributes = [{key, "Key", text},
+ {version_id, "VersionId", text},
+ {is_latest, "IsLatest", boolean},
+ {owner, "Owner", fun extract_user/1}],
+ erlcloud_xml:decode(Attributes, Node).
extract_bucket(Node) ->
- erlcloud_xml:decode(
- [
- {name, "Name", text},
- {creation_date, "CreationDate", time}
- ], Node).
+ erlcloud_xml:decode([{name, "Name", text},
+ {creation_date, "CreationDate", time}],
+ Node).
+
+-spec put_object(string(), string(), iolist()) -> proplist().
--spec put_object/3 :: (string(), string(), iolist()) -> proplist().
put_object(BucketName, Key, Value) ->
put_object(BucketName, Key, Value, []).
--spec put_object/4 :: (string(), string(), iolist(), proplist() | aws_config()) -> proplist().
+-spec put_object(string(), string(), iolist(), proplist() | aws_config()) -> proplist().
+
put_object(BucketName, Key, Value, Config)
when is_record(Config, aws_config) ->
put_object(BucketName, Key, Value, [], Config);
+
put_object(BucketName, Key, Value, Options) ->
put_object(BucketName, Key, Value, Options, default_config()).
--spec put_object/5 :: (string(), string(), iolist(), proplist(), [{string(), string()}] | aws_config()) -> proplist().
+-spec put_object(string(), string(), iolist(), proplist(), [{string(), string()}] | aws_config()) -> proplist().
+
put_object(BucketName, Key, Value, Options, Config)
when is_record(Config, aws_config) ->
put_object(BucketName, Key, Value, Options, [], Config);
+
put_object(BucketName, Key, Value, Options, HTTPHeaders) ->
put_object(BucketName, Key, Value, Options, HTTPHeaders, default_config()).
--spec put_object/6 :: (string(), string(), iolist(), proplist(), [{string(), string()}], aws_config()) -> proplist().
+-spec put_object(string(), string(), iolist(), proplist(), [{string(), string()}], aws_config()) -> proplist().
+
put_object(BucketName, Key, Value, Options, HTTPHeaders, Config)
when is_list(BucketName), is_list(Key), is_list(Value) orelse is_binary(Value),
is_list(Options) ->
- RequestHeaders = [
- {"x-amz-acl", encode_acl(proplists:get_value(acl, Options))}
- |HTTPHeaders
- ] ++ [{["x-amz-meta-"|string:to_lower(MKey)], MValue} || {MKey, MValue} <- proplists:get_value(meta, Options, [])],
- POSTData = {iolist_to_binary(Value), proplists:get_value("content-type", HTTPHeaders, "application/octet_stream")},
-
+ RequestHeaders = [{"x-amz-acl", encode_acl(proplists:get_value(acl, Options))}|HTTPHeaders]
+ ++ [{["x-amz-meta-"|string:to_lower(MKey)], MValue} ||
+ {MKey, MValue} <- proplists:get_value(meta, Options, [])],
+ ContentType = proplists:get_value("content-type", HTTPHeaders, "application/octet_stream"),
+ POSTData = {iolist_to_binary(Value), ContentType},
{Headers, _Body} = s3_request(Config, put, BucketName, [$/|Key], "", [],
POSTData, RequestHeaders),
- [
- {version_id, proplists:get_value("x-amz-version-id", Headers, "null")}
- ].
+ [{version_id, proplists:get_value("x-amz-version-id", Headers, "null")}].
+
+-spec set_object_acl(string(), string(), proplist()) -> ok.
--spec set_object_acl/3 :: (string(), string(), proplist()) -> ok.
set_object_acl(BucketName, Key, ACL) ->
set_object_acl(BucketName, Key, ACL, default_config()).
--spec set_object_acl/4 :: (string(), string(), proplist(), aws_config()) -> ok.
+-spec set_object_acl(string(), string(), proplist(), aws_config()) -> ok.
+
set_object_acl(BucketName, Key, ACL, Config)
when is_list(BucketName), is_list(Key), is_list(ACL) ->
+ Id = proplists:get_value(id, proplists:get_value(owner, ACL)),
+ DisplayName = proplists:get_value(display_name, proplists:get_value(owner, ACL)),
+ ACL1 = proplists:get_value(access_control_list, ACL),
XML = {'AccessControlPolicy',
- [
- {'Owner',
- [
- {'ID', [proplists:get_value(id, proplists:get_value(owner, ACL))]},
- {'DisplayName', [proplists:get_value(display_name, proplists:get_value(owner, ACL))]}
- ]
- },
- {'AccessControlList', encode_grants(proplists:get_value(access_control_list, ACL))}
- ]
- },
+ [{'Owner', [{'ID', [Id]}, {'DisplayName', [DisplayName]}]},
+ {'AccessControlList', encode_grants(ACL1)}]},
XMLText = list_to_binary(xmerl:export_simple([XML], xmerl_xml)),
s3_simple_request(Config, put, BucketName, [$/|Key], "acl", [], XMLText, []).
--spec set_bucket_attribute/3 :: (string(), atom(), term()) -> ok.
+-spec set_bucket_attribute(string(), atom(), term()) -> ok.
+
set_bucket_attribute(BucketName, AttributeName, Value) ->
set_bucket_attribute(BucketName, AttributeName, Value, default_config()).
--spec set_bucket_attribute/4 :: (string(), atom(), term(), aws_config()) -> ok.
+-spec set_bucket_attribute(string(), atom(), term(), aws_config()) -> ok.
+
set_bucket_attribute(BucketName, AttributeName, Value, Config)
when is_list(BucketName) ->
- {Subresource, XML} = case AttributeName of
- acl ->
- ACLXML = {'AccessControlPolicy',
- [
- {'Owner',
- [
- {'ID', [proplists:get_value(id, proplists:get_value(owner, Value))]},
- {'DisplayName', [proplists:get_value(display_name, proplists:get_value(owner, Value))]}
- ]
- },
- {'AccessControlList', encode_grants(proplists:get_value(access_control_list, Value))}
- ]
- },
- {"acl", ACLXML};
- logging ->
- LoggingXML = {'BucketLoggingStatus',
- [{xmlns, ?XMLNS_S3}],
- case proplists:get_bool(enabled, Value) of
- true ->
- [{'LoggingEnabled',
- [
- {'TargetBucket', [proplists:get_value(target_bucket, Value)]},
- {'TargetPrefix', [proplists:get_value(target_prefix, Value)]},
- {'TargetGrants', encode_grants(proplists:get_value(target_grants, Value, []))}
- ]
- }];
- false ->
- []
- end},
- {"logging", LoggingXML};
- request_payment ->
- PayerName = case Value of
- requester -> "Requester";
- bucket_owner -> "BucketOwner"
- end,
- RPXML = {'RequestPaymentConfiguration', [{xmlns, ?XMLNS_S3}],
- [
- {'Payer', [PayerName]}
- ]
- },
- {"requestPayment", RPXML};
- versioning ->
- Status = case proplists:get_value(status, Value) of
- suspended -> "Suspended";
- enabled -> "Enabled"
- end,
- MFADelete = case proplists:get_value(mfa_delete, Value, disabled) of
- enabled -> "Enabled";
- disabled -> "Disabled"
- end,
- VersioningXML = {'VersioningConfiguration', [{xmlns, ?XMLNS_S3}],
- [
- {'Status', [Status]},
- {'MfaDelete', [MFADelete]}
- ]
- },
- {"versioning", VersioningXML}
- end,
+ {Subresource, XML} =
+ case AttributeName of
+ acl ->
+ ACLXML = {'AccessControlPolicy',
+ [{'Owner',
+ [{'ID', [proplists:get_value(id, proplists:get_value(owner, Value))]},
+ {'DisplayName', [proplists:get_value(display_name, proplists:get_value(owner, Value))]}]},
+ {'AccessControlList', encode_grants(proplists:get_value(access_control_list, Value))}]},
+ {"acl", ACLXML};
+ logging ->
+ LoggingXML = {'BucketLoggingStatus',
+ [{xmlns, ?XMLNS_S3}],
+ case proplists:get_bool(enabled, Value) of
+ true ->
+ [{'LoggingEnabled',
+ [
+ {'TargetBucket', [proplists:get_value(target_bucket, Value)]},
+ {'TargetPrefix', [proplists:get_value(target_prefix, Value)]},
+ {'TargetGrants', encode_grants(proplists:get_value(target_grants, Value, []))}
+ ]
+ }];
+ false ->
+ []
+ end},
+ {"logging", LoggingXML};
+ request_payment ->
+ PayerName = case Value of
+ requester -> "Requester";
+ bucket_owner -> "BucketOwner"
+ end,
+ RPXML = {'RequestPaymentConfiguration', [{xmlns, ?XMLNS_S3}],
+ [
+ {'Payer', [PayerName]}
+ ]
+ },
+ {"requestPayment", RPXML};
+ versioning ->
+ Status = case proplists:get_value(status, Value) of
+ suspended -> "Suspended";
+ enabled -> "Enabled"
+ end,
+ MFADelete = case proplists:get_value(mfa_delete, Value, disabled) of
+ enabled -> "Enabled";
+ disabled -> "Disabled"
+ end,
+ VersioningXML = {'VersioningConfiguration', [{xmlns, ?XMLNS_S3}],
+ [{'Status', [Status]},
+ {'MfaDelete', [MFADelete]}]},
+ {"versioning", VersioningXML}
+ end,
POSTData = list_to_binary(xmerl:export_simple([XML], xmerl_xml)),
Headers = [{"content-type", "application/xml"}],
s3_simple_request(Config, put, BucketName, "/", Subresource, [], POSTData, Headers).
@@ -608,17 +622,10 @@ encode_grants(Grants) ->
encode_grant(Grant) ->
Grantee = proplists:get_value(grantee, Grant),
{'Grant',
- [
- {'Grantee', [{xmlns, ?XMLNS_S3}],
- [
- {'ID', [proplists:get_value(id, proplists:get_value(owner, Grantee))]},
- {'DisplayName', [proplists:get_value(display_name, proplists:get_value(owner, Grantee))]}
- ]
- },
- {'Permission', [encode_permission(proplists:get_value(permission, Grant))]}
- ]
- }.
-
+ [{'Grantee', [{xmlns, ?XMLNS_S3}],
+ [{'ID', [proplists:get_value(id, proplists:get_value(owner, Grantee))]},
+ {'DisplayName', [proplists:get_value(display_name, proplists:get_value(owner, Grantee))]}]},
+ {'Permission', [encode_permission(proplists:get_value(permission, Grant))]}]}.
s3_simple_request(Config, Method, Host, Path, Subresource, Params, POSTData, Headers) ->
case s3_request(Config, Method, Host, Path, Subresource, Params, POSTData, Headers) of
@@ -648,24 +655,21 @@ s3_xml_request(Config, Method, Host, Path, Subresource, Params, POSTData, Header
end.
s3_request(Config, Method, Host, Path, Subresource, Params, POSTData, Headers) ->
- {ContentMD5, ContentType, Body} = case POSTData of
- {PD, CT} ->
- {base64:encode(crypto:md5(PD)), CT, PD};
- PD -> {"", "", PD}
- end,
+ {ContentMD5, ContentType, Body} =
+ case POSTData of
+ {PD, CT} -> {base64:encode(crypto:md5(PD)), CT, PD}; PD -> {"", "", PD}
+ end,
AmzHeaders = lists:filter(fun ({"x-amz-" ++ _, V}) when V =/= undefined -> true; (_) -> false end, Headers),
Date = httpd_util:rfc1123_date(erlang:localtime()),
EscapedPath = erlcloud_http:url_encode_loose(Path),
Authorization = make_authorization(Config, Method, ContentMD5, ContentType,
Date, AmzHeaders, Host, EscapedPath, Subresource),
-
FHeaders = [Header || {_, Value} = Header <- Headers, Value =/= undefined],
RequestHeaders = [{"date", Date}, {"authorization", Authorization}|FHeaders] ++
case ContentMD5 of
"" -> [];
_ -> [{"content-md5", binary_to_list(ContentMD5)}]
end,
-
RequestURI = lists:flatten([
"https://",
case Host of "" -> ""; _ -> [Host, $.] end,
@@ -678,13 +682,11 @@ s3_request(Config, Method, Host, Path, Subresource, Params, POSTData, Headers) -
true -> [$&, erlcloud_http:make_query_string(Params)]
end
]),
-
Response = case Method of
- get -> http:request(Method, {RequestURI, RequestHeaders}, [], []);
- delete -> http:request(Method, {RequestURI, RequestHeaders}, [], []);
- _ -> http:request(Method, {RequestURI, RequestHeaders, ContentType, Body}, [], [])
+ get -> httpc:request(Method, {RequestURI, RequestHeaders}, [], []);
+ delete -> httpc:request(Method, {RequestURI, RequestHeaders}, [], []);
+ _ -> httpc:request(Method, {RequestURI, RequestHeaders, ContentType, Body}, [], [])
end,
-
case Response of
{ok, {{_HTTPVer, OKStatus, _StatusLine}, ResponseHeaders, ResponseBody}}
when OKStatus >= 200, OKStatus =< 299 ->
@@ -699,19 +701,15 @@ make_authorization(Config, Method, ContentMD5, ContentType, Date, AmzHeaders,
Host, Resource, Subresource) ->
CanonizedAmzHeaders =
[[Name, $:, Value, $\n] || {Name, Value} <- lists:sort(AmzHeaders)],
-
- StringToSign = [
- string:to_upper(atom_to_list(Method)), $\n,
- ContentMD5, $\n,
- ContentType, $\n,
- Date, $\n,
- CanonizedAmzHeaders,
- case Host of "" -> ""; _ -> [$/, Host] end,
- Resource, case Subresource of "" -> ""; _ -> [$?, Subresource] end
- ],
-
+ StringToSign = [string:to_upper(atom_to_list(Method)), $\n,
+ ContentMD5, $\n,
+ ContentType, $\n,
+ Date, $\n,
+ CanonizedAmzHeaders,
+ case Host of "" -> ""; _ -> [$/, Host] end,
+ Resource, case Subresource of "" -> ""; _ -> [$?, Subresource] end
+ ],
Signature = base64:encode(crypto:sha_mac(Config#aws_config.secret_access_key, StringToSign)),
-
["AWS ", Config#aws_config.access_key_id, $:, Signature].
default_config() -> erlcloud_aws:default_config().
Please sign in to comment.
Something went wrong with that request. Please try again.