\r
public Uri RootAddressUri { get; set; }\r
\r
- /* private WebProxy _proxy;\r
- public WebProxy Proxy\r
- {\r
- get { return _proxy; }\r
- set\r
- {\r
- _proxy = value;\r
- if (_baseClient != null)\r
- _baseClient.Proxy = value; \r
- }\r
- }\r
-*/\r
-\r
- /* private Uri _proxy;\r
- public Uri Proxy\r
- {\r
- get { return _proxy; }\r
- set\r
- {\r
- _proxy = value;\r
- if (_baseClient != null)\r
- _baseClient.Proxy = new WebProxy(value); \r
- }\r
- }*/\r
\r
public double DownloadPercentLimit { get; set; }\r
public double UploadPercentLimit { get; set; }\r
var groups = new List<Group>();\r
\r
using (var authClient = new HttpClient(_httpClientHandler,false){ BaseAddress = new Uri(AuthenticationUrl),Timeout=TimeSpan.FromSeconds(30) })\r
- //using (var authClient = new RestClient{BaseAddress=AuthenticationUrl})\r
{ \r
- /* if (Proxy != null)\r
- authClient.Proxy = Proxy;*/\r
-\r
- //Contract.Assume(authClient.DefaultRequestHeaders != null);\r
\r
authClient.DefaultRequestHeaders.Add("X-Auth-User", UserName);\r
authClient.DefaultRequestHeaders.Add("X-Auth-Key", ApiKey);\r
\r
- //Func<Task<HttpResponseMessage>> call = () => ;\r
string storageUrl;\r
string token;\r
\r
{\r
AssertStatusOK(response,"Authentication failed");\r
\r
- storageUrl = response.Headers.GetValues("X-Storage-Url").First();\r
+ storageUrl = response.Headers.GetFirstValue("X-Storage-Url");\r
if (String.IsNullOrWhiteSpace(storageUrl))\r
throw new InvalidOperationException("Failed to obtain storage url");\r
\r
- token = response.Headers.GetValues(TOKEN_HEADER).First();\r
+ token = response.Headers.GetFirstValue(TOKEN_HEADER);\r
if (String.IsNullOrWhiteSpace(token))\r
throw new InvalidOperationException("Failed to obtain token url");\r
\r
BaseAddress = storageUrl,\r
Timeout = 30000,\r
Retries = 3, \r
- //Proxy=Proxy\r
};\r
\r
StorageUrl = new Uri(storageUrl);\r
Log.InfoFormat("[{0}] {1} {2}", method, DateTime.Now, actualAddress);\r
}\r
\r
- private async Task<string> GetStringAsync(Uri targetUri, string errorMessage,DateTime? since=null)\r
+ private async Task<string> GetStringAsync(Uri targetUri, string errorMessage,DateTimeOffset? since=null)\r
{\r
TraceStart("GET",targetUri);\r
var request = new HttpRequestMessage(HttpMethod.Get, targetUri); \r
{\r
request.Headers.IfModifiedSince = since.Value;\r
}\r
- //Func<Task<HttpResponseMessage>> call = () => _baseHttpClient.SendAsync(request);\r
using (var response = await _baseHttpClient.SendAsyncWithRetries(request,3).ConfigureAwait(false))\r
{\r
AssertStatusOK(response, errorMessage);\r
return infos;\r
}\r
\r
- //public IList<ContainerInfo> ListContainers(string account)\r
- //{\r
-\r
- // var targetUrl = GetTargetUrl(account);\r
- // var targetUri=new Uri(String.Format("{0}?format=json",targetUrl));\r
- // var result = GetStringAsync(targetUri, "List Containers failed").Result;\r
- // if (String.IsNullOrWhiteSpace(result))\r
- // return new List<ContainerInfo>();\r
- // var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(result); \r
- // foreach (var info in infos)\r
- // {\r
- // info.Account = account;\r
- // }\r
- // return infos;\r
- // /* using (var client = new RestClient(_baseClient))\r
- // {\r
- // if (!String.IsNullOrWhiteSpace(account))\r
- // client.BaseAddress = GetAccountUrl(account);\r
- \r
- // client.Parameters.Clear();\r
- // client.Parameters.Add("format", "json");\r
- // var content = client.DownloadStringWithRetryRelative(_emptyUri, 3);\r
- // client.AssertStatusOK("List Containers failed");\r
-\r
- // if (client.StatusCode == HttpStatusCode.NoContent)\r
- // return new List<ContainerInfo>();\r
- // var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(content);\r
- \r
- // foreach (var info in infos)\r
- // {\r
- // info.Account = account;\r
- // }\r
- // return infos;\r
- // } */ \r
-\r
- //}\r
-\r
+ \r
private string GetAccountUrl(string account)\r
{\r
return RootAddressUri.Combine(account).AbsoluteUri;\r
\r
Log.DebugFormat("END");\r
return infos;\r
-/*\r
- using (var client = new RestClient(_baseClient))\r
- {\r
- client.Parameters.Clear();\r
- client.Parameters.Add("format", "json");\r
- client.IfModifiedSince = since;\r
-\r
- //Extract the username from the base address\r
- client.BaseAddress = RootAddressUri.AbsoluteUri; \r
-\r
- var content = client.DownloadStringWithRetryRelative(_emptyUri, 3);\r
-\r
- client.AssertStatusOK("ListSharingAccounts failed");\r
-\r
- //If the result is empty, return an empty list,\r
- var infos = String.IsNullOrWhiteSpace(content)\r
- ? new List<ShareAccountInfo>()\r
- //Otherwise deserialize the account list into a list of ShareAccountInfos\r
- : JsonConvert.DeserializeObject<IList<ShareAccountInfo>>(content);\r
-\r
- Log.DebugFormat("END");\r
- return infos;\r
- }\r
-*/\r
}\r
}\r
\r
/// </param>\r
/// <param name="since"></param>\r
/// <returns></returns>\r
- public IList<ObjectInfo> ListSharedObjects(HashSet<string> knownContainers,DateTime? since = null )\r
+ public IList<ObjectInfo> ListSharedObjects(HashSet<string> knownContainers, DateTimeOffset? since)\r
{\r
\r
using (ThreadContext.Stacks["Share"].Push("List Objects"))\r
\r
}\r
\r
- public AccountInfo GetAccountPolicies(AccountInfo accountInfo)\r
+ public async Task<AccountInfo> GetAccountPolicies(AccountInfo accountInfo)\r
{\r
if (accountInfo==null)\r
throw new ArgumentNullException("accountInfo");\r
{\r
if (Log.IsDebugEnabled) Log.DebugFormat("START");\r
\r
+/*\r
if (_baseClient == null)\r
{\r
_baseClient = new RestClient\r
};\r
}\r
\r
- using (var client = new RestClient(_baseClient))\r
+*/ \r
+ var containerUri = GetTargetUri(accountInfo.UserName);\r
+ var targetUri = new Uri(String.Format("{0}?format=json", containerUri), UriKind.Absolute);\r
+ using(var response=await _baseHttpClient.HeadAsyncWithRetries(targetUri,3).ConfigureAwait(false))\r
{\r
- if (!String.IsNullOrWhiteSpace(accountInfo.UserName))\r
- client.BaseAddress = GetAccountUrl(accountInfo.UserName);\r
-\r
- client.Parameters.Clear();\r
- client.Parameters.Add("format", "json"); \r
- client.Head(_emptyUri, 3);\r
-\r
- var quotaValue=client.ResponseHeaders["X-Account-Policy-Quota"];\r
- var bytesValue= client.ResponseHeaders["X-Account-Bytes-Used"];\r
-\r
+ \r
+ var quotaValue=response.Headers.GetFirstValue("X-Account-Policy-Quota");\r
+ var bytesValue = response.Headers.GetFirstValue("X-Account-Bytes-Used");\r
long quota, bytes;\r
if (long.TryParse(quotaValue, out quota))\r
accountInfo.Quota = quota;\r
if (long.TryParse(bytesValue, out bytes))\r
accountInfo.BytesUsed = bytes;\r
- \r
- return accountInfo;\r
\r
+ return accountInfo; \r
}\r
\r
+\r
+ //using (var client = new RestClient(_baseClient))\r
+ //{\r
+ // if (!String.IsNullOrWhiteSpace(accountInfo.UserName))\r
+ // client.BaseAddress = GetAccountUrl(accountInfo.UserName);\r
+\r
+ // client.Parameters.Clear();\r
+ // client.Parameters.Add("format", "json"); \r
+ // client.Head(_emptyUri, 3);\r
+\r
+ // var quotaValue=client.ResponseHeaders["X-Account-Policy-Quota"];\r
+ // var bytesValue= client.ResponseHeaders["X-Account-Bytes-Used"];\r
+\r
+ // long quota, bytes;\r
+ // if (long.TryParse(quotaValue, out quota))\r
+ // accountInfo.Quota = quota;\r
+ // if (long.TryParse(bytesValue, out bytes))\r
+ // accountInfo.BytesUsed = bytes;\r
+ \r
+ // return accountInfo;\r
+\r
+ //}\r
+\r
}\r
}\r
\r
client.Headers.Add("X-Object-Public", isPublic);\r
\r
\r
- /*var uriBuilder = client.GetAddressBuilder(objectInfo.Container, objectInfo.Name);\r
- uriBuilder.Query = "update=";\r
- var uri = uriBuilder.Uri.MakeRelativeUri(this.RootAddressUri);*/\r
var address = String.Format("{0}/{1}?update=",objectInfo.Container, objectInfo.Name);\r
client.PostWithRetry(new Uri(address,UriKind.Relative),"application/xml");\r
\r
- //client.UploadValues(uri,new NameValueCollection());\r
-\r
-\r
client.AssertStatusOK("UpdateMetadata failed");\r
//If the status is NOT ACCEPTED or OK we have a problem\r
if (!(client.StatusCode == HttpStatusCode.Accepted || client.StatusCode == HttpStatusCode.OK))\r
\r
\r
\r
- public IList<ObjectInfo> ListObjects(string account, Uri container, DateTime? since = null)\r
+ public IList<ObjectInfo> ListObjects(string account, Uri container, DateTimeOffset? since = null)\r
{\r
if (container==null)\r
throw new ArgumentNullException("container");\r
\r
using (ThreadContext.Stacks["Objects"].Push("List"))\r
{\r
- /*if (Log.IsDebugEnabled) Log.DebugFormat("START");\r
-\r
- var targetUrl = String.IsNullOrWhiteSpace(account)\r
- ? _baseHttpClient.BaseAddress.ToString()\r
- : GetAccountUrl(account);\r
- var targetUri = new Uri(String.Format("{0}?format=json", targetUrl));\r
- var result = GetString(targetUri, "ListObjects failed",since).Result;\r
-\r
- if (String.IsNullOrWhiteSpace(result))\r
- return new[]{new NoModificationInfo(account,container)};\r
- //If the result is empty, return an empty list,\r
- var infos = String.IsNullOrWhiteSpace(result)\r
- ? new List<ObjectInfo>()\r
- //Otherwise deserialize the object list into a list of ObjectInfos\r
- : JsonConvert.DeserializeObject<IList<ObjectInfo>>(result);\r
-\r
- foreach (var info in infos)\r
- {\r
- info.Container = container;\r
- info.Account = account;\r
- info.StorageUri = StorageUrl;\r
- }\r
- if (Log.IsDebugEnabled) Log.DebugFormat("END");\r
- return infos;*/\r
\r
var containerUri = GetTargetUri(account).Combine(container);\r
var targetUri = new Uri(String.Format("{0}?format=json", containerUri), UriKind.Absolute);\r
}\r
if (Log.IsDebugEnabled) Log.DebugFormat("END");\r
return infos;\r
-/*\r
- using (var client = new RestClient(_baseClient))\r
- {\r
- if (!String.IsNullOrWhiteSpace(account))\r
- client.BaseAddress = GetAccountUrl(account);\r
-\r
- client.Parameters.Clear();\r
- client.Parameters.Add("format", "json");\r
- client.IfModifiedSince = since;\r
- var content = client.DownloadStringWithRetryRelative(container, 3);\r
-\r
- client.AssertStatusOK("ListObjects failed");\r
-\r
- if (client.StatusCode == HttpStatusCode.NotModified)\r
- return new[] {new NoModificationInfo(account, container)};\r
- //If the result is empty, return an empty list,\r
- var infos = String.IsNullOrWhiteSpace(content)\r
- ? new List<ObjectInfo>()\r
- //Otherwise deserialize the object list into a list of ObjectInfos\r
- : JsonConvert.DeserializeObject<IList<ObjectInfo>>(content);\r
-\r
- foreach (var info in infos)\r
- {\r
- info.Container = container;\r
- info.Account = account;\r
- info.StorageUri = StorageUrl;\r
- }\r
- if (Log.IsDebugEnabled) Log.DebugFormat("END");\r
- return infos;\r
- }\r
-*/\r
}\r
}\r
\r
- public IList<ObjectInfo> ListObjects(string account, Uri container, Uri folder, DateTime? since = null)\r
+ public IList<ObjectInfo> ListObjects(string account, Uri container, Uri folder, DateTimeOffset? since = null)\r
{\r
if (container==null)\r
throw new ArgumentNullException("container");\r
if (container.IsAbsoluteUri)\r
throw new ArgumentException("container");\r
-/*\r
- if (String.IsNullOrWhiteSpace(folder))\r
- throw new ArgumentNullException("folder");\r
-*/\r
Contract.EndContractBlock();\r
\r
using (ThreadContext.Stacks["Objects"].Push("List"))\r
\r
}\r
\r
- public ObjectInfo GetObjectInfo(string account, Uri container, Uri objectName)\r
+ public async Task<ObjectInfo> GetObjectInfo(string account, Uri container, Uri objectName)\r
{\r
if (container == null)\r
throw new ArgumentNullException("container", "The container property can't be empty");\r
if (container.IsAbsoluteUri)\r
- throw new ArgumentException("The container must be relative","container");\r
+ throw new ArgumentException("The container must be relative", "container");\r
if (objectName == null)\r
throw new ArgumentNullException("objectName", "The objectName property can't be empty");\r
if (objectName.IsAbsoluteUri)\r
- throw new ArgumentException("The objectName must be relative","objectName");\r
+ throw new ArgumentException("The objectName must be relative", "objectName");\r
Contract.EndContractBlock();\r
\r
using (ThreadContext.Stacks["Objects"].Push("GetObjectInfo"))\r
- { \r
+ {\r
\r
- using (var client = new RestClient(_baseClient))\r
+ var targetUri = GetTargetUri(account).Combine(container).Combine(objectName);\r
+ try\r
+ {\r
+ using (var response = await _baseHttpClient.HeadAsyncWithRetries(targetUri, 3,true))\r
+ {\r
+ switch (response.StatusCode)\r
+ {\r
+ case HttpStatusCode.OK:\r
+ case HttpStatusCode.NoContent:\r
+ var tags = response.Headers.GetMeta("X-Object-Meta-");\r
+ var extensions = (from header in response.Headers\r
+ where\r
+ header.Key.StartsWith("X-Object-") &&\r
+ !header.Key.StartsWith("X-Object-Meta-")\r
+ select new {Name = header.Key, Value = header.Value.FirstOrDefault()})\r
+ .ToDictionary(t => t.Name, t => t.Value);\r
+\r
+ var permissions = response.Headers.GetFirstValue("X-Object-Sharing");\r
+\r
+\r
+ var info = new ObjectInfo\r
+ {\r
+ Account = account,\r
+ Container = container,\r
+ Name = objectName,\r
+ ETag = response.Headers.ETag.NullSafe(e=>e.Tag),\r
+ UUID = response.Headers.GetFirstValue("X-Object-UUID"),\r
+ X_Object_Hash = response.Headers.GetFirstValue("X-Object-Hash"),\r
+ Content_Type = response.Headers.GetFirstValue("Content-Type"),\r
+ Bytes = Convert.ToInt64(response.Content.Headers.ContentLength),\r
+ Tags = tags,\r
+ Last_Modified = response.Content.Headers.LastModified,\r
+ Extensions = extensions,\r
+ ContentEncoding =\r
+ response.Content.Headers.ContentEncoding.FirstOrDefault(),\r
+ ContendDisposition =\r
+ response.Content.Headers.ContentDisposition.NullSafe(c=>c.ToString()),\r
+ Manifest = response.Headers.GetFirstValue("X-Object-Manifest"),\r
+ PublicUrl = response.Headers.GetFirstValue("X-Object-Public"),\r
+ StorageUri = StorageUrl,\r
+ };\r
+ info.SetPermissions(permissions);\r
+ return info;\r
+ case HttpStatusCode.NotFound:\r
+ return ObjectInfo.Empty;\r
+ default:\r
+ throw new WebException(\r
+ String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}",\r
+ objectName, response.StatusCode));\r
+ }\r
+ }\r
+ }\r
+ catch (RetryException)\r
+ {\r
+ Log.WarnFormat("[RETRY FAIL] GetObjectInfo for {0} failed.", objectName);\r
+ return ObjectInfo.Empty;\r
+ }\r
+ catch (WebException e)\r
+ {\r
+ Log.Error(\r
+ String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status {1}",\r
+ objectName, e.Status), e);\r
+ throw;\r
+ }\r
+ } /* using (var client = new RestClient(_baseClient))\r
{\r
if (!String.IsNullOrWhiteSpace(account))\r
client.BaseAddress = GetAccountUrl(account);\r
objectName, client.StatusCode), e);\r
throw;\r
}\r
- } \r
- }\r
+ } */\r
+\r
\r
}\r
\r
- \r
+\r
\r
public void CreateFolder(string account, Uri container, Uri folder)\r
{\r
*/\r
}\r
\r
- \r
+ private Dictionary<string, string> GetMeta(HttpResponseMessage response,string metaPrefix)\r
+ {\r
+ if (String.IsNullOrWhiteSpace(metaPrefix))\r
+ throw new ArgumentNullException("metaPrefix");\r
+ Contract.EndContractBlock();\r
+\r
+ var dict = (from header in response.Headers\r
+ where header.Key.StartsWith(metaPrefix)\r
+ select new { Name = header.Key, Value = String.Join(",", header.Value) })\r
+ .ToDictionary(t => t.Name, t => t.Value);\r
+\r
+ \r
+ return dict;\r
+ }\r
+\r
\r
public ContainerInfo GetContainerInfo(string account, Uri container)\r
{\r
throw new ArgumentException("The container must be relative","container");\r
Contract.EndContractBlock();\r
\r
- using (var client = new RestClient(_baseClient))\r
+ var targetUri = GetTargetUri(account).Combine(container); \r
+ using (var response = _baseHttpClient.HeadAsyncWithRetries(targetUri, 3).Result)\r
{\r
- if (!String.IsNullOrWhiteSpace(account))\r
- client.BaseAddress = GetAccountUrl(account); \r
-\r
- client.Head(container);\r
- switch (client.StatusCode)\r
+ if (Log.IsDebugEnabled)\r
+ Log.DebugFormat("ContainerInfo data: {0}\n{1}",response,response.Content.ReadAsStringAsync().Result);\r
+ switch (response.StatusCode)\r
{\r
case HttpStatusCode.OK:\r
case HttpStatusCode.NoContent:\r
- var tags = client.GetMeta("X-Container-Meta-");\r
- var policies = client.GetMeta("X-Container-Policy-");\r
+ var tags = GetMeta(response,"X-Container-Meta-");\r
+ var policies = GetMeta(response,"X-Container-Policy-");\r
\r
var containerInfo = new ContainerInfo\r
{\r
- Account=account,\r
+ Account = account,\r
Name = container,\r
- StorageUrl=StorageUrl.ToString(),\r
- Count =\r
- long.Parse(client.GetHeaderValue("X-Container-Object-Count")),\r
- Bytes = long.Parse(client.GetHeaderValue("X-Container-Bytes-Used")),\r
- BlockHash = client.GetHeaderValue("X-Container-Block-Hash"),\r
- BlockSize=int.Parse(client.GetHeaderValue("X-Container-Block-Size")),\r
- Last_Modified=client.LastModified,\r
- Tags=tags,\r
- Policies=policies\r
+ StorageUrl = StorageUrl.ToString(),\r
+ Count =long.Parse(response.Headers.GetFirstValue("X-Container-Object-Count")),\r
+ Bytes = long.Parse(response.Headers.GetFirstValue("X-Container-Bytes-Used")),\r
+ BlockHash = response.Headers.GetFirstValue("X-Container-Block-Hash"),\r
+ BlockSize =\r
+ int.Parse(response.Headers.GetFirstValue("X-Container-Block-Size")),\r
+ Last_Modified = response.Content.Headers.LastModified,\r
+ Tags = tags,\r
+ Policies = policies\r
};\r
- \r
+\r
\r
return containerInfo;\r
case HttpStatusCode.NotFound:\r
return ContainerInfo.Empty;\r
default:\r
- throw CreateWebException("GetContainerInfo", client.StatusCode);\r
+ throw CreateWebException("GetContainerInfo", response.StatusCode);\r
}\r
- }\r
+ } \r
}\r
\r
public void CreateContainer(string account, Uri container)\r
*/\r
}\r
\r
- public void WipeContainer(string account, Uri container)\r
+ public async Task WipeContainer(string account, Uri container)\r
{\r
if (container == null)\r
throw new ArgumentNullException("container", "The container property can't be empty");\r
throw new ArgumentException("The container must be relative", "container");\r
Contract.EndContractBlock();\r
\r
- DeleteContainer(account, new Uri(String.Format("{0}&delimiter=//", container), UriKind.Relative));\r
+ await DeleteContainer(account, new Uri(String.Format("{0}?delimiter=/", container), UriKind.Relative)).ConfigureAwait(false);\r
}\r
\r
\r
- public void DeleteContainer(string account, Uri container)\r
+ public async Task DeleteContainer(string account, Uri container)\r
{\r
if (container == null)\r
throw new ArgumentNullException("container", "The container property can't be empty");\r
\r
var targetUri = GetTargetUri(account).Combine(container);\r
var message = new HttpRequestMessage(HttpMethod.Delete, targetUri);\r
- using (var response = _baseHttpClient.SendAsyncWithRetries(message, 3).Result)\r
+ using (var response = await _baseHttpClient.SendAsyncWithRetries(message, 3).ConfigureAwait(false))\r
{\r
var expectedCodes = new[] { HttpStatusCode.NotFound, HttpStatusCode.NoContent };\r
if (!expectedCodes.Contains(response.StatusCode))\r
throw CreateWebException("DeleteContainer", response.StatusCode);\r
}\r
-/*\r
- using (var client = new RestClient(_baseClient))\r
- {\r
- if (!String.IsNullOrWhiteSpace(account))\r
- client.BaseAddress = GetAccountUrl(account);\r
-\r
- client.DeleteWithRetry(container, 3);\r
- var expectedCodes = new[] {HttpStatusCode.NotFound, HttpStatusCode.NoContent};\r
- if (!expectedCodes.Contains(client.StatusCode))\r
- throw CreateWebException("DeleteContainer", client.StatusCode);\r
- }\r
-*/\r
\r
}\r
\r
\r
}\r
\r
-/*\r
- public Task<IList<string>> PutHashMap(string account, Uri container, Uri objectName, TreeHash hash)\r
- {\r
- if (container == null)\r
- throw new ArgumentNullException("container", "The container property can't be empty");\r
- if (container.IsAbsoluteUri)\r
- throw new ArgumentException("The container must be relative","container");\r
- if (objectName == null)\r
- throw new ArgumentNullException("objectName", "The objectName property can't be empty");\r
- if (objectName.IsAbsoluteUri)\r
- throw new ArgumentException("The objectName must be relative","objectName");\r
- if (hash == null)\r
- throw new ArgumentNullException("hash");\r
- if (String.IsNullOrWhiteSpace(Token))\r
- throw new InvalidOperationException("Invalid Token");\r
- if (StorageUrl == null)\r
- throw new InvalidOperationException("Invalid Storage Url");\r
- Contract.EndContractBlock();\r
-\r
- \r
-\r
- //Don't use a timeout because putting the hashmap may be a long process\r
- var client = new RestClient(_baseClient) { Timeout = 0 }; \r
- if (!String.IsNullOrWhiteSpace(account))\r
- client.BaseAddress = GetAccountUrl(account);\r
-\r
- //The container and objectName are relative names. They are joined with the client's\r
- //BaseAddress to create the object's absolute address\r
- var builder = client.GetAddressBuilder(container, objectName);\r
- builder.Query = "format=json&hashmap";\r
- var uri = builder.Uri;\r
-\r
-\r
- //Send the tree hash as Json to the server \r
- client.Headers[HttpRequestHeader.ContentType] = "application/octet-stream";\r
- var jsonHash = hash.ToJson();\r
- \r
- client.Headers.Add("ETag",hash.TopHash.ToHashString());\r
- var uploadTask=client.UploadStringTask(uri, "PUT", jsonHash);\r
- if (Log.IsDebugEnabled)\r
- Log.DebugFormat("Hashes:\r\n{0}", jsonHash);\r
- return uploadTask.ContinueWith(t =>\r
- {\r
-\r
- var empty = (IList<string>)new List<string>();\r
- \r
-\r
- //The server will respond either with 201-created if all blocks were already on the server\r
- if (client.StatusCode == HttpStatusCode.Created) \r
- {\r
- //in which case we return an empty hash list\r
- return empty;\r
- }\r
- //or with a 409-conflict and return the list of missing parts\r
- //A 409 will cause an exception so we need to check t.IsFaulted to avoid propagating the exception \r
- if (t.IsFaulted)\r
- {\r
- var ex = t.Exception.InnerException;\r
- var we = ex as WebException;\r
- var response = we.Response as HttpWebResponse;\r
- if (response!=null && response.StatusCode==HttpStatusCode.Conflict)\r
- {\r
- //In case of 409 the missing parts will be in the response content \r
- using (var stream = response.GetResponseStream())\r
- using(var reader=stream.GetLoggedReader(Log))\r
- {\r
- //We used to have to cleanup the content before returning it because it contains\r
- //error content after the list of hashes\r
- //\r
- //As of 30/1/2012, the result is a proper Json array so we don't need to read the content\r
- //line by line\r
- \r
- var serializer = new JsonSerializer(); \r
- serializer.Error += (sender, args) => Log.ErrorFormat("Deserialization error at [{0}] [{1}]", args.ErrorContext.Error, args.ErrorContext.Member);\r
- var hashes = (List<string>)serializer.Deserialize(reader, typeof(List<string>));\r
- return hashes;\r
- } \r
- } \r
- //Any other status code is unexpected and the exception should be rethrown\r
- Log.LogError(response);\r
- throw ex;\r
- \r
- }\r
-\r
- //Any other status code is unexpected but there was no exception. We can probably continue processing\r
- Log.WarnFormat("Unexcpected status code when putting map: {0} - {1}",client.StatusCode,client.StatusDescription); \r
- \r
- return empty;\r
- });\r
-\r
- }\r
-\r
-*/\r
-\r
- \r
\r
public async Task<byte[]> GetBlock(string account, Uri container, Uri relativeUrl, long start, long? end, CancellationToken cancellationToken)\r
{\r
\r
var targetUri = GetTargetUri(account).Combine(container).Combine(relativeUrl);\r
var message = new HttpRequestMessage(HttpMethod.Get, targetUri);\r
- message.Headers.Range.Ranges.Add(new RangeItemHeaderValue(start,end));\r
+ message.Headers.Range=new RangeHeaderValue(start,end);\r
\r
//Don't use a timeout because putting the hashmap may be a long process\r
\r
});\r
\r
\r
- using (var response = await _baseHttpClientNoTimeout.SendAsyncWithRetries(message, 3, HttpCompletionOption.ResponseHeadersRead,\r
+ using (var response = await _baseHttpClientNoTimeout.SendAsyncWithRetries(message, 3, false,HttpCompletionOption.ResponseHeadersRead,\r
cancellationToken).ConfigureAwait(false))\r
using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))\r
using(var targetStream=new MemoryStream())\r
var result = targetStream.ToArray();\r
return result;\r
}\r
- /*using (var client = new RestClient(_baseClient) {Timeout = 0, RangeFrom = start, RangeTo = end})\r
- {\r
- if (!String.IsNullOrWhiteSpace(account))\r
- client.BaseAddress = GetAccountUrl(account);\r
-\r
- var builder = client.GetAddressBuilder(container, relativeUrl);\r
- var uri = builder.Uri;\r
-\r
-/* client.DownloadProgressChanged += (sender, args) =>\r
- {\r
- Log.DebugFormat("[GET PROGRESS] {0} {1}% {2} of {3}",\r
- uri.Segments.Last(), args.ProgressPercentage,\r
- args.BytesReceived,\r
- args.TotalBytesToReceive);\r
- DownloadProgressChanged(sender, args);\r
- };#1#\r
- var progress = new Progress<DownloadProgressChangedEventArgs>(args =>\r
- {\r
- Log.DebugFormat("[GET PROGRESS] {0} {1}% {2} of {3}",\r
- uri.Segments.Last(), args.ProgressPercentage,\r
- args.BytesReceived,\r
- args.TotalBytesToReceive);\r
- if (DownloadProgressChanged!=null)\r
- DownloadProgressChanged(this, args);\r
- });\r
-\r
-\r
- var result = await client.DownloadDataTaskAsync(uri, cancellationToken,progress).ConfigureAwait(false);\r
- return result;\r
- }*/\r
+ \r
}\r
\r
public event EventHandler<UploadArgs> UploadProgressChanged;\r
message.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(@"application/octet-stream");\r
\r
//Send the block\r
- using (var response = await _baseHttpClientNoTimeout.SendAsyncWithRetries(message, 3).ConfigureAwait(false))\r
+ using (var response = await _baseHttpClientNoTimeout.SendAsyncWithRetries(message, 3,false,HttpCompletionOption.ResponseContentRead,token).ConfigureAwait(false))\r
{ \r
Log.InfoFormat("[BLOCK POST PROGRESS] Completed ");\r
response.EnsureSuccessStatusCode();\r
if (responseHash.Equals(cleanHash,StringComparison.OrdinalIgnoreCase))\r
Log.ErrorFormat("Block hash mismatch posting to [{0}]:[{1}], expected [{2}] but was [{3}]",account,container,blockHash,responseHash);\r
}\r
- Log.InfoFormat("[BLOCK POST] END");\r
- /*using (var client = new RestClient(_baseClient) { Timeout = 0 })\r
- {\r
- if (!String.IsNullOrWhiteSpace(account))\r
- client.BaseAddress = GetAccountUrl(account);\r
-\r
- var builder = client.GetAddressBuilder(container, _emptyUri);\r
- //We are doing an update\r
- builder.Query = "update";\r
- var uri = builder.Uri;\r
-\r
- client.Headers[HttpRequestHeader.ContentType] = "application/octet-stream";\r
-\r
- Log.InfoFormat("[BLOCK POST] START");\r
-\r
- client.UploadFileCompleted += (sender, args) =>\r
- Log.InfoFormat("[BLOCK POST PROGRESS] Completed ");\r
-\r
- var progress=new Progress<UploadProgressChangedEventArgs>(args=>\r
- {\r
- Log.InfoFormat("[BLOCK POST PROGRESS] {0}% {1} of {2}",\r
- args.ProgressPercentage, args.BytesSent,\r
- args.TotalBytesToSend);\r
- if (UploadProgressChanged!=null)\r
- UploadProgressChanged(this, new UploadArgs(args)); \r
- });\r
- var buffer = new byte[count];\r
- Buffer.BlockCopy(block, offset, buffer, 0, count);\r
- //Send the block\r
- \r
- var response=await client.UploadDataTaskAsync(uri, "POST", buffer,token,progress).ConfigureAwait(false);\r
- Log.InfoFormat("[BLOCK POST] END");\r
- }*/\r
+ Log.InfoFormat("[BLOCK POST] END"); \r
}\r
catch (TaskCanceledException )\r
{\r
var treeHash = TreeHash.Parse(json);\r
Log.InfoFormat("[GET HASH] END {0}", objectName);\r
return treeHash;\r
- /*\r
- using (var client = new RestClient(_baseClient) { Timeout = 0 })\r
- {\r
- if (!String.IsNullOrWhiteSpace(account))\r
- client.BaseAddress = GetAccountUrl(account);\r
-\r
- //The container and objectName are relative names. They are joined with the client's\r
- //BaseAddress to create the object's absolute address\r
- \r
- var builder = client.GetAddressBuilder(container, objectName);\r
- builder.Query = "format=json&hashmap";\r
- var uri = builder.Uri;\r
\r
-\r
- var json = await client.DownloadStringTaskAsync(uri).ConfigureAwait(false);\r
- var treeHash = TreeHash.Parse(json);\r
- Log.InfoFormat("[GET HASH] END {0}", objectName);\r
- return treeHash;\r
- }\r
- */\r
}\r
catch (Exception exc)\r
{\r
throw new ArgumentException("The objectName must be relative","objectName");\r
if (String.IsNullOrWhiteSpace(fileName))\r
throw new ArgumentNullException("fileName", "The fileName property can't be empty");\r
-/*\r
- if (!File.Exists(fileName) && !Directory.Exists(fileName))\r
- throw new FileNotFoundException("The file or directory does not exist",fileName);\r
-*/\r
- \r
try\r
{\r
\r
} \r
\r
}\r
- \r
- \r
-/*\r
- private static string CalculateHash(string fileName)\r
- {\r
- Contract.Requires(!String.IsNullOrWhiteSpace(fileName));\r
- Contract.EndContractBlock();\r
-\r
- string hash;\r
- using (var hasher = MD5.Create())\r
- using(var stream=File.OpenRead(fileName))\r
- {\r
- var hashBuilder=new StringBuilder();\r
- foreach (byte b in hasher.ComputeHash(stream))\r
- hashBuilder.Append(b.ToString("x2").ToLower());\r
- hash = hashBuilder.ToString(); \r
- }\r
- return hash;\r
- }\r
-*/\r
-\r
\r
public void MoveObject(string account, Uri sourceContainer, Uri oldObjectName, Uri targetContainer, Uri newObjectName)\r
{\r
if (!expectedCodes.Contains(response.StatusCode))\r
throw CreateWebException("MoveObject", response.StatusCode);\r
}\r
-/*\r
- using (var client = new RestClient(_baseClient))\r
- {\r
- if (!String.IsNullOrWhiteSpace(account))\r
- client.BaseAddress = GetAccountUrl(account);\r
-\r
- client.Headers.Add("X-Move-From", sourceUri.ToString());\r
- client.PutWithRetry(targetUri, 3);\r
-\r
- var expectedCodes = new[] {HttpStatusCode.OK, HttpStatusCode.NoContent, HttpStatusCode.Created};\r
- if (!expectedCodes.Contains(client.StatusCode))\r
- throw CreateWebException("MoveObject", client.StatusCode);\r
- }\r
-*/\r
}\r
\r
- public void DeleteObject(string account, Uri sourceContainer, Uri objectName, bool isDirectory)\r
+ public async Task DeleteObject(string account, Uri sourceContainer, Uri objectName, bool isDirectory)\r
{\r
if (sourceContainer == null)\r
throw new ArgumentNullException("sourceContainer", "The sourceContainer property can't be empty");\r
throw new ArgumentException("The objectName must be relative","objectName");\r
Contract.EndContractBlock();\r
\r
+\r
+\r
+ var sourceUri = new Uri(String.Format("/{0}/{1}", sourceContainer, objectName),UriKind.Relative);\r
+\r
+ \r
+ if (objectName.OriginalString.EndsWith(".ignore"))\r
+ using(var response = await _baseHttpClient.DeleteAsync(sourceUri)){}\r
+ else\r
+ {\r
+ var relativeUri = new Uri(String.Format("{0}/{1}", FolderConstants.TrashContainer, objectName),\r
+ UriKind.Relative);\r
+\r
+/*\r
+ var relativeUri = isDirectory\r
+ ? new Uri(\r
+ String.Format("{0}/{1}?delimiter=/", FolderConstants.TrashContainer,\r
+ objectName), UriKind.Relative)\r
+ : new Uri(String.Format("{0}/{1}", FolderConstants.TrashContainer, objectName),\r
+ UriKind.Relative);\r
+\r
+*/\r
+ var targetUri = GetTargetUri(account).Combine(relativeUri);\r
+\r
+\r
+ var message = new HttpRequestMessage(HttpMethod.Put, targetUri);\r
+ message.Headers.Add("X-Move-From", sourceUri.ToString());\r
+\r
+ Log.InfoFormat("[TRASH] [{0}] to [{1}]", sourceUri, targetUri);\r
+ using (var response = await _baseHttpClient.SendAsyncWithRetries(message, 3))\r
+ {\r
+ var expectedCodes = new[]\r
+ {\r
+ HttpStatusCode.OK, HttpStatusCode.NoContent, HttpStatusCode.Created,\r
+ HttpStatusCode.NotFound\r
+ };\r
+ if (!expectedCodes.Contains(response.StatusCode))\r
+ throw CreateWebException("DeleteObject", response.StatusCode);\r
+ }\r
+ }\r
+/*\r
+ \r
+\r
var targetUrl = FolderConstants.TrashContainer + "/" + objectName;\r
/*\r
if (isDirectory)\r
targetUrl = targetUrl + "?delimiter=/";\r
-*/\r
+#1#\r
\r
var sourceUrl = String.Format("/{0}/{1}", sourceContainer, objectName);\r
\r
if (!expectedCodes.Contains(client.StatusCode))\r
throw CreateWebException("DeleteObject", client.StatusCode);\r
}\r
+*/\r
}\r
\r
\r
}\r
\r
\r
-/*\r
- public IEnumerable<ObjectInfo> ListDirectories(ContainerInfo container)\r
- {\r
- var directories=this.ListObjects(container.Account, container.Name, "/");\r
- }\r
-*/\r
-\r
- public bool CanUpload(string account, ObjectInfo cloudFile)\r
+ public async Task<bool> CanUpload(string account, ObjectInfo cloudFile)\r
{\r
Contract.Requires(!String.IsNullOrWhiteSpace(account));\r
Contract.Requires(cloudFile!=null);\r
\r
- using (var client = new RestClient(_baseClient))\r
- {\r
- if (!String.IsNullOrWhiteSpace(account))\r
- client.BaseAddress = GetAccountUrl(account);\r
-\r
-\r
var parts = cloudFile.Name.ToString().Split('/');\r
var folder = String.Join("/", parts,0,parts.Length-1);\r
\r
var fileName = String.Format("{0}/{1}.pithos.ignore", folder, Guid.NewGuid());\r
var fileUri=fileName.ToEscapedUri(); \r
\r
- client.Parameters.Clear();\r
try\r
{\r
var relativeUri = cloudFile.Container.Combine(fileUri);\r
- client.PutWithRetry(relativeUri, 3, @"application/octet-stream");\r
-\r
+ var targetUri = GetTargetUri(account).Combine(relativeUri);\r
+ var message = new HttpRequestMessage(HttpMethod.Put, targetUri);\r
+ message.Content.Headers.ContentType =new MediaTypeHeaderValue("application/octet-stream");\r
+ var response=await _baseHttpClient.SendAsyncWithRetries(message, 3); \r
var expectedCodes = new[] { HttpStatusCode.OK, HttpStatusCode.NoContent, HttpStatusCode.Created};\r
- var result=(expectedCodes.Contains(client.StatusCode));\r
- DeleteObject(account, cloudFile.Container, fileUri, cloudFile.IsDirectory);\r
+ var result=(expectedCodes.Contains(response.StatusCode));\r
+ await DeleteObject(account, cloudFile.Container, fileUri, cloudFile.IsDirectory);\r
return result;\r
}\r
catch\r
{\r
return false;\r
}\r
- }\r
+ \r
}\r
\r
~CloudFilesClient()\r