2 using System.Collections.Generic;
\r
3 using System.ComponentModel.Composition;
\r
7 using System.Threading;
\r
8 using System.Threading.Tasks;
\r
9 using System.Windows;
\r
10 using Caliburn.Micro;
\r
12 using Pithos.Core.Agents;
\r
13 using Pithos.Interfaces;
\r
14 using Pithos.Network;
\r
16 namespace Pithos.Client.WPF.FileProperties
\r
18 [Export(typeof(IConflictResolver))]
\r
19 public class ConflictResolver : IConflictResolver
\r
22 public IStatusKeeper StatusAgent { get; set; }
\r
25 public ShellViewModel Shell { get; set; }
\r
28 public IStatusKeeper StatusKeeper { get; set; }
\r
31 public NetworkAgent NetworkAgent { get; set; }
\r
34 public IStatusNotification StatusNotification { get; set; }
\r
36 public void Resolve(IEnumerable<ConflictFile> conflicts)
\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
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
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
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
61 //This can be done either by scheduling the appropriate action, ignoring the hash
\r
62 //Or directly downloading the file.
\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
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
74 filesToDelete.Apply(f=>
\r
77 StatusAgent.ClearFileStatus(f.FullName);
\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
88 foreach (var action in downloadActions)
\r
92 action.LocalFile.Delete();
\r
93 StatusAgent.SetFileState(action.FileState.FilePath, FileStatus.Unchanged, FileOverlayStatus.Normal, "Resolve by downloading");
\r
95 catch (Exception exc)
\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
103 //downloadActions.Apply(NetworkAgent.Post);
\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
112 var accounts = (from monitor in Shell.Monitors
\r
113 select monitor.Value.Account).ToList();
\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
123 foreach (var action in actions)
\r
125 DeleteCloudFile(action);
\r
126 StatusAgent.SetFileState(action.FileState.FilePath, FileStatus.Modified, FileOverlayStatus.Normal, "Resolve by downloading");
\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
134 private void DeleteCloudFile(CloudUploadAction action)
\r
136 using (StatusNotification.GetNotifier("Deleting server {0}", "Deleted server {0}", Path.GetFileName(action.LocalFile.Name)))
\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
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
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
152 //Downloading the server file is probably much faster with ADSL connections
\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