Revision 43dd02a8
b/trunk/Pithos.Client.WPF/Shell/ShellViewModel.cs | ||
---|---|---|
125 | 125 |
private readonly PollAgent _pollAgent; |
126 | 126 |
private readonly NetworkAgent _networkAgent; |
127 | 127 |
|
128 |
[Import] |
|
129 |
public Selectives Selectives { get; set; } |
|
128 | 130 |
|
129 | 131 |
private MiniStatusViewModel _miniStatus; |
130 | 132 |
|
... | ... | |
318 | 320 |
|
319 | 321 |
MigrateFolders(account); |
320 | 322 |
|
323 |
Selectives.SetIsSelectiveEnabled(account.AccountKey, account.SelectiveSyncEnabled); |
|
324 |
|
|
321 | 325 |
if (Monitors.TryGetValue(account.AccountKey, out monitor)) |
322 | 326 |
{ |
323 | 327 |
//If the account is active |
... | ... | |
1012 | 1016 |
PithosMonitor monitor; |
1013 | 1017 |
if (Monitors.TryGetValue(message.Account.AccountKey, out monitor)) |
1014 | 1018 |
{ |
1015 |
monitor.Selectives.SetIsSelectiveEnabled(message.Account.AccountKey, message.Enabled);
|
|
1019 |
Selectives.SetIsSelectiveEnabled(message.Account.AccountKey, message.Enabled); |
|
1016 | 1020 |
monitor.SetSelectivePaths(message.Uris, message.Added, message.Removed); |
1017 | 1021 |
} |
1018 | 1022 |
|
b/trunk/Pithos.Core.Test/LocalFileComparerTest.cs | ||
---|---|---|
16 | 16 |
{ |
17 | 17 |
var comparer = new LocalFileComparer(); |
18 | 18 |
var account = new AccountInfo(); |
19 |
var x = new Agents.CloudDownloadAction(account, new ObjectInfo {Account="a",Container="c",Name = "x", Hash = "a"}); |
|
20 |
var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "x", Hash = "a" }); |
|
19 |
var x = new Agents.CloudDownloadAction(account, new ObjectInfo {Account="a",Container="c",Name = "x", Hash = "a"},null);
|
|
20 |
var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "x", Hash = "a" }, null);
|
|
21 | 21 |
Assert.That(comparer.Equals(x, y), Is.True); |
22 | 22 |
} |
23 | 23 |
|
... | ... | |
26 | 26 |
{ |
27 | 27 |
var comparer = new LocalFileComparer(); |
28 | 28 |
var account = new AccountInfo(); |
29 |
var x = new Agents.CloudDownloadAction(account, new ObjectInfo {Account="a",Container="c",Name = "x", Hash = "a"});
|
|
30 |
var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "y", Hash = "a" }); |
|
29 |
var x = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "x", Hash = "a" }, null);
|
|
30 |
var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "y", Hash = "a" }, null);
|
|
31 | 31 |
Assert.That(comparer.Equals(x, y), Is.True); |
32 | 32 |
} |
33 | 33 |
[Test] |
... | ... | |
35 | 35 |
{ |
36 | 36 |
var comparer = new LocalFileComparer(); |
37 | 37 |
var account = new AccountInfo(); |
38 |
var x = new Agents.CloudDownloadAction(account, new ObjectInfo {Account="a",Container="c",Name = "x", Hash = "a",Content_Type = "application/directory"}); |
|
39 |
var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "y", Hash = "a", Content_Type = "application/directory" }); |
|
38 |
var x = new Agents.CloudDownloadAction(account, new ObjectInfo {Account="a",Container="c",Name = "x", Hash = "a",Content_Type = "application/directory"},null);
|
|
39 |
var y = new Agents.CloudDownloadAction(account, new ObjectInfo { Account = "a", Container = "c", Name = "y", Hash = "a", Content_Type = "application/directory" }, null);
|
|
40 | 40 |
Assert.That(comparer.Equals(x, y), Is.False); |
41 | 41 |
} |
42 | 42 |
|
b/trunk/Pithos.Core/Agents/CloudTransferAction.cs | ||
---|---|---|
61 | 61 |
|
62 | 62 |
public class CloudAction |
63 | 63 |
{ |
64 |
|
|
65 |
public object Originator { get; set; } |
|
64 | 66 |
public AccountInfo AccountInfo { get; set; } |
65 | 67 |
public CloudActionType Action { get; set; } |
66 | 68 |
public FileSystemInfo LocalFile { get; set; } |
... | ... | |
86 | 88 |
get { return CloudFile!=null && AccountInfo.UserName != CloudFile.Account; } |
87 | 89 |
} |
88 | 90 |
|
89 |
protected CloudAction(AccountInfo accountInfo,CloudActionType action) |
|
91 |
protected CloudAction(AccountInfo accountInfo,CloudActionType action,object originator)
|
|
90 | 92 |
{ |
91 | 93 |
if (accountInfo==null) |
92 | 94 |
throw new ArgumentNullException("accountInfo"); |
... | ... | |
94 | 96 |
|
95 | 97 |
Action = action; |
96 | 98 |
AccountInfo = accountInfo; |
99 |
Originator = originator; |
|
97 | 100 |
} |
98 | 101 |
|
99 |
public CloudAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo localFile, ObjectInfo cloudFile, FileState state, int blockSize, string algorithm) |
|
100 |
: this(accountInfo,action) |
|
102 |
public CloudAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo localFile, ObjectInfo cloudFile, FileState state, int blockSize, string algorithm,object originator)
|
|
103 |
: this(accountInfo,action,originator)
|
|
101 | 104 |
{ |
102 | 105 |
if(blockSize<=0) |
103 | 106 |
throw new ArgumentOutOfRangeException("blockSize"); |
... | ... | |
168 | 171 |
|
169 | 172 |
public class CloudDownloadAction:CloudAction |
170 | 173 |
{ |
171 |
public CloudDownloadAction(AccountInfo accountInfo, ObjectInfo cloudFile) |
|
172 |
:base(accountInfo,CloudActionType.DownloadUnconditional) |
|
174 |
public CloudDownloadAction(AccountInfo accountInfo, ObjectInfo cloudFile,object originator)
|
|
175 |
:base(accountInfo,CloudActionType.DownloadUnconditional,originator)
|
|
173 | 176 |
{ |
174 | 177 |
if (String.IsNullOrWhiteSpace(cloudFile.Container)) |
175 | 178 |
throw new ArgumentException("CloudFile.Container","cloudFile"); |
... | ... | |
192 | 195 |
} |
193 | 196 |
public class CloudDeleteAction:CloudAction |
194 | 197 |
{ |
195 |
public CloudDeleteAction(AccountInfo accountInfo,FileSystemInfo fileInfo, FileState fileState) |
|
196 |
: this(accountInfo,fileInfo,CreateObjectInfoFor(accountInfo, fileInfo),fileState) |
|
198 |
public CloudDeleteAction(AccountInfo accountInfo,FileSystemInfo fileInfo, FileState fileState,object originator)
|
|
199 |
: this(accountInfo,fileInfo,CreateObjectInfoFor(accountInfo, fileInfo),fileState,originator)
|
|
197 | 200 |
{ |
198 | 201 |
} |
199 | 202 |
|
200 |
public CloudDeleteAction(AccountInfo accountInfo, FileSystemInfo fileInfo,ObjectInfo cloudFile, FileState fileState) |
|
201 |
: base(accountInfo,CloudActionType.DeleteCloud) |
|
203 |
public CloudDeleteAction(AccountInfo accountInfo, FileSystemInfo fileInfo,ObjectInfo cloudFile, FileState fileState,object originator)
|
|
204 |
: base(accountInfo,CloudActionType.DeleteCloud,originator)
|
|
202 | 205 |
{ |
203 | 206 |
CloudFile = cloudFile; |
204 | 207 |
LocalFile = fileInfo; |
... | ... | |
206 | 209 |
} |
207 | 210 |
|
208 | 211 |
public CloudDeleteAction(CloudAction action) |
209 |
: this(action.AccountInfo,action.LocalFile,action.CloudFile,action.FileState) |
|
212 |
: this(action.AccountInfo,action.LocalFile,action.CloudFile,action.FileState,action)
|
|
210 | 213 |
{} |
211 | 214 |
|
212 | 215 |
[ContractInvariantMethod] |
... | ... | |
224 | 227 |
|
225 | 228 |
public class CloudUploadAction:CloudAction |
226 | 229 |
{ |
227 |
public CloudUploadAction(AccountInfo accountInfo, FileSystemInfo fileInfo, FileState state, int blockSize, string algorithm) |
|
228 |
: base(accountInfo, CloudActionType.UploadUnconditional,fileInfo,CreateObjectInfoFor(accountInfo,fileInfo),state,blockSize,algorithm) |
|
230 |
public CloudUploadAction(AccountInfo accountInfo, FileSystemInfo fileInfo, FileState state, int blockSize, string algorithm,object originator)
|
|
231 |
: base(accountInfo, CloudActionType.UploadUnconditional,fileInfo,CreateObjectInfoFor(accountInfo,fileInfo),state,blockSize,algorithm,originator)
|
|
229 | 232 |
{ |
230 | 233 |
} |
231 | 234 |
|
... | ... | |
243 | 246 |
|
244 | 247 |
public FileSystemInfo OldLocalFile { get; set; } |
245 | 248 |
|
246 |
public CloudMoveAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo oldFile, FileSystemInfo newFile) |
|
247 |
:base(accountInfo,action) |
|
249 |
public CloudMoveAction(AccountInfo accountInfo, CloudActionType action, FileSystemInfo oldFile, FileSystemInfo newFile,object originator)
|
|
250 |
:base(accountInfo,action,originator)
|
|
248 | 251 |
{ |
249 | 252 |
LocalFile = newFile; |
250 | 253 |
CloudFile = CreateObjectInfoFor(accountInfo, newFile); |
b/trunk/Pithos.Core/Agents/Downloader.cs | ||
---|---|---|
184 | 184 |
if (!localHashes.ContainsKey(upHash)) |
185 | 185 |
{ |
186 | 186 |
StatusNotification.Notify(new CloudNotification { Data = cloudFile }); |
187 |
ReportDownloadProgress(Path.GetFileName(localPath), i, upHashes.Length, cloudFile.Bytes); |
|
187 | 188 |
|
188 | 189 |
if (blockUpdater.UseOrphan(i, upHash)) |
189 | 190 |
{ |
... | ... | |
244 | 245 |
var localPath = FileInfoExtensions.GetProperFilePathCapitalization(filePath); |
245 | 246 |
StatusNotification.SetPithosStatus(PithosStatus.LocalSyncing, String.Format("Downloading {0}", Path.GetFileName(localPath))); |
246 | 247 |
StatusNotification.Notify(new CloudNotification { Data = cloudFile }); |
248 |
ReportDownloadProgress(Path.GetFileName(localPath), 1, 1, cloudFile.Bytes); |
|
247 | 249 |
|
248 | 250 |
var fileAgent = GetFileAgent(accountInfo); |
249 | 251 |
//Calculate the relative file path for the new file |
b/trunk/Pithos.Core/Agents/FileAgent.cs | ||
---|---|---|
94 | 94 |
if (change.ChangeType == WatcherChangeTypes.Renamed) |
95 | 95 |
{ |
96 | 96 |
var rename = (MovedEventArgs) change; |
97 |
_agent.Post(new WorkflowState |
|
97 |
_agent.Post(new WorkflowState(change)
|
|
98 | 98 |
{ |
99 | 99 |
AccountInfo = AccountInfo, |
100 | 100 |
OldPath = rename.OldFullPath, |
... | ... | |
105 | 105 |
}); |
106 | 106 |
} |
107 | 107 |
else |
108 |
_agent.Post(new WorkflowState |
|
108 |
_agent.Post(new WorkflowState(change)
|
|
109 | 109 |
{ |
110 | 110 |
AccountInfo = AccountInfo, |
111 | 111 |
Path = change.FullPath, |
b/trunk/Pithos.Core/Agents/PollAgent.cs | ||
---|---|---|
507 | 507 |
|
508 | 508 |
yield return new CloudAction(accountInfo, CloudActionType.MustSynch, |
509 | 509 |
localFile, objectInfo, state, accountInfo.BlockSize, |
510 |
accountInfo.BlockHash); |
|
510 |
accountInfo.BlockHash,"Poll Changes");
|
|
511 | 511 |
} |
512 | 512 |
} |
513 | 513 |
else |
514 | 514 |
{ |
515 | 515 |
//Remote files should be downloaded |
516 |
yield return new CloudDownloadAction(accountInfo, objectInfo); |
|
516 |
yield return new CloudDownloadAction(accountInfo, objectInfo,"Poll Changes");
|
|
517 | 517 |
} |
518 | 518 |
} |
519 | 519 |
} |
... | ... | |
548 | 548 |
//For each moved object we need to move both the local file and update |
549 | 549 |
yield return new CloudAction(accountInfo, CloudActionType.RenameLocal, |
550 | 550 |
previousFile, objectInfo, state, accountInfo.BlockSize, |
551 |
accountInfo.BlockHash); |
|
551 |
accountInfo.BlockHash,"Poll Moves");
|
|
552 | 552 |
//For modified files, we need to download the changes as well |
553 | 553 |
if (objectInfo.Hash!=objectInfo.PreviousHash) |
554 |
yield return new CloudDownloadAction(accountInfo,objectInfo); |
|
554 |
yield return new CloudDownloadAction(accountInfo,objectInfo, "Poll Moves");
|
|
555 | 555 |
} |
556 | 556 |
} |
557 | 557 |
//If the previous file does not exist, we need to download it in the new location |
558 | 558 |
else |
559 | 559 |
{ |
560 | 560 |
//Remote files should be downloaded |
561 |
yield return new CloudDownloadAction(accountInfo, objectInfo); |
|
561 |
yield return new CloudDownloadAction(accountInfo, objectInfo, "Poll Moves");
|
|
562 | 562 |
} |
563 | 563 |
} |
564 | 564 |
} |
... | ... | |
593 | 593 |
var state = StatusKeeper.GetStateByFilePath(localFile.WithProperCapitalization().FullName); |
594 | 594 |
yield return new CloudAction(accountInfo, CloudActionType.MustSynch, |
595 | 595 |
localFile, objectInfo, state, accountInfo.BlockSize, |
596 |
accountInfo.BlockHash); |
|
596 |
accountInfo.BlockHash,"Poll Creates");
|
|
597 | 597 |
} |
598 | 598 |
else |
599 | 599 |
{ |
600 | 600 |
//Remote files should be downloaded |
601 |
yield return new CloudDownloadAction(accountInfo, objectInfo); |
|
601 |
yield return new CloudDownloadAction(accountInfo, objectInfo,"Poll Creates");
|
|
602 | 602 |
} |
603 | 603 |
|
604 | 604 |
} |
b/trunk/Pithos.Core/Agents/Uploader.cs | ||
---|---|---|
7 | 7 |
using System.Linq; |
8 | 8 |
using System.Net; |
9 | 9 |
using System.Reflection; |
10 |
using System.Security.Cryptography; |
|
10 | 11 |
using System.Threading; |
11 | 12 |
using System.Threading.Tasks; |
12 | 13 |
using Pithos.Interfaces; |
... | ... | |
144 | 145 |
topHash = treeHash.TopHash.ToHashString(); |
145 | 146 |
} |
146 | 147 |
|
148 |
|
|
149 |
|
|
147 | 150 |
//If the file hashes match, abort the upload |
148 |
if (cloudInfo != ObjectInfo.Empty && topHash == cloudHash)
|
|
151 |
if (cloudInfo != ObjectInfo.Empty && (topHash == cloudHash ))
|
|
149 | 152 |
{ |
150 | 153 |
//but store any metadata changes |
151 | 154 |
StatusKeeper.StoreInfo(fullFileName, cloudInfo); |
b/trunk/Pithos.Core/Agents/WorkflowAgent.cs | ||
---|---|---|
134 | 134 |
case FileStatus.Modified: |
135 | 135 |
NetworkAgent.Post(new CloudUploadAction(accountInfo, info, fileState, |
136 | 136 |
accountInfo.BlockSize, |
137 |
accountInfo.BlockHash)); |
|
137 |
accountInfo.BlockHash,state));
|
|
138 | 138 |
break; |
139 | 139 |
case FileStatus.Deleted: |
140 | 140 |
DeleteChildObjects(state, fileState); |
141 |
NetworkAgent.Post(new CloudDeleteAction(accountInfo, info, fileState)); |
|
141 |
NetworkAgent.Post(new CloudDeleteAction(accountInfo, info, fileState,state));
|
|
142 | 142 |
break; |
143 | 143 |
case FileStatus.Renamed: |
144 | 144 |
if (state.OldPath == null) |
... | ... | |
156 | 156 |
: new FileInfo(state.Path); |
157 | 157 |
NetworkAgent.Post(new CloudMoveAction(accountInfo, CloudActionType.RenameCloud, |
158 | 158 |
oldInfo, |
159 |
newInfo)); |
|
159 |
newInfo,state));
|
|
160 | 160 |
//TODO: Do I have to move children as well or will Pithos handle this? |
161 | 161 |
//Need to find all children of the OLD filepath |
162 | 162 |
//MoveChildObjects(state); |
... | ... | |
185 | 185 |
var childInfo = child.IsFolder |
186 | 186 |
? (FileSystemInfo) new DirectoryInfo(child.FilePath) |
187 | 187 |
: new FileInfo(child.FilePath); |
188 |
NetworkAgent.Post(new CloudDeleteAction(state.AccountInfo, childInfo, child)); |
|
188 |
NetworkAgent.Post(new CloudDeleteAction(state.AccountInfo, childInfo, child,state));
|
|
189 | 189 |
} |
190 | 190 |
} |
191 | 191 |
} |
b/trunk/Pithos.Core/WorkflowState.cs | ||
---|---|---|
52 | 52 |
{ |
53 | 53 |
public class WorkflowState |
54 | 54 |
{ |
55 |
public object Originator { get; set; } |
|
55 | 56 |
public AccountInfo AccountInfo { get; set; } |
56 | 57 |
|
57 | 58 |
public string Path { get; set; } |
... | ... | |
76 | 77 |
} |
77 | 78 |
*/ |
78 | 79 |
|
79 |
public WorkflowState() |
|
80 |
public WorkflowState(object originator)
|
|
80 | 81 |
{ |
81 |
|
|
82 |
Originator = originator; |
|
82 | 83 |
} |
83 | 84 |
|
84 | 85 |
public WorkflowState(AccountInfo accountInfo, FileState state) |
... | ... | |
89 | 90 |
throw new ArgumentNullException("state"); |
90 | 91 |
Contract.EndContractBlock(); |
91 | 92 |
|
93 |
Originator = "Restart"; |
|
92 | 94 |
AccountInfo = accountInfo; |
93 | 95 |
Path = state.FilePath.ToLower(); |
94 | 96 |
FileName = System.IO.Path.GetFileName(state.FilePath).ToLower(); |
b/trunk/Pithos.Interfaces/ObjectInfo.cs | ||
---|---|---|
57 | 57 |
{ |
58 | 58 |
private readonly List<string> _knownContainers= new List<string>{"trash"}; |
59 | 59 |
public string Name { get; set; } |
60 |
|
|
61 |
|
|
60 |
|
|
61 |
public string ETag { get; set; } |
|
62 |
|
|
62 | 63 |
public string Hash { get; set; } |
63 | 64 |
|
64 | 65 |
public string X_Object_Hash { get { return Hash; } set { Hash = value; } } |
b/trunk/Pithos.Network/CloudFilesClient.cs | ||
---|---|---|
788 | 788 |
Account = account, |
789 | 789 |
Container = container, |
790 | 790 |
Name = objectName, |
791 |
Hash = client.GetHeaderValue("ETag"), |
|
791 |
ETag = client.GetHeaderValue("ETag"), |
|
792 |
X_Object_Hash = client.GetHeaderValue("X-Object-Hash"), |
|
792 | 793 |
Content_Type = client.GetHeaderValue("Content-Type"), |
793 | 794 |
Bytes = Convert.ToInt64(client.GetHeaderValue("Content-Length",true)), |
794 | 795 |
Tags = tags, |
b/trunk/Pithos.Network/Signature.cs | ||
---|---|---|
204 | 204 |
{ |
205 | 205 |
Bytes = length, |
206 | 206 |
BlockSize = blockSize, |
207 |
Hashes = list |
|
207 |
Hashes = list,
|
|
208 | 208 |
}; |
209 | 209 |
|
210 |
string fileHash; |
|
211 |
var hasher = HashAlgorithm.Create("MD5"); |
|
212 |
stream.Position = 0; |
|
213 |
treeHash.MD5= hasher.ComputeHash(stream).ToHashString(); |
|
214 |
|
|
210 | 215 |
return treeHash; |
211 | 216 |
} |
212 | 217 |
} |
b/trunk/Pithos.Network/TreeHash.cs | ||
---|---|---|
172 | 172 |
} |
173 | 173 |
} |
174 | 174 |
|
175 |
public string MD5 { get; set; } |
|
176 |
|
|
175 | 177 |
//Saves the Json representation to a file |
176 | 178 |
public async Task Save(string filePath) |
177 | 179 |
{ |
Also available in: Unified diff