Skip to content

Commit eba8862

Browse files
committed
Merge pull request #250 from sharwell/fix-218
Add preliminary support for the Cloud Files Extract Archive operation
2 parents 1c069f4 + 89f825d commit eba8862

File tree

14 files changed

+695
-0
lines changed

14 files changed

+695
-0
lines changed

src/corelib/Providers/Rackspace/CloudFilesProvider.cs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using net.openstack.Providers.Rackspace.Objects.Mapping;
2121
using net.openstack.Providers.Rackspace.Objects.Response;
2222
using net.openstack.Providers.Rackspace.Validators;
23+
using Newtonsoft.Json;
2324

2425
namespace net.openstack.Providers.Rackspace
2526
{
@@ -1279,6 +1280,146 @@ public void BulkDelete(IEnumerable<KeyValuePair<string, string>> items, Dictiona
12791280
}
12801281
}
12811282

1283+
/// <summary>
1284+
/// Upload and automatically extract an archive of files.
1285+
/// </summary>
1286+
/// <param name="filePath">The source file path. Example <localUri>c:\folder1\folder2\archive_name.tar.gz</localUri></param>
1287+
/// <param name="uploadPath">The target path for the extracted files. For details about this value, see the Extract Archive reference link in the documentation for this method.</param>
1288+
/// <param name="archiveFormat">The archive format.</param>
1289+
/// <param name="contentType">The content type of the files extracted from the archive. If the value is <c>null</c> or empty, the content type of the extracted files is unspecified.</param>
1290+
/// <param name="chunkSize">The buffer size to use for copying streaming data.</param>
1291+
/// <param name="headers">A collection of custom HTTP headers to associate with the object (see <see cref="GetObjectHeaders"/>).</param>
1292+
/// <param name="region">The region in which to execute this action. If not specified, the user's default region will be used.</param>
1293+
/// <param name="progressUpdated">A callback for progress updates. If the value is <c>null</c>, no progress updates are reported.</param>
1294+
/// <param name="useInternalUrl"><c>true</c> to use the endpoint's <see cref="Endpoint.InternalURL"/>; otherwise <c>false</c> to use the endpoint's <see cref="Endpoint.PublicURL"/>.</param>
1295+
/// <param name="identity">The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used.</param>
1296+
/// <returns>An <see cref="ExtractArchiveResponse"/> object containing the detailed result of the extract archive operation.</returns>
1297+
/// <exception cref="ArgumentNullException">
1298+
/// If <paramref name="filePath"/> is <c>null</c>.
1299+
/// <para>-or-</para>
1300+
/// <para>If <paramref name="uploadPath"/> is <c>null</c>.</para>
1301+
/// <para>-or-</para>
1302+
/// <para>If <paramref name="archiveFormat"/> is <c>null</c>.</para>
1303+
/// </exception>
1304+
/// <exception cref="ArgumentException">
1305+
/// If <paramref name="filePath"/> is empty.
1306+
/// <para>-or-</para>
1307+
/// <para>If <paramref name="headers"/> contains two equivalent keys when compared using <see cref="StringComparer.OrdinalIgnoreCase"/>.</para>
1308+
/// </exception>
1309+
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="chunkSize"/> is less than 0.</exception>
1310+
/// <exception cref="FileNotFoundException">If the file <paramref name="filePath"/> could not be found.</exception>
1311+
/// <exception cref="NotSupportedException">
1312+
/// If the provider does not support the given <paramref name="identity"/> type.
1313+
/// <para>-or-</para>
1314+
/// <para>The specified <paramref name="archiveFormat"/> is not supported by the provider.</para>
1315+
/// <para>-or-</para>
1316+
/// <para>The specified <paramref name="region"/> is not supported.</para>
1317+
/// <para>-or-</para>
1318+
/// <para><paramref name="useInternalUrl"/> is <c>true</c> and the provider does not support internal URLs.</para>
1319+
/// </exception>
1320+
/// <exception cref="InvalidOperationException">
1321+
/// If <paramref name="identity"/> is <c>null</c> and no default identity is available for the provider.
1322+
/// <para>-or-</para>
1323+
/// <para>If <paramref name="region"/> is <c>null</c> and no default region is available for the provider.</para>
1324+
/// </exception>
1325+
/// <exception cref="ResponseException">If the REST API request failed.</exception>
1326+
/// <seealso href="http://docs.rackspace.com/files/api/v1/cf-devguide/content/Extract_Archive-d1e2338.html">Extract Archive (Rackspace Cloud Files Developer Guide - API v1)</seealso>
1327+
/// <preliminary/>
1328+
public ExtractArchiveResponse ExtractArchiveFromFile(string filePath, string uploadPath, ArchiveFormat archiveFormat, string contentType = null, int chunkSize = 4096, Dictionary<string, string> headers = null, string region = null, Action<long> progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null)
1329+
{
1330+
if (filePath == null)
1331+
throw new ArgumentNullException("filePath");
1332+
if (uploadPath == null)
1333+
throw new ArgumentNullException("uploadPath");
1334+
if (archiveFormat == null)
1335+
throw new ArgumentNullException("archiveFormat");
1336+
if (string.IsNullOrEmpty(filePath))
1337+
throw new ArgumentException("filePath cannot be empty");
1338+
if (chunkSize < 0)
1339+
throw new ArgumentOutOfRangeException("chunkSize");
1340+
CheckIdentity(identity);
1341+
1342+
using (var stream = File.OpenRead(filePath))
1343+
{
1344+
return ExtractArchive(stream, uploadPath, archiveFormat, contentType, chunkSize, headers, region, progressUpdated, useInternalUrl, identity);
1345+
}
1346+
}
1347+
1348+
/// <summary>
1349+
/// Upload and automatically extract an archive of files.
1350+
/// </summary>
1351+
/// <param name="stream">A <see cref="Stream"/> providing the data for the archive.</param>
1352+
/// <param name="uploadPath">The target path for the extracted files. For details about this value, see the Extract Archive reference link in the documentation for this method.</param>
1353+
/// <param name="archiveFormat">The archive format.</param>
1354+
/// <param name="contentType">The content type of the files extracted from the archive. If the value is <c>null</c> or empty, the content type of the extracted files is unspecified.</param>
1355+
/// <param name="chunkSize">The buffer size to use for copying streaming data.</param>
1356+
/// <param name="headers">A collection of custom HTTP headers to associate with the object (see <see cref="GetObjectHeaders"/>).</param>
1357+
/// <param name="region">The region in which to execute this action. If not specified, the user's default region will be used.</param>
1358+
/// <param name="progressUpdated">A callback for progress updates. If the value is <c>null</c>, no progress updates are reported.</param>
1359+
/// <param name="useInternalUrl"><c>true</c> to use the endpoint's <see cref="Endpoint.InternalURL"/>; otherwise <c>false</c> to use the endpoint's <see cref="Endpoint.PublicURL"/>.</param>
1360+
/// <param name="identity">The cloud identity to use for this request. If not specified, the default identity for the current provider instance will be used.</param>
1361+
/// <returns>An <see cref="ExtractArchiveResponse"/> object containing the detailed result of the extract archive operation.</returns>
1362+
/// <exception cref="ArgumentNullException">
1363+
/// If <paramref name="stream"/> is <c>null</c>.
1364+
/// <para>-or-</para>
1365+
/// <para>If <paramref name="uploadPath"/> is <c>null</c>.</para>
1366+
/// <para>-or-</para>
1367+
/// <para>If <paramref name="archiveFormat"/> is <c>null</c>.</para>
1368+
/// </exception>
1369+
/// <exception cref="ArgumentException">
1370+
/// If <paramref name="headers"/> contains two equivalent keys when compared using <see cref="StringComparer.OrdinalIgnoreCase"/>.
1371+
/// </exception>
1372+
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="chunkSize"/> is less than 0.</exception>
1373+
/// <exception cref="NotSupportedException">
1374+
/// If the provider does not support the given <paramref name="identity"/> type.
1375+
/// <para>-or-</para>
1376+
/// <para>The specified <paramref name="archiveFormat"/> is not supported by the provider.</para>
1377+
/// <para>-or-</para>
1378+
/// <para>The specified <paramref name="region"/> is not supported.</para>
1379+
/// <para>-or-</para>
1380+
/// <para><paramref name="useInternalUrl"/> is <c>true</c> and the provider does not support internal URLs.</para>
1381+
/// </exception>
1382+
/// <exception cref="InvalidOperationException">
1383+
/// If <paramref name="identity"/> is <c>null</c> and no default identity is available for the provider.
1384+
/// <para>-or-</para>
1385+
/// <para>If <paramref name="region"/> is <c>null</c> and no default region is available for the provider.</para>
1386+
/// </exception>
1387+
/// <exception cref="ResponseException">If the REST API request failed.</exception>
1388+
/// <seealso href="http://docs.rackspace.com/files/api/v1/cf-devguide/content/Extract_Archive-d1e2338.html">Extract Archive (Rackspace Cloud Files Developer Guide - API v1)</seealso>
1389+
/// <preliminary/>
1390+
public ExtractArchiveResponse ExtractArchive(Stream stream, string uploadPath, ArchiveFormat archiveFormat, string contentType = null, int chunkSize = 4096, Dictionary<string, string> headers = null, string region = null, Action<long> progressUpdated = null, bool useInternalUrl = false, CloudIdentity identity = null)
1391+
{
1392+
if (stream == null)
1393+
throw new ArgumentNullException("stream");
1394+
if (uploadPath == null)
1395+
throw new ArgumentNullException("uploadPath");
1396+
if (archiveFormat == null)
1397+
throw new ArgumentNullException("archiveFormat");
1398+
if (chunkSize < 0)
1399+
throw new ArgumentOutOfRangeException("chunkSize");
1400+
CheckIdentity(identity);
1401+
1402+
UriTemplate template;
1403+
if (!string.IsNullOrEmpty(uploadPath))
1404+
template = new UriTemplate("{uploadPath}?extract-archive={archiveFormat}");
1405+
else
1406+
template = new UriTemplate("?extract-archive={archiveFormat}");
1407+
1408+
Uri baseAddress = new Uri(GetServiceEndpointCloudFiles(identity, region, useInternalUrl));
1409+
Dictionary<string, string> parameters = new Dictionary<string, string> { { "archiveFormat", archiveFormat.ToString() } };
1410+
if (!string.IsNullOrEmpty(uploadPath))
1411+
parameters.Add("uploadPath", uploadPath);
1412+
1413+
Uri urlPath = template.BindByName(baseAddress, parameters);
1414+
1415+
RequestSettings settings = BuildDefaultRequestSettings();
1416+
settings.ChunkRequest = true;
1417+
settings.ContentType = contentType;
1418+
1419+
Response response = StreamRESTRequest(identity, urlPath, HttpMethod.PUT, stream, chunkSize, headers: headers, progressUpdated: progressUpdated, requestSettings: settings);
1420+
return JsonConvert.DeserializeObject<ExtractArchiveResponse>(response.RawBody);
1421+
}
1422+
12821423
/// <inheritdoc />
12831424
public void MoveObject(string sourceContainer, string sourceObjectName, string destinationContainer, string destinationObjectName, string destinationContentType = null, Dictionary<string, string> headers = null, string region = null, bool useInternalUrl = false, CloudIdentity identity = null)
12841425
{
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
namespace net.openstack.Providers.Rackspace.Objects
2+
{
3+
using System;
4+
using System.Collections.Concurrent;
5+
using net.openstack.Core;
6+
using Newtonsoft.Json;
7+
8+
/// <summary>
9+
/// Represents a archive format for the Cloud Files Extract Archive operation.
10+
/// </summary>
11+
/// <remarks>
12+
/// This class functions as a strongly-typed enumeration of known archive types,
13+
/// with added support for unknown types returned or supported by a server extension.
14+
/// </remarks>
15+
/// <seealso cref="CloudFilesProvider.ExtractArchive"/>
16+
/// <seealso cref="CloudFilesProvider.ExtractArchiveFromFile"/>
17+
/// <threadsafety static="true" instance="false"/>
18+
/// <preliminary/>
19+
[JsonConverter(typeof(ArchiveFormat.Converter))]
20+
public sealed class ArchiveFormat : ExtensibleEnum<ArchiveFormat>
21+
{
22+
private static readonly ConcurrentDictionary<string, ArchiveFormat> _types =
23+
new ConcurrentDictionary<string, ArchiveFormat>(StringComparer.OrdinalIgnoreCase);
24+
private static readonly ArchiveFormat _tar = FromName("tar");
25+
private static readonly ArchiveFormat _tarGz = FromName("tar.gz");
26+
private static readonly ArchiveFormat _tarBz2 = FromName("tar.bz2");
27+
28+
/// <summary>
29+
/// Initializes a new instance of the <see cref="ArchiveFormat"/> class with the specified name.
30+
/// </summary>
31+
/// <inheritdoc/>
32+
private ArchiveFormat(string name)
33+
: base(name)
34+
{
35+
}
36+
37+
/// <summary>
38+
/// Gets the <see cref="ArchiveFormat"/> instance with the specified name.
39+
/// </summary>
40+
/// <param name="name">The name.</param>
41+
/// <exception cref="ArgumentNullException">If <paramref name="name"/> is <c>null</c>.</exception>
42+
/// <exception cref="ArgumentException">If <paramref name="name"/> is empty.</exception>
43+
public static ArchiveFormat FromName(string name)
44+
{
45+
if (name == null)
46+
throw new ArgumentNullException("name");
47+
if (string.IsNullOrEmpty(name))
48+
throw new ArgumentException("name cannot be empty");
49+
50+
return _types.GetOrAdd(name, i => new ArchiveFormat(i));
51+
}
52+
53+
/// <summary>
54+
/// Gets an <see cref="ArchiveFormat"/> representing <c>tar</c> files.
55+
/// </summary>
56+
public static ArchiveFormat Tar
57+
{
58+
get
59+
{
60+
return _tar;
61+
}
62+
}
63+
64+
/// <summary>
65+
/// Gets an <see cref="ArchiveFormat"/> representing <c>tar.gz</c> files.
66+
/// </summary>
67+
public static ArchiveFormat TarGz
68+
{
69+
get
70+
{
71+
return _tarGz;
72+
}
73+
}
74+
75+
/// <summary>
76+
/// Gets an <see cref="ArchiveFormat"/> representing <c>tar.bz2</c> files.
77+
/// </summary>
78+
public static ArchiveFormat TarBz2
79+
{
80+
get
81+
{
82+
return _tarBz2;
83+
}
84+
}
85+
86+
/// <summary>
87+
/// Provides support for serializing and deserializing <see cref="ArchiveFormat"/>
88+
/// objects to JSON string values.
89+
/// </summary>
90+
/// <threadsafety static="true" instance="false"/>
91+
/// <preliminary/>
92+
private sealed class Converter : ConverterBase
93+
{
94+
/// <inheritdoc/>
95+
protected override ArchiveFormat FromName(string name)
96+
{
97+
return ArchiveFormat.FromName(name);
98+
}
99+
}
100+
}
101+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
namespace net.openstack.Providers.Rackspace.Objects.Response
2+
{
3+
using System;
4+
5+
/// <summary>
6+
/// Represents an error which occurred while extracting a file during an Extract Archive operation.
7+
/// </summary>
8+
/// <seealso cref="CloudFilesProvider.ExtractArchive"/>
9+
/// <seealso cref="CloudFilesProvider.ExtractArchiveFromFile"/>
10+
/// <threadsafety static="true" instance="false"/>
11+
/// <preliminary/>
12+
public class ExtractArchiveError
13+
{
14+
/// <summary>
15+
/// This is the backing field for the <see cref="Path"/> property.
16+
/// </summary>
17+
private readonly string _path;
18+
19+
/// <summary>
20+
/// This is the backing field for the <see cref="Status"/> property.
21+
/// </summary>
22+
private readonly string _status;
23+
24+
/// <summary>
25+
/// Initializes a new instance of the <see cref="ExtractArchiveError"/> class
26+
/// with the specified path and status.
27+
/// </summary>
28+
/// <param name="path">The path of the file affected by this error.</param>
29+
/// <param name="status">The specific status for the error affecting the file.</param>
30+
/// <exception cref="ArgumentNullException">If <paramref name="path"/> is <c>null</c>.</exception>
31+
/// <exception cref="ArgumentException">If <paramref name="path"/> is empty.</exception>
32+
public ExtractArchiveError(string path, string status)
33+
{
34+
if (path == null)
35+
throw new ArgumentNullException("path");
36+
if (string.IsNullOrEmpty(path))
37+
throw new ArgumentException("path cannot be empty");
38+
39+
_path = path;
40+
_status = status;
41+
}
42+
43+
/// <summary>
44+
/// Gets the path of the file affected by this error.
45+
/// </summary>
46+
public string Path
47+
{
48+
get
49+
{
50+
return _path;
51+
}
52+
}
53+
54+
/// <summary>
55+
/// Gets the specific status for the error affecting the file.
56+
/// </summary>
57+
public string Status
58+
{
59+
get
60+
{
61+
return _status;
62+
}
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)