try\r
{\r
SetBusy("Validating Credentials", "");\r
- var client = new CloudFilesClient(AccountName, Token) { AuthenticationUrl = CurrentServer,/*Proxy=Proxy */}; \r
- await TaskEx.Run(() =>\r
- {\r
- client.Authenticate();\r
- return client.ListContainers(AccountName);\r
- }).ConfigureAwait(false);\r
+ var client = new CloudFilesClient(AccountName, Token) { AuthenticationUrl = CurrentServer,/*Proxy=Proxy */};\r
+ await client.Authenticate().ConfigureAwait(false);\r
+ await client.ListContainers(AccountName).ConfigureAwait(false);\r
HasValidCredentials = true;\r
ValidationMessage = "Credentials Validated";\r
}\r
<Window x:Class="Pithos.Client.WPF.Preferences.PreferencesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:cal="http://www.caliburnproject.org"
- xmlns:extToolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit/extended"
xmlns:Converters="clr-namespace:Pithos.Client.WPF.Converters"\r
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" x:Name="TheView"
Title="Pithos+ Preferences" Height="436" Width="732"
\r
\r
readonly List<AccountSettings> _accountsToAdd=new List<AccountSettings>();\r
- public void AddAccount()\r
+ public async void AddAccount()\r
{\r
var wizard = new AddAccountViewModel();\r
if (_windowManager.ShowDialog(wizard) == true)\r
AuthenticationUrl = newAccount.ServerUrl, UsePithos = true\r
};\r
\r
- InitializeSelectiveFolders(newAccount, client);\r
+ await InitializeSelectiveFolders(newAccount, client);\r
\r
\r
//TODO:Add the "pithos" container as a default selection \r
\r
}\r
\r
- private void InitializeSelectiveFolders(AccountSettings newAccount, CloudFilesClient client,int retries=3)\r
+ private async Task InitializeSelectiveFolders(AccountSettings newAccount, CloudFilesClient client,int retries=3)\r
{\r
- try\r
- {\r
- client.Authenticate();\r
-\r
- var containers = client.ListContainers(newAccount.AccountName);\r
- var containerUris = from container in containers\r
- select String.Format(@"{0}/v1/{1}/{2}",\r
- newAccount.ServerUrl, newAccount.AccountName,\r
- container.Name);\r
-\r
- newAccount.SelectiveFolders.AddRange(containerUris.ToArray());\r
-\r
- var objectInfos = (from container in containers\r
- from dir in client.ListObjects(newAccount.AccountName, container.Name)\r
- where container.Name.ToString() != "trash"\r
- select dir).ToList();\r
- var tree = objectInfos.ToTree();\r
-\r
- var selected = (from root in tree\r
- from child in root\r
- select child.Uri.ToString()).ToArray();\r
- newAccount.SelectiveFolders.AddRange(selected); \r
- }\r
- catch (WebException)\r
+ while(true)\r
{\r
- if (retries>0)\r
- InitializeSelectiveFolders(newAccount,client,retries-1);\r
- else\r
- throw;\r
+ try\r
+ {\r
+ await client.Authenticate().ConfigureAwait(false);\r
+\r
+ var containers = await client.ListContainers(newAccount.AccountName).ConfigureAwait(false);\r
+ var containerUris = from container in containers\r
+ select String.Format(@"{0}/v1/{1}/{2}",\r
+ newAccount.ServerUrl, newAccount.AccountName,\r
+ container.Name);\r
+\r
+ newAccount.SelectiveFolders.AddRange(containerUris.ToArray());\r
+\r
+ var objectInfos = (from container in containers\r
+ from dir in client.ListObjects(newAccount.AccountName, container.Name)\r
+ where container.Name.ToString() != "trash"\r
+ select dir).ToList();\r
+ var tree = objectInfos.ToTree();\r
+\r
+ var selected = (from root in tree\r
+ from child in root\r
+ select child.Uri.ToString()).ToArray();\r
+ newAccount.SelectiveFolders.AddRange(selected);\r
+ return;\r
+ }\r
+ catch (WebException)\r
+ {\r
+ if (retries > 0)\r
+ retries--;\r
+ else\r
+ throw;\r
+ }\r
}\r
}\r
\r
//_monitor = monitor;\r
_events = events;\r
_apiKey = apiKey;\r
- //IsEnabled = account.SelectiveSyncEnabled;\r
+ //IsEnabled = account.SelectiveSyncEnabled; \r
TaskEx.Run(()=>LoadRootNode(forSelectiveActivation));\r
}\r
\r
- private void LoadRootNode(bool forSelectiveActivation)\r
+ private async void LoadRootNode(bool forSelectiveActivation)\r
{ \r
//TODO: Check this\r
var client = new CloudFilesClient(AccountName,_apiKey){AuthenticationUrl=Account.ServerUrl,UsePithos=true};\r
- client.Authenticate();\r
+ await client.Authenticate().ConfigureAwait(false);\r
\r
//NEED to get the local folders here as well,\r
// and combine them with the cloud folders\r
\r
\r
- var dirs = from container in client.ListContainers(AccountName) \r
+ var containerInfos = await client.ListContainers(AccountName).ConfigureAwait(false);\r
+ var dirs = from container in containerInfos \r
where container.Name.ToUnescapedString() != "trash"\r
select new DirectoryRecord\r
{\r
{\r
DisplayName=account.name,\r
Uri=client.StorageUrl.Combine("../"+ account.name),\r
- Directories=(from container in client.ListContainers(account.name)\r
+ Directories=(from container in client.ListContainers(account.name).Result\r
select new DirectoryRecord\r
{\r
DisplayName=container.Name.ToUnescapedString(),\r
var client = new CloudFilesClient(accountInfo);\r
\r
//We don't need to check the trash container\r
- var containers = client.ListContainers(accountInfo.UserName)\r
+ var allContainers=await client.ListContainers(accountInfo.UserName).ConfigureAwait(false);\r
+ var containers = allContainers\r
.Where(c=>c.Name.ToString()!="trash")\r
.ToList();\r
\r
SelectivePaths = new ConcurrentDictionary<Uri, ConcurrentBag<string>>();\r
}\r
\r
- readonly Dictionary<Uri, bool> _selectiveEnabled = new Dictionary<Uri, bool>();\r
+ readonly ConcurrentDictionary<Uri, bool> _selectiveEnabled = new ConcurrentDictionary<Uri, bool>();\r
\r
/*\r
public void SetIsSelectiveEnabled(AccountInfo account,bool value)\r
}\r
_cancellationSource = new CancellationTokenSource();\r
\r
- lock (this)\r
- {\r
- CloudClient = new CloudFilesClient(UserName, ApiKey)\r
- {UsePithos = true, AuthenticationUrl = AuthenticationUrl};\r
- _accountInfo = CloudClient.Authenticate();\r
- }\r
+ CloudClient = new CloudFilesClient(UserName, ApiKey)\r
+ {UsePithos = true, AuthenticationUrl = AuthenticationUrl};\r
+ \r
+ _accountInfo = await CloudClient.Authenticate().ConfigureAwait(false);\r
_accountInfo.SiteUri = AuthenticationUrl;\r
_accountInfo.AccountPath = RootPath;\r
\r
{\r
\r
[Export(typeof(ICloudClient))]\r
- public class CloudFilesClient:ICloudClient\r
+ public class CloudFilesClient:ICloudClient,IDisposable\r
{\r
private const string TOKEN_HEADER = "X-Auth-Token";\r
private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);\r
private readonly string _emptyGuid = Guid.Empty.ToString();\r
private readonly Uri _emptyUri = new Uri("",UriKind.Relative);\r
\r
+ private HttpClientHandler _httpClientHandler = new HttpClientHandler\r
+ {\r
+ AllowAutoRedirect = true,\r
+ AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,\r
+ UseCookies = true, \r
+ };\r
+\r
\r
public string Token\r
{\r
throw new WebException(String.Format("{0} with code {1} - {2}", message, statusCode, response.ReasonPhrase));\r
}\r
\r
- public AccountInfo Authenticate()\r
+ public async Task<AccountInfo> Authenticate()\r
{\r
if (String.IsNullOrWhiteSpace(UserName))\r
throw new InvalidOperationException("UserName is empty");\r
\r
var groups = new List<Group>();\r
\r
- var httpClientHandler = new HttpClientHandler\r
- {\r
- AllowAutoRedirect = true,\r
- AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,\r
- UseCookies = true, \r
- };\r
-\r
- using (var authClient = new HttpClient(httpClientHandler){ BaseAddress = new Uri(AuthenticationUrl),Timeout=TimeSpan.FromSeconds(30) })\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
string storageUrl;\r
string token;\r
\r
- using (var response = authClient.GetAsyncWithRetries(new Uri(VersionPath, UriKind.Relative),3).Result) // .DownloadStringWithRetryRelative(new Uri(VersionPath, UriKind.Relative), 3); \r
+ using (var response = await authClient.GetAsyncWithRetries(new Uri(VersionPath, UriKind.Relative),3).ConfigureAwait(false)) // .DownloadStringWithRetryRelative(new Uri(VersionPath, UriKind.Relative), 3); \r
{\r
AssertStatusOK(response,"Authentication failed");\r
\r
RootAddressUri = new Uri(rootUrl);\r
\r
\r
- _baseHttpClient = new HttpClient(httpClientHandler)\r
+ _baseHttpClient = new HttpClient(_httpClientHandler,false)\r
{\r
BaseAddress = StorageUrl,\r
Timeout = TimeSpan.FromSeconds(30)\r
};\r
_baseHttpClient.DefaultRequestHeaders.Add(TOKEN_HEADER, token);\r
\r
- _baseHttpClientNoTimeout = new HttpClient(httpClientHandler)\r
+ _baseHttpClientNoTimeout = new HttpClient(_httpClientHandler,false)\r
{\r
BaseAddress = StorageUrl,\r
Timeout = TimeSpan.FromMilliseconds(-1)\r
}\r
}\r
\r
- public IList<ContainerInfo> ListContainers(string account)\r
+ public async Task<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
+ var targetUri = new Uri(String.Format("{0}?format=json", targetUrl));\r
+ var result = await GetStringAsync(targetUri, "List Containers failed").ConfigureAwait(false);\r
if (String.IsNullOrWhiteSpace(result))\r
return new List<ContainerInfo>();\r
- var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(result); \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
\r
- if (client.StatusCode == HttpStatusCode.NoContent)\r
- return new List<ContainerInfo>();\r
- var infos = JsonConvert.DeserializeObject<IList<ContainerInfo>>(content);\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
- foreach (var info in infos)\r
- {\r
- info.Account = account;\r
- }\r
- return infos;\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
if (Log.IsDebugEnabled) Log.DebugFormat("START");\r
\r
var targetUri = new Uri(String.Format("{0}?format=json", RootAddressUri), UriKind.Absolute);\r
- var content=GetStringAsync(targetUri, "ListSharingAccounts failed", since).Result;\r
+ var content=TaskEx.Run(async ()=>await GetStringAsync(targetUri, "ListSharingAccounts failed", since).ConfigureAwait(false)).Result;\r
\r
//If the result is empty, return an empty list,\r
var infos = String.IsNullOrWhiteSpace(content)\r
\r
Func<ContainerInfo, string> getKey = c => String.Format("{0}\\{1}", c.Account, c.Name);\r
\r
- var accounts = ListSharingAccounts();\r
- var containers = (from account in accounts\r
- let conts = ListContainers(account.name)\r
+ var containers = (from account in ListSharingAccounts()\r
+ let conts = ListContainers(account.name).Result\r
from container in conts\r
select container).ToList(); \r
var items = from container in containers \r
\r
var containerUri = GetTargetUri(account).Combine(container);\r
var targetUri = new Uri(String.Format("{0}?format=json", containerUri), UriKind.Absolute);\r
- var content = GetStringAsync(targetUri, "ListObjects failed", since).Result;\r
+\r
+ var content =TaskEx.Run(async ()=>await GetStringAsync(targetUri, "ListObjects failed", since).ConfigureAwait(false)).Result;\r
\r
//304 will result in an empty string. Empty containers return an empty json array\r
if (String.IsNullOrWhiteSpace(content))\r
\r
var containerUri = GetTargetUri(account).Combine(container);\r
var targetUri = new Uri(String.Format("{0}?format=json&path={1}", containerUri,folder), UriKind.Absolute);\r
- var content = GetStringAsync(targetUri, "ListObjects failed", since).Result; \r
+ var content = TaskEx.Run(async ()=>await GetStringAsync(targetUri, "ListObjects failed", since).ConfigureAwait(false)).Result; \r
\r
//304 will result in an empty string. Empty containers return an empty json array\r
if (String.IsNullOrWhiteSpace(content))\r
}\r
}\r
}\r
+\r
+ ~CloudFilesClient()\r
+ {\r
+ Dispose(false);\r
+ }\r
+\r
+ public void Dispose()\r
+ {\r
+ Dispose(true);\r
+ GC.SuppressFinalize(this);\r
+ }\r
+\r
+ protected virtual void Dispose(bool disposing)\r
+ {\r
+ if (disposing)\r
+ {\r
+ if (_httpClientHandler!=null)\r
+ _httpClientHandler.Dispose();\r
+ if (_baseClient!=null)\r
+ _baseClient.Dispose();\r
+ if(_baseHttpClient!=null)\r
+ _baseHttpClient.Dispose();\r
+ if (_baseHttpClientNoTimeout!=null)\r
+ _baseHttpClientNoTimeout.Dispose();\r
+ }\r
+ _httpClientHandler = null;\r
+ _baseClient = null;\r
+ _baseHttpClient = null;\r
+ _baseHttpClientNoTimeout = null;\r
+ }\r
}\r
\r
public class ShareAccountInfo\r
string Token { get; set; }\r
\r
bool UsePithos { get; set; }\r
- AccountInfo Authenticate();\r
+ Task<AccountInfo> Authenticate();\r
//WebProxy Proxy { get; set; }\r
double DownloadPercentLimit { get; set; }\r
double UploadPercentLimit { get; set; }\r
\r
#region Container operations\r
\r
- IList<ContainerInfo> ListContainers(string account);\r
+ Task<IList<ContainerInfo>> ListContainers(string account);\r
IList<ObjectInfo> ListObjects(string account, Uri container, DateTime? since = null);\r
IList<ObjectInfo> ListObjects(string account, Uri container, Uri folder, DateTime? since = null);\r
bool ContainerExists(string account, Uri container);\r
\r
public bool UsePithos { get; set; }\r
\r
- public AccountInfo Authenticate()\r
+ public Task<AccountInfo> Authenticate()\r
{\r
Contract.Requires<ArgumentNullException>(!String.IsNullOrWhiteSpace(ApiKey), "ApiKey must be filled before calling Authenticate");\r
Contract.Requires<ArgumentNullException>(!String.IsNullOrWhiteSpace(UserName), "UserName must be filled before calling Authenticate");\r
\r
- return default(AccountInfo);\r
+ return default(Task<AccountInfo>);\r
}\r
\r
- public IList<ContainerInfo> ListContainers(string account)\r
+ public Task<IList<ContainerInfo>> ListContainers(string account)\r
{\r
Contract.Requires(!String.IsNullOrWhiteSpace(Token));\r
Contract.Requires(StorageUrl!=null); \r
\r
- return default(IList<ContainerInfo>);\r
+ return default(Task<IList<ContainerInfo>>);\r
}\r
\r
public IList<ObjectInfo> ListSharedObjects(HashSet<string> knownContainers, DateTime? since)\r
{\r
try\r
{\r
- var result = await func();\r
+ var result = await func().ConfigureAwait(false);\r
return result;\r
}\r
catch (Exception exc)\r
HttpStatusCode.RedirectMethod,HttpStatusCode.NotModified,HttpStatusCode.TemporaryRedirect,HttpStatusCode.RedirectKeepVerb};\r
while (retries > 0)\r
{\r
- var result = await func();\r
+ var result = await func().ConfigureAwait(false);\r
if (result.IsSuccessStatusCode || acceptedCodes.Contains(result.StatusCode))\r
return result;\r
\r
if (result.StatusCode == HttpStatusCode.ServiceUnavailable)\r
{\r
Log.InfoFormat("[UNAVAILABLE] Waiting before retry: {0}",result.ReasonPhrase);\r
- await TaskEx.Delay(waitTime);\r
+ await TaskEx.Delay(waitTime).ConfigureAwait(false);\r
//increase the timeout for repeated timeouts\r
if (waitTime<TimeSpan.FromSeconds(10))\r
waitTime = waitTime.Add(TimeSpan.FromSeconds(10));\r
request.Headers.IfModifiedSince = since.Value;\r
}\r
//Func<Task<HttpResponseMessage>> call = () => _baseHttpClient.SendAsync(request);\r
- using (var response = await client.SendAsyncWithRetries(request,3))\r
+ using (var response = await client.SendAsyncWithRetries(request,3).ConfigureAwait(false))\r
{\r
if (response.StatusCode == HttpStatusCode.NoContent)\r
return String.Empty;\r
\r
- var content = await response.Content.ReadAsStringAsync();\r
+ var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);\r
return content;\r
}\r
\r
{\r
if (Log.IsDebugEnabled)\r
Log.DebugFormat("[REQUEST] {0}",message);\r
- var result = await client.SendAsync(message,completionOption,cancellationToken);\r
+ HttpResponseMessage result;\r
+ try\r
+ {\r
+ result = await client.SendAsync(message, completionOption, cancellationToken).ConfigureAwait(false);\r
+ }\r
+ catch (Exception exc)\r
+ {\r
+ Log.FatalFormat("Unexpected error while sending:\n{0}\n{1}",message,exc);\r
+ throw;\r
+ }\r
+ \r
if (result.IsSuccessStatusCode || acceptedCodes.Contains(result.StatusCode))\r
{\r
if (Log.IsDebugEnabled)\r
{\r
\r
Log.WarnFormat("[UNAVAILABLE] Waiting before retrying [{0}]:[{1}] due to [{2}]",message.Method, message.RequestUri,result.ReasonPhrase); \r
- await TaskEx.Delay(waitTime);\r
+ await TaskEx.Delay(waitTime).ConfigureAwait(false);\r
//increase the timeout for repeated timeouts\r
if (waitTime<TimeSpan.FromSeconds(10))\r
waitTime = waitTime.Add(TimeSpan.FromSeconds(10));\r