Revision 692ec33b

b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs
131 131
        private async Task StartMonitoring()
132 132
        {
133 133
            try
134
            {                  
134
            {
135
                var accounts = Settings.Accounts.Select(MonitorAccount);
136
                await TaskEx.WhenAll(accounts);
137
                _statusService = StatusService.Start();
138

  
139
/*
135 140
                foreach (var account in Settings.Accounts)
136 141
                {
137 142
                    await MonitorAccount(account);
138 143
                }
139
                _statusService = StatusService.Start();
144
*/
145
                
140 146
            }
141 147
            catch (AggregateException exc)
142 148
            {
b/trunk/Pithos.Core/Agents/NetworkAgent.cs
478 478
            var fileAgent = GetFileAgent(accountInfo);
479 479
            foreach (var trashObject in trashObjects)
480 480
            {
481
                var relativePath = trashObject.RelativeUrlToFilePath(accountInfo.UserName);
482
                //and remove any matching objects from the list, adding them to the commonObjects list
481
                var barePath = trashObject.RelativeUrlToFilePath(accountInfo.UserName);
482
                //HACK: Assume only the "pithos" container is used. Must find out what happens when
483
                //deleting a file from a different container
484
                var relativePath = Path.Combine("pithos", barePath);
483 485
                fileAgent.Delete(relativePath);                                
484 486
            }
485 487
        }
......
747 749
            try
748 750
            {
749 751
                if (action == null)
750
                    throw new ArgumentNullException("action");            
752
                    throw new ArgumentNullException("action");
751 753
                Contract.EndContractBlock();
752 754

  
753
                var accountInfo=action.AccountInfo;
754
            
755
                var fileInfo=action.LocalFile;                        
755
                var accountInfo = action.AccountInfo;
756

  
757
                var fileInfo = action.LocalFile;
756 758

  
757 759
                if (fileInfo.Extension.Equals("ignore", StringComparison.InvariantCultureIgnoreCase))
758 760
                    return;
......
760 762
                var relativePath = fileInfo.AsRelativeTo(accountInfo.AccountPath);
761 763
                if (relativePath.StartsWith(FolderConstants.OthersFolder))
762 764
                {
763
                    var parts=relativePath.Split('\\');
765
                    var parts = relativePath.Split('\\');
764 766
                    var accountName = parts[1];
765 767
                    var oldName = accountInfo.UserName;
766 768
                    var absoluteUri = accountInfo.StorageUri.AbsoluteUri;
767
                    var nameIndex=absoluteUri.IndexOf(oldName);
768
                    var root=absoluteUri.Substring(0, nameIndex);
769
                    var nameIndex = absoluteUri.IndexOf(oldName);
770
                    var root = absoluteUri.Substring(0, nameIndex);
769 771

  
770 772
                    accountInfo = new AccountInfo
771 773
                    {
772 774
                        UserName = accountName,
773 775
                        AccountPath = Path.Combine(accountInfo.AccountPath, parts[0], parts[1]),
774 776
                        StorageUri = new Uri(root + accountName),
775
                        BlockHash=accountInfo.BlockHash,
776
                        BlockSize=accountInfo.BlockSize,
777
                        Token=accountInfo.Token
777
                        BlockHash = accountInfo.BlockHash,
778
                        BlockSize = accountInfo.BlockSize,
779
                        Token = accountInfo.Token
778 780
                    };
779 781
                }
780 782

  
781 783

  
782 784
                var fullFileName = fileInfo.FullName;
783
                using(var gate=NetworkGate.Acquire(fullFileName,NetworkOperation.Uploading))
785
                using (var gate = NetworkGate.Acquire(fullFileName, NetworkOperation.Uploading))
784 786
                {
785 787
                    //Abort if the file is already being uploaded or downloaded
786 788
                    if (gate.Failed)
......
791 793

  
792 794
                    var client = new CloudFilesClient(accountInfo);
793 795
                    //Even if GetObjectInfo times out, we can proceed with the upload            
794
                    var info = client.GetObjectInfo(account, cloudFile.Container, cloudFile.Name);                
796
                    var info = client.GetObjectInfo(account, cloudFile.Container, cloudFile.Name);
795 797
                    var cloudHash = info.Hash.ToLower();
796 798

  
797 799
                    var hash = action.LocalHash.Value;
798 800
                    var topHash = action.TopHash.Value;
799 801

  
800 802
                    //If the file hashes match, abort the upload
801
                    if (hash == cloudHash  || topHash ==cloudHash)
803
                    if (hash == cloudHash || topHash == cloudHash)
802 804
                    {
803 805
                        //but store any metadata changes 
804 806
                        this.StatusKeeper.StoreInfo(fullFileName, info);
......
806 808
                        return;
807 809
                    }
808 810

  
809
                    if (info.AllowedTo=="read")
811
                    if (info.AllowedTo == "read")
810 812
                        return;
811 813

  
812 814
                    //Mark the file as modified while we upload it
......
818 820

  
819 821
                    //First, calculate the tree hash
820 822
                    var treeHash = await Signature.CalculateTreeHashAsync(fileInfo.FullName, accountInfo.BlockSize,
821
                        accountInfo.BlockHash);                
822
                    
823
                    await UploadWithHashMap(accountInfo,cloudFile,fileInfo,cloudFile.Name,treeHash);
823
                        accountInfo.BlockHash);
824

  
825
                    await UploadWithHashMap(accountInfo, cloudFile, fileInfo, cloudFile.Name, treeHash);
824 826

  
825 827
                    //If everything succeeds, change the file and overlay status to normal
826 828
                    this.StatusKeeper.SetFileState(fullFileName, FileStatus.Unchanged, FileOverlayStatus.Normal);
......
834 836
                var exc = ex.InnerException as WebException;
835 837
                if (exc == null)
836 838
                    throw ex.InnerException;
837
                var response = exc.Response as HttpWebResponse;
838
                if (response == null)
839
                    throw exc;
840
                if (response.StatusCode == HttpStatusCode.Unauthorized)
841
                {
842
                    Log.Error("Not allowed to upload file", exc);
843
                    var message = String.Format("Not allowed to uplad file {0}", action.LocalFile.FullName);
844
                    StatusKeeper.SetFileState(action.LocalFile.FullName, FileStatus.Unchanged, FileOverlayStatus.Normal);
845
                    StatusNotification.NotifyChange(message, TraceLevel.Warning);
839
                if (HandleUploadWebException(action, exc)) 
846 840
                    return;
847
                }
841
                throw;
842
            }
843
            catch (WebException ex)
844
            {
845
                if (HandleUploadWebException(action, ex))
846
                    return;
847
                throw;
848
            }
849
            catch (Exception ex)
850
            {
851
                Log.Error("Unexpected error while uploading file", ex);
848 852
                throw;
849 853
            }
850 854

  
851 855
        }
852 856

  
857
        private bool HandleUploadWebException(CloudAction action, WebException exc)
858
        {
859
            var response = exc.Response as HttpWebResponse;
860
            if (response == null)
861
                throw exc;
862
            if (response.StatusCode == HttpStatusCode.Unauthorized)
863
            {
864
                Log.Error("Not allowed to upload file", exc);
865
                var message = String.Format("Not allowed to uplad file {0}", action.LocalFile.FullName);
866
                StatusKeeper.SetFileState(action.LocalFile.FullName, FileStatus.Unchanged, FileOverlayStatus.Normal);
867
                StatusNotification.NotifyChange(message, TraceLevel.Warning);
868
                return true;
869
            }
870
            return false;
871
        }
872

  
853 873
        public async Task UploadWithHashMap(AccountInfo accountInfo,ObjectInfo cloudFile,FileInfo fileInfo,string url,TreeHash treeHash)
854 874
        {
855 875
            if (accountInfo == null)
b/trunk/Pithos.Network/CloudFilesClient.cs
7 7
using System.Collections.Generic;
8 8
using System.Collections.Specialized;
9 9
using System.ComponentModel.Composition;
10
using System.Diagnostics;
10 11
using System.Diagnostics.Contracts;
11 12
using System.IO;
12 13
using System.Linq;
......
946 947

  
947 948

  
948 949
            //Don't use a timeout because putting the hashmap may be a long process
949
            var client = new RestClient(_baseClient) { Timeout = 0 };
950
            var client = new RestClient(_baseClient) { Timeout = 0 };           
950 951
            if (!String.IsNullOrWhiteSpace(account))
951 952
                client.BaseAddress = GetAccountUrl(account);
952 953

  
......
959 960

  
960 961
            //Send the tree hash as Json to the server            
961 962
            client.Headers[HttpRequestHeader.ContentType] = "application/octet-stream";
962
            var uploadTask=client.UploadStringTask(uri, "PUT", hash.ToJson());
963

  
963
            var jsonHash = hash.ToJson();
964
            var uploadTask=client.UploadStringTask(uri, "PUT", jsonHash);
964 965
            
965 966
            return uploadTask.ContinueWith(t =>
966 967
            {
......
987 988
                        using (var stream = response.GetResponseStream())
988 989
                        using(var reader=new StreamReader(stream))
989 990
                        {
991
                            Debug.Assert(stream.Position == 0);
990 992
                            //We need to cleanup the content before returning it because it contains
991 993
                            //error content after the list of hashes
992 994
                            var hashes = new List<string>();
b/trunk/Pithos.Network/RestClient.cs
85 85
        }
86 86

  
87 87

  
88
        private WebHeaderCollection _responseHeaders;
89

  
90
        public new WebHeaderCollection ResponseHeaders
91
        {
92
            get
93
            {
94
                if (base.ResponseHeaders==null)
95
                {
96
                    return _responseHeaders;
97
                }
98
                else
99
                {
100
                    _responseHeaders = null;
101
                    return base.ResponseHeaders;   
102
                }
103
                
104
            }
105

  
106
            set { _responseHeaders = value; }
107
        } 
108 88
        protected override WebRequest GetWebRequest(Uri address)
109 89
        {
110 90
            TimedOut = false;
......
187 167
            //Does the response have any content to log?
188 168
            if (exc.Response.ContentLength > 0)
189 169
            {
190
                var content = GetContent(exc.Response);
170
                var content = LogContent(exc.Response);
191 171
                Log.ErrorFormat(content);
192 172
            }
193 173
            return false;
......
205 185

  
206 186
        public DateTime LastModified { get; private set; }
207 187

  
208
        private static string GetContent(WebResponse webResponse)
188
        private static string LogContent(WebResponse webResponse)
209 189
        {
210 190
            if (webResponse == null)
211 191
                throw new ArgumentNullException("webResponse");
212 192
            Contract.EndContractBlock();
213 193

  
214
            string content;
215
            using (var stream = webResponse.GetResponseStream())
216
            using (var reader = new StreamReader(stream))
194
            //The response stream must be copied to avoid affecting other code by disposing of the 
195
            //original response stream.
196
            var stream = webResponse.GetResponseStream();            
197
            using(var memStream=new MemoryStream((int) stream.Length))
198
            using (var reader = new StreamReader(memStream))
217 199
            {
218
                content = reader.ReadToEnd();
200
                stream.CopyTo(memStream);                
201
                string content = reader.ReadToEnd();
202

  
203
                stream.Seek(0,SeekOrigin.Begin);
204
                return content;
219 205
            }
220
            return content;
221 206
        }
222 207

  
223 208
        public string DownloadStringWithRetry(string address,int retries=0)
......
232 217
            
233 218
            var actualRetries = (retries == 0) ? Retries : retries;
234 219

  
235
            
220
            var uriString = String.Join("/", BaseAddress.TrimEnd('/'), actualAddress);
221

  
236 222
            var task = Retry(() =>
237
            {
238
                var uriString = String.Join("/", BaseAddress.TrimEnd('/'), actualAddress);                
223
            {                
239 224
                var content = base.DownloadString(uriString);
240 225

  
241 226
                if (StatusCode == HttpStatusCode.NoContent)
......
308 293
                if (method == "PUT")
309 294
                    request.ContentLength = 0;
310 295

  
296
                //Have to use try/finally instead of using here, because WebClient needs a valid WebResponse object
297
                //in order to return response headers
311 298
                var response = (HttpWebResponse)GetWebResponse(request);
312
                //var response = (HttpWebResponse)request.GetResponse();
299
                try
300
                {
301
                    LastModified = response.LastModified;
302
                    StatusCode = response.StatusCode;
303
                    StatusDescription = response.StatusDescription;
304
                }
305
                finally
306
                {
307
                    response.Close();
308
                }
313 309
                
314
                //ResponseHeaders= response.Headers;
315

  
316
                LastModified = response.LastModified;
317
                StatusCode = response.StatusCode;
318
                StatusDescription = response.StatusDescription;
319
                response.Close();
320 310

  
321 311
                return 0;
322 312
            }, actualRetries);

Also available in: Unified diff