Statistics
| Branch: | Revision:

root / trunk / Pithos.Network / CloudFilesClient.cs @ 126f90b3

History | View | Annotate | Download (58.6 kB)

1 255f5f86 Panagiotis Kanavos
#region
2 255f5f86 Panagiotis Kanavos
/* -----------------------------------------------------------------------
3 255f5f86 Panagiotis Kanavos
 * <copyright file="CloudFilesClient.cs" company="GRNet">
4 255f5f86 Panagiotis Kanavos
 * 
5 255f5f86 Panagiotis Kanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 255f5f86 Panagiotis Kanavos
 *
7 255f5f86 Panagiotis Kanavos
 * Redistribution and use in source and binary forms, with or
8 255f5f86 Panagiotis Kanavos
 * without modification, are permitted provided that the following
9 255f5f86 Panagiotis Kanavos
 * conditions are met:
10 255f5f86 Panagiotis Kanavos
 *
11 255f5f86 Panagiotis Kanavos
 *   1. Redistributions of source code must retain the above
12 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
13 255f5f86 Panagiotis Kanavos
 *      disclaimer.
14 255f5f86 Panagiotis Kanavos
 *
15 255f5f86 Panagiotis Kanavos
 *   2. Redistributions in binary form must reproduce the above
16 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
17 255f5f86 Panagiotis Kanavos
 *      disclaimer in the documentation and/or other materials
18 255f5f86 Panagiotis Kanavos
 *      provided with the distribution.
19 255f5f86 Panagiotis Kanavos
 *
20 255f5f86 Panagiotis Kanavos
 *
21 255f5f86 Panagiotis Kanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 255f5f86 Panagiotis Kanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 255f5f86 Panagiotis Kanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 255f5f86 Panagiotis Kanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 255f5f86 Panagiotis Kanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 255f5f86 Panagiotis Kanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 255f5f86 Panagiotis Kanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 255f5f86 Panagiotis Kanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 255f5f86 Panagiotis Kanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 255f5f86 Panagiotis Kanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 255f5f86 Panagiotis Kanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 255f5f86 Panagiotis Kanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 255f5f86 Panagiotis Kanavos
 *
34 255f5f86 Panagiotis Kanavos
 * The views and conclusions contained in the software and
35 255f5f86 Panagiotis Kanavos
 * documentation are those of the authors and should not be
36 255f5f86 Panagiotis Kanavos
 * interpreted as representing official policies, either expressed
37 255f5f86 Panagiotis Kanavos
 * or implied, of GRNET S.A.
38 255f5f86 Panagiotis Kanavos
 * </copyright>
39 255f5f86 Panagiotis Kanavos
 * -----------------------------------------------------------------------
40 255f5f86 Panagiotis Kanavos
 */
41 255f5f86 Panagiotis Kanavos
#endregion
42 f3d080df Panagiotis Kanavos
43 f3d080df Panagiotis Kanavos
// **CloudFilesClient** provides a simple client interface to CloudFiles and Pithos
44 5ce54458 Panagiotis Kanavos
//
45 5ce54458 Panagiotis Kanavos
// The class provides methods to upload/download files, delete files, manage containers
46 5ce54458 Panagiotis Kanavos
47 5ce54458 Panagiotis Kanavos
48 5ce54458 Panagiotis Kanavos
using System;
49 d78cbf09 Panagiotis Kanavos
using System.Collections.Generic;
50 aba9e6d9 Panagiotis Kanavos
using System.Collections.Specialized;
51 d78cbf09 Panagiotis Kanavos
using System.ComponentModel.Composition;
52 692ec33b Panagiotis Kanavos
using System.Diagnostics;
53 d78cbf09 Panagiotis Kanavos
using System.Diagnostics.Contracts;
54 d78cbf09 Panagiotis Kanavos
using System.IO;
55 d78cbf09 Panagiotis Kanavos
using System.Linq;
56 d78cbf09 Panagiotis Kanavos
using System.Net;
57 d78cbf09 Panagiotis Kanavos
using System.Security.Cryptography;
58 d78cbf09 Panagiotis Kanavos
using System.Text;
59 b5061ac8 Panagiotis Kanavos
using System.Threading.Tasks;
60 d78cbf09 Panagiotis Kanavos
using Newtonsoft.Json;
61 d78cbf09 Panagiotis Kanavos
using Pithos.Interfaces;
62 5120f3cb Panagiotis Kanavos
using log4net;
63 d78cbf09 Panagiotis Kanavos
64 d78cbf09 Panagiotis Kanavos
namespace Pithos.Network
65 d78cbf09 Panagiotis Kanavos
{
66 d78cbf09 Panagiotis Kanavos
    [Export(typeof(ICloudClient))]
67 d78cbf09 Panagiotis Kanavos
    public class CloudFilesClient:ICloudClient
68 d78cbf09 Panagiotis Kanavos
    {
69 5ce54458 Panagiotis Kanavos
        //CloudFilesClient uses *_baseClient* internally to communicate with the server
70 5ce54458 Panagiotis Kanavos
        //RestClient provides a REST-friendly interface over the standard WebClient.
71 9c4346c9 Panagiotis Kanavos
        private RestClient _baseClient;
72 5ce54458 Panagiotis Kanavos
        
73 c53aa229 Panagiotis Kanavos
74 5ce54458 Panagiotis Kanavos
        //During authentication the client provides a UserName 
75 d78cbf09 Panagiotis Kanavos
        public string UserName { get; set; }
76 5ce54458 Panagiotis Kanavos
        
77 5ce54458 Panagiotis Kanavos
        //and and ApiKey to the server
78 5ce54458 Panagiotis Kanavos
        public string ApiKey { get; set; }
79 5ce54458 Panagiotis Kanavos
        
80 5ce54458 Panagiotis Kanavos
        //And receives an authentication Token. This token must be provided in ALL other operations,
81 5ce54458 Panagiotis Kanavos
        //in the X-Auth-Token header
82 c53aa229 Panagiotis Kanavos
        private string _token;
83 c53aa229 Panagiotis Kanavos
        public string Token
84 c53aa229 Panagiotis Kanavos
        {
85 c53aa229 Panagiotis Kanavos
            get { return _token; }
86 c53aa229 Panagiotis Kanavos
            set
87 c53aa229 Panagiotis Kanavos
            {
88 c53aa229 Panagiotis Kanavos
                _token = value;
89 c53aa229 Panagiotis Kanavos
                _baseClient.Headers["X-Auth-Token"] = value;
90 c53aa229 Panagiotis Kanavos
            }
91 c53aa229 Panagiotis Kanavos
        }
92 c53aa229 Panagiotis Kanavos
93 5ce54458 Panagiotis Kanavos
        //The client also receives a StorageUrl after authentication. All subsequent operations must
94 5ce54458 Panagiotis Kanavos
        //use this url
95 5ce54458 Panagiotis Kanavos
        public Uri StorageUrl { get; set; }
96 cfed7823 Panagiotis Kanavos
97 c53aa229 Panagiotis Kanavos
98 cfed7823 Panagiotis Kanavos
        protected Uri RootAddressUri { get; set; }
99 cfed7823 Panagiotis Kanavos
100 34bdb91d Panagiotis Kanavos
       /* private WebProxy _proxy;
101 65282d58 Panagiotis Kanavos
        public WebProxy Proxy
102 65282d58 Panagiotis Kanavos
        {
103 65282d58 Panagiotis Kanavos
            get { return _proxy; }
104 65282d58 Panagiotis Kanavos
            set
105 65282d58 Panagiotis Kanavos
            {
106 65282d58 Panagiotis Kanavos
                _proxy = value;
107 65282d58 Panagiotis Kanavos
                if (_baseClient != null)
108 65282d58 Panagiotis Kanavos
                    _baseClient.Proxy = value;                
109 65282d58 Panagiotis Kanavos
            }
110 65282d58 Panagiotis Kanavos
        }
111 34bdb91d Panagiotis Kanavos
*/
112 65282d58 Panagiotis Kanavos
113 65282d58 Panagiotis Kanavos
        /* private Uri _proxy;
114 c53aa229 Panagiotis Kanavos
        public Uri Proxy
115 c53aa229 Panagiotis Kanavos
        {
116 c53aa229 Panagiotis Kanavos
            get { return _proxy; }
117 c53aa229 Panagiotis Kanavos
            set
118 c53aa229 Panagiotis Kanavos
            {
119 c53aa229 Panagiotis Kanavos
                _proxy = value;
120 c53aa229 Panagiotis Kanavos
                if (_baseClient != null)
121 c53aa229 Panagiotis Kanavos
                    _baseClient.Proxy = new WebProxy(value);                
122 c53aa229 Panagiotis Kanavos
            }
123 65282d58 Panagiotis Kanavos
        }*/
124 b5061ac8 Panagiotis Kanavos
125 b5061ac8 Panagiotis Kanavos
        public double DownloadPercentLimit { get; set; }
126 b5061ac8 Panagiotis Kanavos
        public double UploadPercentLimit { get; set; }
127 79736291 Panagiotis Kanavos
128 79736291 Panagiotis Kanavos
        public string AuthenticationUrl { get; set; }
129 79736291 Panagiotis Kanavos
130 1482f9ad Panagiotis Kanavos
 
131 1482f9ad Panagiotis Kanavos
        public string VersionPath
132 1482f9ad Panagiotis Kanavos
        {
133 1482f9ad Panagiotis Kanavos
            get { return UsePithos ? "v1" : "v1.0"; }
134 1482f9ad Panagiotis Kanavos
        }
135 2c053915 Panagiotis Kanavos
136 2c053915 Panagiotis Kanavos
        public bool UsePithos { get; set; }
137 d78cbf09 Panagiotis Kanavos
138 3c43ec9b Panagiotis Kanavos
139 5120f3cb Panagiotis Kanavos
        private static readonly ILog Log = LogManager.GetLogger("CloudFilesClient");
140 5120f3cb Panagiotis Kanavos
141 c53aa229 Panagiotis Kanavos
        public CloudFilesClient(string userName, string apiKey)
142 d78cbf09 Panagiotis Kanavos
        {
143 c53aa229 Panagiotis Kanavos
            UserName = userName;
144 c53aa229 Panagiotis Kanavos
            ApiKey = apiKey;
145 c53aa229 Panagiotis Kanavos
        }
146 c53aa229 Panagiotis Kanavos
147 c53aa229 Panagiotis Kanavos
        public CloudFilesClient(AccountInfo accountInfo)
148 c53aa229 Panagiotis Kanavos
        {
149 c53aa229 Panagiotis Kanavos
            if (accountInfo==null)
150 c53aa229 Panagiotis Kanavos
                throw new ArgumentNullException("accountInfo");
151 c53aa229 Panagiotis Kanavos
            Contract.Ensures(!String.IsNullOrWhiteSpace(Token));
152 c53aa229 Panagiotis Kanavos
            Contract.Ensures(StorageUrl != null);
153 cfed7823 Panagiotis Kanavos
            Contract.Ensures(_baseClient != null);
154 c53aa229 Panagiotis Kanavos
            Contract.Ensures(RootAddressUri != null);
155 422c9598 Panagiotis Kanavos
            Contract.EndContractBlock();          
156 cfed7823 Panagiotis Kanavos
157 c53aa229 Panagiotis Kanavos
            _baseClient = new RestClient
158 c53aa229 Panagiotis Kanavos
            {
159 c53aa229 Panagiotis Kanavos
                BaseAddress = accountInfo.StorageUri.ToString(),
160 c53aa229 Panagiotis Kanavos
                Timeout = 10000,
161 65282d58 Panagiotis Kanavos
                Retries = 3,
162 c53aa229 Panagiotis Kanavos
            };
163 c53aa229 Panagiotis Kanavos
            StorageUrl = accountInfo.StorageUri;
164 c53aa229 Panagiotis Kanavos
            Token = accountInfo.Token;
165 c53aa229 Panagiotis Kanavos
            UserName = accountInfo.UserName;
166 c53aa229 Panagiotis Kanavos
167 c53aa229 Panagiotis Kanavos
            //Get the root address (StorageUrl without the account)
168 c53aa229 Panagiotis Kanavos
            var storageUrl = StorageUrl.AbsoluteUri;
169 c53aa229 Panagiotis Kanavos
            var usernameIndex = storageUrl.LastIndexOf(UserName);
170 c53aa229 Panagiotis Kanavos
            var rootUrl = storageUrl.Substring(0, usernameIndex);
171 c53aa229 Panagiotis Kanavos
            RootAddressUri = new Uri(rootUrl);
172 c53aa229 Panagiotis Kanavos
        }
173 d78cbf09 Panagiotis Kanavos
174 3c43ec9b Panagiotis Kanavos
175 c53aa229 Panagiotis Kanavos
        public AccountInfo Authenticate()
176 c53aa229 Panagiotis Kanavos
        {
177 c53aa229 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(UserName))
178 c53aa229 Panagiotis Kanavos
                throw new InvalidOperationException("UserName is empty");
179 c53aa229 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(ApiKey))
180 c53aa229 Panagiotis Kanavos
                throw new InvalidOperationException("ApiKey is empty");
181 c53aa229 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(AuthenticationUrl))
182 c53aa229 Panagiotis Kanavos
                throw new InvalidOperationException("AuthenticationUrl is empty");
183 c53aa229 Panagiotis Kanavos
            Contract.Ensures(!String.IsNullOrWhiteSpace(Token));
184 c53aa229 Panagiotis Kanavos
            Contract.Ensures(StorageUrl != null);
185 c53aa229 Panagiotis Kanavos
            Contract.Ensures(_baseClient != null);
186 c53aa229 Panagiotis Kanavos
            Contract.Ensures(RootAddressUri != null);
187 c53aa229 Panagiotis Kanavos
            Contract.EndContractBlock();
188 c53aa229 Panagiotis Kanavos
189 c53aa229 Panagiotis Kanavos
190 c53aa229 Panagiotis Kanavos
            Log.InfoFormat("[AUTHENTICATE] Start for {0}", UserName);
191 d78cbf09 Panagiotis Kanavos
192 c92e02f3 Panagiotis Kanavos
            var groups = new List<Group>();
193 c92e02f3 Panagiotis Kanavos
194 9c4346c9 Panagiotis Kanavos
            using (var authClient = new RestClient{BaseAddress=AuthenticationUrl})
195 65282d58 Panagiotis Kanavos
            {                
196 34bdb91d Panagiotis Kanavos
               /* if (Proxy != null)
197 34bdb91d Panagiotis Kanavos
                    authClient.Proxy = Proxy;*/
198 d78cbf09 Panagiotis Kanavos
199 cfed7823 Panagiotis Kanavos
                Contract.Assume(authClient.Headers!=null);
200 cfed7823 Panagiotis Kanavos
201 4d301e8e Panagiotis Kanavos
                authClient.Headers.Add("X-Auth-User", UserName);
202 4d301e8e Panagiotis Kanavos
                authClient.Headers.Add("X-Auth-Key", ApiKey);
203 0eea575a Panagiotis Kanavos
204 cd7c162f Panagiotis Kanavos
                authClient.DownloadStringWithRetry(VersionPath, 3);
205 0eea575a Panagiotis Kanavos
206 4d301e8e Panagiotis Kanavos
                authClient.AssertStatusOK("Authentication failed");
207 0eea575a Panagiotis Kanavos
208 cd7c162f Panagiotis Kanavos
                var storageUrl = authClient.GetHeaderValue("X-Storage-Url");
209 0eea575a Panagiotis Kanavos
                if (String.IsNullOrWhiteSpace(storageUrl))
210 0eea575a Panagiotis Kanavos
                    throw new InvalidOperationException("Failed to obtain storage url");
211 c53aa229 Panagiotis Kanavos
                
212 c53aa229 Panagiotis Kanavos
                _baseClient = new RestClient
213 c53aa229 Panagiotis Kanavos
                {
214 c53aa229 Panagiotis Kanavos
                    BaseAddress = storageUrl,
215 c53aa229 Panagiotis Kanavos
                    Timeout = 10000,
216 65282d58 Panagiotis Kanavos
                    Retries = 3,
217 34bdb91d Panagiotis Kanavos
                    //Proxy=Proxy
218 c53aa229 Panagiotis Kanavos
                };
219 c53aa229 Panagiotis Kanavos
220 0eea575a Panagiotis Kanavos
                StorageUrl = new Uri(storageUrl);
221 d9643dd6 Panagiotis Kanavos
                
222 cfed7823 Panagiotis Kanavos
                //Get the root address (StorageUrl without the account)
223 cfed7823 Panagiotis Kanavos
                var usernameIndex=storageUrl.LastIndexOf(UserName);
224 cfed7823 Panagiotis Kanavos
                var rootUrl = storageUrl.Substring(0, usernameIndex);
225 cfed7823 Panagiotis Kanavos
                RootAddressUri = new Uri(rootUrl);
226 cfed7823 Panagiotis Kanavos
                
227 4d301e8e Panagiotis Kanavos
                var token = authClient.GetHeaderValue("X-Auth-Token");
228 b6c72f62 Panagiotis Kanavos
                if (String.IsNullOrWhiteSpace(token))
229 b6c72f62 Panagiotis Kanavos
                    throw new InvalidOperationException("Failed to obtain token url");
230 b6c72f62 Panagiotis Kanavos
                Token = token;
231 c53aa229 Panagiotis Kanavos
232 c92e02f3 Panagiotis Kanavos
               /* var keys = authClient.ResponseHeaders.AllKeys.AsQueryable();
233 c92e02f3 Panagiotis Kanavos
                groups = (from key in keys
234 c92e02f3 Panagiotis Kanavos
                            where key.StartsWith("X-Account-Group-")
235 c92e02f3 Panagiotis Kanavos
                            let name = key.Substring(16)
236 c92e02f3 Panagiotis Kanavos
                            select new Group(name, authClient.ResponseHeaders[key]))
237 c92e02f3 Panagiotis Kanavos
                        .ToList();
238 c92e02f3 Panagiotis Kanavos
                    
239 c92e02f3 Panagiotis Kanavos
*/
240 b6c72f62 Panagiotis Kanavos
            }
241 d78cbf09 Panagiotis Kanavos
242 c53aa229 Panagiotis Kanavos
            Log.InfoFormat("[AUTHENTICATE] End for {0}", UserName);
243 0bd56b7c Panagiotis Kanavos
            
244 9c4346c9 Panagiotis Kanavos
245 c92e02f3 Panagiotis Kanavos
            return new AccountInfo {StorageUri = StorageUrl, Token = Token, UserName = UserName,Groups=groups};            
246 2c053915 Panagiotis Kanavos
247 b5061ac8 Panagiotis Kanavos
        }
248 d78cbf09 Panagiotis Kanavos
249 d78cbf09 Panagiotis Kanavos
250 cfed7823 Panagiotis Kanavos
251 cfed7823 Panagiotis Kanavos
        public IList<ContainerInfo> ListContainers(string account)
252 9c4346c9 Panagiotis Kanavos
        {
253 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
254 9c4346c9 Panagiotis Kanavos
            {
255 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
256 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
257 cfed7823 Panagiotis Kanavos
                
258 9c4346c9 Panagiotis Kanavos
                client.Parameters.Clear();
259 9c4346c9 Panagiotis Kanavos
                client.Parameters.Add("format", "json");
260 5ce54458 Panagiotis Kanavos
                var content = client.DownloadStringWithRetry("", 3);
261 9c4346c9 Panagiotis Kanavos
                client.AssertStatusOK("List Containers failed");
262 9c4346c9 Panagiotis Kanavos
263 9c4346c9 Panagiotis Kanavos
                if (client.StatusCode == HttpStatusCode.NoContent)
264 9c4346c9 Panagiotis Kanavos
                    return new List<ContainerInfo>();
265 9c4346c9 Panagiotis Kanavos
                var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(content);
266 5750d7cc Panagiotis Kanavos
                
267 5750d7cc Panagiotis Kanavos
                foreach (var info in infos)
268 5750d7cc Panagiotis Kanavos
                {
269 5750d7cc Panagiotis Kanavos
                    info.Account = account;
270 5750d7cc Panagiotis Kanavos
                }
271 9c4346c9 Panagiotis Kanavos
                return infos;
272 9c4346c9 Panagiotis Kanavos
            }
273 4d301e8e Panagiotis Kanavos
274 d78cbf09 Panagiotis Kanavos
        }
275 d78cbf09 Panagiotis Kanavos
276 cfed7823 Panagiotis Kanavos
        private string GetAccountUrl(string account)
277 cfed7823 Panagiotis Kanavos
        {
278 4f6d51d4 Panagiotis Kanavos
            return new Uri(RootAddressUri, new Uri(account,UriKind.Relative)).AbsoluteUri;
279 cfed7823 Panagiotis Kanavos
        }
280 cfed7823 Panagiotis Kanavos
281 cfed7823 Panagiotis Kanavos
        public IList<ShareAccountInfo> ListSharingAccounts(DateTime? since=null)
282 cfed7823 Panagiotis Kanavos
        {
283 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Share"].Push("List Accounts"))
284 cfed7823 Panagiotis Kanavos
            {
285 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
286 cfed7823 Panagiotis Kanavos
287 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
288 5120f3cb Panagiotis Kanavos
                {
289 5120f3cb Panagiotis Kanavos
                    client.Parameters.Clear();
290 5120f3cb Panagiotis Kanavos
                    client.Parameters.Add("format", "json");
291 5120f3cb Panagiotis Kanavos
                    client.IfModifiedSince = since;
292 cfed7823 Panagiotis Kanavos
293 5120f3cb Panagiotis Kanavos
                    //Extract the username from the base address
294 5120f3cb Panagiotis Kanavos
                    client.BaseAddress = RootAddressUri.AbsoluteUri;
295 cfed7823 Panagiotis Kanavos
296 5120f3cb Panagiotis Kanavos
                    var content = client.DownloadStringWithRetry(@"", 3);
297 cfed7823 Panagiotis Kanavos
298 5120f3cb Panagiotis Kanavos
                    client.AssertStatusOK("ListSharingAccounts failed");
299 5120f3cb Panagiotis Kanavos
300 5120f3cb Panagiotis Kanavos
                    //If the result is empty, return an empty list,
301 5120f3cb Panagiotis Kanavos
                    var infos = String.IsNullOrWhiteSpace(content)
302 5120f3cb Panagiotis Kanavos
                                    ? new List<ShareAccountInfo>()
303 5120f3cb Panagiotis Kanavos
                                //Otherwise deserialize the account list into a list of ShareAccountInfos
304 5120f3cb Panagiotis Kanavos
                                    : JsonConvert.DeserializeObject<IList<ShareAccountInfo>>(content);
305 5120f3cb Panagiotis Kanavos
306 5120f3cb Panagiotis Kanavos
                    Log.DebugFormat("END");
307 5120f3cb Panagiotis Kanavos
                    return infos;
308 5120f3cb Panagiotis Kanavos
                }
309 cfed7823 Panagiotis Kanavos
            }
310 cfed7823 Panagiotis Kanavos
        }
311 cfed7823 Panagiotis Kanavos
312 5ce54458 Panagiotis Kanavos
        //Request listing of all objects in a container modified since a specific time.
313 5ce54458 Panagiotis Kanavos
        //If the *since* value is missing, return all objects
314 cfed7823 Panagiotis Kanavos
        public IList<ObjectInfo> ListSharedObjects(DateTime? since = null)
315 cfed7823 Panagiotis Kanavos
        {
316 cfed7823 Panagiotis Kanavos
317 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Share"].Push("List Objects"))
318 cfed7823 Panagiotis Kanavos
            {
319 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
320 5120f3cb Panagiotis Kanavos
321 5120f3cb Panagiotis Kanavos
                var accounts = ListSharingAccounts(since);
322 126f90b3 Panagiotis Kanavos
                var items = from account in accounts 
323 126f90b3 Panagiotis Kanavos
                            let containers = ListContainers(account.name) 
324 126f90b3 Panagiotis Kanavos
                            from container in containers 
325 126f90b3 Panagiotis Kanavos
                            select ListObjects(account.name, container.Name);
326 126f90b3 Panagiotis Kanavos
                var objects=items.SelectMany(r=> r).ToList();
327 126f90b3 Panagiotis Kanavos
/*
328 126f90b3 Panagiotis Kanavos
                var objects = new List<ObjectInfo>();
329 126f90b3 Panagiotis Kanavos
                foreach (var containerObjects in items)
330 cfed7823 Panagiotis Kanavos
                {
331 126f90b3 Panagiotis Kanavos
                    objects.AddRange(containerObjects);
332 cfed7823 Panagiotis Kanavos
                }
333 126f90b3 Panagiotis Kanavos
*/
334 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("END");
335 5120f3cb Panagiotis Kanavos
                return objects;
336 cfed7823 Panagiotis Kanavos
            }
337 cfed7823 Panagiotis Kanavos
        }
338 cfed7823 Panagiotis Kanavos
339 ff26eb71 Panagiotis Kanavos
        public void SetTags(ObjectInfo target,IDictionary<string,string> tags)
340 ff26eb71 Panagiotis Kanavos
        {
341 ff26eb71 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
342 ff26eb71 Panagiotis Kanavos
                throw new InvalidOperationException("The Token is not set");
343 ff26eb71 Panagiotis Kanavos
            if (StorageUrl == null)
344 ff26eb71 Panagiotis Kanavos
                throw new InvalidOperationException("The StorageUrl is not set");
345 ff26eb71 Panagiotis Kanavos
            if (target == null)
346 ff26eb71 Panagiotis Kanavos
                throw new ArgumentNullException("target");
347 ff26eb71 Panagiotis Kanavos
            Contract.EndContractBlock();
348 ff26eb71 Panagiotis Kanavos
349 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Share"].Push("Share Object"))
350 ff26eb71 Panagiotis Kanavos
            {
351 ff26eb71 Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
352 ff26eb71 Panagiotis Kanavos
353 ff26eb71 Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
354 ff26eb71 Panagiotis Kanavos
                {
355 ff26eb71 Panagiotis Kanavos
356 ff26eb71 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(target.Account);
357 ff26eb71 Panagiotis Kanavos
358 ff26eb71 Panagiotis Kanavos
                    client.Parameters.Clear();
359 ff26eb71 Panagiotis Kanavos
                    client.Parameters.Add("update", "");
360 ff26eb71 Panagiotis Kanavos
361 ff26eb71 Panagiotis Kanavos
                    foreach (var tag in tags)
362 ff26eb71 Panagiotis Kanavos
                    {
363 ff26eb71 Panagiotis Kanavos
                        var headerTag = String.Format("X-Object-Meta-{0}", tag.Key);
364 ff26eb71 Panagiotis Kanavos
                        client.Headers.Add(headerTag, tag.Value);
365 ff26eb71 Panagiotis Kanavos
                    }
366 ff26eb71 Panagiotis Kanavos
                    
367 4f6d51d4 Panagiotis Kanavos
                    client.DownloadStringWithRetry(target.Container, 3);
368 ff26eb71 Panagiotis Kanavos
369 ff26eb71 Panagiotis Kanavos
                    
370 ff26eb71 Panagiotis Kanavos
                    client.AssertStatusOK("SetTags failed");
371 ff26eb71 Panagiotis Kanavos
                    //If the status is NOT ACCEPTED we have a problem
372 ff26eb71 Panagiotis Kanavos
                    if (client.StatusCode != HttpStatusCode.Accepted)
373 ff26eb71 Panagiotis Kanavos
                    {
374 ff26eb71 Panagiotis Kanavos
                        Log.Error("Failed to set tags");
375 ff26eb71 Panagiotis Kanavos
                        throw new Exception("Failed to set tags");
376 ff26eb71 Panagiotis Kanavos
                    }
377 ff26eb71 Panagiotis Kanavos
378 ff26eb71 Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
379 ff26eb71 Panagiotis Kanavos
                }
380 ff26eb71 Panagiotis Kanavos
            }
381 ff26eb71 Panagiotis Kanavos
382 ff26eb71 Panagiotis Kanavos
383 ff26eb71 Panagiotis Kanavos
        }
384 ff26eb71 Panagiotis Kanavos
385 cfed7823 Panagiotis Kanavos
        public void ShareObject(string account, string container, string objectName, string shareTo, bool read, bool write)
386 cfed7823 Panagiotis Kanavos
        {
387 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
388 cfed7823 Panagiotis Kanavos
                throw new InvalidOperationException("The Token is not set");
389 cfed7823 Panagiotis Kanavos
            if (StorageUrl==null)
390 cfed7823 Panagiotis Kanavos
                throw new InvalidOperationException("The StorageUrl is not set");
391 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
392 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("container");
393 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
394 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("objectName");
395 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(account))
396 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("account");
397 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(shareTo))
398 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("shareTo");
399 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
400 cfed7823 Panagiotis Kanavos
401 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Share"].Push("Share Object"))
402 cfed7823 Panagiotis Kanavos
            {
403 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
404 5120f3cb Panagiotis Kanavos
                
405 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
406 5120f3cb Panagiotis Kanavos
                {
407 cfed7823 Panagiotis Kanavos
408 5120f3cb Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
409 cfed7823 Panagiotis Kanavos
410 5120f3cb Panagiotis Kanavos
                    client.Parameters.Clear();
411 5120f3cb Panagiotis Kanavos
                    client.Parameters.Add("format", "json");
412 5120f3cb Panagiotis Kanavos
413 5120f3cb Panagiotis Kanavos
                    string permission = "";
414 5120f3cb Panagiotis Kanavos
                    if (write)
415 5120f3cb Panagiotis Kanavos
                        permission = String.Format("write={0}", shareTo);
416 5120f3cb Panagiotis Kanavos
                    else if (read)
417 5120f3cb Panagiotis Kanavos
                        permission = String.Format("read={0}", shareTo);
418 5120f3cb Panagiotis Kanavos
                    client.Headers.Add("X-Object-Sharing", permission);
419 cfed7823 Panagiotis Kanavos
420 5120f3cb Panagiotis Kanavos
                    var content = client.DownloadStringWithRetry(container, 3);
421 cfed7823 Panagiotis Kanavos
422 5120f3cb Panagiotis Kanavos
                    client.AssertStatusOK("ShareObject failed");
423 cfed7823 Panagiotis Kanavos
424 5120f3cb Panagiotis Kanavos
                    //If the result is empty, return an empty list,
425 5120f3cb Panagiotis Kanavos
                    var infos = String.IsNullOrWhiteSpace(content)
426 5120f3cb Panagiotis Kanavos
                                    ? new List<ObjectInfo>()
427 5120f3cb Panagiotis Kanavos
                                //Otherwise deserialize the object list into a list of ObjectInfos
428 5120f3cb Panagiotis Kanavos
                                    : JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
429 5120f3cb Panagiotis Kanavos
430 5120f3cb Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
431 5120f3cb Panagiotis Kanavos
                }
432 cfed7823 Panagiotis Kanavos
            }
433 cfed7823 Panagiotis Kanavos
434 5120f3cb Panagiotis Kanavos
435 cfed7823 Panagiotis Kanavos
        }
436 cfed7823 Panagiotis Kanavos
437 0bd56b7c Panagiotis Kanavos
        public AccountInfo GetAccountPolicies(AccountInfo accountInfo)
438 0bd56b7c Panagiotis Kanavos
        {
439 0bd56b7c Panagiotis Kanavos
            if (accountInfo==null)
440 0bd56b7c Panagiotis Kanavos
                throw new ArgumentNullException("accountInfo");
441 0bd56b7c Panagiotis Kanavos
            Contract.EndContractBlock();
442 0bd56b7c Panagiotis Kanavos
443 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Account"].Push("GetPolicies"))
444 0bd56b7c Panagiotis Kanavos
            {
445 0bd56b7c Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
446 0bd56b7c Panagiotis Kanavos
447 0bd56b7c Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
448 0bd56b7c Panagiotis Kanavos
                {
449 0bd56b7c Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(accountInfo.UserName))
450 0bd56b7c Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(accountInfo.UserName);
451 0bd56b7c Panagiotis Kanavos
452 0bd56b7c Panagiotis Kanavos
                    client.Parameters.Clear();
453 0bd56b7c Panagiotis Kanavos
                    client.Parameters.Add("format", "json");                    
454 0bd56b7c Panagiotis Kanavos
                    client.Head(String.Empty, 3);
455 0bd56b7c Panagiotis Kanavos
456 0bd56b7c Panagiotis Kanavos
                    var quotaValue=client.ResponseHeaders["X-Account-Policy-Quota"];
457 0bd56b7c Panagiotis Kanavos
                    var bytesValue= client.ResponseHeaders["X-Account-Bytes-Used"];
458 0bd56b7c Panagiotis Kanavos
459 0bd56b7c Panagiotis Kanavos
                    long quota, bytes;
460 0bd56b7c Panagiotis Kanavos
                    if (long.TryParse(quotaValue, out quota))
461 0bd56b7c Panagiotis Kanavos
                        accountInfo.Quota = quota;
462 0bd56b7c Panagiotis Kanavos
                    if (long.TryParse(bytesValue, out bytes))
463 0bd56b7c Panagiotis Kanavos
                        accountInfo.BytesUsed = bytes;
464 0bd56b7c Panagiotis Kanavos
                    
465 0bd56b7c Panagiotis Kanavos
                    return accountInfo;
466 0bd56b7c Panagiotis Kanavos
467 0bd56b7c Panagiotis Kanavos
                }
468 0bd56b7c Panagiotis Kanavos
469 0bd56b7c Panagiotis Kanavos
            }
470 0bd56b7c Panagiotis Kanavos
        }
471 0bd56b7c Panagiotis Kanavos
472 aba9e6d9 Panagiotis Kanavos
        public void UpdateMetadata(ObjectInfo objectInfo)
473 aba9e6d9 Panagiotis Kanavos
        {
474 aba9e6d9 Panagiotis Kanavos
            if (objectInfo == null)
475 aba9e6d9 Panagiotis Kanavos
                throw new ArgumentNullException("objectInfo");
476 aba9e6d9 Panagiotis Kanavos
            Contract.EndContractBlock();
477 aba9e6d9 Panagiotis Kanavos
478 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Objects"].Push("UpdateMetadata"))
479 aba9e6d9 Panagiotis Kanavos
            {
480 aba9e6d9 Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
481 aba9e6d9 Panagiotis Kanavos
482 aba9e6d9 Panagiotis Kanavos
483 aba9e6d9 Panagiotis Kanavos
                using(var client=new RestClient(_baseClient))
484 aba9e6d9 Panagiotis Kanavos
                {
485 aba9e6d9 Panagiotis Kanavos
486 aba9e6d9 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(objectInfo.Account);
487 aba9e6d9 Panagiotis Kanavos
                    
488 aba9e6d9 Panagiotis Kanavos
                    client.Parameters.Clear();
489 aba9e6d9 Panagiotis Kanavos
                    
490 aba9e6d9 Panagiotis Kanavos
491 aba9e6d9 Panagiotis Kanavos
                    //Set Tags
492 aba9e6d9 Panagiotis Kanavos
                    foreach (var tag in objectInfo.Tags)
493 aba9e6d9 Panagiotis Kanavos
                    {
494 aba9e6d9 Panagiotis Kanavos
                        var headerTag = String.Format("X-Object-Meta-{0}", tag.Key);
495 aba9e6d9 Panagiotis Kanavos
                        client.Headers.Add(headerTag, tag.Value);
496 aba9e6d9 Panagiotis Kanavos
                    }
497 aba9e6d9 Panagiotis Kanavos
498 aba9e6d9 Panagiotis Kanavos
                    //Set Permissions
499 aba9e6d9 Panagiotis Kanavos
500 aba9e6d9 Panagiotis Kanavos
                    var permissions=objectInfo.GetPermissionString();
501 aba9e6d9 Panagiotis Kanavos
                    client.SetNonEmptyHeaderValue("X-Object-Sharing",permissions);
502 aba9e6d9 Panagiotis Kanavos
503 aba9e6d9 Panagiotis Kanavos
                    client.SetNonEmptyHeaderValue("Content-Disposition",objectInfo.ContendDisposition);
504 aba9e6d9 Panagiotis Kanavos
                    client.SetNonEmptyHeaderValue("Content-Encoding",objectInfo.ContentEncoding);
505 aba9e6d9 Panagiotis Kanavos
                    client.SetNonEmptyHeaderValue("X-Object-Manifest",objectInfo.Manifest);
506 f0947233 Panagiotis Kanavos
                    var isPublic = objectInfo.IsPublic.ToString().ToLower();
507 f0947233 Panagiotis Kanavos
                    client.Headers.Add("X-Object-Public", isPublic);
508 aba9e6d9 Panagiotis Kanavos
509 aba9e6d9 Panagiotis Kanavos
510 aba9e6d9 Panagiotis Kanavos
                    var uriBuilder = client.GetAddressBuilder(objectInfo.Container, objectInfo.Name);
511 aba9e6d9 Panagiotis Kanavos
                    var uri = uriBuilder.Uri;
512 aba9e6d9 Panagiotis Kanavos
513 4f6d51d4 Panagiotis Kanavos
                    client.UploadValues(uri,new NameValueCollection());
514 aba9e6d9 Panagiotis Kanavos
515 aba9e6d9 Panagiotis Kanavos
516 aba9e6d9 Panagiotis Kanavos
                    client.AssertStatusOK("UpdateMetadata failed");
517 aba9e6d9 Panagiotis Kanavos
                    //If the status is NOT ACCEPTED or OK we have a problem
518 aba9e6d9 Panagiotis Kanavos
                    if (!(client.StatusCode == HttpStatusCode.Accepted || client.StatusCode == HttpStatusCode.OK))
519 aba9e6d9 Panagiotis Kanavos
                    {
520 aba9e6d9 Panagiotis Kanavos
                        Log.Error("Failed to update metadata");
521 aba9e6d9 Panagiotis Kanavos
                        throw new Exception("Failed to update metadata");
522 aba9e6d9 Panagiotis Kanavos
                    }
523 aba9e6d9 Panagiotis Kanavos
524 aba9e6d9 Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
525 aba9e6d9 Panagiotis Kanavos
                }
526 aba9e6d9 Panagiotis Kanavos
            }
527 aba9e6d9 Panagiotis Kanavos
528 aba9e6d9 Panagiotis Kanavos
        }
529 aba9e6d9 Panagiotis Kanavos
530 c92e02f3 Panagiotis Kanavos
        public void UpdateMetadata(ContainerInfo containerInfo)
531 c92e02f3 Panagiotis Kanavos
        {
532 c92e02f3 Panagiotis Kanavos
            if (containerInfo == null)
533 c92e02f3 Panagiotis Kanavos
                throw new ArgumentNullException("containerInfo");
534 c92e02f3 Panagiotis Kanavos
            Contract.EndContractBlock();
535 c92e02f3 Panagiotis Kanavos
536 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Containers"].Push("UpdateMetadata"))
537 c92e02f3 Panagiotis Kanavos
            {
538 c92e02f3 Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
539 c92e02f3 Panagiotis Kanavos
540 c92e02f3 Panagiotis Kanavos
541 c92e02f3 Panagiotis Kanavos
                using(var client=new RestClient(_baseClient))
542 c92e02f3 Panagiotis Kanavos
                {
543 c92e02f3 Panagiotis Kanavos
544 c92e02f3 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(containerInfo.Account);
545 c92e02f3 Panagiotis Kanavos
                    
546 c92e02f3 Panagiotis Kanavos
                    client.Parameters.Clear();
547 c92e02f3 Panagiotis Kanavos
                    
548 c92e02f3 Panagiotis Kanavos
549 c92e02f3 Panagiotis Kanavos
                    //Set Tags
550 c92e02f3 Panagiotis Kanavos
                    foreach (var tag in containerInfo.Tags)
551 c92e02f3 Panagiotis Kanavos
                    {
552 c92e02f3 Panagiotis Kanavos
                        var headerTag = String.Format("X-Container-Meta-{0}", tag.Key);
553 c92e02f3 Panagiotis Kanavos
                        client.Headers.Add(headerTag, tag.Value);
554 c92e02f3 Panagiotis Kanavos
                    }
555 c92e02f3 Panagiotis Kanavos
556 c92e02f3 Panagiotis Kanavos
                    
557 c92e02f3 Panagiotis Kanavos
                    //Set Policies
558 c92e02f3 Panagiotis Kanavos
                    foreach (var policy in containerInfo.Policies)
559 c92e02f3 Panagiotis Kanavos
                    {
560 c92e02f3 Panagiotis Kanavos
                        var headerPolicy = String.Format("X-Container-Policy-{0}", policy.Key);
561 c92e02f3 Panagiotis Kanavos
                        client.Headers.Add(headerPolicy, policy.Value);
562 c92e02f3 Panagiotis Kanavos
                    }
563 c92e02f3 Panagiotis Kanavos
564 c92e02f3 Panagiotis Kanavos
565 c92e02f3 Panagiotis Kanavos
                    var uriBuilder = client.GetAddressBuilder(containerInfo.Name,"");
566 c92e02f3 Panagiotis Kanavos
                    var uri = uriBuilder.Uri;
567 c92e02f3 Panagiotis Kanavos
568 4f6d51d4 Panagiotis Kanavos
                    client.UploadValues(uri,new NameValueCollection());
569 c92e02f3 Panagiotis Kanavos
570 c92e02f3 Panagiotis Kanavos
571 c92e02f3 Panagiotis Kanavos
                    client.AssertStatusOK("UpdateMetadata failed");
572 c92e02f3 Panagiotis Kanavos
                    //If the status is NOT ACCEPTED or OK we have a problem
573 c92e02f3 Panagiotis Kanavos
                    if (!(client.StatusCode == HttpStatusCode.Accepted || client.StatusCode == HttpStatusCode.OK))
574 c92e02f3 Panagiotis Kanavos
                    {
575 c92e02f3 Panagiotis Kanavos
                        Log.Error("Failed to update metadata");
576 c92e02f3 Panagiotis Kanavos
                        throw new Exception("Failed to update metadata");
577 c92e02f3 Panagiotis Kanavos
                    }
578 c92e02f3 Panagiotis Kanavos
579 c92e02f3 Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
580 c92e02f3 Panagiotis Kanavos
                }
581 c92e02f3 Panagiotis Kanavos
            }
582 c92e02f3 Panagiotis Kanavos
583 c92e02f3 Panagiotis Kanavos
        }
584 c92e02f3 Panagiotis Kanavos
585 cfed7823 Panagiotis Kanavos
586 cfed7823 Panagiotis Kanavos
        public IList<ObjectInfo> ListObjects(string account, string container, DateTime? since = null)
587 d78cbf09 Panagiotis Kanavos
        {
588 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
589 9c4346c9 Panagiotis Kanavos
                throw new ArgumentNullException("container");
590 9c4346c9 Panagiotis Kanavos
            Contract.EndContractBlock();
591 d78cbf09 Panagiotis Kanavos
592 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Objects"].Push("List"))
593 9c4346c9 Panagiotis Kanavos
            {
594 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
595 cfed7823 Panagiotis Kanavos
596 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
597 5120f3cb Panagiotis Kanavos
                {
598 5120f3cb Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
599 5120f3cb Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
600 4d301e8e Panagiotis Kanavos
601 5120f3cb Panagiotis Kanavos
                    client.Parameters.Clear();
602 5120f3cb Panagiotis Kanavos
                    client.Parameters.Add("format", "json");
603 5120f3cb Panagiotis Kanavos
                    client.IfModifiedSince = since;
604 5120f3cb Panagiotis Kanavos
                    var content = client.DownloadStringWithRetry(container, 3);
605 4d301e8e Panagiotis Kanavos
606 5120f3cb Panagiotis Kanavos
                    client.AssertStatusOK("ListObjects failed");
607 d78cbf09 Panagiotis Kanavos
608 126f90b3 Panagiotis Kanavos
                    //HACK: Must add it to all other operations as well
609 126f90b3 Panagiotis Kanavos
                    StatusCode = client.StatusCode;
610 5120f3cb Panagiotis Kanavos
                    //If the result is empty, return an empty list,
611 5120f3cb Panagiotis Kanavos
                    var infos = String.IsNullOrWhiteSpace(content)
612 5120f3cb Panagiotis Kanavos
                                    ? new List<ObjectInfo>()
613 5120f3cb Panagiotis Kanavos
                                //Otherwise deserialize the object list into a list of ObjectInfos
614 5120f3cb Panagiotis Kanavos
                                    : JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
615 5120f3cb Panagiotis Kanavos
616 5120f3cb Panagiotis Kanavos
                    foreach (var info in infos)
617 5120f3cb Panagiotis Kanavos
                    {
618 5120f3cb Panagiotis Kanavos
                        info.Container = container;
619 5120f3cb Panagiotis Kanavos
                        info.Account = account;
620 759bd3c4 Panagiotis Kanavos
                        info.StorageUri = this.StorageUrl;
621 5120f3cb Panagiotis Kanavos
                    }
622 126f90b3 Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
623 5120f3cb Panagiotis Kanavos
                    return infos;
624 cfed7823 Panagiotis Kanavos
                }
625 9c4346c9 Panagiotis Kanavos
            }
626 d78cbf09 Panagiotis Kanavos
        }
627 d78cbf09 Panagiotis Kanavos
628 126f90b3 Panagiotis Kanavos
        public HttpStatusCode StatusCode { get; set; }
629 637bc368 Panagiotis Kanavos
630 5bcf6d70 Panagiotis Kanavos
631 cfed7823 Panagiotis Kanavos
        public IList<ObjectInfo> ListObjects(string account, string container, string folder, DateTime? since = null)
632 637bc368 Panagiotis Kanavos
        {
633 637bc368 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
634 9c4346c9 Panagiotis Kanavos
                throw new ArgumentNullException("container");
635 93dc3a84 Panagiotis Kanavos
/*
636 9c4346c9 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(folder))
637 9c4346c9 Panagiotis Kanavos
                throw new ArgumentNullException("folder");
638 93dc3a84 Panagiotis Kanavos
*/
639 9c4346c9 Panagiotis Kanavos
            Contract.EndContractBlock();
640 637bc368 Panagiotis Kanavos
641 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Objects"].Push("List"))
642 9c4346c9 Panagiotis Kanavos
            {
643 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
644 cfed7823 Panagiotis Kanavos
645 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
646 5120f3cb Panagiotis Kanavos
                {
647 5120f3cb Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
648 5120f3cb Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
649 4d301e8e Panagiotis Kanavos
650 5120f3cb Panagiotis Kanavos
                    client.Parameters.Clear();
651 5120f3cb Panagiotis Kanavos
                    client.Parameters.Add("format", "json");
652 5120f3cb Panagiotis Kanavos
                    client.Parameters.Add("path", folder);
653 5120f3cb Panagiotis Kanavos
                    client.IfModifiedSince = since;
654 5120f3cb Panagiotis Kanavos
                    var content = client.DownloadStringWithRetry(container, 3);
655 5120f3cb Panagiotis Kanavos
                    client.AssertStatusOK("ListObjects failed");
656 5bcf6d70 Panagiotis Kanavos
657 5120f3cb Panagiotis Kanavos
                    var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);
658 93dc3a84 Panagiotis Kanavos
                    foreach (var info in infos)
659 93dc3a84 Panagiotis Kanavos
                    {
660 93dc3a84 Panagiotis Kanavos
                        info.Account = account;
661 759bd3c4 Panagiotis Kanavos
                        if (info.Container == null)
662 759bd3c4 Panagiotis Kanavos
                            info.Container = container;
663 759bd3c4 Panagiotis Kanavos
                        info.StorageUri = this.StorageUrl;
664 93dc3a84 Panagiotis Kanavos
                    }
665 5120f3cb Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
666 5120f3cb Panagiotis Kanavos
                    return infos;
667 5120f3cb Panagiotis Kanavos
                }
668 9c4346c9 Panagiotis Kanavos
            }
669 5bcf6d70 Panagiotis Kanavos
        }
670 5bcf6d70 Panagiotis Kanavos
671 d15e99b4 Panagiotis Kanavos
 
672 cfed7823 Panagiotis Kanavos
        public bool ContainerExists(string account, string container)
673 d78cbf09 Panagiotis Kanavos
        {
674 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
675 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
676 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
677 cfed7823 Panagiotis Kanavos
678 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Containters"].Push("Exists"))
679 d78cbf09 Panagiotis Kanavos
            {
680 5120f3cb Panagiotis Kanavos
                if (Log.IsDebugEnabled) Log.DebugFormat("START");
681 cfed7823 Panagiotis Kanavos
682 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
683 9c4346c9 Panagiotis Kanavos
                {
684 5120f3cb Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
685 5120f3cb Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
686 5120f3cb Panagiotis Kanavos
687 5120f3cb Panagiotis Kanavos
                    client.Parameters.Clear();
688 5120f3cb Panagiotis Kanavos
                    client.Head(container, 3);
689 5120f3cb Panagiotis Kanavos
                                        
690 5120f3cb Panagiotis Kanavos
                    bool result;
691 5120f3cb Panagiotis Kanavos
                    switch (client.StatusCode)
692 5120f3cb Panagiotis Kanavos
                    {
693 5120f3cb Panagiotis Kanavos
                        case HttpStatusCode.OK:
694 5120f3cb Panagiotis Kanavos
                        case HttpStatusCode.NoContent:
695 5120f3cb Panagiotis Kanavos
                            result=true;
696 5120f3cb Panagiotis Kanavos
                            break;
697 5120f3cb Panagiotis Kanavos
                        case HttpStatusCode.NotFound:
698 5120f3cb Panagiotis Kanavos
                            result=false;
699 5120f3cb Panagiotis Kanavos
                            break;
700 5120f3cb Panagiotis Kanavos
                        default:
701 5120f3cb Panagiotis Kanavos
                            throw CreateWebException("ContainerExists", client.StatusCode);
702 5120f3cb Panagiotis Kanavos
                    }
703 5120f3cb Panagiotis Kanavos
                    if (Log.IsDebugEnabled) Log.DebugFormat("END");
704 5120f3cb Panagiotis Kanavos
705 5120f3cb Panagiotis Kanavos
                    return result;
706 9c4346c9 Panagiotis Kanavos
                }
707 5120f3cb Panagiotis Kanavos
                
708 d78cbf09 Panagiotis Kanavos
            }
709 d78cbf09 Panagiotis Kanavos
        }
710 d78cbf09 Panagiotis Kanavos
711 cfed7823 Panagiotis Kanavos
        public bool ObjectExists(string account, string container, string objectName)
712 d78cbf09 Panagiotis Kanavos
        {
713 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
714 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
715 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
716 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
717 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
718 cfed7823 Panagiotis Kanavos
719 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
720 d78cbf09 Panagiotis Kanavos
            {
721 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
722 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
723 cfed7823 Panagiotis Kanavos
724 9c4346c9 Panagiotis Kanavos
                client.Parameters.Clear();
725 9c4346c9 Panagiotis Kanavos
                client.Head(container + "/" + objectName, 3);
726 9c4346c9 Panagiotis Kanavos
727 9c4346c9 Panagiotis Kanavos
                switch (client.StatusCode)
728 9c4346c9 Panagiotis Kanavos
                {
729 9c4346c9 Panagiotis Kanavos
                    case HttpStatusCode.OK:
730 9c4346c9 Panagiotis Kanavos
                    case HttpStatusCode.NoContent:
731 9c4346c9 Panagiotis Kanavos
                        return true;
732 9c4346c9 Panagiotis Kanavos
                    case HttpStatusCode.NotFound:
733 9c4346c9 Panagiotis Kanavos
                        return false;
734 9c4346c9 Panagiotis Kanavos
                    default:
735 9c4346c9 Panagiotis Kanavos
                        throw CreateWebException("ObjectExists", client.StatusCode);
736 9c4346c9 Panagiotis Kanavos
                }
737 d78cbf09 Panagiotis Kanavos
            }
738 9c4346c9 Panagiotis Kanavos
739 d78cbf09 Panagiotis Kanavos
        }
740 d78cbf09 Panagiotis Kanavos
741 cfed7823 Panagiotis Kanavos
        public ObjectInfo GetObjectInfo(string account, string container, string objectName)
742 d78cbf09 Panagiotis Kanavos
        {
743 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
744 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
745 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
746 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
747 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
748 d78cbf09 Panagiotis Kanavos
749 4f6d51d4 Panagiotis Kanavos
            using (ThreadContext.Stacks["Objects"].Push("GetObjectInfo"))
750 5120f3cb Panagiotis Kanavos
            {                
751 5120f3cb Panagiotis Kanavos
752 5120f3cb Panagiotis Kanavos
                using (var client = new RestClient(_baseClient))
753 9c4346c9 Panagiotis Kanavos
                {
754 5120f3cb Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
755 5120f3cb Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
756 5120f3cb Panagiotis Kanavos
                    try
757 5120f3cb Panagiotis Kanavos
                    {
758 5120f3cb Panagiotis Kanavos
                        client.Parameters.Clear();
759 d78cbf09 Panagiotis Kanavos
760 5120f3cb Panagiotis Kanavos
                        client.Head(container + "/" + objectName, 3);
761 d78cbf09 Panagiotis Kanavos
762 5120f3cb Panagiotis Kanavos
                        if (client.TimedOut)
763 5120f3cb Panagiotis Kanavos
                            return ObjectInfo.Empty;
764 9c4346c9 Panagiotis Kanavos
765 5120f3cb Panagiotis Kanavos
                        switch (client.StatusCode)
766 5120f3cb Panagiotis Kanavos
                        {
767 5120f3cb Panagiotis Kanavos
                            case HttpStatusCode.OK:
768 5120f3cb Panagiotis Kanavos
                            case HttpStatusCode.NoContent:
769 5120f3cb Panagiotis Kanavos
                                var keys = client.ResponseHeaders.AllKeys.AsQueryable();
770 c92e02f3 Panagiotis Kanavos
                                var tags = client.GetMeta("X-Object-Meta-");
771 5120f3cb Panagiotis Kanavos
                                var extensions = (from key in keys
772 5120f3cb Panagiotis Kanavos
                                                  where key.StartsWith("X-Object-") && !key.StartsWith("X-Object-Meta-")
773 5120f3cb Panagiotis Kanavos
                                                  select new {Name = key, Value = client.ResponseHeaders[key]})
774 5120f3cb Panagiotis Kanavos
                                    .ToDictionary(t => t.Name, t => t.Value);
775 f0947233 Panagiotis Kanavos
776 c92e02f3 Panagiotis Kanavos
                                var permissions=client.GetHeaderValue("X-Object-Sharing", true);
777 aba9e6d9 Panagiotis Kanavos
                                
778 aba9e6d9 Panagiotis Kanavos
                                
779 5120f3cb Panagiotis Kanavos
                                var info = new ObjectInfo
780 5120f3cb Panagiotis Kanavos
                                               {
781 7b0a5fec Panagiotis Kanavos
                                                   Account = account,
782 7b0a5fec Panagiotis Kanavos
                                                   Container = container,
783 5120f3cb Panagiotis Kanavos
                                                   Name = objectName,
784 5120f3cb Panagiotis Kanavos
                                                   Hash = client.GetHeaderValue("ETag"),
785 5120f3cb Panagiotis Kanavos
                                                   Content_Type = client.GetHeaderValue("Content-Type"),
786 52e8e7d9 Panagiotis Kanavos
                                                   Bytes = Convert.ToInt64(client.GetHeaderValue("Content-Length",true)),
787 5120f3cb Panagiotis Kanavos
                                                   Tags = tags,
788 5120f3cb Panagiotis Kanavos
                                                   Last_Modified = client.LastModified,
789 aba9e6d9 Panagiotis Kanavos
                                                   Extensions = extensions,
790 aba9e6d9 Panagiotis Kanavos
                                                   ContentEncoding=client.GetHeaderValue("Content-Encoding",true),
791 aba9e6d9 Panagiotis Kanavos
                                                   ContendDisposition = client.GetHeaderValue("Content-Disposition",true),
792 aba9e6d9 Panagiotis Kanavos
                                                   Manifest=client.GetHeaderValue("X-Object-Manifest",true),
793 f0947233 Panagiotis Kanavos
                                                   PublicUrl=client.GetHeaderValue("X-Object-Public",true),                                                   
794 5120f3cb Panagiotis Kanavos
                                               };
795 f0947233 Panagiotis Kanavos
                                info.SetPermissions(permissions);
796 5120f3cb Panagiotis Kanavos
                                return info;
797 5120f3cb Panagiotis Kanavos
                            case HttpStatusCode.NotFound:
798 5120f3cb Panagiotis Kanavos
                                return ObjectInfo.Empty;
799 5120f3cb Panagiotis Kanavos
                            default:
800 5120f3cb Panagiotis Kanavos
                                throw new WebException(
801 5120f3cb Panagiotis Kanavos
                                    String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",
802 5120f3cb Panagiotis Kanavos
                                                  objectName, client.StatusCode));
803 5120f3cb Panagiotis Kanavos
                        }
804 5120f3cb Panagiotis Kanavos
805 5120f3cb Panagiotis Kanavos
                    }
806 5120f3cb Panagiotis Kanavos
                    catch (RetryException)
807 9c4346c9 Panagiotis Kanavos
                    {
808 4f6d51d4 Panagiotis Kanavos
                        Log.WarnFormat("[RETRY FAIL] GetObjectInfo for {0} failed.",objectName);
809 5120f3cb Panagiotis Kanavos
                        return ObjectInfo.Empty;
810 9c4346c9 Panagiotis Kanavos
                    }
811 5120f3cb Panagiotis Kanavos
                    catch (WebException e)
812 5120f3cb Panagiotis Kanavos
                    {
813 5120f3cb Panagiotis Kanavos
                        Log.Error(
814 5120f3cb Panagiotis Kanavos
                            String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",
815 5120f3cb Panagiotis Kanavos
                                          objectName, client.StatusCode), e);
816 5120f3cb Panagiotis Kanavos
                        throw;
817 5120f3cb Panagiotis Kanavos
                    }
818 5120f3cb Panagiotis Kanavos
                }                
819 d78cbf09 Panagiotis Kanavos
            }
820 9c4346c9 Panagiotis Kanavos
821 d78cbf09 Panagiotis Kanavos
        }
822 d78cbf09 Panagiotis Kanavos
823 cfed7823 Panagiotis Kanavos
        public void CreateFolder(string account, string container, string folder)
824 10523ad9 Panagiotis Kanavos
        {
825 10523ad9 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
826 10523ad9 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
827 10523ad9 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(folder))
828 10523ad9 Panagiotis Kanavos
                throw new ArgumentNullException("folder", "The folder property can't be empty");
829 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
830 10523ad9 Panagiotis Kanavos
831 10523ad9 Panagiotis Kanavos
            var folderUrl=String.Format("{0}/{1}",container,folder);
832 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
833 9c4346c9 Panagiotis Kanavos
            {
834 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
835 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
836 cfed7823 Panagiotis Kanavos
837 9c4346c9 Panagiotis Kanavos
                client.Parameters.Clear();
838 9c4346c9 Panagiotis Kanavos
                client.Headers.Add("Content-Type", @"application/directory");
839 9c4346c9 Panagiotis Kanavos
                client.Headers.Add("Content-Length", "0");
840 9c4346c9 Panagiotis Kanavos
                client.PutWithRetry(folderUrl, 3);
841 10523ad9 Panagiotis Kanavos
842 9c4346c9 Panagiotis Kanavos
                if (client.StatusCode != HttpStatusCode.Created && client.StatusCode != HttpStatusCode.Accepted)
843 9c4346c9 Panagiotis Kanavos
                    throw CreateWebException("CreateFolder", client.StatusCode);
844 9c4346c9 Panagiotis Kanavos
            }
845 10523ad9 Panagiotis Kanavos
        }
846 10523ad9 Panagiotis Kanavos
847 c92e02f3 Panagiotis Kanavos
     
848 c92e02f3 Panagiotis Kanavos
849 cfed7823 Panagiotis Kanavos
        public ContainerInfo GetContainerInfo(string account, string container)
850 d78cbf09 Panagiotis Kanavos
        {
851 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
852 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
853 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
854 cfed7823 Panagiotis Kanavos
855 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
856 d78cbf09 Panagiotis Kanavos
            {
857 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
858 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);                
859 cfed7823 Panagiotis Kanavos
860 9c4346c9 Panagiotis Kanavos
                client.Head(container);
861 9c4346c9 Panagiotis Kanavos
                switch (client.StatusCode)
862 9c4346c9 Panagiotis Kanavos
                {
863 5ce54458 Panagiotis Kanavos
                    case HttpStatusCode.OK:
864 9c4346c9 Panagiotis Kanavos
                    case HttpStatusCode.NoContent:
865 c92e02f3 Panagiotis Kanavos
                        var tags = client.GetMeta("X-Container-Meta-");
866 c92e02f3 Panagiotis Kanavos
                        var policies = client.GetMeta("X-Container-Policy-");
867 27361404 Panagiotis Kanavos
868 9c4346c9 Panagiotis Kanavos
                        var containerInfo = new ContainerInfo
869 9c4346c9 Panagiotis Kanavos
                                                {
870 42800be8 Panagiotis Kanavos
                                                    Account=account,
871 9c4346c9 Panagiotis Kanavos
                                                    Name = container,
872 9c4346c9 Panagiotis Kanavos
                                                    Count =
873 9c4346c9 Panagiotis Kanavos
                                                        long.Parse(client.GetHeaderValue("X-Container-Object-Count")),
874 5ce54458 Panagiotis Kanavos
                                                    Bytes = long.Parse(client.GetHeaderValue("X-Container-Bytes-Used")),
875 5ce54458 Panagiotis Kanavos
                                                    BlockHash = client.GetHeaderValue("X-Container-Block-Hash"),
876 42800be8 Panagiotis Kanavos
                                                    BlockSize=int.Parse(client.GetHeaderValue("X-Container-Block-Size")),
877 27361404 Panagiotis Kanavos
                                                    Last_Modified=client.LastModified,
878 27361404 Panagiotis Kanavos
                                                    Tags=tags,
879 27361404 Panagiotis Kanavos
                                                    Policies=policies
880 9c4346c9 Panagiotis Kanavos
                                                };
881 27361404 Panagiotis Kanavos
                        
882 27361404 Panagiotis Kanavos
883 9c4346c9 Panagiotis Kanavos
                        return containerInfo;
884 9c4346c9 Panagiotis Kanavos
                    case HttpStatusCode.NotFound:
885 9c4346c9 Panagiotis Kanavos
                        return ContainerInfo.Empty;
886 9c4346c9 Panagiotis Kanavos
                    default:
887 9c4346c9 Panagiotis Kanavos
                        throw CreateWebException("GetContainerInfo", client.StatusCode);
888 9c4346c9 Panagiotis Kanavos
                }
889 d78cbf09 Panagiotis Kanavos
            }
890 d78cbf09 Panagiotis Kanavos
        }
891 d78cbf09 Panagiotis Kanavos
892 cfed7823 Panagiotis Kanavos
        public void CreateContainer(string account, string container)
893 b12f73e8 Panagiotis Kanavos
        {
894 b12f73e8 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(account))
895 b12f73e8 Panagiotis Kanavos
                throw new ArgumentNullException("account");
896 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
897 b12f73e8 Panagiotis Kanavos
                throw new ArgumentNullException("container");
898 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
899 cfed7823 Panagiotis Kanavos
900 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
901 9c4346c9 Panagiotis Kanavos
            {
902 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
903 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
904 cfed7823 Panagiotis Kanavos
905 9c4346c9 Panagiotis Kanavos
                client.PutWithRetry(container, 3);
906 9c4346c9 Panagiotis Kanavos
                var expectedCodes = new[] {HttpStatusCode.Created, HttpStatusCode.Accepted, HttpStatusCode.OK};
907 9c4346c9 Panagiotis Kanavos
                if (!expectedCodes.Contains(client.StatusCode))
908 9c4346c9 Panagiotis Kanavos
                    throw CreateWebException("CreateContainer", client.StatusCode);
909 9c4346c9 Panagiotis Kanavos
            }
910 d78cbf09 Panagiotis Kanavos
        }
911 d78cbf09 Panagiotis Kanavos
912 cfed7823 Panagiotis Kanavos
        public void DeleteContainer(string account, string container)
913 2c053915 Panagiotis Kanavos
        {
914 2c053915 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
915 2c053915 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
916 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
917 cfed7823 Panagiotis Kanavos
918 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
919 9c4346c9 Panagiotis Kanavos
            {
920 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
921 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
922 cfed7823 Panagiotis Kanavos
923 9c4346c9 Panagiotis Kanavos
                client.DeleteWithRetry(container, 3);
924 9c4346c9 Panagiotis Kanavos
                var expectedCodes = new[] {HttpStatusCode.NotFound, HttpStatusCode.NoContent};
925 9c4346c9 Panagiotis Kanavos
                if (!expectedCodes.Contains(client.StatusCode))
926 9c4346c9 Panagiotis Kanavos
                    throw CreateWebException("DeleteContainer", client.StatusCode);
927 9c4346c9 Panagiotis Kanavos
            }
928 2c053915 Panagiotis Kanavos
929 2c053915 Panagiotis Kanavos
        }
930 2c053915 Panagiotis Kanavos
931 5bcf6d70 Panagiotis Kanavos
        /// <summary>
932 5bcf6d70 Panagiotis Kanavos
        /// 
933 5bcf6d70 Panagiotis Kanavos
        /// </summary>
934 cfed7823 Panagiotis Kanavos
        /// <param name="account"></param>
935 5bcf6d70 Panagiotis Kanavos
        /// <param name="container"></param>
936 5bcf6d70 Panagiotis Kanavos
        /// <param name="objectName"></param>
937 283809f3 Panagiotis Kanavos
        /// <param name="fileName"></param>
938 5bcf6d70 Panagiotis Kanavos
        /// <returns></returns>
939 5ce54458 Panagiotis Kanavos
        /// <remarks>This method should have no timeout or a very long one</remarks>
940 5ce54458 Panagiotis Kanavos
        //Asynchronously download the object specified by *objectName* in a specific *container* to 
941 5ce54458 Panagiotis Kanavos
        // a local file
942 cfed7823 Panagiotis Kanavos
        public Task GetObject(string account, string container, string objectName, string fileName)
943 d78cbf09 Panagiotis Kanavos
        {
944 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
945 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
946 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
947 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");            
948 5ce54458 Panagiotis Kanavos
            Contract.EndContractBlock();
949 5ce54458 Panagiotis Kanavos
950 283809f3 Panagiotis Kanavos
            try
951 283809f3 Panagiotis Kanavos
            {
952 5ce54458 Panagiotis Kanavos
                //WebClient, and by extension RestClient, are not thread-safe. Create a new RestClient
953 5ce54458 Panagiotis Kanavos
                //object to avoid concurrency errors.
954 5ce54458 Panagiotis Kanavos
                //
955 5ce54458 Panagiotis Kanavos
                //Download operations take a long time therefore they have no timeout.
956 9c4346c9 Panagiotis Kanavos
                var client = new RestClient(_baseClient) { Timeout = 0 };
957 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
958 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
959 cfed7823 Panagiotis Kanavos
960 cfed7823 Panagiotis Kanavos
                //The container and objectName are relative names. They are joined with the client's
961 cfed7823 Panagiotis Kanavos
                //BaseAddress to create the object's absolute address
962 cfed7823 Panagiotis Kanavos
                var builder = client.GetAddressBuilder(container, objectName);
963 cfed7823 Panagiotis Kanavos
                var uri = builder.Uri;
964 cfed7823 Panagiotis Kanavos
965 5ce54458 Panagiotis Kanavos
                //Download progress is reported to the Trace log
966 5120f3cb Panagiotis Kanavos
                Log.InfoFormat("[GET] START {0}", objectName);
967 283809f3 Panagiotis Kanavos
                client.DownloadProgressChanged += (sender, args) => 
968 5120f3cb Panagiotis Kanavos
                    Log.InfoFormat("[GET PROGRESS] {0} {1}% {2} of {3}",
969 283809f3 Panagiotis Kanavos
                                    fileName, args.ProgressPercentage,
970 283809f3 Panagiotis Kanavos
                                    args.BytesReceived,
971 5ce54458 Panagiotis Kanavos
                                    args.TotalBytesToReceive);                                
972 5ce54458 Panagiotis Kanavos
973 5ce54458 Panagiotis Kanavos
974 5ce54458 Panagiotis Kanavos
                //Start downloading the object asynchronously
975 5ce54458 Panagiotis Kanavos
                var downloadTask = client.DownloadFileTask(uri, fileName);
976 283809f3 Panagiotis Kanavos
                
977 5ce54458 Panagiotis Kanavos
                //Once the download completes
978 5ce54458 Panagiotis Kanavos
                return downloadTask.ContinueWith(download =>
979 283809f3 Panagiotis Kanavos
                                      {
980 5ce54458 Panagiotis Kanavos
                                          //Delete the local client object
981 283809f3 Panagiotis Kanavos
                                          client.Dispose();
982 5ce54458 Panagiotis Kanavos
                                          //And report failure or completion
983 283809f3 Panagiotis Kanavos
                                          if (download.IsFaulted)
984 283809f3 Panagiotis Kanavos
                                          {
985 5120f3cb Panagiotis Kanavos
                                              Log.ErrorFormat("[GET] FAIL for {0} with \r{1}", objectName,
986 283809f3 Panagiotis Kanavos
                                                               download.Exception);
987 283809f3 Panagiotis Kanavos
                                          }
988 283809f3 Panagiotis Kanavos
                                          else
989 283809f3 Panagiotis Kanavos
                                          {
990 5120f3cb Panagiotis Kanavos
                                              Log.InfoFormat("[GET] END {0}", objectName);                                             
991 283809f3 Panagiotis Kanavos
                                          }
992 283809f3 Panagiotis Kanavos
                                      });
993 283809f3 Panagiotis Kanavos
            }
994 283809f3 Panagiotis Kanavos
            catch (Exception exc)
995 d78cbf09 Panagiotis Kanavos
            {
996 5120f3cb Panagiotis Kanavos
                Log.ErrorFormat("[GET] END {0} with {1}", objectName, exc);
997 283809f3 Panagiotis Kanavos
                throw;
998 d78cbf09 Panagiotis Kanavos
            }
999 283809f3 Panagiotis Kanavos
1000 283809f3 Panagiotis Kanavos
1001 283809f3 Panagiotis Kanavos
1002 d78cbf09 Panagiotis Kanavos
        }
1003 d78cbf09 Panagiotis Kanavos
1004 cfed7823 Panagiotis Kanavos
        public Task<IList<string>> PutHashMap(string account, string container, string objectName, TreeHash hash)
1005 5ce54458 Panagiotis Kanavos
        {
1006 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
1007 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("container");
1008 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
1009 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("objectName");
1010 5ce54458 Panagiotis Kanavos
            if (hash==null)
1011 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("hash");
1012 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
1013 5ce54458 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Token");
1014 5ce54458 Panagiotis Kanavos
            if (StorageUrl == null)
1015 5ce54458 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Storage Url");
1016 5ce54458 Panagiotis Kanavos
            Contract.EndContractBlock();
1017 cfed7823 Panagiotis Kanavos
1018 cfed7823 Panagiotis Kanavos
1019 cfed7823 Panagiotis Kanavos
            //Don't use a timeout because putting the hashmap may be a long process
1020 692ec33b Panagiotis Kanavos
            var client = new RestClient(_baseClient) { Timeout = 0 };           
1021 cfed7823 Panagiotis Kanavos
            if (!String.IsNullOrWhiteSpace(account))
1022 cfed7823 Panagiotis Kanavos
                client.BaseAddress = GetAccountUrl(account);
1023 cfed7823 Panagiotis Kanavos
1024 5ce54458 Panagiotis Kanavos
            //The container and objectName are relative names. They are joined with the client's
1025 5ce54458 Panagiotis Kanavos
            //BaseAddress to create the object's absolute address
1026 cfed7823 Panagiotis Kanavos
            var builder = client.GetAddressBuilder(container, objectName);
1027 5ce54458 Panagiotis Kanavos
            builder.Query = "format=json&hashmap";
1028 5ce54458 Panagiotis Kanavos
            var uri = builder.Uri;
1029 5ce54458 Panagiotis Kanavos
1030 5ce54458 Panagiotis Kanavos
1031 5ce54458 Panagiotis Kanavos
            //Send the tree hash as Json to the server            
1032 5ce54458 Panagiotis Kanavos
            client.Headers[HttpRequestHeader.ContentType] = "application/octet-stream";
1033 692ec33b Panagiotis Kanavos
            var jsonHash = hash.ToJson();
1034 692ec33b Panagiotis Kanavos
            var uploadTask=client.UploadStringTask(uri, "PUT", jsonHash);
1035 5ce54458 Panagiotis Kanavos
            
1036 5ce54458 Panagiotis Kanavos
            return uploadTask.ContinueWith(t =>
1037 5ce54458 Panagiotis Kanavos
            {
1038 a27aa447 Panagiotis Kanavos
1039 a27aa447 Panagiotis Kanavos
                var empty = (IList<string>)new List<string>();
1040 5ce54458 Panagiotis Kanavos
                
1041 5ce54458 Panagiotis Kanavos
1042 5ce54458 Panagiotis Kanavos
                //The server will respond either with 201-created if all blocks were already on the server
1043 a27aa447 Panagiotis Kanavos
                if (client.StatusCode == HttpStatusCode.Created)                    
1044 a27aa447 Panagiotis Kanavos
                {
1045 5ce54458 Panagiotis Kanavos
                    //in which case we return an empty hash list
1046 a27aa447 Panagiotis Kanavos
                    return empty;
1047 a27aa447 Panagiotis Kanavos
                }
1048 5ce54458 Panagiotis Kanavos
                //or with a 409-conflict and return the list of missing parts
1049 5ce54458 Panagiotis Kanavos
                //A 409 will cause an exception so we need to check t.IsFaulted to avoid propagating the exception                
1050 5ce54458 Panagiotis Kanavos
                if (t.IsFaulted)
1051 5ce54458 Panagiotis Kanavos
                {
1052 5ce54458 Panagiotis Kanavos
                    var ex = t.Exception.InnerException;
1053 5ce54458 Panagiotis Kanavos
                    var we = ex as WebException;
1054 5ce54458 Panagiotis Kanavos
                    var response = we.Response as HttpWebResponse;
1055 5ce54458 Panagiotis Kanavos
                    if (response!=null && response.StatusCode==HttpStatusCode.Conflict)
1056 5ce54458 Panagiotis Kanavos
                    {
1057 5ce54458 Panagiotis Kanavos
                        //In case of 409 the missing parts will be in the response content                        
1058 5ce54458 Panagiotis Kanavos
                        using (var stream = response.GetResponseStream())
1059 5ce54458 Panagiotis Kanavos
                        using(var reader=new StreamReader(stream))
1060 5ce54458 Panagiotis Kanavos
                        {
1061 692ec33b Panagiotis Kanavos
                            Debug.Assert(stream.Position == 0);
1062 d9b1cbeb Panagiotis Kanavos
                            //We used to have to cleanup the content before returning it because it contains
1063 a27aa447 Panagiotis Kanavos
                            //error content after the list of hashes
1064 d9b1cbeb Panagiotis Kanavos
                            //
1065 d9b1cbeb Panagiotis Kanavos
                            //As of 30/1/2012, the result is a proper Json array so we don't need to read the content
1066 d9b1cbeb Panagiotis Kanavos
                            //line by line
1067 d9b1cbeb Panagiotis Kanavos
                            
1068 d9b1cbeb Panagiotis Kanavos
                            var serializer = new JsonSerializer();                            
1069 d9b1cbeb Panagiotis Kanavos
                            var hashes=(List<string>)serializer.Deserialize(reader, typeof (List<string>));
1070 a27aa447 Panagiotis Kanavos
1071 a27aa447 Panagiotis Kanavos
                            return hashes;
1072 5ce54458 Panagiotis Kanavos
                        }                        
1073 4f6d51d4 Panagiotis Kanavos
                    }                    
1074 4f6d51d4 Panagiotis Kanavos
                    //Any other status code is unexpected and the exception should be rethrown
1075 4f6d51d4 Panagiotis Kanavos
                    throw ex;
1076 5ce54458 Panagiotis Kanavos
                    
1077 5ce54458 Panagiotis Kanavos
                }
1078 5ce54458 Panagiotis Kanavos
                //Any other status code is unexpected but there was no exception. We can probably continue processing
1079 4f6d51d4 Panagiotis Kanavos
                Log.WarnFormat("Unexcpected status code when putting map: {0} - {1}",client.StatusCode,client.StatusDescription);                    
1080 4f6d51d4 Panagiotis Kanavos
                
1081 a27aa447 Panagiotis Kanavos
                return empty;
1082 5ce54458 Panagiotis Kanavos
            });
1083 5ce54458 Panagiotis Kanavos
1084 5ce54458 Panagiotis Kanavos
        }
1085 5ce54458 Panagiotis Kanavos
1086 cfed7823 Panagiotis Kanavos
        public Task<byte[]> GetBlock(string account, string container, Uri relativeUrl, long start, long? end)
1087 a27aa447 Panagiotis Kanavos
        {
1088 a27aa447 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
1089 a27aa447 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Token");
1090 a27aa447 Panagiotis Kanavos
            if (StorageUrl == null)
1091 a27aa447 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Storage Url");
1092 a27aa447 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
1093 a27aa447 Panagiotis Kanavos
                throw new ArgumentNullException("container");
1094 a27aa447 Panagiotis Kanavos
            if (relativeUrl== null)
1095 a27aa447 Panagiotis Kanavos
                throw new ArgumentNullException("relativeUrl");
1096 a27aa447 Panagiotis Kanavos
            if (end.HasValue && end<0)
1097 a27aa447 Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("end");
1098 a27aa447 Panagiotis Kanavos
            if (start<0)
1099 a27aa447 Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("start");
1100 a27aa447 Panagiotis Kanavos
            Contract.EndContractBlock();
1101 a27aa447 Panagiotis Kanavos
1102 a27aa447 Panagiotis Kanavos
1103 a27aa447 Panagiotis Kanavos
            //Don't use a timeout because putting the hashmap may be a long process
1104 a27aa447 Panagiotis Kanavos
            var client = new RestClient(_baseClient) {Timeout = 0, RangeFrom = start, RangeTo = end};
1105 cfed7823 Panagiotis Kanavos
            if (!String.IsNullOrWhiteSpace(account))
1106 cfed7823 Panagiotis Kanavos
                client.BaseAddress = GetAccountUrl(account);
1107 cfed7823 Panagiotis Kanavos
1108 cfed7823 Panagiotis Kanavos
            var builder = client.GetAddressBuilder(container, relativeUrl.ToString());
1109 cfed7823 Panagiotis Kanavos
            var uri = builder.Uri;
1110 cfed7823 Panagiotis Kanavos
1111 a27aa447 Panagiotis Kanavos
            return client.DownloadDataTask(uri)
1112 a27aa447 Panagiotis Kanavos
                .ContinueWith(t=>
1113 a27aa447 Panagiotis Kanavos
                                  {
1114 a27aa447 Panagiotis Kanavos
                                      client.Dispose();
1115 a27aa447 Panagiotis Kanavos
                                      return t.Result;
1116 a27aa447 Panagiotis Kanavos
                                  });
1117 a27aa447 Panagiotis Kanavos
        }
1118 a27aa447 Panagiotis Kanavos
1119 a27aa447 Panagiotis Kanavos
1120 4f6d51d4 Panagiotis Kanavos
        public async Task PostBlock(string account, string container, byte[] block, int offset, int count)
1121 a27aa447 Panagiotis Kanavos
        {
1122 a27aa447 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
1123 a27aa447 Panagiotis Kanavos
                throw new ArgumentNullException("container");
1124 a27aa447 Panagiotis Kanavos
            if (block == null)
1125 a27aa447 Panagiotis Kanavos
                throw new ArgumentNullException("block");
1126 0af3141d Panagiotis Kanavos
            if (offset < 0 || offset >= block.Length)
1127 0af3141d Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("offset");
1128 0af3141d Panagiotis Kanavos
            if (count < 0 || count > block.Length)
1129 0af3141d Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("count");
1130 a27aa447 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
1131 a27aa447 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Token");
1132 a27aa447 Panagiotis Kanavos
            if (StorageUrl == null)
1133 0af3141d Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Storage Url");                        
1134 a27aa447 Panagiotis Kanavos
            Contract.EndContractBlock();
1135 a27aa447 Panagiotis Kanavos
1136 cfed7823 Panagiotis Kanavos
1137 4f6d51d4 Panagiotis Kanavos
            try
1138 4f6d51d4 Panagiotis Kanavos
            {
1139 cfed7823 Panagiotis Kanavos
1140 4f6d51d4 Panagiotis Kanavos
            //Don't use a timeout because putting the hashmap may be a long process
1141 4f6d51d4 Panagiotis Kanavos
                using (var client = new RestClient(_baseClient) { Timeout = 0 })
1142 4f6d51d4 Panagiotis Kanavos
                {
1143 4f6d51d4 Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
1144 4f6d51d4 Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
1145 4f6d51d4 Panagiotis Kanavos
1146 4f6d51d4 Panagiotis Kanavos
                    var builder = client.GetAddressBuilder(container, "");
1147 4f6d51d4 Panagiotis Kanavos
                    //We are doing an update
1148 4f6d51d4 Panagiotis Kanavos
                    builder.Query = "update";
1149 4f6d51d4 Panagiotis Kanavos
                    var uri = builder.Uri;
1150 a27aa447 Panagiotis Kanavos
1151 4f6d51d4 Panagiotis Kanavos
                    client.Headers[HttpRequestHeader.ContentType] = "application/octet-stream";
1152 a27aa447 Panagiotis Kanavos
1153 4f6d51d4 Panagiotis Kanavos
                    Log.InfoFormat("[BLOCK POST] START");
1154 a27aa447 Panagiotis Kanavos
1155 4f6d51d4 Panagiotis Kanavos
                    client.UploadProgressChanged += (sender, args) =>
1156 4f6d51d4 Panagiotis Kanavos
                                                    Log.InfoFormat("[BLOCK POST PROGRESS] {0}% {1} of {2}",
1157 4f6d51d4 Panagiotis Kanavos
                                                                   args.ProgressPercentage, args.BytesSent,
1158 4f6d51d4 Panagiotis Kanavos
                                                                   args.TotalBytesToSend);
1159 4f6d51d4 Panagiotis Kanavos
                    client.UploadFileCompleted += (sender, args) =>
1160 4f6d51d4 Panagiotis Kanavos
                                                  Log.InfoFormat("[BLOCK POST PROGRESS] Completed ");
1161 a27aa447 Panagiotis Kanavos
1162 4f6d51d4 Panagiotis Kanavos
                    var buffer = new byte[count];
1163 4f6d51d4 Panagiotis Kanavos
                    Buffer.BlockCopy(block, offset, buffer, 0, count);
1164 4f6d51d4 Panagiotis Kanavos
                    //Send the block
1165 4f6d51d4 Panagiotis Kanavos
                    await client.UploadDataTask(uri, "POST", buffer);
1166 4f6d51d4 Panagiotis Kanavos
                    Log.InfoFormat("[BLOCK POST] END");
1167 a64c87c8 Panagiotis Kanavos
                }
1168 4f6d51d4 Panagiotis Kanavos
            }
1169 4f6d51d4 Panagiotis Kanavos
            catch (Exception exc)
1170 4f6d51d4 Panagiotis Kanavos
            {
1171 4f6d51d4 Panagiotis Kanavos
                Log.ErrorFormat("[BLOCK POST] FAIL with \r{0}", exc);                                        
1172 4f6d51d4 Panagiotis Kanavos
                throw;
1173 4f6d51d4 Panagiotis Kanavos
            }
1174 a27aa447 Panagiotis Kanavos
        }
1175 a27aa447 Panagiotis Kanavos
1176 5ce54458 Panagiotis Kanavos
1177 a0dcfcc9 Panagiotis Kanavos
        public async Task<TreeHash> GetHashMap(string account, string container, string objectName)
1178 5ce54458 Panagiotis Kanavos
        {
1179 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
1180 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("container");
1181 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
1182 5ce54458 Panagiotis Kanavos
                throw new ArgumentNullException("objectName");
1183 5ce54458 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(Token))
1184 5ce54458 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Token");
1185 5ce54458 Panagiotis Kanavos
            if (StorageUrl == null)
1186 5ce54458 Panagiotis Kanavos
                throw new InvalidOperationException("Invalid Storage Url");
1187 5ce54458 Panagiotis Kanavos
            Contract.EndContractBlock();
1188 5ce54458 Panagiotis Kanavos
1189 5ce54458 Panagiotis Kanavos
            try
1190 5ce54458 Panagiotis Kanavos
            {
1191 5ce54458 Panagiotis Kanavos
                //WebClient, and by extension RestClient, are not thread-safe. Create a new RestClient
1192 5ce54458 Panagiotis Kanavos
                //object to avoid concurrency errors.
1193 5ce54458 Panagiotis Kanavos
                //
1194 5ce54458 Panagiotis Kanavos
                //Download operations take a long time therefore they have no timeout.
1195 a0dcfcc9 Panagiotis Kanavos
                //TODO: Do they really? this is a hashmap operation, not a download
1196 cfed7823 Panagiotis Kanavos
                
1197 5ce54458 Panagiotis Kanavos
                //Start downloading the object asynchronously
1198 a0dcfcc9 Panagiotis Kanavos
                using (var client = new RestClient(_baseClient) { Timeout = 0 })
1199 5ce54458 Panagiotis Kanavos
                {
1200 a0dcfcc9 Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
1201 a0dcfcc9 Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
1202 a0dcfcc9 Panagiotis Kanavos
1203 a0dcfcc9 Panagiotis Kanavos
                    //The container and objectName are relative names. They are joined with the client's
1204 a0dcfcc9 Panagiotis Kanavos
                    //BaseAddress to create the object's absolute address
1205 a0dcfcc9 Panagiotis Kanavos
                    var builder = client.GetAddressBuilder(container, objectName);
1206 a0dcfcc9 Panagiotis Kanavos
                    builder.Query = "format=json&hashmap";
1207 a0dcfcc9 Panagiotis Kanavos
                    var uri = builder.Uri;
1208 a0dcfcc9 Panagiotis Kanavos
1209 a0dcfcc9 Panagiotis Kanavos
1210 a0dcfcc9 Panagiotis Kanavos
                    var json = await client.DownloadStringTaskAsync(uri);
1211 5ce54458 Panagiotis Kanavos
                    var treeHash = TreeHash.Parse(json);
1212 a0dcfcc9 Panagiotis Kanavos
                    Log.InfoFormat("[GET HASH] END {0}", objectName);
1213 5ce54458 Panagiotis Kanavos
                    return treeHash;
1214 a0dcfcc9 Panagiotis Kanavos
                }
1215 5ce54458 Panagiotis Kanavos
            }
1216 5ce54458 Panagiotis Kanavos
            catch (Exception exc)
1217 5ce54458 Panagiotis Kanavos
            {
1218 5120f3cb Panagiotis Kanavos
                Log.ErrorFormat("[GET HASH] END {0} with {1}", objectName, exc);
1219 5ce54458 Panagiotis Kanavos
                throw;
1220 5ce54458 Panagiotis Kanavos
            }
1221 5ce54458 Panagiotis Kanavos
1222 5ce54458 Panagiotis Kanavos
        }
1223 5ce54458 Panagiotis Kanavos
1224 5ce54458 Panagiotis Kanavos
1225 5bcf6d70 Panagiotis Kanavos
        /// <summary>
1226 5bcf6d70 Panagiotis Kanavos
        /// 
1227 5bcf6d70 Panagiotis Kanavos
        /// </summary>
1228 cfed7823 Panagiotis Kanavos
        /// <param name="account"></param>
1229 5bcf6d70 Panagiotis Kanavos
        /// <param name="container"></param>
1230 5bcf6d70 Panagiotis Kanavos
        /// <param name="objectName"></param>
1231 5bcf6d70 Panagiotis Kanavos
        /// <param name="fileName"></param>
1232 b5061ac8 Panagiotis Kanavos
        /// <param name="hash">Optional hash value for the file. If no hash is provided, the method calculates a new hash</param>
1233 5bcf6d70 Panagiotis Kanavos
        /// <remarks>>This method should have no timeout or a very long one</remarks>
1234 4f6d51d4 Panagiotis Kanavos
        public async Task PutObject(string account, string container, string objectName, string fileName, string hash = null, string contentType = "application/octet-stream")
1235 d78cbf09 Panagiotis Kanavos
        {
1236 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(container))
1237 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("container", "The container property can't be empty");
1238 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
1239 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("objectName", "The objectName property can't be empty");
1240 b6c72f62 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(fileName))
1241 b6c72f62 Panagiotis Kanavos
                throw new ArgumentNullException("fileName", "The fileName property can't be empty");
1242 4f6d51d4 Panagiotis Kanavos
/*
1243 4f6d51d4 Panagiotis Kanavos
            if (!File.Exists(fileName) && !Directory.Exists(fileName))
1244 4f6d51d4 Panagiotis Kanavos
                throw new FileNotFoundException("The file or directory does not exist",fileName);
1245 4f6d51d4 Panagiotis Kanavos
*/
1246 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
1247 b6c72f62 Panagiotis Kanavos
            
1248 b5061ac8 Panagiotis Kanavos
            try
1249 b5061ac8 Panagiotis Kanavos
            {
1250 cfed7823 Panagiotis Kanavos
1251 4f6d51d4 Panagiotis Kanavos
                using (var client = new RestClient(_baseClient) { Timeout = 0 })
1252 0eea575a Panagiotis Kanavos
                {
1253 4f6d51d4 Panagiotis Kanavos
                    if (!String.IsNullOrWhiteSpace(account))
1254 4f6d51d4 Panagiotis Kanavos
                        client.BaseAddress = GetAccountUrl(account);
1255 bfc13ed8 Panagiotis Kanavos
1256 4f6d51d4 Panagiotis Kanavos
                    var builder = client.GetAddressBuilder(container, objectName);
1257 4f6d51d4 Panagiotis Kanavos
                    var uri = builder.Uri;
1258 0eea575a Panagiotis Kanavos
1259 4f6d51d4 Panagiotis Kanavos
                    string etag = hash ?? CalculateHash(fileName);
1260 4f6d51d4 Panagiotis Kanavos
1261 4f6d51d4 Panagiotis Kanavos
                    client.Headers.Add("Content-Type", contentType);
1262 4f6d51d4 Panagiotis Kanavos
                    client.Headers.Add("ETag", etag);
1263 4f6d51d4 Panagiotis Kanavos
1264 4f6d51d4 Panagiotis Kanavos
1265 4f6d51d4 Panagiotis Kanavos
                    Log.InfoFormat("[PUT] START {0}", objectName);
1266 4f6d51d4 Panagiotis Kanavos
                    client.UploadProgressChanged += (sender, args) =>
1267 4f6d51d4 Panagiotis Kanavos
                                                        {
1268 4f6d51d4 Panagiotis Kanavos
                                                            using (ThreadContext.Stacks["PUT"].Push("Progress"))
1269 4f6d51d4 Panagiotis Kanavos
                                                            {
1270 4f6d51d4 Panagiotis Kanavos
                                                                Log.InfoFormat("{0} {1}% {2} of {3}", fileName,
1271 4f6d51d4 Panagiotis Kanavos
                                                                               args.ProgressPercentage,
1272 4f6d51d4 Panagiotis Kanavos
                                                                               args.BytesSent, args.TotalBytesToSend);
1273 4f6d51d4 Panagiotis Kanavos
                                                            }
1274 4f6d51d4 Panagiotis Kanavos
                                                        };
1275 4f6d51d4 Panagiotis Kanavos
1276 4f6d51d4 Panagiotis Kanavos
                    client.UploadFileCompleted += (sender, args) =>
1277 4f6d51d4 Panagiotis Kanavos
                                                      {
1278 4f6d51d4 Panagiotis Kanavos
                                                          using (ThreadContext.Stacks["PUT"].Push("Progress"))
1279 4f6d51d4 Panagiotis Kanavos
                                                          {
1280 4f6d51d4 Panagiotis Kanavos
                                                              Log.InfoFormat("Completed {0}", fileName);
1281 4f6d51d4 Panagiotis Kanavos
                                                          }
1282 4f6d51d4 Panagiotis Kanavos
                                                      };
1283 4f6d51d4 Panagiotis Kanavos
                    if (contentType=="application/directory")
1284 4f6d51d4 Panagiotis Kanavos
                        await client.UploadDataTaskAsync(uri, "PUT", new byte[0]);
1285 4f6d51d4 Panagiotis Kanavos
                    else
1286 4f6d51d4 Panagiotis Kanavos
                        await client.UploadFileTaskAsync(uri, "PUT", fileName);
1287 4f6d51d4 Panagiotis Kanavos
                }
1288 4f6d51d4 Panagiotis Kanavos
1289 4f6d51d4 Panagiotis Kanavos
                Log.InfoFormat("[PUT] END {0}", objectName);
1290 b5061ac8 Panagiotis Kanavos
            }
1291 b5061ac8 Panagiotis Kanavos
            catch (Exception exc)
1292 b5061ac8 Panagiotis Kanavos
            {
1293 5120f3cb Panagiotis Kanavos
                Log.ErrorFormat("[PUT] END {0} with {1}", objectName, exc);
1294 b5061ac8 Panagiotis Kanavos
                throw;
1295 b5061ac8 Panagiotis Kanavos
            }                
1296 b5061ac8 Panagiotis Kanavos
1297 0eea575a Panagiotis Kanavos
        }
1298 0050438e Panagiotis Kanavos
       
1299 4d301e8e Panagiotis Kanavos
        
1300 b6c72f62 Panagiotis Kanavos
        private static string CalculateHash(string fileName)
1301 d78cbf09 Panagiotis Kanavos
        {
1302 0bd56b7c Panagiotis Kanavos
            Contract.Requires(!String.IsNullOrWhiteSpace(fileName));
1303 0bd56b7c Panagiotis Kanavos
            Contract.EndContractBlock();
1304 0bd56b7c Panagiotis Kanavos
1305 d78cbf09 Panagiotis Kanavos
            string hash;
1306 d78cbf09 Panagiotis Kanavos
            using (var hasher = MD5.Create())
1307 b6c72f62 Panagiotis Kanavos
            using(var stream=File.OpenRead(fileName))
1308 d78cbf09 Panagiotis Kanavos
            {
1309 d78cbf09 Panagiotis Kanavos
                var hashBuilder=new StringBuilder();
1310 b6c72f62 Panagiotis Kanavos
                foreach (byte b in hasher.ComputeHash(stream))
1311 d78cbf09 Panagiotis Kanavos
                    hashBuilder.Append(b.ToString("x2").ToLower());
1312 d78cbf09 Panagiotis Kanavos
                hash = hashBuilder.ToString();                
1313 d78cbf09 Panagiotis Kanavos
            }
1314 d78cbf09 Panagiotis Kanavos
            return hash;
1315 d78cbf09 Panagiotis Kanavos
        }
1316 0bd56b7c Panagiotis Kanavos
        
1317 cfed7823 Panagiotis Kanavos
        public void MoveObject(string account, string sourceContainer, string oldObjectName, string targetContainer, string newObjectName)
1318 d78cbf09 Panagiotis Kanavos
        {
1319 3c43ec9b Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(sourceContainer))
1320 3c43ec9b Panagiotis Kanavos
                throw new ArgumentNullException("sourceContainer", "The container property can't be empty");
1321 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(oldObjectName))
1322 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("oldObjectName", "The oldObjectName property can't be empty");
1323 3c43ec9b Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(targetContainer))
1324 3c43ec9b Panagiotis Kanavos
                throw new ArgumentNullException("targetContainer", "The container property can't be empty");
1325 d78cbf09 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(newObjectName))
1326 d78cbf09 Panagiotis Kanavos
                throw new ArgumentNullException("newObjectName", "The newObjectName property can't be empty");
1327 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
1328 d78cbf09 Panagiotis Kanavos
1329 3c43ec9b Panagiotis Kanavos
            var targetUrl = targetContainer + "/" + newObjectName;
1330 3c43ec9b Panagiotis Kanavos
            var sourceUrl = String.Format("/{0}/{1}", sourceContainer, oldObjectName);
1331 3c43ec9b Panagiotis Kanavos
1332 9c4346c9 Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
1333 d78cbf09 Panagiotis Kanavos
            {
1334 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
1335 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
1336 cfed7823 Panagiotis Kanavos
1337 0af3141d Panagiotis Kanavos
                client.Headers.Add("X-Move-From", sourceUrl);
1338 9c4346c9 Panagiotis Kanavos
                client.PutWithRetry(targetUrl, 3);
1339 9c4346c9 Panagiotis Kanavos
1340 9c4346c9 Panagiotis Kanavos
                var expectedCodes = new[] {HttpStatusCode.OK, HttpStatusCode.NoContent, HttpStatusCode.Created};
1341 0af3141d Panagiotis Kanavos
                if (!expectedCodes.Contains(client.StatusCode))
1342 9c4346c9 Panagiotis Kanavos
                    throw CreateWebException("MoveObject", client.StatusCode);
1343 9c4346c9 Panagiotis Kanavos
            }
1344 d78cbf09 Panagiotis Kanavos
        }
1345 d78cbf09 Panagiotis Kanavos
1346 c53aa229 Panagiotis Kanavos
        public void DeleteObject(string account, string sourceContainer, string objectName)
1347 0af3141d Panagiotis Kanavos
        {            
1348 0af3141d Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(sourceContainer))
1349 0af3141d Panagiotis Kanavos
                throw new ArgumentNullException("sourceContainer", "The container property can't be empty");
1350 0af3141d Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(objectName))
1351 0af3141d Panagiotis Kanavos
                throw new ArgumentNullException("objectName", "The oldObjectName property can't be empty");
1352 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
1353 0af3141d Panagiotis Kanavos
1354 c53aa229 Panagiotis Kanavos
            var targetUrl = FolderConstants.TrashContainer + "/" + objectName;
1355 0af3141d Panagiotis Kanavos
            var sourceUrl = String.Format("/{0}/{1}", sourceContainer, objectName);
1356 0af3141d Panagiotis Kanavos
1357 0af3141d Panagiotis Kanavos
            using (var client = new RestClient(_baseClient))
1358 0af3141d Panagiotis Kanavos
            {
1359 cfed7823 Panagiotis Kanavos
                if (!String.IsNullOrWhiteSpace(account))
1360 cfed7823 Panagiotis Kanavos
                    client.BaseAddress = GetAccountUrl(account);
1361 cfed7823 Panagiotis Kanavos
1362 0af3141d Panagiotis Kanavos
                client.Headers.Add("X-Move-From", sourceUrl);
1363 c53aa229 Panagiotis Kanavos
                client.AllowedStatusCodes.Add(HttpStatusCode.NotFound);
1364 0af3141d Panagiotis Kanavos
                client.PutWithRetry(targetUrl, 3);
1365 0af3141d Panagiotis Kanavos
1366 0af3141d Panagiotis Kanavos
                var expectedCodes = new[] {HttpStatusCode.OK, HttpStatusCode.NoContent, HttpStatusCode.Created,HttpStatusCode.NotFound};
1367 0af3141d Panagiotis Kanavos
                if (!expectedCodes.Contains(client.StatusCode))
1368 0af3141d Panagiotis Kanavos
                    throw CreateWebException("DeleteObject", client.StatusCode);
1369 0af3141d Panagiotis Kanavos
            }
1370 0af3141d Panagiotis Kanavos
        }
1371 0af3141d Panagiotis Kanavos
1372 4d301e8e Panagiotis Kanavos
      
1373 3c43ec9b Panagiotis Kanavos
        private static WebException CreateWebException(string operation, HttpStatusCode statusCode)
1374 3c43ec9b Panagiotis Kanavos
        {
1375 3c43ec9b Panagiotis Kanavos
            return new WebException(String.Format("{0} failed with unexpected status code {1}", operation, statusCode));
1376 3c43ec9b Panagiotis Kanavos
        }
1377 3c43ec9b Panagiotis Kanavos
1378 93dc3a84 Panagiotis Kanavos
1379 93dc3a84 Panagiotis Kanavos
/*
1380 93dc3a84 Panagiotis Kanavos
        public IEnumerable<ObjectInfo> ListDirectories(ContainerInfo container)
1381 93dc3a84 Panagiotis Kanavos
        {
1382 93dc3a84 Panagiotis Kanavos
            var directories=this.ListObjects(container.Account, container.Name, "/");
1383 93dc3a84 Panagiotis Kanavos
        }
1384 93dc3a84 Panagiotis Kanavos
*/
1385 d78cbf09 Panagiotis Kanavos
    }
1386 cfed7823 Panagiotis Kanavos
1387 cfed7823 Panagiotis Kanavos
    public class ShareAccountInfo
1388 cfed7823 Panagiotis Kanavos
    {
1389 cfed7823 Panagiotis Kanavos
        public DateTime? last_modified { get; set; }
1390 cfed7823 Panagiotis Kanavos
        public string name { get; set; }
1391 cfed7823 Panagiotis Kanavos
    }
1392 d78cbf09 Panagiotis Kanavos
}