Some timeout issues
[pithos-ms-client] / trunk / Pithos.Client.WPF / FileProperties / ConflictResolver.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.ComponentModel.Composition;\r
4 using System.IO;\r
5 using System.Linq;\r
6 using System.Text;\r
7 using System.Threading;\r
8 using System.Threading.Tasks;\r
9 using System.Windows;\r
10 using Caliburn.Micro;\r
11 using Pithos.Core;\r
12 using Pithos.Core.Agents;\r
13 using Pithos.Interfaces;\r
14 using Pithos.Network;\r
15 \r
16 namespace Pithos.Client.WPF.FileProperties\r
17 {\r
18     [Export(typeof(IConflictResolver))]\r
19     public class ConflictResolver : IConflictResolver\r
20     {\r
21         [Import]\r
22         public IStatusKeeper StatusAgent { get; set; }\r
23 \r
24         [Import]\r
25         public ShellViewModel Shell { get; set; }\r
26 \r
27         [Import]\r
28         public IStatusKeeper  StatusKeeper { get; set; }\r
29 \r
30         [Import]\r
31         public NetworkAgent NetworkAgent { get; set; }\r
32 \r
33         [Import]\r
34         public IStatusNotification StatusNotification { get; set; }\r
35 \r
36         public void Resolve(IEnumerable<ConflictFile> conflicts)\r
37         {\r
38             KeepServer(conflicts.Where(c => c.Action == ConflictAction.KeepServer));\r
39             KeepLocal(conflicts.Where(c => c.Action == ConflictAction.KeepLocal));\r
40             //KeepBoth(conflicts.Where(c => c.Action == ConflictAction.KeepBoth));\r
41             ClearLocal(conflicts.Where(c => c.Action == ConflictAction.ClearLocal));\r
42         }\r
43 \r
44 \r
45         //Clearing the local state means that we clear the conflict state of the local file.\r
46         //This is needed to clear wrong conflicts\r
47         private void ClearLocal(IEnumerable<ConflictFile> conflicts)\r
48         {\r
49             //This can be done simply by changing the local Filestate status to normal\r
50             conflicts.Apply(clear =>\r
51                 StatusAgent.SetFileState(clear.FilePath, FileStatus.Unchanged, FileOverlayStatus.Normal, ""));    \r
52 \r
53         }\r
54 \r
55 \r
56         //Keeping the server version means that we need to \r
57         //download the server's version of the file.\r
58         private void KeepServer(IEnumerable<ConflictFile> conflicts)\r
59         {\r
60 \r
61             //This can be done either by scheduling the appropriate action, ignoring the hash\r
62             //Or directly downloading the file.\r
63 \r
64             //This can be done either by scheduling the appropriate action, ignoring the hash\r
65             //Or directly uploading the file.\r
66             var monitors = Shell.Monitors.Select(m => m.Value);\r
67 \r
68             //Files that were not deleted\r
69             var filesToDelete= from conflict in conflicts  \r
70                           where conflict.State.OverlayStatus == FileOverlayStatus.Deleted\r
71                           let info=FileInfoExtensions.FromPath(conflict.FilePath)\r
72                           where info.Exists\r
73                           select info;\r
74             filesToDelete.Apply(f=>\r
75                                     {\r
76                                         f.Delete();\r
77                                         StatusAgent.ClearFileStatus(f.FullName);\r
78                                     });\r
79 \r
80             //Files that were not deleted\r
81             var downloadActions = from conflict in conflicts  \r
82                           where conflict.State.OverlayStatus != FileOverlayStatus.Deleted\r
83                           let monitor=monitors.First(m=> conflict.FilePath.StartsWith(m.Account.AccountPath, StringComparison.InvariantCultureIgnoreCase))\r
84                           let account = monitor.Account\r
85                           let info = TaskEx.Run(async ()=> await monitor.GetObjectInfo(conflict.FilePath).ConfigureAwait(false)).Result\r
86                           select new CloudDownloadAction(account, info, "Resolver");\r
87 \r
88             foreach (var action in downloadActions)\r
89             {\r
90                 try\r
91                 {\r
92                     action.LocalFile.Delete();\r
93                     StatusAgent.SetFileState(action.FileState.FilePath, FileStatus.Unchanged, FileOverlayStatus.Normal, "Resolve by downloading");\r
94                 }\r
95                 catch (Exception exc)\r
96                 {\r
97                     MessageBox.Show(\r
98                         String.Format("The file {0} is in use and can't be deleted", action.LocalFile.FullName),\r
99                         "Pithos+. Can't delete file");                    \r
100                 }\r
101                 \r
102             }\r
103             //downloadActions.Apply(NetworkAgent.Post);            \r
104 \r
105         }\r
106 \r
107         //Keeping the server version means that we need to \r
108         //upload the local version of the file to the server\r
109         private void KeepLocal(IEnumerable<ConflictFile> conflicts)\r
110         {\r
111 \r
112             var accounts = (from monitor in Shell.Monitors                           \r
113                            select monitor.Value.Account).ToList();\r
114 \r
115             //This can be done either by scheduling the appropriate action, ignoring the hash\r
116             //Or directly uploading the file.\r
117             var actions = from conflict in conflicts\r
118                           let account = accounts.First(acc => conflict.FilePath.StartsWith(acc.AccountPath, StringComparison.InvariantCultureIgnoreCase))\r
119                           let info = FileInfoExtensions.FromPath(conflict.FilePath)\r
120                           select new CloudUploadAction(account, info, conflict.State, \r
121                               account.BlockSize, account.BlockHash,"Resolver",false,CancellationToken.None, new Progress<HashProgress>());\r
122 \r
123             foreach (var action in actions)\r
124             {\r
125                 DeleteCloudFile(action);\r
126                 StatusAgent.SetFileState(action.FileState.FilePath, FileStatus.Modified, FileOverlayStatus.Normal, "Resolve by downloading");\r
127                 \r
128             }\r
129             \r
130             //If C!=S, C!=L, S!=L, C!=Null, S!=Null and we delete the server file, we will cause an upload of the new file\r
131             //actions.Apply(NetworkAgent.Post);\r
132         }\r
133 \r
134         private void DeleteCloudFile(CloudUploadAction action)\r
135         {\r
136             using (StatusNotification.GetNotifier("Deleting server {0}", "Deleted server {0}", true,Path.GetFileName(action.LocalFile.Name)))\r
137             {\r
138 \r
139                 StatusKeeper.SetFileState(action.LocalFile.FullName, FileStatus.Deleted,\r
140                                           FileOverlayStatus.Deleted, "");\r
141                 NetworkAgent.DeleteAgent.DeleteCloudFile(action.AccountInfo, action.CloudFile);\r
142                 StatusKeeper.ClearFileStatus(action.LocalFile.FullName);\r
143             }\r
144         }\r
145         //Keeping both versions means that we need to copy one of them\r
146         //somewhere and keep the other \r
147         private void KeepBoth(IEnumerable<ConflictFile> conflicts)\r
148         {\r
149             //We can copy the rename the local file to another name and download the server file\r
150             //Or rename the server file and upload the local file\r
151 \r
152             //Downloading the server file is probably much faster with ADSL connections\r
153 \r
154             //We could probably use the local file as a source of blocks to download fewer data,\r
155             //We create a hashmap of the local file, download the differences from the server\r
156             //and merge common and changed blocks to create the new file.\r
157         }\r
158     }\r
159 }\r