Statistics
| Branch: | Revision:

root / trunk / Pithos.Network / CloudFilesClient.cs @ f3d080df

History | View | Annotate | Download (57.4 kB)

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