More fixes and changes to DateTimeOffset dates
authorpkanavos <pkanavos@gmail.com>
Fri, 28 Sep 2012 11:30:40 +0000 (14:30 +0300)
committerpkanavos <pkanavos@gmail.com>
Fri, 28 Sep 2012 11:30:40 +0000 (14:30 +0300)
15 files changed:
trunk/Pithos.Client.WPF/App.xaml.cs
trunk/Pithos.Client.WPF/FileProperties/ConflictResolver.cs
trunk/Pithos.Client.WPF/FileProperties/FilePropertiesViewModel.cs
trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
trunk/Pithos.Core/Agents/BlockUpdater.cs
trunk/Pithos.Core/Agents/PollAgent.cs
trunk/Pithos.Core/Agents/StatusAgent.cs
trunk/Pithos.Core/Agents/Uploader.cs
trunk/Pithos.Core/FileState.cs
trunk/Pithos.Core/Pithos.Core.csproj
trunk/Pithos.Core/PithosMonitor.cs
trunk/Pithos.Interfaces/ObjectInfo.cs
trunk/Pithos.Network/CloudFilesClient.cs
trunk/Pithos.Network/ICloudClient.cs
trunk/Pithos.Network/WebExtensions.cs

index e9ab29e..b9e86cb 100644 (file)
@@ -173,6 +173,7 @@ namespace Pithos.Client.WPF
             {\r
                 _singleInstanceMutex.Dispose();\r
                 _singleInstanceMutex = null;\r
             {\r
                 _singleInstanceMutex.Dispose();\r
                 _singleInstanceMutex = null;\r
+                Log.Warn("An instance of Pithos+ is already running. Terminating.");\r
                 Shutdown();\r
                 return;\r
             }\r
                 Shutdown();\r
                 return;\r
             }\r
index c5e1fca..8725bb6 100644 (file)
@@ -5,6 +5,7 @@ using System.IO;
 using System.Linq;\r
 using System.Text;\r
 using System.Threading;\r
 using System.Linq;\r
 using System.Text;\r
 using System.Threading;\r
+using System.Threading.Tasks;\r
 using System.Windows;\r
 using Caliburn.Micro;\r
 using Pithos.Core;\r
 using System.Windows;\r
 using Caliburn.Micro;\r
 using Pithos.Core;\r
@@ -81,7 +82,7 @@ namespace Pithos.Client.WPF.FileProperties
                           where conflict.State.OverlayStatus != FileOverlayStatus.Deleted\r
                           let monitor=monitors.First(m=> conflict.FilePath.StartsWith(m.Account.AccountPath, StringComparison.InvariantCultureIgnoreCase))\r
                           let account = monitor.Account\r
                           where conflict.State.OverlayStatus != FileOverlayStatus.Deleted\r
                           let monitor=monitors.First(m=> conflict.FilePath.StartsWith(m.Account.AccountPath, StringComparison.InvariantCultureIgnoreCase))\r
                           let account = monitor.Account\r
-                          let info = monitor.GetObjectInfo(conflict.FilePath)\r
+                          let info = TaskEx.Run(async ()=> await monitor.GetObjectInfo(conflict.FilePath).ConfigureAwait(false)).Result\r
                           select new CloudDownloadAction(account, info, "Resolver");\r
 \r
             foreach (var action in downloadActions)\r
                           select new CloudDownloadAction(account, info, "Resolver");\r
 \r
             foreach (var action in downloadActions)\r
index 5281718..3d9be85 100644 (file)
@@ -168,8 +168,8 @@ namespace Pithos.Client.WPF
             }\r
         }\r
 \r
             }\r
         }\r
 \r
-        private DateTime _modified;\r
-        public DateTime Modified\r
+        private DateTimeOffset? _modified;\r
+        public DateTimeOffset? Modified\r
         {\r
             get { return _modified; }\r
             set\r
         {\r
             get { return _modified; }\r
             set\r
@@ -507,9 +507,9 @@ namespace Pithos.Client.WPF
             get { return _permissions; }\r
         }\r
 \r
             get { return _permissions; }\r
         }\r
 \r
-        public void Reload()\r
+        public async void Reload()\r
         {\r
         {\r
-            PithosFile=Shell.RefreshObjectInfo(PithosFile);\r
+            PithosFile=await Shell.RefreshObjectInfo(PithosFile);\r
         }\r
 \r
         public override void CanClose(Action<bool> callback)\r
         }\r
 \r
         public override void CanClose(Action<bool> callback)\r
index 5053ed0..e63b513 100644 (file)
@@ -636,7 +636,7 @@ namespace Pithos.Client.WPF {
                        ShowFileProperties(files[idx].FullName);            \r
                }\r
 \r
                        ShowFileProperties(files[idx].FullName);            \r
                }\r
 \r
-               public void ShowFileProperties(string filePath)\r
+               public async void ShowFileProperties(string filePath)\r
                {\r
                        if (String.IsNullOrWhiteSpace(filePath))\r
                                throw new ArgumentNullException("filePath");\r
                {\r
                        if (String.IsNullOrWhiteSpace(filePath))\r
                                throw new ArgumentNullException("filePath");\r
@@ -652,7 +652,7 @@ namespace Pithos.Client.WPF {
                        if (accountMonitor == null)\r
                                return;\r
 \r
                        if (accountMonitor == null)\r
                                return;\r
 \r
-                       var infoTask=Task.Factory.StartNew(()=>accountMonitor.GetObjectInfo(filePath));\r
+                       var infoTask=accountMonitor.GetObjectInfo(filePath);\r
 \r
                        \r
 \r
 \r
                        \r
 \r
@@ -695,13 +695,13 @@ namespace Pithos.Client.WPF {
                        _pollAgent.SynchNow();\r
                }\r
 \r
                        _pollAgent.SynchNow();\r
                }\r
 \r
-               public ObjectInfo RefreshObjectInfo(ObjectInfo currentInfo)\r
+               public async Task<ObjectInfo> RefreshObjectInfo(ObjectInfo currentInfo)\r
                {\r
                        if (currentInfo==null)\r
                                throw new ArgumentNullException("currentInfo");\r
                        Contract.EndContractBlock();                \r
             var monitor = Monitors[currentInfo.AccountKey];\r
                {\r
                        if (currentInfo==null)\r
                                throw new ArgumentNullException("currentInfo");\r
                        Contract.EndContractBlock();                \r
             var monitor = Monitors[currentInfo.AccountKey];\r
-                       var newInfo=monitor.CloudClient.GetObjectInfo(currentInfo.Account, currentInfo.Container, currentInfo.Name);\r
+                       var newInfo=await monitor.CloudClient.GetObjectInfo(currentInfo.Account, currentInfo.Container, currentInfo.Name).ConfigureAwait(false);\r
                        return newInfo;\r
                }\r
 \r
                        return newInfo;\r
                }\r
 \r
index 7ac2a8c..c77b2d0 100644 (file)
@@ -193,8 +193,8 @@ namespace Pithos.Core.Agents
                 throw new InvalidOperationException("TempPath is empty");\r
             Contract.EndContractBlock();\r
 \r
                 throw new InvalidOperationException("TempPath is empty");\r
             Contract.EndContractBlock();\r
 \r
-            var drive=DriveInfo.GetDrives().First(d => FilePath.StartsWith(d.Name,StringComparison.OrdinalIgnoreCase));\r
-            var isNTFS=(drive.DriveFormat == "NTFS");\r
+            var info = Alpha.Volume.GetVolumeInformation(Alpha.Path.GetPathRoot(FilePath));            \r
+            var isNTFS = info.FileSystemName.Equals("NTFS");                \r
 \r
 \r
             if (isNTFS && MS.WindowsAPICodePack.Internal.CoreHelpers.RunningOnVista)\r
 \r
 \r
             if (isNTFS && MS.WindowsAPICodePack.Internal.CoreHelpers.RunningOnVista)\r
index fa30cc5..c95d6af 100644 (file)
@@ -174,7 +174,7 @@ namespace Pithos.Core.Agents
         /// </summary>\r
         /// <param name="since"></param>\r
         /// <returns></returns>\r
         /// </summary>\r
         /// <param name="since"></param>\r
         /// <returns></returns>\r
-        public  void PollRemoteFiles(DateTime? since = null)\r
+        public  void PollRemoteFiles(DateTimeOffset? since = null)\r
         {\r
             if (Log.IsDebugEnabled)\r
                 Log.DebugFormat("Polling changes after [{0}]",since);\r
         {\r
             if (Log.IsDebugEnabled)\r
                 Log.DebugFormat("Polling changes after [{0}]",since);\r
@@ -186,7 +186,7 @@ namespace Pithos.Core.Agents
             using (ThreadContext.Stacks["Retrieve Remote"].Push("All accounts"))\r
             {\r
                 //If this poll fails, we will retry with the same since value\r
             using (ThreadContext.Stacks["Retrieve Remote"].Push("All accounts"))\r
             {\r
                 //If this poll fails, we will retry with the same since value\r
-                var nextSince = since;\r
+                DateTimeOffset? nextSince = since;\r
                 try\r
                 {\r
                     _unPauseEvent.Wait();\r
                 try\r
                 {\r
                     _unPauseEvent.Wait();\r
@@ -203,7 +203,7 @@ namespace Pithos.Core.Agents
                     \r
                     var moves=Interlocked.Exchange(ref _moves, new ConcurrentDictionary<string, MovedEventArgs>());\r
 \r
                     \r
                     var moves=Interlocked.Exchange(ref _moves, new ConcurrentDictionary<string, MovedEventArgs>());\r
 \r
-                    var tasks = new List<Task<DateTime?>>();\r
+                    var tasks = new List<Task<DateTimeOffset?>>();\r
                     foreach(var accountInfo in _accounts.Values)\r
                     {\r
                         IEnumerable<string> accountBatch ;\r
                     foreach(var accountInfo in _accounts.Values)\r
                     {\r
                         IEnumerable<string> accountBatch ;\r
@@ -251,7 +251,7 @@ namespace Pithos.Core.Agents
         /// </summary>\r
         /// <param name="since"></param>\r
         /// <returns></returns>\r
         /// </summary>\r
         /// <param name="since"></param>\r
         /// <returns></returns>\r
-        private async Task<DateTime?> WaitForScheduledOrManualPoll(DateTime? since)\r
+        private async Task<DateTimeOffset?> WaitForScheduledOrManualPoll(DateTimeOffset? since)\r
         {\r
             var sync = _syncEvent.WaitAsync();\r
             var delay = TimeSpan.FromSeconds(Settings.PollingInterval);\r
         {\r
             var sync = _syncEvent.WaitAsync();\r
             var delay = TimeSpan.FromSeconds(Settings.PollingInterval);\r
@@ -279,7 +279,7 @@ namespace Pithos.Core.Agents
 \r
         \r
 \r
 \r
         \r
 \r
-        public async Task<DateTime?> ProcessAccountFiles(AccountInfo accountInfo, IEnumerable<string> accountBatch, ConcurrentDictionary<string, MovedEventArgs> moves, DateTime? since = null)\r
+        public async Task<DateTimeOffset?> ProcessAccountFiles(AccountInfo accountInfo, IEnumerable<string> accountBatch, ConcurrentDictionary<string, MovedEventArgs> moves, DateTimeOffset? since = null)\r
         {\r
             if (accountInfo == null)\r
                 throw new ArgumentNullException("accountInfo");\r
         {\r
             if (accountInfo == null)\r
                 throw new ArgumentNullException("accountInfo");\r
@@ -308,7 +308,7 @@ namespace Pithos.Core.Agents
                 //The nextSince time fallback time is the same as the current.\r
                 //If polling succeeds, the next Since time will be the smallest of the maximum modification times\r
                 //of the shared and account objects\r
                 //The nextSince time fallback time is the same as the current.\r
                 //If polling succeeds, the next Since time will be the smallest of the maximum modification times\r
                 //of the shared and account objects\r
-                var nextSince = since;\r
+                DateTimeOffset? nextSince = since;\r
 \r
                 try\r
                 {\r
 \r
                 try\r
                 {\r
@@ -1097,14 +1097,14 @@ namespace Pithos.Core.Agents
         /// <param name="threshold"></param>\r
         /// <param name="cloudObjects"></param>\r
         /// <returns></returns>\r
         /// <param name="threshold"></param>\r
         /// <param name="cloudObjects"></param>\r
         /// <returns></returns>\r
-        private static DateTime? GetLatestDateBefore(DateTime? threshold, IList<ObjectInfo> cloudObjects)\r
+        private static DateTimeOffset? GetLatestDateBefore(DateTime? threshold, IList<ObjectInfo> cloudObjects)\r
         {\r
         {\r
-            DateTime? maxDate = null;\r
+            DateTimeOffset? maxDate = null;\r
             if (cloudObjects!=null &&  cloudObjects.Count > 0)\r
                 maxDate = cloudObjects.Max(obj => obj.Last_Modified);\r
             if (cloudObjects!=null &&  cloudObjects.Count > 0)\r
                 maxDate = cloudObjects.Max(obj => obj.Last_Modified);\r
-            if (maxDate == null || maxDate == DateTime.MinValue)\r
+            if (!maxDate.HasValue)\r
                 return threshold;\r
                 return threshold;\r
-            if (threshold == null || threshold == DateTime.MinValue || threshold > maxDate)\r
+            if (!threshold.HasValue|| threshold > maxDate)\r
                 return maxDate;\r
             return threshold;\r
         }\r
                 return maxDate;\r
             return threshold;\r
         }\r
@@ -1116,14 +1116,14 @@ namespace Pithos.Core.Agents
         /// <param name="threshold"></param>\r
         /// <param name="cloudObjects"></param>\r
         /// <returns></returns>\r
         /// <param name="threshold"></param>\r
         /// <param name="cloudObjects"></param>\r
         /// <returns></returns>\r
-        private static DateTime? GetLatestDateAfter(DateTime? threshold, IList<ObjectInfo> cloudObjects)\r
+        private static DateTimeOffset? GetLatestDateAfter(DateTimeOffset? threshold, IList<ObjectInfo> cloudObjects)\r
         {\r
         {\r
-            DateTime? maxDate = null;\r
+            DateTimeOffset? maxDate = null;\r
             if (cloudObjects!=null &&  cloudObjects.Count > 0)\r
                 maxDate = cloudObjects.Max(obj => obj.Last_Modified);\r
             if (cloudObjects!=null &&  cloudObjects.Count > 0)\r
                 maxDate = cloudObjects.Max(obj => obj.Last_Modified);\r
-            if (maxDate == null || maxDate == DateTime.MinValue)\r
+            if (!maxDate.HasValue)\r
                 return threshold;\r
                 return threshold;\r
-            if (threshold == null || threshold == DateTime.MinValue || threshold < maxDate)\r
+            if (!threshold.HasValue|| threshold < maxDate)\r
                 return maxDate;\r
             return threshold;\r
         }\r
                 return maxDate;\r
             return threshold;\r
         }\r
index 2241a1c..91a183f 100644 (file)
@@ -335,9 +335,10 @@ namespace Pithos.Core.Agents
                 {\r
                         //var updatecmd = session.CreateSQLQuery(\r
                     var updatecmd = session.CreateQuery(\r
                 {\r
                         //var updatecmd = session.CreateSQLQuery(\r
                     var updatecmd = session.CreateQuery(\r
-                        "update FileState set FileStatus= :fileStatus where Id = :id  ")\r
+                        "update FileState set FileStatus= :fileStatus, Modified=:modified where Id = :id  ")\r
                         .SetGuid("id", id)\r
                         .SetGuid("id", id)\r
-                        .SetEnum("fileStatus", status);\r
+                        .SetEnum("fileStatus", status)\r
+                        .SetDateTime("modified",DateTime.Now);\r
                     var affected = updatecmd.ExecuteUpdate();\r
                         session.Flush();\r
                     return affected;\r
                     var affected = updatecmd.ExecuteUpdate();\r
                         session.Flush();\r
                     return affected;\r
@@ -468,11 +469,12 @@ namespace Pithos.Core.Agents
                     {\r
 \r
                         //var updatecmd = session.CreateSQLQuery("update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus,ConflictReason= :conflictReason where FilePath = :path ")\r
                     {\r
 \r
                         //var updatecmd = session.CreateSQLQuery("update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus,ConflictReason= :conflictReason where FilePath = :path ")\r
-                        var updatecmd = session.CreateQuery("update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus,ConflictReason= :conflictReason where FilePath = :path")\r
+                        var updatecmd = session.CreateQuery("update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus,ConflictReason= :conflictReason, Modified=:modified where FilePath = :path")\r
                             .SetString("path", path)\r
                             .SetEnum("fileStatus", fileStatus)\r
                             .SetEnum("overlayStatus", overlayStatus)\r
                             .SetString("path", path)\r
                             .SetEnum("fileStatus", fileStatus)\r
                             .SetEnum("overlayStatus", overlayStatus)\r
-                            .SetString("conflictReason", conflictReason);\r
+                            .SetString("conflictReason", conflictReason)\r
+                            .SetDateTime("modified",DateTime.Now);\r
                         var affected = updatecmd.ExecuteUpdate();\r
 \r
                         if (affected == 0)\r
                         var affected = updatecmd.ExecuteUpdate();\r
 \r
                         if (affected == 0)\r
@@ -603,9 +605,10 @@ namespace Pithos.Core.Agents
 \r
                         //var updatecmd = session.CreateSQLQuery(\r
                         var updatecmd = session.CreateQuery(\r
 \r
                         //var updatecmd = session.CreateSQLQuery(\r
                         var updatecmd = session.CreateQuery(\r
-                            "update FileState set FileStatus= :fileStatus where FilePath = :path ")\r
+                            "update FileState set FileStatus= :fileStatus, Modified=:modified where FilePath = :path ")\r
                             .SetString("path", path)\r
                             .SetString("path", path)\r
-                            .SetEnum("fileStatus", status);\r
+                            .SetEnum("fileStatus", status)\r
+                            .SetDateTime("modified",DateTime.Now);\r
                         var affected = updatecmd.ExecuteUpdate();\r
 \r
                         if (affected == 0)\r
                         var affected = updatecmd.ExecuteUpdate();\r
 \r
                         if (affected == 0)\r
@@ -888,10 +891,11 @@ namespace Pithos.Core.Agents
             ExecuteWithRetry((session, instance) =>\r
             {\r
                 const string hqlUpdate =\r
             ExecuteWithRetry((session, instance) =>\r
             {\r
                 const string hqlUpdate =\r
-                    "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' ";\r
+                    "update FileState set FilePath = replace(FilePath,:oldPath,:newPath), Modified=:modified where FilePath like :oldPath || '%' ";\r
                 var renames = session.CreateQuery(hqlUpdate)\r
                     .SetString("oldPath", oldPath)\r
                     .SetString("newPath", newPath)\r
                 var renames = session.CreateQuery(hqlUpdate)\r
                     .SetString("oldPath", oldPath)\r
                     .SetString("newPath", newPath)\r
+                    .SetDateTime("modified",DateTime.Now)\r
                     .ExecuteUpdate();\r
                 return renames;\r
             }, null);\r
                     .ExecuteUpdate();\r
                 return renames;\r
             }, null);\r
@@ -984,12 +988,13 @@ namespace Pithos.Core.Agents
 \r
             ExecuteWithRetry((session, instance) =>\r
             {\r
 \r
             ExecuteWithRetry((session, instance) =>\r
             {\r
-                const string hqlUpdate = "update FileState set Checksum= :checksum,Hashes=:hashes,ETag=:etag where FilePath = :path ";\r
+                const string hqlUpdate = "update FileState set Checksum= :checksum,Hashes=:hashes,ETag=:etag, Modified=:modified where FilePath = :path ";\r
                 var updatedEntities = session.CreateQuery(hqlUpdate)\r
                     .SetString("path", path)\r
                     .SetString("checksum", topHash)\r
                     .SetString("hashes", hashes)\r
                     .SetString("etag", etag)\r
                 var updatedEntities = session.CreateQuery(hqlUpdate)\r
                     .SetString("path", path)\r
                     .SetString("checksum", topHash)\r
                     .SetString("hashes", hashes)\r
                     .SetString("etag", etag)\r
+                    .SetDateTime("modified", DateTime.Now)\r
                     .ExecuteUpdate();\r
                 return updatedEntities;\r
             }, null);\r
                     .ExecuteUpdate();\r
                 return updatedEntities;\r
             }, null);\r
@@ -1008,7 +1013,7 @@ namespace Pithos.Core.Agents
             ExecuteWithRetry((session, instance) =>\r
             {\r
 \r
             ExecuteWithRetry((session, instance) =>\r
             {\r
 \r
-                const string hqlUpdate = "update FileState set Hashes=:hashes where FilePath = :path ";\r
+                const string hqlUpdate = "update FileState set Hashes=:hashes,Modified=:modified where FilePath = :path ";\r
 /*\r
                 const string hqlUpdate = "update FileState set Checksum= :checksum,Hashes=:hashes where FilePath = :path ";\r
 */\r
 /*\r
                 const string hqlUpdate = "update FileState set Checksum= :checksum,Hashes=:hashes where FilePath = :path ";\r
 */\r
@@ -1017,6 +1022,7 @@ namespace Pithos.Core.Agents
                     //.SetString("checksum", topHash)\r
                     //                    .SetString("md5",treeHash.MD5)\r
                     .SetString("hashes", hashes)\r
                     //.SetString("checksum", topHash)\r
                     //                    .SetString("md5",treeHash.MD5)\r
                     .SetString("hashes", hashes)\r
+                    .SetDateTime("modified", DateTime.Now)\r
                     .ExecuteUpdate();\r
                 return updatedEntities;\r
             }, null);\r
                     .ExecuteUpdate();\r
                 return updatedEntities;\r
             }, null);\r
@@ -1032,10 +1038,11 @@ namespace Pithos.Core.Agents
             ExecuteWithRetry((session, instance) =>\r
             {\r
                 const string hqlUpdate =\r
             ExecuteWithRetry((session, instance) =>\r
             {\r
                 const string hqlUpdate =\r
-                    "update FileState set FilePath= :newPath where FilePath = :oldPath ";\r
+                    "update FileState set FilePath= :newPath, Modified=:modified where FilePath = :oldPath ";\r
                 var updatedEntities = session.CreateQuery(hqlUpdate)\r
                     .SetString("oldPath", oldPath)\r
                     .SetString("newPath", newPath)\r
                 var updatedEntities = session.CreateQuery(hqlUpdate)\r
                     .SetString("oldPath", oldPath)\r
                     .SetString("newPath", newPath)\r
+                    .SetDateTime("modified", DateTime.Now)\r
                     .ExecuteUpdate();\r
                 return updatedEntities;\r
             }, null);\r
                     .ExecuteUpdate();\r
                 return updatedEntities;\r
             }, null);\r
@@ -1058,7 +1065,8 @@ namespace Pithos.Core.Agents
                             OverlayStatus = newStatus,\r
                             ETag = Signature.MERKLE_EMPTY,\r
                             //LastMD5=String.Empty,\r
                             OverlayStatus = newStatus,\r
                             ETag = Signature.MERKLE_EMPTY,\r
                             //LastMD5=String.Empty,\r
-                            IsFolder = Directory.Exists(absolutePath)\r
+                            IsFolder = Directory.Exists(absolutePath),\r
+                            Modified=DateTime.Now\r
                         };\r
                     state.OverlayStatus = newStatus;\r
                     session.SaveOrUpdate(state);\r
                         };\r
                     state.OverlayStatus = newStatus;\r
                     session.SaveOrUpdate(state);\r
index bab5f1f..18da934 100644 (file)
@@ -120,7 +120,7 @@ namespace Pithos.Core.Agents
                             var client = new CloudFilesClient(accountInfo);\r
 \r
                             //Even if GetObjectInfo times out, we can proceed with the upload            \r
                             var client = new CloudFilesClient(accountInfo);\r
 \r
                             //Even if GetObjectInfo times out, we can proceed with the upload            \r
-                            var cloudInfo = client.GetObjectInfo(account, cloudFile.Container, cloudFile.Name);\r
+                            var cloudInfo = await client.GetObjectInfo(account, cloudFile.Container, cloudFile.Name).ConfigureAwait(false);\r
 \r
                             //If this a shared file\r
                             if (!cloudFile.Account.Equals(action.AccountInfo.UserName,StringComparison.InvariantCultureIgnoreCase))\r
 \r
                             //If this a shared file\r
                             if (!cloudFile.Account.Equals(action.AccountInfo.UserName,StringComparison.InvariantCultureIgnoreCase))\r
@@ -211,8 +211,8 @@ namespace Pithos.Core.Agents
                                                           treeHash, cancellationToken).ConfigureAwait(false);\r
                                 }\r
 \r
                                                           treeHash, cancellationToken).ConfigureAwait(false);\r
                                 }\r
 \r
-                                var currentInfo = client.GetObjectInfo(cloudFile.Account, cloudFile.Container,\r
-                                                                       cloudFile.Name);\r
+                                var currentInfo =await client.GetObjectInfo(cloudFile.Account, cloudFile.Container,\r
+                                                                       cloudFile.Name).ConfigureAwait(false);\r
 \r
                                 StatusKeeper.StoreInfo(fullFileName, currentInfo, localTreeHash);\r
                                 //Ensure the status is cleared\r
 \r
                                 StatusKeeper.StoreInfo(fullFileName, currentInfo, localTreeHash);\r
                                 //Ensure the status is cleared\r
index 7bc793e..c955bba 100644 (file)
@@ -73,6 +73,8 @@ namespace Pithos.Core
         /*////[Property]*/\r
         public virtual string ObjectID { get; set; }\r
 \r
         /*////[Property]*/\r
         public virtual string ObjectID { get; set; }\r
 \r
+        public virtual long FileId { get; set; }\r
+\r
  /*       //[Property(Unique = true, UniqueKey = "IX_FileState_FilePath")]*/\r
         public virtual string FilePath { get; set; }\r
 \r
  /*       //[Property(Unique = true, UniqueKey = "IX_FileState_FilePath")]*/\r
         public virtual string FilePath { get; set; }\r
 \r
@@ -381,7 +383,8 @@ namespace Pithos.Core
                                     //LastMD5=md5,\r
                                     LastWriteDate=lastWriteTime,\r
                                     LastLength=length,\r
                                     //LastMD5=md5,\r
                                     LastWriteDate=lastWriteTime,\r
                                     LastLength=length,\r
-                                    IsFolder=(info is DirectoryInfo)\r
+                                    IsFolder=(info is DirectoryInfo),\r
+                                    Modified=DateTime.Now\r
                                 };\r
             return fileState;\r
         }\r
                                 };\r
             return fileState;\r
         }\r
index 8252154..a131aba 100644 (file)
     <Compile Include="IPithosWorkflow.cs" />\r
     <Compile Include="IStatusKeeper.cs" />\r
     <Compile Include="NativeMethods.cs" />\r
     <Compile Include="IPithosWorkflow.cs" />\r
     <Compile Include="IStatusKeeper.cs" />\r
     <Compile Include="NativeMethods.cs" />\r
+    <Compile Include="NtfsExtensions.cs" />\r
     <Compile Include="PithosMonitor.cs" />\r
     <Compile Include="PithosWorkflow.cs" />\r
     <Compile Include="Properties\AssemblyInfo.cs" />\r
     <Compile Include="PithosMonitor.cs" />\r
     <Compile Include="PithosWorkflow.cs" />\r
     <Compile Include="Properties\AssemblyInfo.cs" />\r
index ec51f4f..1c79811 100644 (file)
@@ -241,7 +241,7 @@ namespace Pithos.Core
             //Create the cache folder and ensure it is hidden\r
             CreateHiddenFolder(RootPath, FolderConstants.CacheFolder);\r
 \r
             //Create the cache folder and ensure it is hidden\r
             CreateHiddenFolder(RootPath, FolderConstants.CacheFolder);\r
 \r
-            var policy=CloudClient.GetAccountPolicies(_accountInfo);\r
+            var policy=await CloudClient.GetAccountPolicies(_accountInfo);\r
 \r
             StatusNotification.NotifyAccount(policy);\r
             EnsurePithosContainers();\r
 \r
             StatusNotification.NotifyAccount(policy);\r
             EnsurePithosContainers();\r
@@ -554,7 +554,7 @@ namespace Pithos.Core
         }\r
 \r
 \r
         }\r
 \r
 \r
-        public ObjectInfo GetObjectInfo(string filePath)\r
+        public async Task<ObjectInfo> GetObjectInfo(string filePath)\r
         {\r
             if (String.IsNullOrWhiteSpace(filePath))\r
                 throw new ArgumentNullException("filePath");\r
         {\r
             if (String.IsNullOrWhiteSpace(filePath))\r
                 throw new ArgumentNullException("filePath");\r
@@ -598,7 +598,7 @@ namespace Pithos.Core
             }\r
             \r
             var client = new CloudFilesClient(accountInfo);\r
             }\r
             \r
             var client = new CloudFilesClient(accountInfo);\r
-            var objectInfo=client.GetObjectInfo(accountName, container.ToEscapedUri(), relativeUrl.ToEscapedUri());\r
+            var objectInfo=await client.GetObjectInfo(accountName, container.ToEscapedUri(), relativeUrl.ToEscapedUri()).ConfigureAwait(false);\r
             return objectInfo;\r
         }\r
         \r
             return objectInfo;\r
         }\r
         \r
index 03aecc1..f8d5731 100644 (file)
@@ -87,7 +87,7 @@ namespace Pithos.Interfaces
 \r
         public long Bytes { get; set; }\r
         public string Content_Type { get; set; }\r
 \r
         public long Bytes { get; set; }\r
         public string Content_Type { get; set; }\r
-        public DateTime Last_Modified { get; set; }\r
+        public DateTimeOffset? Last_Modified { get; set; }\r
 \r
         private Dictionary<string, string> _tags=new Dictionary<string, string>();\r
         public Dictionary<string, string> Tags\r
 \r
         private Dictionary<string, string> _tags=new Dictionary<string, string>();\r
         public Dictionary<string, string> Tags\r
@@ -267,7 +267,6 @@ namespace Pithos.Interfaces
             X_Object_Hash= String.Empty,\r
             Bytes = 0,\r
             Content_Type = String.Empty,\r
             X_Object_Hash= String.Empty,\r
             Bytes = 0,\r
             Content_Type = String.Empty,\r
-            Last_Modified = DateTime.MinValue,\r
             Exists=false\r
         };\r
 \r
             Exists=false\r
         };\r
 \r
index e181eb0..87aa5e4 100644 (file)
@@ -231,11 +231,11 @@ namespace Pithos.Network
                 {\r
                     AssertStatusOK(response,"Authentication failed");\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
                     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
                     if (String.IsNullOrWhiteSpace(token))\r
                         throw new InvalidOperationException("Failed to obtain token url");\r
 \r
@@ -297,7 +297,7 @@ namespace Pithos.Network
             Log.InfoFormat("[{0}] {1} {2}", method, DateTime.Now, actualAddress);\r
         }\r
 \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
             TraceStart("GET",targetUri);\r
             var request = new HttpRequestMessage(HttpMethod.Get, targetUri);            \r
@@ -369,7 +369,7 @@ namespace Pithos.Network
         /// </param>\r
         /// <param name="since"></param>\r
         /// <returns></returns>\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
             using (ThreadContext.Stacks["Share"].Push("List Objects"))\r
@@ -570,7 +570,7 @@ namespace Pithos.Network
 \r
         }\r
 \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 (accountInfo==null)\r
                 throw new ArgumentNullException("accountInfo");\r
@@ -580,6 +580,7 @@ namespace Pithos.Network
             {\r
                 if (Log.IsDebugEnabled) Log.DebugFormat("START");\r
 \r
             {\r
                 if (Log.IsDebugEnabled) Log.DebugFormat("START");\r
 \r
+/*\r
                 if (_baseClient == null)\r
                 {\r
                     _baseClient = new RestClient\r
                 if (_baseClient == null)\r
                 {\r
                     _baseClient = new RestClient\r
@@ -590,28 +591,46 @@ namespace Pithos.Network
                     };\r
                 }\r
 \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
                 {\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
                     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
+                    return accountInfo;   \r
                 }\r
 \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
             }\r
         }\r
 \r
@@ -728,7 +747,7 @@ namespace Pithos.Network
        \r
 \r
 \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
             if (container==null)\r
                 throw new ArgumentNullException("container");\r
@@ -765,7 +784,7 @@ namespace Pithos.Network
             }\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
         {\r
             if (container==null)\r
                 throw new ArgumentNullException("container");\r
@@ -957,22 +976,86 @@ namespace Pithos.Network
 \r
         }\r
 \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
         {\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
             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
             Contract.EndContractBlock();\r
 \r
             using (ThreadContext.Stacks["Objects"].Push("GetObjectInfo"))\r
-            {                \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))\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.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.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
                 {\r
                     if (!String.IsNullOrWhiteSpace(account))\r
                         client.BaseAddress = GetAccountUrl(account);\r
@@ -1041,12 +1124,12 @@ namespace Pithos.Network
                                           objectName, client.StatusCode), e);\r
                         throw;\r
                     }\r
                                           objectName, client.StatusCode), e);\r
                         throw;\r
                     }\r
-                }                \r
-            }\r
+                } */\r
+\r
 \r
         }\r
 \r
 \r
         }\r
 \r
-        \r
+\r
 \r
         public void CreateFolder(string account, Uri container, Uri folder)\r
         {\r
 \r
         public void CreateFolder(string account, Uri container, Uri folder)\r
         {\r
@@ -1112,9 +1195,8 @@ namespace Pithos.Network
                 throw new ArgumentException("The container must be relative","container");\r
             Contract.EndContractBlock();\r
 \r
                 throw new ArgumentException("The container must be relative","container");\r
             Contract.EndContractBlock();\r
 \r
-            var targetUri = GetTargetUri(account).Combine(container);\r
-            var message = new HttpRequestMessage(HttpMethod.Head, targetUri);\r
-            using (var response = _baseHttpClient.SendAsyncWithRetries(message, 3).Result)\r
+            var targetUri = GetTargetUri(account).Combine(container);            \r
+            using (var response = _baseHttpClient.HeadAsyncWithRetries(targetUri, 3).Result)\r
             {\r
                 if (Log.IsDebugEnabled)\r
                     Log.DebugFormat("ContainerInfo data: {0}\n{1}",response,response.Content.ReadAsStringAsync().Result);\r
             {\r
                 if (Log.IsDebugEnabled)\r
                     Log.DebugFormat("ContainerInfo data: {0}\n{1}",response,response.Content.ReadAsStringAsync().Result);\r
@@ -1130,11 +1212,11 @@ namespace Pithos.Network
                                                     Account = account,\r
                                                     Name = container,\r
                                                     StorageUrl = StorageUrl.ToString(),\r
                                                     Account = account,\r
                                                     Name = container,\r
                                                     StorageUrl = StorageUrl.ToString(),\r
-                                                    Count =long.Parse(response.Headers.GetValues("X-Container-Object-Count").First()),\r
-                                                    Bytes = long.Parse(response.Headers.GetValues("X-Container-Bytes-Used").First()),\r
-                                                    BlockHash = response.Headers.GetValues("X-Container-Block-Hash").First(),\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
                                                     BlockSize =\r
-                                                        int.Parse(response.Headers.GetValues("X-Container-Block-Size").First()),\r
+                                                        int.Parse(response.Headers.GetFirstValue("X-Container-Block-Size")),\r
                                                     Last_Modified = response.Content.Headers.LastModified,\r
                                                     Tags = tags,\r
                                                     Policies = policies\r
                                                     Last_Modified = response.Content.Headers.LastModified,\r
                                                     Tags = tags,\r
                                                     Policies = policies\r
index caeaab8..cab3eb7 100644 (file)
@@ -69,8 +69,8 @@ namespace Pithos.Network
         #region Container operations\r
 \r
         Task<IList<ContainerInfo>> ListContainers(string account);\r
         #region Container operations\r
 \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
+        IList<ObjectInfo> ListObjects(string account, Uri container, DateTimeOffset? since = null);\r
+        IList<ObjectInfo> ListObjects(string account, Uri container, Uri folder, DateTimeOffset? since = null);\r
         bool ContainerExists(string account, Uri container);\r
         ContainerInfo GetContainerInfo(string account, Uri container);\r
         void CreateContainer(string account, Uri container);\r
         bool ContainerExists(string account, Uri container);\r
         ContainerInfo GetContainerInfo(string account, Uri container);\r
         void CreateContainer(string account, Uri container);\r
@@ -84,7 +84,7 @@ namespace Pithos.Network
         //void DeleteObject(string container, string objectName, string account = null);\r
         void MoveObject(string account, Uri sourceContainer, Uri oldObjectName, Uri targetContainer, Uri newObjectName);\r
         bool ObjectExists(string account, Uri container, Uri objectName);\r
         //void DeleteObject(string container, string objectName, string account = null);\r
         void MoveObject(string account, Uri sourceContainer, Uri oldObjectName, Uri targetContainer, Uri newObjectName);\r
         bool ObjectExists(string account, Uri container, Uri objectName);\r
-        ObjectInfo GetObjectInfo(string account, Uri container, Uri objectName);\r
+        Task<ObjectInfo> GetObjectInfo(string account, Uri container, Uri objectName);\r
         void CreateFolder(string account, Uri container, Uri folder);\r
         #endregion\r
 \r
         void CreateFolder(string account, Uri container, Uri folder);\r
         #endregion\r
 \r
@@ -96,12 +96,12 @@ namespace Pithos.Network
         #endregion\r
 \r
         #region Sharing operations        \r
         #endregion\r
 \r
         #region Sharing operations        \r
-        IList<ObjectInfo> ListSharedObjects(HashSet<string> knownContainers, DateTime? since);\r
+        IList<ObjectInfo> ListSharedObjects(HashSet<string> knownContainers, DateTimeOffset? since);\r
         void ShareObject(string account, Uri container, Uri objectName, string shareTo, bool read, bool write);\r
 \r
         #endregion\r
 \r
         void ShareObject(string account, Uri container, Uri objectName, string shareTo, bool read, bool write);\r
 \r
         #endregion\r
 \r
-        AccountInfo GetAccountPolicies(AccountInfo accountInfo);\r
+        Task<AccountInfo> GetAccountPolicies(AccountInfo accountInfo);\r
 \r
         void UpdateMetadata(ObjectInfo objectInfo);\r
 \r
 \r
         void UpdateMetadata(ObjectInfo objectInfo);\r
 \r
@@ -143,7 +143,7 @@ namespace Pithos.Network
             return default(Task<IList<ContainerInfo>>);\r
         }\r
 \r
             return default(Task<IList<ContainerInfo>>);\r
         }\r
 \r
-        public IList<ObjectInfo> ListSharedObjects(HashSet<string> knownContainers, DateTime? since)\r
+        public IList<ObjectInfo> ListSharedObjects(HashSet<string> knownContainers, DateTimeOffset? since)\r
         {\r
 \r
             Contract.Requires(knownContainers!=null);\r
         {\r
 \r
             Contract.Requires(knownContainers!=null);\r
@@ -167,11 +167,11 @@ namespace Pithos.Network
    \r
         }\r
 \r
    \r
         }\r
 \r
-        public AccountInfo GetAccountPolicies(AccountInfo accountInfo)\r
+        public Task<AccountInfo> GetAccountPolicies(AccountInfo accountInfo)\r
         {\r
             Contract.Requires(accountInfo!=null);\r
 \r
         {\r
             Contract.Requires(accountInfo!=null);\r
 \r
-            return default(AccountInfo);\r
+            return default(Task<AccountInfo>);\r
         }\r
 \r
         public void UpdateMetadata(ObjectInfo objectInfo)\r
         }\r
 \r
         public void UpdateMetadata(ObjectInfo objectInfo)\r
@@ -204,7 +204,7 @@ namespace Pithos.Network
         }\r
 \r
 \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
             \r
             Contract.Requires(!String.IsNullOrWhiteSpace(Token));\r
         {\r
             \r
             Contract.Requires(!String.IsNullOrWhiteSpace(Token));\r
@@ -215,7 +215,7 @@ namespace Pithos.Network
             return default(IList<ObjectInfo>);\r
         }\r
 \r
             return default(IList<ObjectInfo>);\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
             \r
             Contract.Requires(!String.IsNullOrWhiteSpace(Token));\r
         {\r
             \r
             Contract.Requires(!String.IsNullOrWhiteSpace(Token));\r
@@ -339,7 +339,7 @@ namespace Pithos.Network
             return default(bool);\r
         }\r
 \r
             return default(bool);\r
         }\r
 \r
-        public ObjectInfo GetObjectInfo(string account, Uri container, Uri objectName)\r
+        public Task<ObjectInfo> GetObjectInfo(string account, Uri container, Uri objectName)\r
         {\r
             \r
             Contract.Requires(!String.IsNullOrWhiteSpace(Token));\r
         {\r
             \r
             Contract.Requires(!String.IsNullOrWhiteSpace(Token));\r
@@ -349,7 +349,7 @@ namespace Pithos.Network
             Contract.Requires(objectName != null);\r
             Contract.Requires(!objectName.IsAbsoluteUri);\r
 \r
             Contract.Requires(objectName != null);\r
             Contract.Requires(!objectName.IsAbsoluteUri);\r
 \r
-            return default(ObjectInfo);\r
+            return default(Task<ObjectInfo>);\r
         }\r
 \r
         public void CreateFolder(string account, Uri container, Uri folder)\r
         }\r
 \r
         public void CreateFolder(string account, Uri container, Uri folder)\r
index c1ef3a5..ca78e1d 100644 (file)
@@ -4,6 +4,7 @@ using System.ComponentModel;
 using System.Diagnostics.Contracts;\r
 using System.Linq;\r
 using System.Net.Http;\r
 using System.Diagnostics.Contracts;\r
 using System.Linq;\r
 using System.Net.Http;\r
+using System.Net.Http.Headers;\r
 using System.Reflection;\r
 using System.Text;\r
 using System.Net;\r
 using System.Reflection;\r
 using System.Text;\r
 using System.Net;\r
@@ -217,49 +218,101 @@ namespace Pithos.Network
                 HttpStatusCode.RedirectMethod,HttpStatusCode.NotModified,HttpStatusCode.TemporaryRedirect,HttpStatusCode.RedirectKeepVerb,HttpStatusCode.Conflict};\r
             while (retries > 0)\r
             {\r
                 HttpStatusCode.RedirectMethod,HttpStatusCode.NotModified,HttpStatusCode.TemporaryRedirect,HttpStatusCode.RedirectKeepVerb,HttpStatusCode.Conflict};\r
             while (retries > 0)\r
             {\r
+                var timedOut = false;\r
                 if (Log.IsDebugEnabled)\r
                 if (Log.IsDebugEnabled)\r
-                    Log.DebugFormat("[REQUEST] {0}",message);\r
-                HttpResponseMessage result;\r
+                    Log.DebugFormat("[REQUEST] {0}", message);\r
+                HttpResponseMessage result=null;\r
                 try\r
                 {\r
                     result = await client.SendAsync(message, completionOption, cancellationToken).ConfigureAwait(false);\r
                 }\r
                 try\r
                 {\r
                     result = await client.SendAsync(message, completionOption, cancellationToken).ConfigureAwait(false);\r
                 }\r
+                catch (WebException exc)\r
+                {\r
+                    if (exc.Status != WebExceptionStatus.Timeout)\r
+                        throw;\r
+                    timedOut = true;\r
+                    if (Log.IsDebugEnabled)\r
+                        Log.DebugFormat("[RESPONSE] [{0}]:[{1}] FAIL WITH TIMEOUT", message.Method, message.RequestUri);\r
+                }\r
                 catch (Exception exc)\r
                 {\r
                 catch (Exception exc)\r
                 {\r
-                    Log.FatalFormat("Unexpected error while sending:\n{0}\n{1}",message,exc);\r
+                    Log.FatalFormat("Unexpected error while sending:\n{0}\n{1}", message, exc);\r
                     throw;\r
                 }\r
                     throw;\r
                 }\r
-                \r
+\r
+                if (timedOut)\r
+                {\r
+                    if (--retries == 0)\r
+                        throw new RetryException("Failed too many times");\r
+                    continue;\r
+                }\r
+\r
                 if (result.IsSuccessStatusCode || acceptedCodes.Contains(result.StatusCode))\r
                 {\r
                     if (Log.IsDebugEnabled)\r
                 if (result.IsSuccessStatusCode || acceptedCodes.Contains(result.StatusCode))\r
                 {\r
                     if (Log.IsDebugEnabled)\r
-                        Log.DebugFormat("[RESPONSE] [{0}]:[{1}] OK: [{2}]", message.Method,message.RequestUri, result.StatusCode);\r
+                        Log.DebugFormat("[RESPONSE] [{0}]:[{1}] OK: [{2}]", message.Method, message.RequestUri,\r
+                                        result.StatusCode);\r
                     return result;\r
                 }\r
                 //Failed, will have to abort or retry\r
                 if (Log.IsDebugEnabled)\r
                     return result;\r
                 }\r
                 //Failed, will have to abort or retry\r
                 if (Log.IsDebugEnabled)\r
-                    Log.DebugFormat("[RESPONSE] [{0}]:[{1}] FAIL: [{2}]\n{3}", message.Method,message.RequestUri, result.StatusCode,result);\r
+                    Log.DebugFormat("[RESPONSE] [{0}]:[{1}] FAIL: [{2}]\n{3}", message.Method, message.RequestUri,\r
+                                    result.StatusCode, result);\r
 \r
                 if (--retries == 0)\r
                     throw new RetryException("Failed too many times");\r
 \r
                 //Wait for service unavailable\r
 \r
                 if (--retries == 0)\r
                     throw new RetryException("Failed too many times");\r
 \r
                 //Wait for service unavailable\r
-                if (result.StatusCode == HttpStatusCode.ServiceUnavailable || result.StatusCode==HttpStatusCode.BadGateway)\r
+                if (result.StatusCode == HttpStatusCode.ServiceUnavailable ||\r
+                    result.StatusCode == HttpStatusCode.BadGateway)\r
                 {\r
                 {\r
-                    \r
-                    Log.WarnFormat("[UNAVAILABLE] Waiting before retrying [{0}]:[{1}] due to [{2}]",message.Method, message.RequestUri,result.ReasonPhrase);                    \r
+\r
+                    Log.WarnFormat("[UNAVAILABLE] Waiting before retrying [{0}]:[{1}] due to [{2}]", message.Method,\r
+                                   message.RequestUri, result.ReasonPhrase);\r
                     await TaskEx.Delay(waitTime).ConfigureAwait(false);\r
                     //increase the timeout for repeated timeouts\r
                     await TaskEx.Delay(waitTime).ConfigureAwait(false);\r
                     //increase the timeout for repeated timeouts\r
-                    if (waitTime<TimeSpan.FromSeconds(10))\r
+                    if (waitTime < TimeSpan.FromSeconds(10))\r
                         waitTime = waitTime.Add(TimeSpan.FromSeconds(10));\r
                         waitTime = waitTime.Add(TimeSpan.FromSeconds(10));\r
-                }                \r
-                //Throw in all other cases\r
-                else \r
+                }\r
+                    //Throw in all other cases\r
+                else\r
                     result.EnsureSuccessStatusCode();\r
             }\r
             throw new RetryException();\r
         }\r
 \r
                     result.EnsureSuccessStatusCode();\r
             }\r
             throw new RetryException();\r
         }\r
 \r
+        public static string GetFirstValue(this HttpResponseHeaders headers, string name)\r
+        {\r
+            if (headers==null)\r
+                throw new ArgumentNullException("headers");\r
+            if (String.IsNullOrWhiteSpace(name))\r
+                throw new ArgumentNullException("name");\r
+            Contract.EndContractBlock();\r
+\r
+            IEnumerable<string> values;\r
+            if (headers.TryGetValues(name, out values))\r
+            {\r
+                return values.FirstOrDefault();\r
+            }\r
+            return null;\r
+        }\r
+\r
+        public static  Dictionary<string, string> GetMeta(this HttpResponseHeaders headers,string metaPrefix)\r
+        {\r
+            if (headers == null)\r
+                throw new ArgumentNullException("headers");\r
+            if (String.IsNullOrWhiteSpace(metaPrefix))\r
+                throw new ArgumentNullException("metaPrefix");\r
+            Contract.EndContractBlock();\r
+\r
+            var dict = (from header in headers\r
+                        where header.Key.StartsWith(metaPrefix)\r
+                        let name = header.Key.Substring(metaPrefix.Length)\r
+                        select new { Name = name, Value = String.Join(",",header.Value) })\r
+                        .ToDictionary(t => t.Name, t => t.Value);\r
+            return dict;\r
+        }\r
+\r
     }\r
 \r
     internal static class PithosEAPCommon\r
     }\r
 \r
     internal static class PithosEAPCommon\r