Fixed frequent timeout by always closing WebResponse objects
authorPanagiotis Kanavos <pkanavos@gmail.com>
Tue, 20 Dec 2011 20:40:35 +0000 (22:40 +0200)
committerPanagiotis Kanavos <pkanavos@gmail.com>
Tue, 20 Dec 2011 20:40:35 +0000 (22:40 +0200)
trunk/Pithos.Client.WPF/Converters/DummyConverter.cs [new file with mode: 0644]
trunk/Pithos.Client.WPF/Preferences/AddAccountView.xaml
trunk/Pithos.Client.WPF/Preferences/AddAccountViewModel.cs
trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
trunk/Pithos.Client.WPF/app.config
trunk/Pithos.Core/Agents/StatusAgent.cs
trunk/Pithos.Core/TaskExtensions.cs
trunk/Pithos.Interfaces/ObjectInfo.cs
trunk/Pithos.Network/RestClient.cs
trunk/Pithos.sln

diff --git a/trunk/Pithos.Client.WPF/Converters/DummyConverter.cs b/trunk/Pithos.Client.WPF/Converters/DummyConverter.cs
new file mode 100644 (file)
index 0000000..71550b7
--- /dev/null
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Windows.Data;
+
+namespace Pithos.Client.WPF.Converters
+{
+       public class DummyConverter:IValueConverter
+       {
+           public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+           {
+               return value;
+           }
+
+           public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+           {
+               return value;
+           }
+       }
+}
index 4ee67cf..c0d28a9 100644 (file)
     <extToolkit:Wizard FinishButtonClosesWindow="True" Name="AccountWizard" PageChanged="AccountWizard_PageChanged">
         <extToolkit:WizardPage x:Name="IntroPage" 
                                    Title="Add new Pithos Account"
-                                   Description="This Wizard will walk you through adding a new Pithos account and retrieving an authentication token" />
+                                   Description="This Wizard will walk you through adding a new Pithos account and retrieving an authentication token" 
+                               BackButtonVisibility="Collapsed"
+                               FinishButtonVisibility="Collapsed"/>
         <extToolkit:WizardPage x:Name="ChooseServer" PageType="Interior"
                                    Title="Where do you want to connect?"
                                    Description="You can connect to the production or development server, or enter your own server URL"                               
+                               FinishButtonVisibility="Collapsed"
                                     CanSelectNextPage="{Binding IsValidServer}"
                                     >
             <StackPanel >
@@ -36,6 +39,7 @@
         <extToolkit:WizardPage x:Name="ChooseMethodPage" PageType="Interior"
                                    Title="How do you want to add the account?"
                                    Description="You can add an account either by logging in the Pithos Web Site or by entering your username and password manually"                               
+                               FinishButtonVisibility="Collapsed"
                                     CanSelectNextPage="False">
             <StackPanel >
                 <RadioButton x:Name="Automatic" Content="By logging to Pithos" Checked="Automatic_Checked" Margin="5"/>
@@ -46,6 +50,7 @@
                                    Title="Add an account manually"
                                    Description="Please enter the account credentials and press &quot;Validate Credentials&quot;"
                                NextPage="{Binding ElementName=AccountPathPage}"                               
+                               FinishButtonVisibility="Collapsed"
                                CanSelectNextPage="{Binding HasValidCredentials}" 
                                >
             <extToolkit:BusyIndicator x:Name="ManualBusyIndicator" IsBusy="{Binding IsWorking,NotifyOnSourceUpdated=true}" DisplayAfter="0" >
@@ -69,6 +74,7 @@
                         <Label Content="API Key" Grid.Column="0" Grid.Row="1" Margin="0,5" HorizontalAlignment="Left"/>
                         <TextBox  Name="Token" Grid.Column="1" Grid.Row="1" Margin="5"/>
                         <Button x:Name="TestManualAccount" Content="Validate Credentials" IsEnabled="{Binding HasCredentials}" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center" cal:Message.Attach="TestAccount" Margin="5"/>
+                        <TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding ValidationMessage}" Margin="10" HorizontalAlignment="Center"/>
                     </Grid>
                 </extToolkit:BusyIndicator.Content>
             </extToolkit:BusyIndicator>
@@ -77,6 +83,7 @@
                                    Title="Add an account automatically"
                                    Description="By clicking on the button below you will be taken to the Pithos web site where you can login with your username and password."
                                NextPage="{Binding ElementName=AutoConfirmedPage}"                               
+                               FinishButtonVisibility="Collapsed"
                                CanSelectNextPage="{Binding HasValidCredentials}"                               
                                >
             <extToolkit:BusyIndicator x:Name="AutoBusyIndicator" IsBusy="{Binding IsWorking}" DisplayAfter="0">
                                    Title="Select Account Path"
                                    Description="Please select the roor path for your account"
                                NextPage="{Binding ElementName=LastPage}"
+                               FinishButtonVisibility="Collapsed"
                                CanSelectNextPage="{Binding HasAccountPath}"
                                    >
             <StackPanel>
index 8ee783b..4fbb448 100644 (file)
@@ -198,6 +198,16 @@ namespace Pithos.Client.WPF.Preferences
             }
         }
 
+        private string _validationMessage;
+        public string ValidationMessage
+        {
+            get { return _validationMessage; }
+            set
+            {
+                _validationMessage = value;
+                NotifyOfPropertyChange(()=>ValidationMessage);
+            }
+        }
 
         private bool _isWorking;
         public bool IsWorking
@@ -251,20 +261,31 @@ namespace Pithos.Client.WPF.Preferences
         {
             try
             {
-                SetBusy("Validating Credentials","");
-                var client = new CloudFilesClient(AccountName, Token) {AuthenticationUrl = CurrentServer};                
-                var containers = await TaskEx.Run(()=>
+                SetBusy("Validating Credentials", "");
+                var client = new CloudFilesClient(AccountName, Token) { AuthenticationUrl = CurrentServer };
+                var containers = await TaskEx.Run(() =>
                                                       {
                                                           client.Authenticate();
                                                           return client.ListContainers(AccountName);
                                                       });
-                HasValidCredentials = true;                
+                HasValidCredentials = true;
+                ValidationMessage = "Credentials Validated";
+            }
+/*
+            catch (AggregateException exc)
+            {
+                exc.Handle(ex=>
+                               {
+                                   HasValidCredentials = false;
+                                   MessageBox.Show("The account is not valid", "Account Error", MessageBoxButton.OK, MessageBoxImage.Stop);                                                   
+                               });
             }
+*/
             catch (Exception ex)
             {
                 HasValidCredentials = false;
                 MessageBox.Show("The account is not valid", "Account Error", MessageBoxButton.OK, MessageBoxImage.Stop);
-                throw;
+                ValidationMessage = "Credentials validation failed";
             }
             finally
             {
index b5d6a5e..92cd900 100644 (file)
@@ -621,25 +621,14 @@ namespace Pithos.Client.WPF {
         {
             if (account== null)
                 return;
-
+            //TODO: What happens to an existing account whose Token has changed?
             account.SiteUri= String.Format("{0}/ui/?token={1}&user={2}",
                 account.SiteUri, account.Token,
                 account.UserName);
 
-            IProducerConsumerCollection<AccountInfo> accounts = Accounts;
-            for (var i = 0; i < _accounts.Count; i++)
-            {
-                AccountInfo item;
-                if (accounts.TryTake(out item))
-                {
-                    if (item.UserName!=account.UserName)
-                    {
-                        accounts.TryAdd(item);
-                    }
-                }
-            }
+            if (Accounts.All(item => item.UserName != account.UserName))
+                Accounts.TryAdd(account);
 
-            accounts.TryAdd(account);
         }
 
 
index 93fd18a..7d7adfb 100644 (file)
         <acceptOnMatch value="false" />
       </filter>
     </appender>
+    <logger name="NHibernate.SQL" additivity="false">
+      <level value="DEBUG"/>
+      <appender-ref ref="TraceAppender" />      
+    </logger>
+
     <root>
       <level value="DEBUG" />
       <appender-ref ref="TraceAppender" />
index 8e3526e..338f88e 100644 (file)
@@ -36,35 +36,14 @@ namespace Pithos.Core.Agents
 
             if (!Directory.Exists(_pithosDataPath))
                 Directory.CreateDirectory(_pithosDataPath);
-
-            //File.Delete(Path.Combine(_pithosDataPath, "pithos.db"));
-            
-
             var source = GetConfiguration(_pithosDataPath);
             ActiveRecordStarter.Initialize(source,typeof(FileState),typeof(FileTag));
             ActiveRecordStarter.UpdateSchema();
 
-            ;
             if (!File.Exists(Path.Combine(_pithosDataPath ,"pithos.db")))
                 ActiveRecordStarter.CreateSchema();
-            
-            
-
-            CleanupStaleStates();
-
         }        
 
-        private void CleanupStaleStates()
-        {
-            /*var stales = from state in FileState.Queryable
-                         where state.FilePath.StartsWith(@"e:\pithos\cache")
-                         select state.Id;*/
-/*
-            FileState.DeleteAll(@"FilePath like 'e:\pithos\.pithos.cache%'");
-            ;
-*/
-        }
-
         private static InPlaceConfigurationSource GetConfiguration(string pithosDbPath)
         {
             if (String.IsNullOrWhiteSpace(pithosDbPath))
index 8662d51..9b74d17 100644 (file)
@@ -129,5 +129,18 @@ namespace Pithos.Core
             return false;
         }
 
+        public static bool TryAdd<T>(this ObservableConcurrentCollection<T> collection,T item) where T:class
+        {
+            if (collection==null)
+                throw new ArgumentNullException("collection");
+            Contract.EndContractBlock();
+
+            if (item == null)
+                return false;
+
+            IProducerConsumerCollection<T> items= collection;            
+            return items.TryAdd(item);
+        }
+
     }
 }
\ No newline at end of file
index 582a882..2fe41b5 100644 (file)
@@ -14,7 +14,15 @@ namespace Pithos.Interfaces
     {
         private readonly List<string> _knownContainers= new List<string>{"trash"};
         public string Name { get; set; }
+        
+        
         public string Hash { get; set; }
+
+        public string X_Object_Hash { get { return Hash; } set { Hash = value; } }
+
+        [JsonProperty("x_object_uuid")]
+        public string UUID { get; set; }
+
         public long Bytes { get; set; }
         public string Content_Type { get; set; }
         public DateTime Last_Modified { get; set; }
@@ -85,7 +93,7 @@ namespace Pithos.Interfaces
         public string ContentEncoding { get; set; }
 
         public string Manifest { get; set; }
-
+        
         public bool IsPublic
         {
             get { return !String.IsNullOrWhiteSpace(PublicUrl); }
@@ -98,6 +106,7 @@ namespace Pithos.Interfaces
             }
         }
 
+        [JsonProperty("X_Object_Public")]
         public string PublicUrl { get; set; }
 
         public ObjectInfo()
index 293518a..a2c5e90 100644 (file)
@@ -84,10 +84,31 @@ namespace Pithos.Network
             this.Proxy = other.Proxy;
         }
 
+
+        private WebHeaderCollection _responseHeaders;
+
+        public new WebHeaderCollection ResponseHeaders
+        {
+            get
+            {
+                if (base.ResponseHeaders==null)
+                {
+                    return _responseHeaders;
+                }
+                else
+                {
+                    _responseHeaders = null;
+                    return base.ResponseHeaders;   
+                }
+                
+            }
+
+            set { _responseHeaders = value; }
+        } 
         protected override WebRequest GetWebRequest(Uri address)
         {
             TimedOut = false;
-            var webRequest = base.GetWebRequest(address);
+            var webRequest = base.GetWebRequest(address);            
             var request = (HttpWebRequest)webRequest;
             if (IfModifiedSince.HasValue)
                 request.IfModifiedSince = IfModifiedSince.Value;
@@ -107,50 +128,73 @@ namespace Pithos.Network
 
         public DateTime? IfModifiedSince { get; set; }
 
+        //Asynchronous version
         protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
         {
-            return ProcessResponse(()=>base.GetWebResponse(request, result)); 
-        }
+            Log.InfoFormat("ASYNC [{0}] {1}",request.Method, request.RequestUri);
+            HttpWebResponse response = null;
+
+            try
+            {
+                response = (HttpWebResponse)base.GetWebResponse(request, result);
+            }
+            catch (WebException exc)
+            {
+                if (!TryGetResponse(exc, out response))
+                    throw;
+            }
+
+            StatusCode = response.StatusCode;
+            LastModified = response.LastModified;
+            StatusDescription = response.StatusDescription;
+            return response;
 
-        protected override WebResponse GetWebResponse(WebRequest request)
-        {
-            return ProcessResponse(() => base.GetWebResponse(request));
         }
+      
 
-        private WebResponse ProcessResponse(Func<WebResponse> getResponse)
+        //Synchronous version
+        protected override WebResponse GetWebResponse(WebRequest request)
         {
+            HttpWebResponse response = null;
             try
-            {
-                var response = (HttpWebResponse)getResponse();
-                StatusCode = response.StatusCode;
-                LastModified = response.LastModified;
-                StatusDescription = response.StatusDescription;
-                return response;
+            {                                
+                response = (HttpWebResponse)base.GetWebResponse(request);
             }
             catch (WebException exc)
             {
-                if (exc.Response != null)
-                {
-                    var response = (exc.Response as HttpWebResponse);
-                    if (AllowedStatusCodes.Contains(response.StatusCode))
-                    {
-                        StatusCode = response.StatusCode;
-                        LastModified = response.LastModified;
-                        StatusDescription = response.StatusDescription;
+                if (!TryGetResponse(exc, out response))
+                    throw;
+            }
 
-                        return response;
-                    }
-                    if (exc.Response.ContentLength > 0)
-                    {
-                        string content = GetContent(exc.Response);
-                        Log.ErrorFormat(content);                        
-                    }
-                }
-                throw;
+            StatusCode = response.StatusCode;
+            LastModified = response.LastModified;
+            StatusDescription = response.StatusDescription;
+            return response;
+        }
+
+        private bool TryGetResponse(WebException exc, out HttpWebResponse response)
+        {
+            response = null;
+            //Fail on empty response
+            if (exc.Response == null)
+                return false;
+
+            response = (exc.Response as HttpWebResponse);
+            //Succeed on allowed status codes
+            if (AllowedStatusCodes.Contains(response.StatusCode))
+                return true;
+
+            //Does the response have any content to log?
+            if (exc.Response.ContentLength > 0)
+            {
+                var content = GetContent(exc.Response);
+                Log.ErrorFormat(content);
             }
+            return false;
         }
 
-        private readonly List<HttpStatusCode> _allowedStatusCodes=new List<HttpStatusCode>{HttpStatusCode.NotModified};
+        private readonly List<HttpStatusCode> _allowedStatusCodes=new List<HttpStatusCode>{HttpStatusCode.NotModified};        
+
         public List<HttpStatusCode> AllowedStatusCodes
         {
             get
@@ -263,10 +307,16 @@ namespace Pithos.Network
                 TraceStart(method, uriString);
                 if (method == "PUT")
                     request.ContentLength = 0;
+
                 var response = (HttpWebResponse)GetWebResponse(request);
-                StatusCode = response.StatusCode;
-                StatusDescription = response.StatusDescription;                
+                //var response = (HttpWebResponse)request.GetResponse();
                 
+                //ResponseHeaders= response.Headers;
+
+                LastModified = response.LastModified;
+                StatusCode = response.StatusCode;
+                StatusDescription = response.StatusDescription;
+                response.Close();
 
                 return 0;
             }, actualRetries);
index d0d8612..6474704 100644 (file)
@@ -36,6 +36,8 @@ Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Pithos.Setup.x64", "Pithos.
 EndProject
 Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "Pithos.Setup.x86", "Pithos.Setup.x86\Pithos.Setup.x86.vdproj", "{0D7E50F2-D7B4-4458-AA01-2CAC0F386737}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkTests", "Tests\NetworkTests\NetworkTests.csproj", "{052D04DA-28FE-471F-96FD-BC1E92BF2A54}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug All|Any CPU = Debug All|Any CPU
@@ -532,6 +534,36 @@ Global
                {0D7E50F2-D7B4-4458-AA01-2CAC0F386737}.Test|Mixed Platforms.ActiveCfg = Release
                {0D7E50F2-D7B4-4458-AA01-2CAC0F386737}.Test|x64.ActiveCfg = Release
                {0D7E50F2-D7B4-4458-AA01-2CAC0F386737}.Test|x86.ActiveCfg = Release
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug All|Any CPU.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug All|Mixed Platforms.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug All|Mixed Platforms.Build.0 = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug All|x64.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug All|x86.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug All|x86.Build.0 = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug|Any CPU.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug|Mixed Platforms.Build.0 = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug|x64.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug|x86.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Debug|x86.Build.0 = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Premium Debug|Any CPU.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Premium Debug|Mixed Platforms.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Premium Debug|Mixed Platforms.Build.0 = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Premium Debug|x64.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Premium Debug|x86.ActiveCfg = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Premium Debug|x86.Build.0 = Debug|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Release|Any CPU.ActiveCfg = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Release|Mixed Platforms.ActiveCfg = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Release|Mixed Platforms.Build.0 = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Release|x64.ActiveCfg = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Release|x86.ActiveCfg = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Release|x86.Build.0 = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Test|Any CPU.ActiveCfg = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Test|Mixed Platforms.ActiveCfg = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Test|Mixed Platforms.Build.0 = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Test|x64.ActiveCfg = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Test|x86.ActiveCfg = Release|x86
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54}.Test|x86.Build.0 = Release|x86
        EndGlobalSection
        GlobalSection(SolutionProperties) = preSolution
                HideSolutionNode = FALSE
@@ -541,5 +573,6 @@ Global
                {2CFE2DF1-20AE-47E2-B1BB-36B974600BE1} = {B5DD7C4D-D396-4C55-A8D5-DCFE865AA095}
                {E027200B-C26A-4877-BFD9-1A18CF5DF2F4} = {B5DD7C4D-D396-4C55-A8D5-DCFE865AA095}
                {F9AF3E97-BCB7-46B7-8014-7FC858AEE9BA} = {B5DD7C4D-D396-4C55-A8D5-DCFE865AA095}
+               {052D04DA-28FE-471F-96FD-BC1E92BF2A54} = {B5DD7C4D-D396-4C55-A8D5-DCFE865AA095}
        EndGlobalSection
 EndGlobal