Statistics
| Branch: | Revision:

root / trunk / Pithos.Network / CloudFilesClient.cs @ 6bcdd8e2

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