Permalink
Browse files

pulled ypaq's contrib, bumped to v2.0.0

  • Loading branch information...
2 parents 48256e5 + a91929c commit 5ba2f370dc9a5c1d8a476cc8dd5bec97c6297a36 @ddossot committed Mar 16, 2013
Showing with 551 additions and 460 deletions.
  1. +1 −1 LICENSE
  2. +72 −76 README.md
  3. +26 −3 include/cferl.hrl
  4. +1 −1 int_tests
  5. +2 −2 rebar.config
  6. +1 −1 src/cferl.app.src
  7. +28 −29 src/cferl.erl
  8. +107 −81 src/cferl_connection.erl
  9. +133 −108 src/cferl_container.erl
  10. +6 −0 src/cferl_lib.erl
  11. +104 −89 src/cferl_object.erl
  12. +70 −69 test/cferl_integration_tests.erl
View
@@ -1,6 +1,6 @@
This is the MIT license.
- Copyright (c) 2010 David Dossot
+ Copyright (c) 2010-2013 David Dossot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
View
148 README.md
@@ -1,16 +1,13 @@
-Rackspace Cloud Files Erlang Client
-===================================
+# Rackspace Cloud Files Erlang Client
-Description
------------
+## Description
This is an Erlang interface into the Rackspace Cloud Files service. It has been largely inspired by the existing [Ruby](http://github.com/rackspace/ruby-cloudfiles) API.
-Building
---------
+## Building
-*cferl* relies on [rebar](http://bitbucket.org/basho/rebar/wiki/Home) for its build and dependency management and targets Erlang/OTP R13B04 or above.
+**cferl** relies on [rebar](http://bitbucket.org/basho/rebar/wiki/Home) for its build and dependency management and targets Erlang/OTP R13B04 or above.
Simply run:
@@ -27,10 +24,9 @@ Optionally, to run the integration tests (and generate the code samples visible
If you run the integration tests, you'll need your API key and at least one pre-existing container. Note that a test container will be created and some queries could take a while if you have lots of containers.
-Using
------
+## Using
-*cferl* requires that the ssl and ibrowse applications be started prior to using it.
+**cferl** requires that the ssl and ibrowse applications be started prior to using it.
The following, which is output when running the integration tests, demonstrates a typical usage of the API. Refer to the documentation for the complete reference.
@@ -39,145 +35,145 @@ The following, which is output when running the integration tests, demonstrates
{ok,CloudFiles}=cferl:connect(Username,ApiKey).
# Retrieve the account information record
-{ok,Info}=CloudFiles:get_account_info().
-Info = #cf_account_info{bytes_used=360, container_count=3}
+{ok,Info}=cferl_connection:get_account_info(CloudFiles).
+Info = #cf_account_info{bytes_used=1735871382, container_count=5}
# Retrieve names of all existing containers (within the limits imposed by Cloud Files server)
-{ok,Names}=CloudFiles:get_containers_names().
+{ok,Names}=cferl_connection:get_containers_names(CloudFiles).
# Retrieve names of a maximum of 3 existing containers
-{ok,ThreeNamesMax}=CloudFiles:get_containers_names(#cf_container_query_args{limit=3}).
+{ok,ThreeNamesMax}=cferl_connection:get_containers_names(CloudFiles,#cf_container_query_args{limit=3}).
# Retrieve names of all containers currently CDN activated
-{ok,CurrentPublicNames}=CloudFiles:get_public_containers_names(active).
+{ok,CurrentPublicNames}=cferl_connection:get_public_containers_names(CloudFiles,active).
# Retrieve names of all containers that are currently or have been CDN activated
-{ok,AllTimePublicNames}=CloudFiles:get_public_containers_names(all_time).
+{ok,AllTimePublicNames}=cferl_connection:get_public_containers_names(CloudFiles,all_time).
# Retrieve details for all existing containers (within the server limits)
-{ok,ContainersDetails}=CloudFiles:get_containers_details().
+{ok,ContainersDetails}=cferl_connection:get_containers_details(CloudFiles).
# ContainersDetails is a list of #cf_container_details records
[ContainerDetails|_]=ContainersDetails.
-ContainerDetails = #cf_container_details{name=<<"cferl-test">>, bytes=360, count=1}
+ContainerDetails = #cf_container_details{name=<<".CDN_ACCESS_LOGS">>, bytes=261, count=1}
# Retrieve details for a maximum of 5 containers whose names start at cf
-{ok,CfContainersDetails}=CloudFiles:get_containers_details(#cf_container_query_args{marker=<<"cf">>,limit=5}).
+{ok,CfContainersDetails}=cferl_connection:get_containers_details(CloudFiles,#cf_container_query_args{marker=<<"cf">>,limit=5}).
# Get a container reference by name
-{ok,Container}=CloudFiles:get_container(ContainerDetails#cf_container_details.name).
+{ok,Container}=cferl_connection:get_container(CloudFiles,ContainerDetails#cf_container_details.name).
# Get container details from its reference
-ContainerName=Container:name().
-ContainerBytes=Container:bytes().
-ContainerSize=Container:count().
-ContainerIsEmpty=Container:is_empty().
+ContainerName=cferl_container:name(Container).
+ContainerBytes=cferl_container:bytes(Container).
+ContainerSize=cferl_container:count(Container).
+ContainerIsEmpty=cferl_container:is_empty(Container).
-# -> Name: <<"cferl-test">> - Bytes: 360 - Size: 1 - IsEmpty: false
+# -> Name: <<".CDN_ACCESS_LOGS">> - Bytes: 261 - Size: 1 - IsEmpty: false
# Check a container's existence
-false=CloudFiles:container_exists(NewContainerName).
+false=cferl_connection:container_exists(CloudFiles,NewContainerName).
# Create a new container
-{ok,NewContainer}=CloudFiles:create_container(NewContainerName).
+{ok,NewContainer}=cferl_connection:create_container(CloudFiles,NewContainerName).
-true=CloudFiles:container_exists(NewContainerName).
+true=cferl_connection:container_exists(CloudFiles,NewContainerName).
Check attributes of this newly created container
-NewContainerName=NewContainer:name().
-0=NewContainer:bytes().
-0=NewContainer:count().
-true=NewContainer:is_empty().
-false=NewContainer:is_public().
-<<>>=NewContainer:cdn_url().
-0=NewContainer:cdn_ttl().
-false=NewContainer:log_retention().
+NewContainerName=cferl_container:name(NewContainer).
+0=cferl_container:bytes(NewContainer).
+0=cferl_container:count(NewContainer).
+true=cferl_container:is_empty(NewContainer).
+false=cferl_container:is_public(NewContainer).
+<<>>=cferl_container:cdn_url(NewContainer).
+0=cferl_container:cdn_ttl(NewContainer).
+false=cferl_container:log_retention(NewContainer).
# Make the container public on the CDN (using the default TTL and ACLs)
-ok=NewContainer:make_public().
+ok=cferl_container:make_public(CloudFiles,NewContainer).
# Activate log retention on the new container
-ok=NewContainer:set_log_retention(true).
+ok=cferl_container:set_log_retention(CloudFiles,NewContainer,true).
# Refresh an existing container and check its attributes
-{ok,RefreshedContainer}=NewContainer:refresh().
-true=RefreshedContainer:is_public().
+{ok,RefreshedContainer}=cferl_container:refresh(CloudFiles,NewContainer).
+true=cferl_container:is_public(RefreshedContainer).
-io:format("~s~n~n",[RefreshedContainer:cdn_url()]).
-http://c0027258.cdn1.cloudfiles.rackspacecloud.com
+io:format("~s~n~n",[cferl_container:cdn_url(RefreshedContainer)]).
+http://05f98f987aa9393ccd8c-3d04f8822c5760cb271501bb0c358085.r17.cf1.rackcdn.com
-86400=RefreshedContainer:cdn_ttl().
-true=RefreshedContainer:log_retention().
+86400=cferl_container:cdn_ttl(RefreshedContainer).
+true=cferl_container:log_retention(RefreshedContainer).
ObjectName=<<"test.xml">>.
# Create an object *reference*, nothing is sent to the server yet
-{ok,Object}=RefreshedContainer:create_object(ObjectName).
+{ok,Object}=cferl_container:create_object(CloudFiles,RefreshedContainer,ObjectName).
# As expected, it doesn't exist yet
-false=RefreshedContainer:object_exists(ObjectName).
+false=cferl_container:object_exists(CloudFiles,RefreshedContainer,ObjectName).
# Write data in the object, which creates it on the server
-ok=Object:write_data(<<"<test/>">>,<<"application/xml">>).
+ok=cferl_object:write_data(CloudFiles,Object,<<"<test/>">>,<<"application/xml">>).
# Now it exists!
-true=RefreshedContainer:object_exists(ObjectName).
+true=cferl_container:object_exists(CloudFiles,RefreshedContainer,ObjectName).
# And trying to re-create it just returns it
-{ok,ExistingObject}=RefreshedContainer:create_object(ObjectName).
+{ok,ExistingObject}=cferl_container:create_object(CloudFiles,RefreshedContainer,ObjectName).
# Set custom meta-data on it
-ok=Object:set_metadata([{<<"Key123">>,<<"my123Value">>}]).
+ok=cferl_object:set_metadata(CloudFiles,Object,[{<<"Key123">>,<<"my123Value">>}]).
# An existing object can be accessed directly from its container
-{ok,GotObject}=RefreshedContainer:get_object(ObjectName).
+{ok,GotObject}=cferl_container:get_object(CloudFiles,RefreshedContainer,ObjectName).
# Object names and details can be queried
-{ok,[ObjectName]}=RefreshedContainer:get_objects_names().
-{ok,[ObjectName]}=RefreshedContainer:get_objects_names(#cf_object_query_args{limit=1}).
-{ok,[ObjectDetails]}=RefreshedContainer:get_objects_details().
-ObjectDetails = #cf_object_details{name=<<"test.xml">>, bytes=8, last_modified={{2010,10,14},{15,49,22}}, content_type=application/xml, etag=4366c359d1a7b9b248fa262775613699}
+{ok,[ObjectName]}=cferl_container:get_objects_names(CloudFiles,RefreshedContainer).
+{ok,[ObjectName]}=cferl_container:get_objects_names(CloudFiles,RefreshedContainer,#cf_object_query_args{limit=1}).
+{ok,[ObjectDetails]}=cferl_container:get_objects_details(CloudFiles,RefreshedContainer).
+ObjectDetails = #cf_object_details{name=<<"test.xml">>, bytes=8, last_modified={{2013,3,16},{0,8,47}}, content_type=application/xml, etag=4366c359d1a7b9b248fa262775613699}
# Read the whole data
-{ok,<<"<test/>">>}=Object:read_data().
+{ok,<<"<test/>">>}=cferl_object:read_data(CloudFiles,Object).
# Read the data with an offset and a size
-{ok,<<"test">>}=Object:read_data(1,4).
+{ok,<<"test">>}=cferl_object:read_data(CloudFiles,Object,1,4).
# Refresh the object so its attributes and metadata are up to date
-{ok,RefreshedObject}=Object:refresh().
+{ok,RefreshedObject}=cferl_object:refresh(CloudFiles,Object).
# Get object attributes
-ObjectName=RefreshedObject:name().
-8=RefreshedObject:bytes().
-{{D,M,Y},{H,Mi,S}}=RefreshedObject:last_modified().
-<<"application/xml;charset=UTF-8">>=RefreshedObject:content_type().
-Etag=RefreshedObject:etag().
+ObjectName=cferl_object:name(RefreshedObject).
+8=cferl_object:bytes(RefreshedObject).
+{{D,M,Y},{H,Mi,S}}=cferl_object:last_modified(RefreshedObject).
+<<"application/xml">>=cferl_object:content_type(RefreshedObject).
+Etag=cferl_object:etag(RefreshedObject).
# Get custom meta-data
-[{<<"Key123">>,<<"my123Value">>}]=RefreshedObject:metadata().
+[{<<"Key123">>,<<"my123Value">>}]=cferl_object:metadata(RefreshedObject).
# Delete the object
-ok=RefreshedObject:delete().
+ok=cferl_object:delete(CloudFiles,RefreshedObject).
# Data can be streamed to the server from a generating function
-{ok,StreamedObject}=RefreshedContainer:create_object(<<"streamed.txt">>).
-StreamedObject:write_data_stream(WriteDataFun,<<"text/plain">>,1000).
+{ok,StreamedObject}=cferl_container:create_object(CloudFiles,RefreshedContainer,<<"streamed.txt">>).
+cferl_object:write_data_stream(CloudFiles,StreamedObject,WriteDataFun,<<"text/plain">>,1000).
# Data can be streamed from the server to a receiving function
-ok=StreamedObject:read_data_stream(ReadDataFun).
+ok=cferl_object:read_data_stream(CloudFiles,StreamedObject,ReadDataFun).
# Create all the directory elements for a particular object path
-ok=RefreshedContainer:ensure_dir(<<"photos/plants/fern.jpg">>).
-true=RefreshedContainer:object_exists(<<"photos">>).
-true=RefreshedContainer:object_exists(<<"photos/plants">>).
+ok=cferl_container:ensure_dir(CloudFiles,RefreshedContainer,<<"photos/plants/fern.jpg">>).
+true=cferl_container:object_exists(CloudFiles,RefreshedContainer,<<"photos">>).
+true=cferl_container:object_exists(CloudFiles,RefreshedContainer,<<"photos/plants">>).
# Make the container private
-ok=RefreshedContainer:make_private().
+ok=cferl_container:make_private(CloudFiles,RefreshedContainer).
# Delete an existing container (must be empty)
-ok=RefreshedContainer:delete().
-```
+ok=cferl_container:delete(CloudFiles,RefreshedContainer).
+```
-More information
-----------------
+## More information
Read the Rackspace Cloud Files API specification: <http://www.rackspacecloud.com/cloud_hosting_products/files/api>
Contact the author: <david@dossot.net>
+## Copyright (c) 2010-2013 David Dossot - MIT License
View
@@ -1,24 +1,47 @@
%%%
%%% @doc Rackspace Cloud Files Erlang Client
%%% @author David Dossot <david@dossot.net>
+%%% @author Tilman Holschuh <tilman.holschuh@gmail.com>
%%%
%%% See LICENSE for license information.
%%% Copyright (c) 2010 David Dossot
%%%
--define(API_BASE_URL, "auth.api.rackspacecloud.com").
+-define(US_API_BASE_URL, "identity.api.rackspacecloud.com").
+-define(UK_API_BASE_URL, "lon.identity.api.rackspacecloud.com").
-define(VERSION_PATH, "/v1.0").
-define(DEFAULT_REQUEST_TIMEOUT, 30000).
-define(OBJECT_META_HEADER_PREFIX, "X-Object-Meta-").
-define(DIRECTORY_OBJECT_CONTENT_TYPE, <<"application/directory">>).
+-define(IS_CONNECTION(C), is_record(C, cf_connection)).
+-define(IS_CONTAINER(C), is_record(C, cf_container)).
+-define(IS_OBJECT(O), is_record(O, cf_object)).
+
+-record(cf_connection, {version :: string(),
+ auth_token :: string(),
+ storage_url :: string(),
+ cdn_management_url :: string()
+ }).
+
-record(cf_account_info, {bytes_used, container_count}).
--record(cf_container_query_args, {marker, limit}).
-record(cf_container_details, {name, bytes, count}).
+-record(cf_container, {container_details :: #cf_container_details{},
+ container_path :: string(),
+ cdn_details :: [{atom(), term()}]
+ }).
+
+-record(cf_container_query_args, {marker, limit}).
-record(cf_container_cdn_config, {ttl = 86400, user_agent_acl, referrer_acl}).
--record(cf_object_query_args, {marker, limit, prefix, path}).
-record(cf_object_details, {name, bytes = 0, last_modified, content_type, etag}).
+-record(cf_object, {container :: #cf_container{},
+ object_details :: #cf_object_details{},
+ object_path :: string(),
+ http_headers :: [{string(), string()}]
+ }).
+
+-record(cf_object_query_args, {marker, limit, prefix, path}).
View
@@ -1,4 +1,4 @@
#!/bin/sh
-./rebar get-deps clean compile eunit
+rebar get-deps clean compile eunit
erl -boot start_sasl -config test/elog -pa .eunit -pa ebin -pa deps/ibrowse/ebin -s cferl_integration_tests -noshell
View
@@ -1,7 +1,7 @@
-{erl_opts, [{src_dirs, ["src", "lib"]}]}.
+{erl_opts, [debug_info, {src_dirs, ["src", "lib"]}]}.
{edoc_opts, [{application, ["cferl"]}]}.
{deps_dir, ["deps"]}.
-{deps, [{ibrowse, ".*", {git, "git://github.com/cmullaparthi/ibrowse.git", {branch, master}}}]}.
+{deps, [{ibrowse, ".*", {git, "git://github.com/cmullaparthi/ibrowse.git", {tag, "v4.0.1"}}}]}.
View
@@ -1,7 +1,7 @@
{application,
cferl,
[{description, "Rackspace Cloud Files client application"},
- {vsn, "1.3.2"},
+ {vsn, "2.0.0"},
{modules, [
cferl,
cferl_connection,
Oops, something went wrong.

0 comments on commit 5ba2f37

Please sign in to comment.