Revision 5bcf6d70 trunk/Pithos.Network/CloudFilesClient.cs
b/trunk/Pithos.Network/CloudFilesClient.cs | ||
---|---|---|
1 | 1 |
using System; |
2 | 2 |
using System.Collections.Generic; |
3 | 3 |
using System.ComponentModel.Composition; |
4 |
using System.Diagnostics; |
|
4 | 5 |
using System.Diagnostics.Contracts; |
5 | 6 |
using System.IO; |
6 | 7 |
using System.Linq; |
... | ... | |
11 | 12 |
using Hammock.Caching; |
12 | 13 |
using Hammock.Retries; |
13 | 14 |
using Hammock.Serialization; |
15 |
using Hammock.Tasks; |
|
14 | 16 |
using Hammock.Web; |
15 | 17 |
using Newtonsoft.Json; |
16 | 18 |
using Pithos.Interfaces; |
... | ... | |
24 | 26 |
private string _pithosAuthUrl = "http://pithos.dev.grnet.gr"; |
25 | 27 |
|
26 | 28 |
private RestClient _client; |
27 |
private readonly TimeSpan _timeout = TimeSpan.FromSeconds(10);
|
|
29 |
private readonly TimeSpan _shortTimeout = TimeSpan.FromSeconds(10);
|
|
28 | 30 |
private readonly int _retries = 5; |
29 | 31 |
public string ApiKey { get; set; } |
30 | 32 |
public string UserName { get; set; } |
31 | 33 |
public Uri StorageUrl { get; set; } |
32 | 34 |
public string Token { get; set; } |
35 |
public Uri Proxy { get; set; } |
|
33 | 36 |
|
34 | 37 |
public string AuthUrl |
35 | 38 |
{ |
... | ... | |
56 | 59 |
|
57 | 60 |
string authUrl = UsePithos ? String.Format("{0}/{1}/{2}", AuthUrl, VersionPath,UserName) |
58 | 61 |
: String.Format("{0}/{1}", AuthUrl, VersionPath); |
59 |
var authClient = new RestClient{Path=authUrl}; |
|
62 |
|
|
63 |
var proxy = Proxy != null ? Proxy.ToString():null; |
|
64 |
|
|
65 |
var authClient = new RestClient{Path=authUrl,Proxy=proxy}; |
|
66 |
|
|
60 | 67 |
authClient.AddHeader("X-Auth-User", UserName); |
61 | 68 |
authClient.AddHeader("X-Auth-Key", ApiKey); |
62 | 69 |
|
... | ... | |
87 | 94 |
var retryPolicy = new RetryPolicy { RetryCount = _retries }; |
88 | 95 |
retryPolicy.RetryConditions.Add(new TimeoutRetryCondition()); |
89 | 96 |
|
90 |
_client = new RestClient { Authority = StorageUrl.AbsoluteUri, RetryPolicy = retryPolicy, Timeout = _timeout,Path=UserName };
|
|
97 |
_client = new RestClient { Authority = StorageUrl.AbsoluteUri, Path = UserName, Proxy = proxy, RetryPolicy = retryPolicy, };
|
|
91 | 98 |
|
92 | 99 |
_client.AddHeader("X-Auth-Token", Token); |
93 | 100 |
if (UsePithos) |
... | ... | |
105 | 112 |
//appends a / unless a Path is specified. |
106 | 113 |
|
107 | 114 |
//Create a request with a complete path |
108 |
var request = new RestRequest{Path=StorageUrl.ToString()};
|
|
115 |
var request = new RestRequest { Path = StorageUrl.ToString(), Timeout = _shortTimeout };
|
|
109 | 116 |
request.AddParameter("format","json"); |
110 | 117 |
//Create a client clone |
111 |
var client = new RestClient();
|
|
118 |
var client = new RestClient{Proxy=Proxy.ToString()};
|
|
112 | 119 |
foreach (var header in _client.GetAllHeaders()) |
113 | 120 |
{ |
114 | 121 |
client.AddHeader(header.Name,header.Value); |
... | ... | |
116 | 123 |
|
117 | 124 |
var response = client.Request(request); |
118 | 125 |
|
119 |
ThrowIfNotStatusOK(response, "List Containers failed"); |
|
120 |
|
|
121 | 126 |
if (response.StatusCode == HttpStatusCode.NoContent) |
122 | 127 |
return new List<ContainerInfo>(); |
123 | 128 |
|
129 |
ThrowIfNotStatusOK(response, "List Containers failed"); |
|
130 |
|
|
131 |
|
|
124 | 132 |
var infos=JsonConvert.DeserializeObject<IList<ContainerInfo>>(response.Content); |
125 | 133 |
|
126 | 134 |
return infos; |
... | ... | |
131 | 139 |
if (String.IsNullOrWhiteSpace(container)) |
132 | 140 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
133 | 141 |
|
134 |
var request = new RestRequest{Path=container};
|
|
142 |
var request = new RestRequest { Path = container, Timeout = _shortTimeout };
|
|
135 | 143 |
request.AddParameter("format", "json"); |
136 | 144 |
var response = _client.Request(request); |
137 |
if (response.TimedOut) |
|
138 |
return new List<ObjectInfo>(); |
|
139 |
|
|
140 |
ThrowIfNotStatusOK(response, "List Objects failed"); |
|
141 |
|
|
142 |
if (response.StatusCode == HttpStatusCode.NoContent) |
|
143 |
return new List<ObjectInfo>(); |
|
144 | 145 |
|
145 |
|
|
146 |
var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(response.Content); |
|
146 |
var infos = InfosFromContent(response); |
|
147 | 147 |
|
148 | 148 |
return infos; |
149 | 149 |
} |
150 | 150 |
|
151 | 151 |
|
152 |
|
|
152 | 153 |
public IList<ObjectInfo> ListObjects(string container,string folder) |
153 | 154 |
{ |
154 | 155 |
if (String.IsNullOrWhiteSpace(container)) |
155 | 156 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
156 | 157 |
|
157 |
var request = new RestRequest{Path=container};
|
|
158 |
var request = new RestRequest { Path = container, Timeout = _shortTimeout };
|
|
158 | 159 |
request.AddParameter("format", "json"); |
159 | 160 |
request.AddParameter("path", folder); |
160 | 161 |
var response = _client.Request(request); |
162 |
|
|
163 |
var infos = InfosFromContent(response); |
|
164 |
|
|
165 |
return infos; |
|
166 |
} |
|
167 |
|
|
168 |
private static IList<ObjectInfo> InfosFromContent(RestResponse response) |
|
169 |
{ |
|
161 | 170 |
if (response.TimedOut) |
162 | 171 |
return new List<ObjectInfo>(); |
163 | 172 |
|
164 |
ThrowIfNotStatusOK(response, "List Objects failed"); |
|
173 |
if (response.StatusCode == 0) |
|
174 |
return new List<ObjectInfo>(); |
|
165 | 175 |
|
166 | 176 |
if (response.StatusCode == HttpStatusCode.NoContent) |
167 | 177 |
return new List<ObjectInfo>(); |
168 |
|
|
169 | 178 |
|
170 |
var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(response.Content); |
|
171 | 179 |
|
180 |
var statusCode = (int)response.StatusCode; |
|
181 |
if (statusCode < 200 || statusCode >= 300) |
|
182 |
{ |
|
183 |
Trace.TraceWarning("ListObjects failed with code {1} - {2}", response.StatusCode, response.StatusDescription); |
|
184 |
return new List<ObjectInfo>(); |
|
185 |
} |
|
186 |
|
|
187 |
var infos = JsonConvert.DeserializeObject<IList<ObjectInfo>>(response.Content); |
|
172 | 188 |
return infos; |
173 | 189 |
} |
174 | 190 |
|
... | ... | |
177 | 193 |
if (String.IsNullOrWhiteSpace(container)) |
178 | 194 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
179 | 195 |
|
180 |
var request = new RestRequest {Path = container, Method = WebMethod.Head};
|
|
196 |
var request = new RestRequest { Path = container, Method = WebMethod.Head, Timeout = _shortTimeout };
|
|
181 | 197 |
var response = _client.Request(request); |
182 | 198 |
|
183 | 199 |
switch(response.StatusCode) |
... | ... | |
198 | 214 |
if (String.IsNullOrWhiteSpace(objectName)) |
199 | 215 |
throw new ArgumentNullException("objectName", "The objectName property can't be empty"); |
200 | 216 |
|
201 |
|
|
202 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Head }; |
|
217 |
|
|
218 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Head, Timeout = _shortTimeout };
|
|
203 | 219 |
var response = _client.Request(request); |
204 | 220 |
|
205 | 221 |
switch (response.StatusCode) |
... | ... | |
223 | 239 |
throw new ArgumentNullException("objectName", "The objectName property can't be empty"); |
224 | 240 |
|
225 | 241 |
|
226 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Head }; |
|
242 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Head, Timeout = _shortTimeout };
|
|
227 | 243 |
var response = _client.Request(request); |
228 | 244 |
|
229 | 245 |
if (response.TimedOut) |
... | ... | |
256 | 272 |
throw new ArgumentNullException("folder", "The folder property can't be empty"); |
257 | 273 |
|
258 | 274 |
var folderUrl=String.Format("{0}/{1}",container,folder); |
259 |
var request = new RestRequest { Path = folderUrl, Method = WebMethod.Put }; |
|
275 |
var request = new RestRequest { Path = folderUrl, Method = WebMethod.Put, Timeout = _shortTimeout };
|
|
260 | 276 |
request.AddHeader("Content-Type", @"application/directory"); |
261 | 277 |
request.AddHeader("Content-Length", "0"); |
262 | 278 |
|
... | ... | |
272 | 288 |
if (String.IsNullOrWhiteSpace(container)) |
273 | 289 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
274 | 290 |
|
275 |
var request = new RestRequest {Path = container, Method = WebMethod.Head};
|
|
291 |
var request = new RestRequest { Path = container, Method = WebMethod.Head, Timeout = _shortTimeout };
|
|
276 | 292 |
var response = _client.Request(request); |
277 | 293 |
|
278 | 294 |
switch(response.StatusCode) |
... | ... | |
298 | 314 |
if (String.IsNullOrWhiteSpace(container)) |
299 | 315 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
300 | 316 |
|
301 |
var request = new RestRequest { Path = container, Method = WebMethod.Put }; |
|
317 |
var request = new RestRequest { Path = container, Method = WebMethod.Put, Timeout = _shortTimeout };
|
|
302 | 318 |
|
303 | 319 |
var response = _client.Request(request); |
304 | 320 |
|
... | ... | |
311 | 327 |
if (String.IsNullOrWhiteSpace(container)) |
312 | 328 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
313 | 329 |
|
314 |
var request = new RestRequest { Path = container , Method = WebMethod.Delete };
|
|
330 |
var request = new RestRequest { Path = container, Method = WebMethod.Delete, Timeout = _shortTimeout };
|
|
315 | 331 |
var response = _client.Request(request); |
316 | 332 |
|
317 | 333 |
if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.NoContent) |
... | ... | |
321 | 337 |
|
322 | 338 |
} |
323 | 339 |
|
324 |
|
|
340 |
/// <summary> |
|
341 |
/// |
|
342 |
/// </summary> |
|
343 |
/// <param name="container"></param> |
|
344 |
/// <param name="objectName"></param> |
|
345 |
/// <returns></returns> |
|
346 |
/// <remarks>>This method should have no timeout or a very long one</remarks> |
|
325 | 347 |
public Stream GetObject(string container, string objectName) |
326 | 348 |
{ |
327 | 349 |
if (String.IsNullOrWhiteSpace(container)) |
... | ... | |
342 | 364 |
throw new WebException(String.Format("GetObject failed with unexpected status code {0}", response.StatusCode)); |
343 | 365 |
} |
344 | 366 |
|
367 |
/// <summary> |
|
368 |
/// |
|
369 |
/// </summary> |
|
370 |
/// <param name="container"></param> |
|
371 |
/// <param name="objectName"></param> |
|
372 |
/// <param name="fileName"></param> |
|
373 |
/// <remarks>>This method should have no timeout or a very long one</remarks> |
|
345 | 374 |
public void PutObject(string container, string objectName, string fileName) |
346 | 375 |
{ |
347 | 376 |
if (String.IsNullOrWhiteSpace(container)) |
... | ... | |
357 | 386 |
string url = container + "/" + objectName; |
358 | 387 |
|
359 | 388 |
var request = new RestRequest {Path=url,Method=WebMethod.Put}; |
360 |
|
|
389 |
request.TaskOptions=new TaskOptions<int>{RateLimitPercent=0.5}; |
|
361 | 390 |
|
362 | 391 |
string hash = CalculateHash(fileName); |
363 | 392 |
|
364 | 393 |
request.AddPostContent(File.ReadAllBytes(fileName)); |
365 | 394 |
request.AddHeader("Content-Type","application/octet-stream"); |
366 | 395 |
request.AddHeader("ETag",hash); |
367 |
var response=_client.Request(request);
|
|
368 |
|
|
396 |
var response=_client.Request(request); |
|
397 |
_client.TaskOptions = new TaskOptions<int> {RateLimitPercent = 0.5}; |
|
369 | 398 |
if (response.StatusCode == HttpStatusCode.Created) |
370 | 399 |
return; |
371 | 400 |
if (response.StatusCode == HttpStatusCode.LengthRequired) |
... | ... | |
395 | 424 |
if (String.IsNullOrWhiteSpace(objectName)) |
396 | 425 |
throw new ArgumentNullException("objectName", "The objectName property can't be empty"); |
397 | 426 |
|
398 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Delete }; |
|
427 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Delete, Timeout=_shortTimeout };
|
|
399 | 428 |
var response = _client.Request(request); |
400 | 429 |
|
401 | 430 |
if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.NoContent) |
Also available in: Unified diff