Revision b5061ac8
b/trunk/Pithos.Client.WPF/App.xaml.cs | ||
---|---|---|
21 | 21 |
var extensionController = new ShellExtensionController(); |
22 | 22 |
extensionController.RegisterExtensions(); |
23 | 23 |
|
24 |
/* |
|
24 |
|
|
25 | 25 |
var appPatth = Assembly.GetExecutingAssembly().Location; |
26 | 26 |
Registry.LocalMachine.SetValue(@"Software\Pithos\AppPath",appPatth ); |
27 |
*/ |
|
28 | 27 |
|
29 | 28 |
InitializeComponent(); |
30 | 29 |
//Application.Current.ApplyTheme("BureauBlue"); |
b/trunk/Pithos.Core.Test/MockStatusKeeper.cs | ||
---|---|---|
1 | 1 |
using System; |
2 |
using System.Collections.Concurrent; |
|
2 | 3 |
using System.Collections.Generic; |
3 | 4 |
using System.Diagnostics.Contracts; |
4 | 5 |
using System.Linq; |
... | ... | |
13 | 14 |
|
14 | 15 |
private readonly string[] _states = { "Normal", "Modified", "Conflict", "Synch" }; |
15 | 16 |
|
16 |
Dictionary<string, FileOverlayStatus> _overlayCache = new Dictionary<string, FileOverlayStatus>();
|
|
17 |
Dictionary<string, FileStatus> _statusCache = new Dictionary<string, FileStatus>();
|
|
18 |
Dictionary<string, string> _checksums = new Dictionary<string, string>();
|
|
17 |
ConcurrentDictionary<string, FileOverlayStatus> _overlayCache = new ConcurrentDictionary<string, FileOverlayStatus>();
|
|
18 |
ConcurrentDictionary<string, FileStatus> _statusCache = new ConcurrentDictionary<string, FileStatus>();
|
|
19 |
ConcurrentDictionary<string, string> _checksums = new ConcurrentDictionary<string, string>();
|
|
19 | 20 |
|
20 | 21 |
public FileOverlayStatus GetFileOverlayStatus(string path) |
21 | 22 |
{ |
22 | 23 |
Contract.Requires(!String.IsNullOrWhiteSpace(path)); |
23 | 24 |
if (!_overlayCache.ContainsKey(path)) |
24 |
return FileOverlayStatus.NA;
|
|
25 |
return FileOverlayStatus.Unversioned;
|
|
25 | 26 |
|
26 | 27 |
var pithosPath = Settings.PithosPath; |
27 | 28 |
if (path.StartsWith(pithosPath, true, null)) |
... | ... | |
29 | 30 |
var status = _overlayCache[path]; |
30 | 31 |
return status; |
31 | 32 |
} |
32 |
return FileOverlayStatus.NA; |
|
33 |
return FileOverlayStatus.Unversioned; |
|
34 |
} |
|
35 |
|
|
36 |
public IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths) |
|
37 |
{ |
|
38 |
|
|
39 |
var newFiles = (from file in paths |
|
40 |
where !_overlayCache.ContainsKey(file) |
|
41 |
select new |
|
42 |
{ |
|
43 |
FilePath = file, |
|
44 |
OverlayStatus = FileOverlayStatus.Unversioned, |
|
45 |
FileStatus = FileStatus.Created, |
|
46 |
Checksum = Signature.CalculateHash(file) |
|
47 |
}); |
|
48 |
var files = new ConcurrentBag<string>(); |
|
49 |
newFiles.ForAll(state => |
|
50 |
{ |
|
51 |
_overlayCache[state.FilePath] = state.OverlayStatus; |
|
52 |
_statusCache[state.FilePath] = state.FileStatus; |
|
53 |
_checksums[state.FilePath] = state.Checksum; |
|
54 |
files.Add(state.FilePath); |
|
55 |
}); |
|
56 |
return files.ToList(); |
|
57 |
|
|
33 | 58 |
} |
34 | 59 |
|
35 | 60 |
|
... | ... | |
51 | 76 |
|
52 | 77 |
public void RemoveFileOverlayStatus(string path) |
53 | 78 |
{ |
54 |
_overlayCache.Remove(path); |
|
79 |
FileOverlayStatus value; |
|
80 |
_overlayCache.TryRemove(path, out value); |
|
55 | 81 |
} |
56 | 82 |
|
57 | 83 |
public void RenameFileOverlayStatus(string oldPath, string newPath) |
58 | 84 |
{ |
59 | 85 |
var status = _overlayCache[oldPath]; |
60 | 86 |
_overlayCache[newPath] = status; |
61 |
_overlayCache.Remove(oldPath); |
|
87 |
FileOverlayStatus value; |
|
88 |
_overlayCache.TryRemove(oldPath, out value); |
|
62 | 89 |
} |
63 | 90 |
|
64 | 91 |
public void UpdateFileChecksum(string path, string checksum) |
... | ... | |
80 | 107 |
|
81 | 108 |
public void ClearFileStatus(string path) |
82 | 109 |
{ |
83 |
_statusCache.Remove(path); |
|
110 |
FileStatus value; |
|
111 |
_statusCache.TryRemove(path,out value); |
|
84 | 112 |
} |
85 | 113 |
} |
86 | 114 |
} |
b/trunk/Pithos.Core.Test/StatusCheckerTest.cs | ||
---|---|---|
51 | 51 |
|
52 | 52 |
checker.RemoveFileOverlayStatus(@"e:\pithos\0File3.txt"); |
53 | 53 |
var status = checker.GetFileOverlayStatus(@"e:\pithos\0File3.txt"); |
54 |
Assert.AreEqual(FileOverlayStatus.NA,status);
|
|
54 |
Assert.AreEqual(FileOverlayStatus.Unversioned,status);
|
|
55 | 55 |
|
56 | 56 |
} |
57 | 57 |
|
... | ... | |
77 | 77 |
|
78 | 78 |
|
79 | 79 |
var status = checker.GetFileOverlayStatus(@"e:\pithos\notexisting"); |
80 |
Assert.AreEqual(FileOverlayStatus.NA,status);
|
|
80 |
Assert.AreEqual(FileOverlayStatus.Unversioned,status);
|
|
81 | 81 |
|
82 | 82 |
|
83 | 83 |
} |
b/trunk/Pithos.Core/FileState.cs | ||
---|---|---|
5 | 5 |
// ----------------------------------------------------------------------- |
6 | 6 |
|
7 | 7 |
using Castle.ActiveRecord; |
8 |
using Castle.ActiveRecord.Framework; |
|
8 | 9 |
using Pithos.Interfaces; |
9 | 10 |
|
10 | 11 |
namespace Pithos.Core |
... | ... | |
18 | 19 |
/// TODO: Update summary. |
19 | 20 |
/// </summary> |
20 | 21 |
[ActiveRecord] |
21 |
public class FileState:ActiveRecordBase<FileState> |
|
22 |
public class FileState:ActiveRecordLinqBase<FileState>
|
|
22 | 23 |
{ |
23 | 24 |
[PrimaryKey] |
24 | 25 |
public string FilePath { get; set; } |
b/trunk/Pithos.Core/IStatusKeeper.cs | ||
---|---|---|
1 | 1 |
using System; |
2 |
using System.Collections.Generic; |
|
2 | 3 |
using System.Diagnostics.Contracts; |
4 |
using System.Linq; |
|
3 | 5 |
using Pithos.Interfaces; |
4 | 6 |
|
5 | 7 |
namespace Pithos.Core |
... | ... | |
14 | 16 |
FileStatus GetFileStatus(string path); |
15 | 17 |
void ClearFileStatus(string path); |
16 | 18 |
void SetPithosStatus(PithosStatus status); |
19 |
FileOverlayStatus GetFileOverlayStatus(string path); |
|
20 |
IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths); |
|
17 | 21 |
} |
18 | 22 |
|
19 | 23 |
[ContractClassFor(typeof(IStatusKeeper))] |
... | ... | |
54 | 58 |
return default(FileStatus); |
55 | 59 |
} |
56 | 60 |
|
61 |
public FileOverlayStatus GetFileOverlayStatus(string path) |
|
62 |
{ |
|
63 |
Contract.Requires(!String.IsNullOrWhiteSpace(path)); |
|
64 |
|
|
65 |
return default(FileOverlayStatus); |
|
66 |
} |
|
67 |
|
|
68 |
public IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths) |
|
69 |
{ |
|
70 |
Contract.Requires(paths!=null); |
|
71 |
|
|
72 |
return default(IEnumerable<string>); |
|
73 |
} |
|
74 |
|
|
57 | 75 |
public void ClearFileStatus(string path) |
58 | 76 |
{ |
59 | 77 |
Contract.Requires(!String.IsNullOrWhiteSpace(path)); |
b/trunk/Pithos.Core/InMemStatusChecker.cs | ||
---|---|---|
1 | 1 |
using System; |
2 |
using System.Collections.Concurrent; |
|
2 | 3 |
using System.Collections.Generic; |
3 | 4 |
using System.ComponentModel.Composition; |
4 | 5 |
using System.Diagnostics.Contracts; |
6 |
using System.Linq; |
|
5 | 7 |
using Pithos.Interfaces; |
6 | 8 |
|
7 | 9 |
namespace Pithos.Core |
... | ... | |
14 | 16 |
|
15 | 17 |
private readonly string[] _states = {"Normal", "Modified", "Conflict","Synch"}; |
16 | 18 |
|
17 |
Dictionary<string,FileOverlayStatus> _overlayCache=new Dictionary<string,FileOverlayStatus>();
|
|
18 |
Dictionary<string, FileStatus> _statusCache= new Dictionary<string, FileStatus>();
|
|
19 |
Dictionary<string, string> _checksums = new Dictionary<string, string>();
|
|
19 |
ConcurrentDictionary<string, FileOverlayStatus> _overlayCache = new ConcurrentDictionary<string, FileOverlayStatus>();
|
|
20 |
ConcurrentDictionary<string, FileStatus> _statusCache = new ConcurrentDictionary<string, FileStatus>();
|
|
21 |
ConcurrentDictionary<string, string> _checksums = new ConcurrentDictionary<string, string>();
|
|
20 | 22 |
|
21 | 23 |
public FileOverlayStatus GetFileOverlayStatus(string path) |
22 | 24 |
{ |
23 | 25 |
if (!_overlayCache.ContainsKey(path)) |
24 |
return FileOverlayStatus.NA;
|
|
26 |
return FileOverlayStatus.Unversioned;
|
|
25 | 27 |
|
26 | 28 |
var pithosPath = Settings.PithosPath; |
27 | 29 |
if (path.StartsWith(pithosPath,true,null)) |
... | ... | |
29 | 31 |
var status = _overlayCache[path]; |
30 | 32 |
return status; |
31 | 33 |
} |
32 |
return FileOverlayStatus.NA; |
|
34 |
return FileOverlayStatus.Unversioned; |
|
35 |
} |
|
36 |
|
|
37 |
public IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths) |
|
38 |
{ |
|
39 |
|
|
40 |
var newFiles = (from file in paths |
|
41 |
where !_overlayCache.ContainsKey(file) |
|
42 |
select new { |
|
43 |
FilePath = file, |
|
44 |
OverlayStatus = FileOverlayStatus.Unversioned, |
|
45 |
FileStatus = FileStatus.Created, |
|
46 |
Checksum = Signature.CalculateHash(file) |
|
47 |
}); |
|
48 |
ConcurrentBag<string> files = new ConcurrentBag<string>(); |
|
49 |
newFiles.ForAll(state => |
|
50 |
{ |
|
51 |
_overlayCache[state.FilePath] = state.OverlayStatus; |
|
52 |
_statusCache[state.FilePath] = state.FileStatus; |
|
53 |
_checksums[state.FilePath] = state.Checksum; |
|
54 |
files.Add(state.FilePath); |
|
55 |
}); |
|
56 |
return files.GetConsumingEnumerable(); |
|
33 | 57 |
} |
34 | 58 |
|
35 | 59 |
|
... | ... | |
51 | 75 |
|
52 | 76 |
public void RemoveFileOverlayStatus(string path) |
53 | 77 |
{ |
54 |
_overlayCache.Remove(path); |
|
78 |
FileOverlayStatus value; |
|
79 |
_overlayCache.TryRemove(path, out value); |
|
55 | 80 |
} |
56 | 81 |
|
57 | 82 |
public void RenameFileOverlayStatus(string oldPath, string newPath) |
58 | 83 |
{ |
59 | 84 |
var status=_overlayCache[oldPath]; |
60 |
_overlayCache[newPath] = status; |
|
61 |
_overlayCache.Remove(oldPath); |
|
85 |
_overlayCache[newPath] = status; |
|
86 |
FileOverlayStatus value; |
|
87 |
_overlayCache.TryRemove(oldPath,out value); |
|
62 | 88 |
} |
63 | 89 |
|
64 | 90 |
public void SetFileStatus(string path, FileStatus status) |
... | ... | |
75 | 101 |
|
76 | 102 |
public void ClearFileStatus(string path) |
77 | 103 |
{ |
78 |
_statusCache.Remove(path); |
|
104 |
FileStatus value; |
|
105 |
_statusCache.TryRemove(path,out value); |
|
79 | 106 |
} |
80 | 107 |
|
81 | 108 |
public void UpdateFileChecksum(string path, string checksum) |
b/trunk/Pithos.Core/Pithos.Core.csproj | ||
---|---|---|
115 | 115 |
<ItemGroup> |
116 | 116 |
<Compile Include="FileState.cs" /> |
117 | 117 |
<Compile Include="IStatusService.cs" /> |
118 |
<Compile Include="Signature.cs" /> |
|
118 | 119 |
<Compile Include="StatusChecker.cs" /> |
119 | 120 |
<Compile Include="IPithosWorkflow.cs" /> |
120 | 121 |
<Compile Include="IStatusKeeper.cs" /> |
b/trunk/Pithos.Core/PithosMonitor.cs | ||
---|---|---|
79 | 79 |
string path = Settings.PithosPath; |
80 | 80 |
var proxyUri = ProxyFromSettings(); |
81 | 81 |
CloudClient.Proxy = proxyUri; |
82 |
IndexLocalFiles(path); |
|
82 | 83 |
StartMonitoringFiles(path); |
83 | 84 |
|
84 | 85 |
StartStatusService(); |
... | ... | |
105 | 106 |
return null; |
106 | 107 |
} |
107 | 108 |
|
109 |
private void IndexLocalFiles(string path) |
|
110 |
{ |
|
111 |
Trace.TraceInformation("[START] Inxed Local"); |
|
112 |
try |
|
113 |
{ |
|
114 |
var files = |
|
115 |
from filePath in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories).AsParallel() |
|
116 |
select filePath; |
|
117 |
StatusKeeper.StoreUnversionedFiles(files); |
|
118 |
|
|
119 |
var newFiles= FileState.FindAllByProperty("OverlayStatus", FileOverlayStatus.Unversioned) |
|
120 |
.Select(state=>state.FilePath); |
|
121 |
foreach (var newFile in newFiles) |
|
122 |
{ |
|
123 |
_uploadEvents.Add(new WorkflowState |
|
124 |
{ |
|
125 |
Path = newFile, |
|
126 |
FileName = Path.GetFileName(newFile), |
|
127 |
TriggeringChange = WatcherChangeTypes.Created |
|
128 |
}); |
|
129 |
} |
|
130 |
|
|
131 |
} |
|
132 |
catch (Exception exc) |
|
133 |
{ |
|
134 |
Trace.TraceError("[ERROR] Index Local - {0}", exc); |
|
135 |
} |
|
136 |
finally |
|
137 |
{ |
|
138 |
Trace.TraceInformation("[END] Inxed Local"); |
|
139 |
} |
|
140 |
} |
|
141 |
|
|
108 | 142 |
private void StartStatusService() |
109 | 143 |
{ |
110 | 144 |
// Create a ServiceHost for the CalculatorService type and provide the base address. |
... | ... | |
159 | 193 |
|
160 | 194 |
CloudClient.Authenticate(Settings.UserName, Settings.ApiKey); |
161 | 195 |
|
162 |
StartListening(); |
|
196 |
StartListening(Settings.PithosPath);
|
|
163 | 197 |
StartSending(); |
164 | 198 |
} |
165 | 199 |
catch (Exception) |
... | ... | |
193 | 227 |
Action = action; |
194 | 228 |
LocalFile = localFile; |
195 | 229 |
CloudFile = cloudFile; |
196 |
LocalHash=new Lazy<string>(()=>CalculateHash(LocalFile.FullName),LazyThreadSafetyMode.ExecutionAndPublication); |
|
230 |
LocalHash=new Lazy<string>(()=>Signature.CalculateHash(LocalFile.FullName),LazyThreadSafetyMode.ExecutionAndPublication);
|
|
197 | 231 |
} |
198 | 232 |
|
199 | 233 |
} |
... | ... | |
227 | 261 |
|
228 | 262 |
private Timer timer; |
229 | 263 |
|
230 |
private void StartListening() |
|
264 |
private void StartListening(string accountPath)
|
|
231 | 265 |
{ |
232 | 266 |
|
233 |
Func<Task> listener = ()=>Task.Factory.StartNew(()=>CloudClient.ListObjects("PITHOS")) |
|
267 |
ProcessRemoteFiles(accountPath); |
|
268 |
|
|
269 |
Task.Factory.StartNew(ProcessListenerActions); |
|
270 |
|
|
271 |
} |
|
272 |
|
|
273 |
private Task ProcessRemoteFiles(string accountPath) |
|
274 |
{ |
|
275 |
Trace.TraceInformation("[LISTENER] Scheduled"); |
|
276 |
return Task.Factory.StartNewDelayed(10000) |
|
277 |
.ContinueWith(t=>CloudClient.ListObjects("PITHOS")) |
|
234 | 278 |
.ContinueWith(task => |
235 | 279 |
{ |
236 |
|
|
237 |
var objects = task.Result; |
|
238 |
if (objects.Count == 0) |
|
280 |
Trace.TraceInformation("[LISTENER] Start Processing"); |
|
281 |
|
|
282 |
var remoteObjects = task.Result; |
|
283 |
/* |
|
284 |
if (remoteObjects.Count == 0) |
|
239 | 285 |
return; |
286 |
*/ |
|
240 | 287 |
|
241 |
var pithosDir = new DirectoryInfo(Settings.PithosPath);
|
|
288 |
var pithosDir = new DirectoryInfo(accountPath);
|
|
242 | 289 |
|
243 |
var upFiles = from info in objects
|
|
290 |
var remoteFiles = from info in remoteObjects
|
|
244 | 291 |
select info.Name; |
245 | 292 |
|
246 | 293 |
var onlyLocal = from localFile in pithosDir.EnumerateFiles() |
247 |
where !upFiles.Contains(localFile.Name)
|
|
294 |
where !remoteFiles.Contains(localFile.Name)
|
|
248 | 295 |
select new ListenerAction(CloudActionType.UploadUnconditional, localFile,null); |
249 | 296 |
|
250 | 297 |
|
251 | 298 |
|
252 | 299 |
|
253 | 300 |
var localNames =pithosDir.EnumerateFiles().Select(info => info.Name); |
254 |
var onlyRemote = from upFile in objects
|
|
301 |
var onlyRemote = from upFile in remoteObjects
|
|
255 | 302 |
where !localNames.Contains(upFile.Name) |
256 | 303 |
select new ListenerAction(CloudActionType.DownloadUnconditional,null,upFile); |
257 | 304 |
|
258 | 305 |
|
259 |
var existingObjects = from upFile in objects
|
|
306 |
var commonObjects = from upFile in remoteObjects
|
|
260 | 307 |
join localFile in pithosDir.EnumerateFiles() |
261 |
on upFile.Name equals localFile.Name |
|
262 |
select new ListenerAction(CloudActionType.Download, localFile, upFile); |
|
308 |
on upFile.Name equals localFile.Name
|
|
309 |
select new ListenerAction(CloudActionType.Download, localFile, upFile);
|
|
263 | 310 |
|
264 | 311 |
var uniques = |
265 |
onlyLocal.Union(onlyRemote).Union(existingObjects)
|
|
266 |
.Except(_listenerActions,new LocalFileComparer()); |
|
267 |
|
|
312 |
onlyLocal.Union(onlyRemote).Union(commonObjects)
|
|
313 |
.Except(_listenerActions,new LocalFileComparer());
|
|
314 |
|
|
268 | 315 |
_listenerActions.AddFromEnumerable(uniques, false); |
269 |
|
|
270 |
} |
|
271 |
); |
|
272 | 316 |
|
273 |
Task.Factory.StartNew(() => |
|
274 |
{ |
|
275 |
foreach (var action in _listenerActions.GetConsumingEnumerable()) |
|
276 |
{ |
|
277 |
var localFile = action.LocalFile; |
|
278 |
var cloudFile = action.CloudFile; |
|
279 |
var downloadPath = (cloudFile==null)? String.Empty:Path.Combine(Settings.PithosPath,cloudFile.Name); |
|
280 |
try |
|
281 |
{ |
|
282 |
switch (action.Action) |
|
283 |
{ |
|
284 |
case CloudActionType.UploadUnconditional: |
|
285 |
|
|
286 |
UploadCloudFile(localFile.Name, localFile.Length, |
|
287 |
localFile.FullName, action.LocalHash.Value); |
|
288 |
break; |
|
289 |
case CloudActionType.DownloadUnconditional: |
|
290 |
DownloadCloudFile("PITHOS", cloudFile.Name, downloadPath); |
|
291 |
break; |
|
292 |
case CloudActionType.Download: |
|
293 |
if (File.Exists(downloadPath)) |
|
294 |
{ |
|
295 |
if (cloudFile.Hash != action.LocalHash.Value) |
|
296 |
{ |
|
297 |
var lastLocalTime = localFile.LastWriteTime; |
|
298 |
var lastUpTime = cloudFile.Last_Modified; |
|
299 |
if (lastUpTime <= lastLocalTime) |
|
300 |
{ |
|
301 |
//Files in conflict |
|
302 |
StatusKeeper.SetFileOverlayStatus(downloadPath, |
|
303 |
FileOverlayStatus |
|
304 |
.Conflict); |
|
305 |
} |
|
306 |
else |
|
307 |
DownloadCloudFile("PITHOS", action.CloudFile.Name, |
|
308 |
downloadPath); |
|
309 |
} |
|
310 |
} |
|
311 |
else |
|
312 |
DownloadCloudFile("PITHOS", action.CloudFile.Name, |
|
313 |
downloadPath); |
|
314 |
break; |
|
315 |
} |
|
316 |
} |
|
317 |
catch (Exception exc) |
|
318 |
{ |
|
319 |
Debug.WriteLine("Processing of {0}:{1}->{2} failed. Putting it back in the queue",action.Action,action.LocalFile,action.CloudFile); |
|
320 |
Debug.WriteLine(exc.ToString()); |
|
321 |
_listenerActions.Add(action); |
|
322 |
} |
|
323 |
} |
|
324 |
} |
|
325 |
); |
|
326 |
|
|
327 |
timer = new Timer(o => listener(), null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); |
|
328 |
|
|
317 |
Trace.TraceInformation("[LISTENER] End Processing"); |
|
318 |
|
|
319 |
} |
|
320 |
).ContinueWith(t=> |
|
321 |
{ |
|
322 |
if (t.IsFaulted) |
|
323 |
{ |
|
324 |
Trace.TraceError("[LISTENER] Exception: {0}",t.Exception); |
|
325 |
} |
|
326 |
else |
|
327 |
{ |
|
328 |
Trace.TraceInformation("[LISTENER] Finished"); |
|
329 |
} |
|
330 |
ProcessRemoteFiles(accountPath); |
|
331 |
}); |
|
332 |
} |
|
333 |
|
|
334 |
private void ProcessListenerActions() |
|
335 |
{ |
|
336 |
foreach(var action in _listenerActions.GetConsumingEnumerable()) |
|
337 |
{ |
|
338 |
Trace.TraceInformation("[ACTION] Start Processing {0}:{1}->{2}",action.Action,action.LocalFile,action.CloudFile); |
|
339 |
var localFile = action.LocalFile; |
|
340 |
var cloudFile = action.CloudFile; |
|
341 |
var downloadPath = (cloudFile == null)? String.Empty |
|
342 |
: Path.Combine(Settings.PithosPath,cloudFile.Name); |
|
343 |
try |
|
344 |
{ |
|
345 |
switch (action.Action) |
|
346 |
{ |
|
347 |
case CloudActionType.UploadUnconditional: |
|
348 |
|
|
349 |
UploadCloudFile(localFile.Name,localFile.Length,localFile.FullName,action.LocalHash.Value); |
|
350 |
break; |
|
351 |
case CloudActionType.DownloadUnconditional: |
|
352 |
DownloadCloudFile("PITHOS",cloudFile.Name,downloadPath); |
|
353 |
break; |
|
354 |
case CloudActionType.Download: |
|
355 |
if (File.Exists(downloadPath)) |
|
356 |
{ |
|
357 |
if (cloudFile.Hash !=action.LocalHash.Value) |
|
358 |
{ |
|
359 |
var lastLocalTime =localFile.LastWriteTime; |
|
360 |
var lastUpTime =cloudFile.Last_Modified; |
|
361 |
if (lastUpTime <=lastLocalTime) |
|
362 |
{ |
|
363 |
//Files in conflict |
|
364 |
StatusKeeper.SetFileOverlayStatus(downloadPath,FileOverlayStatus.Conflict); |
|
365 |
} |
|
366 |
else |
|
367 |
DownloadCloudFile("PITHOS",action.CloudFile.Name,downloadPath); |
|
368 |
} |
|
369 |
} |
|
370 |
else |
|
371 |
DownloadCloudFile("PITHOS",action.CloudFile.Name,downloadPath); |
|
372 |
break; |
|
373 |
} |
|
374 |
Trace.TraceInformation("[ACTION] End Processing {0}:{1}->{2}", action.Action, action.LocalFile, action.CloudFile); |
|
375 |
} |
|
376 |
catch (Exception exc) |
|
377 |
{ |
|
378 |
Trace.TraceError("[REQUEUE] {0} : {1} -> {2} due to exception\r\n{3}", |
|
379 |
action.Action, action.LocalFile,action.CloudFile,exc); |
|
380 |
Trace.TraceError(exc.ToString()); |
|
381 |
|
|
382 |
_listenerActions.Add(action); |
|
383 |
} |
|
384 |
} |
|
329 | 385 |
} |
330 | 386 |
|
331 | 387 |
private void DownloadCloudFile(string container, string fileName, string localPath) |
... | ... | |
446 | 502 |
if ( hash != info.Hash) |
447 | 503 |
{ |
448 | 504 |
this.StatusKeeper.SetFileOverlayStatus(path, FileOverlayStatus.Synch); |
449 |
|
|
450 |
CloudClient.PutObject("PITHOS", fileName, path); |
|
451 |
|
|
505 |
|
|
506 |
CloudClient.PutObject("PITHOS", fileName, path, hash).Wait(); |
|
452 | 507 |
} |
453 | 508 |
this.StatusKeeper.SetFileStatus(path,FileStatus.Unchanged); |
454 | 509 |
this.StatusKeeper.SetFileOverlayStatus(path,FileOverlayStatus.Normal); |
... | ... | |
521 | 576 |
return state; |
522 | 577 |
|
523 | 578 |
string path = state.Path; |
524 |
string hash = CalculateHash(path); |
|
579 |
string hash = Signature.CalculateHash(path);
|
|
525 | 580 |
|
526 | 581 |
StatusKeeper.UpdateFileChecksum(path, hash); |
527 | 582 |
|
... | ... | |
529 | 584 |
return state; |
530 | 585 |
} |
531 | 586 |
|
532 |
private static string CalculateHash(string path) |
|
533 |
{ |
|
534 |
string hash; |
|
535 |
using (var hasher = MD5.Create()) |
|
536 |
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, true)) |
|
537 |
{ |
|
538 |
var hashBytes = hasher.ComputeHash(stream); |
|
539 |
var hashBuilder = new StringBuilder(); |
|
540 |
foreach (byte b in hasher.ComputeHash(stream)) |
|
541 |
hashBuilder.Append(b.ToString("x2").ToLower()); |
|
542 |
hash = hashBuilder.ToString(); |
|
543 |
|
|
544 |
} |
|
545 |
return hash; |
|
546 |
} |
|
587 |
|
|
547 | 588 |
|
548 | 589 |
private FileSystemEventArgs CalculateSignature(FileSystemEventArgs arg) |
549 | 590 |
{ |
b/trunk/Pithos.Core/StatusChecker.cs | ||
---|---|---|
1 | 1 |
using System; |
2 |
using System.Collections.Concurrent; |
|
2 | 3 |
using System.Collections.Generic; |
3 | 4 |
using System.ComponentModel.Composition; |
4 | 5 |
using System.Diagnostics; |
5 | 6 |
using System.Diagnostics.Contracts; |
6 | 7 |
using System.IO; |
8 |
using System.Linq; |
|
9 |
using System.Security.Cryptography; |
|
10 |
using System.Text; |
|
11 |
using System.Threading.Tasks; |
|
7 | 12 |
using Castle.ActiveRecord; |
13 |
using Castle.ActiveRecord.Framework; |
|
8 | 14 |
using Castle.ActiveRecord.Framework.Config; |
9 | 15 |
using Pithos.Interfaces; |
10 | 16 |
|
... | ... | |
32 | 38 |
try |
33 | 39 |
{ |
34 | 40 |
var state = FileState.TryFind(path); |
35 |
return state == null ? FileOverlayStatus.NA : state.OverlayStatus;
|
|
41 |
return state == null ? FileOverlayStatus.Unversioned : state.OverlayStatus;
|
|
36 | 42 |
} |
37 | 43 |
catch (Exception exc) |
38 | 44 |
{ |
39 | 45 |
Trace.TraceError(exc.ToString()); |
40 |
return FileOverlayStatus.NA;
|
|
46 |
return FileOverlayStatus.Unversioned;
|
|
41 | 47 |
} |
42 | 48 |
} |
43 | 49 |
|
50 |
public IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths) |
|
51 |
{ |
|
52 |
var existingFiles = FileState.FindAll().Select(state=>state.FilePath); |
|
53 |
|
|
54 |
var newFiles = (from file in paths.Except(existingFiles.AsParallel()) |
|
55 |
select new FileState |
|
56 |
{ |
|
57 |
FilePath = file, |
|
58 |
OverlayStatus = FileOverlayStatus.Unversioned, |
|
59 |
FileStatus=FileStatus.Created, |
|
60 |
Checksum=Signature.CalculateHash(file) |
|
61 |
} |
|
62 |
).AsParallel(); |
|
63 |
|
|
64 |
var files=new ConcurrentBag<string>(); |
|
65 |
newFiles.ForAll(state=> |
|
66 |
{ |
|
67 |
state.Save(); |
|
68 |
files.Add(state.FilePath); |
|
69 |
}); |
|
70 |
|
|
71 |
return files.GetConsumingEnumerable(); |
|
72 |
|
|
73 |
} |
|
74 |
|
|
75 |
/* |
|
76 |
private static Task<string> CalculateHashAsync(string path) |
|
77 |
{ |
|
78 |
|
|
79 |
string hash; |
|
80 |
using (var hasher = MD5.Create()) |
|
81 |
{ |
|
82 |
return FileAsync.ReadAllBytes(path) |
|
83 |
.ContinueWith(t => hasher.ComputeHash(t.Result)) |
|
84 |
.ContinueWith(t => |
|
85 |
{ |
|
86 |
//var hashBuilder = new StringBuilder(); |
|
87 |
return (from byte b in t.Result.AsParallel() |
|
88 |
select b.ToString("x2").ToLower()).Aggregate((s1, s2) => s1 + s2); |
|
89 |
}); |
|
90 |
} |
|
91 |
/*using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, true)) |
|
92 |
{ |
|
93 |
|
|
94 |
stream.ReadAllBytes() |
|
95 |
.ContinueWith(result => hasher.ComputeHash(result.Result)) |
|
96 |
.; |
|
97 |
var hashBytes = hasher.ComputeHash(stream); |
|
98 |
var hashBuilder = new StringBuilder(); |
|
99 |
foreach (byte b in hasher.ComputeHash(stream)) |
|
100 |
hashBuilder.Append(b.ToString("x2").ToLower()); |
|
101 |
hash = hashBuilder.ToString(); |
|
102 |
|
|
103 |
} |
|
104 |
return hash;#1# |
|
105 |
} |
|
106 |
*/ |
|
107 |
|
|
44 | 108 |
|
45 | 109 |
private PithosStatus _pithosStatus=PithosStatus.InSynch; |
46 | 110 |
public void SetPithosStatus(PithosStatus status) |
b/trunk/Pithos.Interfaces/ICloudClient.cs | ||
---|---|---|
4 | 4 |
using System.IO; |
5 | 5 |
using System.Linq; |
6 | 6 |
using System.Text; |
7 |
using System.Threading.Tasks; |
|
7 | 8 |
|
8 | 9 |
namespace Pithos.Interfaces |
9 | 10 |
{ |
... | ... | |
17 | 18 |
bool UsePithos { get; set; } |
18 | 19 |
void Authenticate(string userName,string apiKey); |
19 | 20 |
Uri Proxy { get; set; } |
21 |
double DownloadPercentLimit { get; set; } |
|
22 |
double UploadPercentLimit { get; set; } |
|
23 |
|
|
20 | 24 |
|
21 | 25 |
IList<ContainerInfo> ListContainers(); |
22 | 26 |
IList<ObjectInfo> ListObjects(string container); |
... | ... | |
27 | 31 |
void DeleteContainer(string container); |
28 | 32 |
|
29 | 33 |
Stream GetObject(string container, string objectName); |
30 |
void PutObject(string container, string objectName, string fileName);
|
|
34 |
Task PutObject(string container, string objectName, string fileName, string hash = null);
|
|
31 | 35 |
void DeleteObject(string container, string objectName); |
32 | 36 |
void MoveObject(string container, string oldObjectName, string newObjectName); |
33 | 37 |
bool ObjectExists(string container,string objectName); |
... | ... | |
46 | 50 |
public Uri StorageUrl { get; set; } |
47 | 51 |
public string Token { get; set; } |
48 | 52 |
public Uri Proxy { get; set; } |
53 |
public double DownloadPercentLimit { get; set; } |
|
54 |
public double UploadPercentLimit { get; set; } |
|
49 | 55 |
|
50 | 56 |
public bool UsePithos { get; set; } |
51 | 57 |
|
... | ... | |
131 | 137 |
return default(Stream); |
132 | 138 |
} |
133 | 139 |
|
134 |
public void PutObject(string container, string objectName, string fileName)
|
|
140 |
public Task PutObject(string container, string objectName, string fileName, string hash = null)
|
|
135 | 141 |
{ |
136 | 142 |
Contract.Requires(!String.IsNullOrWhiteSpace(Token)); |
137 | 143 |
Contract.Requires(StorageUrl!=null); |
138 | 144 |
Contract.Requires(!String.IsNullOrWhiteSpace(container)); |
139 | 145 |
Contract.Requires(!String.IsNullOrWhiteSpace(fileName)); |
140 | 146 |
Contract.Requires(!String.IsNullOrWhiteSpace(objectName)); |
147 |
|
|
148 |
return default(Task); |
|
141 | 149 |
} |
142 | 150 |
|
143 | 151 |
public void DeleteObject(string container, string objectName) |
b/trunk/Pithos.Interfaces/IStatusChecker.cs | ||
---|---|---|
34 | 34 |
public enum FileOverlayStatus |
35 | 35 |
{ |
36 | 36 |
Deleted=-2, |
37 |
NA=-1,
|
|
37 |
Unversioned=-1,
|
|
38 | 38 |
Normal=0, |
39 | 39 |
Modified, |
40 | 40 |
Conflict, |
b/trunk/Pithos.Network/CloudFilesClient.cs | ||
---|---|---|
8 | 8 |
using System.Net; |
9 | 9 |
using System.Security.Cryptography; |
10 | 10 |
using System.Text; |
11 |
using System.Threading.Tasks; |
|
11 | 12 |
using Hammock; |
12 | 13 |
using Hammock.Caching; |
13 | 14 |
using Hammock.Retries; |
... | ... | |
28 | 29 |
private RestClient _client; |
29 | 30 |
private readonly TimeSpan _shortTimeout = TimeSpan.FromSeconds(10); |
30 | 31 |
private readonly int _retries = 5; |
32 |
private RetryPolicy _retryPolicy; |
|
31 | 33 |
public string ApiKey { get; set; } |
32 | 34 |
public string UserName { get; set; } |
33 | 35 |
public Uri StorageUrl { get; set; } |
34 | 36 |
public string Token { get; set; } |
35 | 37 |
public Uri Proxy { get; set; } |
38 |
|
|
39 |
public double DownloadPercentLimit { get; set; } |
|
40 |
public double UploadPercentLimit { get; set; } |
|
36 | 41 |
|
37 | 42 |
public string AuthUrl |
38 | 43 |
{ |
... | ... | |
48 | 53 |
|
49 | 54 |
public void Authenticate(string userName,string apiKey) |
50 | 55 |
{ |
56 |
Trace.TraceInformation("[AUTHENTICATE] Start for {0}",userName); |
|
51 | 57 |
if (String.IsNullOrWhiteSpace(userName)) |
52 | 58 |
throw new ArgumentNullException("userName","The userName property can't be empty"); |
53 | 59 |
if (String.IsNullOrWhiteSpace(apiKey)) |
... | ... | |
91 | 97 |
else |
92 | 98 |
Token = "0000"; |
93 | 99 |
|
94 |
var retryPolicy = new RetryPolicy { RetryCount = _retries };
|
|
95 |
retryPolicy.RetryConditions.Add(new TimeoutRetryCondition()); |
|
100 |
_retryPolicy = new RetryPolicy { RetryCount = _retries };
|
|
101 |
_retryPolicy.RetryConditions.Add(new TimeoutRetryCondition());
|
|
96 | 102 |
|
97 |
_client = new RestClient { Authority = StorageUrl.AbsoluteUri, Path = UserName, Proxy = proxy, RetryPolicy = retryPolicy, }; |
|
103 |
_client = new RestClient { Authority = StorageUrl.AbsoluteUri, Path = UserName, Proxy = proxy }; |
|
104 |
_client.FileProgress += OnFileProgress; |
|
98 | 105 |
|
99 | 106 |
_client.AddHeader("X-Auth-Token", Token); |
100 | 107 |
if (UsePithos) |
... | ... | |
103 | 110 |
_client.AddHeader("X-Auth-Key",ApiKey); |
104 | 111 |
} |
105 | 112 |
|
113 |
Trace.TraceInformation("[AUTHENTICATE] End for {0}", userName); |
|
114 |
} |
|
106 | 115 |
|
116 |
private void OnFileProgress(object sender, FileProgressEventArgs e) |
|
117 |
{ |
|
118 |
Trace.TraceInformation("[PROGRESS] {0} {1:p} {2} of {3}",e.FileName,(double)e.BytesWritten/e.TotalBytes, e.BytesWritten,e.TotalBytes); |
|
107 | 119 |
} |
108 | 120 |
|
109 | 121 |
public IList<ContainerInfo> ListContainers() |
... | ... | |
112 | 124 |
//appends a / unless a Path is specified. |
113 | 125 |
|
114 | 126 |
//Create a request with a complete path |
115 |
var request = new RestRequest { Path = StorageUrl.ToString(), Timeout = _shortTimeout }; |
|
127 |
var request = new RestRequest { Path = StorageUrl.ToString(), RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
|
|
116 | 128 |
request.AddParameter("format","json"); |
117 | 129 |
//Create a client clone |
118 | 130 |
var client = new RestClient{Proxy=Proxy.ToString()}; |
... | ... | |
139 | 151 |
if (String.IsNullOrWhiteSpace(container)) |
140 | 152 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
141 | 153 |
|
142 |
var request = new RestRequest { Path = container, Timeout = _shortTimeout }; |
|
154 |
Trace.TraceInformation("[START] ListObjects"); |
|
155 |
|
|
156 |
var request = new RestRequest { Path = container, RetryPolicy = _retryPolicy, Timeout = TimeSpan.FromMinutes(1) }; |
|
143 | 157 |
request.AddParameter("format", "json"); |
144 | 158 |
var response = _client.Request(request); |
145 | 159 |
|
146 | 160 |
var infos = InfosFromContent(response); |
147 | 161 |
|
162 |
Trace.TraceInformation("[END] ListObjects"); |
|
148 | 163 |
return infos; |
149 | 164 |
} |
150 | 165 |
|
... | ... | |
155 | 170 |
if (String.IsNullOrWhiteSpace(container)) |
156 | 171 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
157 | 172 |
|
158 |
var request = new RestRequest { Path = container, Timeout = _shortTimeout }; |
|
173 |
Trace.TraceInformation("[START] ListObjects"); |
|
174 |
|
|
175 |
var request = new RestRequest { Path = container,RetryPolicy = _retryPolicy, Timeout = TimeSpan.FromMinutes(1) }; |
|
159 | 176 |
request.AddParameter("format", "json"); |
160 | 177 |
request.AddParameter("path", folder); |
161 | 178 |
var response = _client.Request(request); |
162 | 179 |
|
163 | 180 |
var infos = InfosFromContent(response); |
164 | 181 |
|
182 |
Trace.TraceInformation("[END] ListObjects"); |
|
165 | 183 |
return infos; |
166 | 184 |
} |
167 | 185 |
|
... | ... | |
193 | 211 |
if (String.IsNullOrWhiteSpace(container)) |
194 | 212 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
195 | 213 |
|
196 |
var request = new RestRequest { Path = container, Method = WebMethod.Head, Timeout = _shortTimeout }; |
|
214 |
var request = new RestRequest { Path = container, Method = WebMethod.Head, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
|
|
197 | 215 |
var response = _client.Request(request); |
198 | 216 |
|
199 | 217 |
switch(response.StatusCode) |
... | ... | |
215 | 233 |
throw new ArgumentNullException("objectName", "The objectName property can't be empty"); |
216 | 234 |
|
217 | 235 |
|
218 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Head, Timeout = _shortTimeout }; |
|
236 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Head,RetryPolicy = _retryPolicy, Timeout = _shortTimeout };
|
|
219 | 237 |
var response = _client.Request(request); |
220 | 238 |
|
221 | 239 |
switch (response.StatusCode) |
... | ... | |
239 | 257 |
throw new ArgumentNullException("objectName", "The objectName property can't be empty"); |
240 | 258 |
|
241 | 259 |
|
242 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Head, Timeout = _shortTimeout }; |
|
260 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Head, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
|
|
243 | 261 |
var response = _client.Request(request); |
244 | 262 |
|
245 | 263 |
if (response.TimedOut) |
... | ... | |
252 | 270 |
var keys = response.Headers.AllKeys.AsQueryable(); |
253 | 271 |
return new ObjectInfo |
254 | 272 |
{ |
255 |
Name=objectName,
|
|
273 |
Name = objectName,
|
|
256 | 274 |
Bytes = long.Parse(GetHeaderValue("Content-Length", response, keys)), |
257 | 275 |
Hash = GetHeaderValue("ETag", response, keys), |
258 | 276 |
Content_Type = GetHeaderValue("Content-Type", response, keys) |
... | ... | |
260 | 278 |
case HttpStatusCode.NotFound: |
261 | 279 |
return ObjectInfo.Empty; |
262 | 280 |
default: |
263 |
throw new WebException(String.Format("GetObjectInfo failed with unexpected status code {0}", response.StatusCode)); |
|
281 |
if (request.RetryState.RepeatCount > 0) |
|
282 |
{ |
|
283 |
Trace.TraceWarning("[RETRY FAIL] GetObjectInfo for {0} failed after {1} retries", |
|
284 |
objectName, request.RetryState.RepeatCount); |
|
285 |
return ObjectInfo.Empty; |
|
286 |
} |
|
287 |
if (response.InnerException != null) |
|
288 |
throw new WebException(String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}", objectName, response.StatusCode), response.InnerException); |
|
289 |
throw new WebException(String.Format("[FAIL] GetObjectInfo for {0} failed with unexpected status code {1}", objectName, response.StatusCode)); |
|
264 | 290 |
} |
265 | 291 |
} |
266 | 292 |
|
... | ... | |
272 | 298 |
throw new ArgumentNullException("folder", "The folder property can't be empty"); |
273 | 299 |
|
274 | 300 |
var folderUrl=String.Format("{0}/{1}",container,folder); |
275 |
var request = new RestRequest { Path = folderUrl, Method = WebMethod.Put, Timeout = _shortTimeout }; |
|
301 |
var request = new RestRequest { Path = folderUrl, Method = WebMethod.Put, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
|
|
276 | 302 |
request.AddHeader("Content-Type", @"application/directory"); |
277 | 303 |
request.AddHeader("Content-Length", "0"); |
278 | 304 |
|
... | ... | |
288 | 314 |
if (String.IsNullOrWhiteSpace(container)) |
289 | 315 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
290 | 316 |
|
291 |
var request = new RestRequest { Path = container, Method = WebMethod.Head, Timeout = _shortTimeout }; |
|
317 |
var request = new RestRequest { Path = container, Method = WebMethod.Head, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
|
|
292 | 318 |
var response = _client.Request(request); |
293 | 319 |
|
294 | 320 |
switch(response.StatusCode) |
... | ... | |
314 | 340 |
if (String.IsNullOrWhiteSpace(container)) |
315 | 341 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
316 | 342 |
|
317 |
var request = new RestRequest { Path = container, Method = WebMethod.Put, Timeout = _shortTimeout }; |
|
343 |
var request = new RestRequest { Path = container, Method = WebMethod.Put, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
|
|
318 | 344 |
|
319 | 345 |
var response = _client.Request(request); |
320 | 346 |
|
... | ... | |
327 | 353 |
if (String.IsNullOrWhiteSpace(container)) |
328 | 354 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
329 | 355 |
|
330 |
var request = new RestRequest { Path = container, Method = WebMethod.Delete, Timeout = _shortTimeout }; |
|
356 |
var request = new RestRequest { Path = container, Method = WebMethod.Delete, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
|
|
331 | 357 |
var response = _client.Request(request); |
332 | 358 |
|
333 | 359 |
if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.NoContent) |
... | ... | |
352 | 378 |
throw new ArgumentNullException("objectName", "The objectName property can't be empty"); |
353 | 379 |
|
354 | 380 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Get }; |
381 |
/* |
|
382 |
if (DownloadPercentLimit > 0) |
|
383 |
request.TaskOptions = new TaskOptions<int> { RateLimitPercent = DownloadPercentLimit }; |
|
384 |
*/ |
|
385 |
|
|
355 | 386 |
var response = _client.Request(request); |
356 | 387 |
|
357 | 388 |
if (response.StatusCode == HttpStatusCode.NotFound) |
... | ... | |
370 | 401 |
/// <param name="container"></param> |
371 | 402 |
/// <param name="objectName"></param> |
372 | 403 |
/// <param name="fileName"></param> |
404 |
/// <param name="hash">Optional hash value for the file. If no hash is provided, the method calculates a new hash</param> |
|
373 | 405 |
/// <remarks>>This method should have no timeout or a very long one</remarks> |
374 |
public void PutObject(string container, string objectName, string fileName)
|
|
406 |
public Task PutObject(string container, string objectName, string fileName, string hash = null)
|
|
375 | 407 |
{ |
376 | 408 |
if (String.IsNullOrWhiteSpace(container)) |
377 | 409 |
throw new ArgumentNullException("container", "The container property can't be empty"); |
... | ... | |
386 | 418 |
string url = container + "/" + objectName; |
387 | 419 |
|
388 | 420 |
var request = new RestRequest {Path=url,Method=WebMethod.Put}; |
389 |
request.TaskOptions=new TaskOptions<int>{RateLimitPercent=0.5}; |
|
390 | 421 |
|
391 |
string hash = CalculateHash(fileName); |
|
392 |
|
|
393 |
request.AddPostContent(File.ReadAllBytes(fileName)); |
|
422 |
/* |
|
423 |
if(UploadPercentLimit>0) |
|
424 |
request.TaskOptions=new TaskOptions<int>{RateLimitPercent=UploadPercentLimit}; |
|
425 |
*/ |
|
426 |
Trace.TraceInformation("[PUT] START {0}",objectName); |
|
427 |
string etag = hash??CalculateHash(fileName); |
|
428 |
request.AddFile(fileName, fileName, fileName); |
|
429 |
//request.AddPostContent(File.ReadAllBytes(fileName)); |
|
394 | 430 |
request.AddHeader("Content-Type","application/octet-stream"); |
395 |
request.AddHeader("ETag",hash); |
|
396 |
var response=_client.Request(request); |
|
397 |
_client.TaskOptions = new TaskOptions<int> {RateLimitPercent = 0.5}; |
|
398 |
if (response.StatusCode == HttpStatusCode.Created) |
|
399 |
return; |
|
400 |
if (response.StatusCode == HttpStatusCode.LengthRequired) |
|
401 |
throw new InvalidOperationException(); |
|
402 |
else |
|
403 |
throw new WebException(String.Format("GetObject failed with unexpected status code {0}", response.StatusCode)); |
|
431 |
request.AddHeader("ETag", etag); |
|
432 |
//_client.TaskOptions = new TaskOptions<int> {RateLimitPercent = 0.5}; |
|
433 |
try |
|
434 |
{ |
|
435 |
|
|
436 |
var response=_client.Request(request); |
|
437 |
Trace.TraceInformation("[PUT] END {0}", objectName); |
|
438 |
|
|
439 |
if (response.StatusCode == HttpStatusCode.Created) |
|
440 |
return Task.Factory.StartNew(()=>{}); |
|
441 |
if (response.StatusCode == HttpStatusCode.LengthRequired) |
|
442 |
throw new InvalidOperationException(); |
|
443 |
else |
|
444 |
throw new WebException(String.Format("GetObject failed with unexpected status code {0}", |
|
445 |
response.StatusCode)); |
|
446 |
/* return Task.Factory.FromAsync(_client.BeginRequest(request),ar=>_client.EndRequest(ar)) |
|
447 |
.ContinueWith(t=> |
|
448 |
{*/ |
|
449 |
} |
|
450 |
catch (Exception exc) |
|
451 |
{ |
|
452 |
Trace.TraceError("[PUT] END {0} with {1}", objectName, exc); |
|
453 |
throw; |
|
454 |
} |
|
455 |
|
|
456 |
/* |
|
457 |
var response = t.Result; |
|
458 |
if (t.IsFaulted) |
|
459 |
Trace.TraceError("[PUT] END {0} with {1}", objectName, t.Exception); |
|
460 |
else |
|
461 |
{ |
|
462 |
Trace.TraceInformation("[PUT] END {0}",objectName); |
|
463 |
} |
|
464 |
*/ |
|
465 |
/* if (response.StatusCode == HttpStatusCode.Created) |
|
466 |
return; |
|
467 |
if (response.StatusCode == HttpStatusCode.LengthRequired) |
|
468 |
throw new InvalidOperationException(); |
|
469 |
else |
|
470 |
throw new WebException(String.Format("GetObject failed with unexpected status code {0}", |
|
471 |
response.StatusCode));*/ |
|
472 |
/*});*/ |
|
404 | 473 |
} |
405 | 474 |
|
406 | 475 |
private static string CalculateHash(string fileName) |
... | ... | |
424 | 493 |
if (String.IsNullOrWhiteSpace(objectName)) |
425 | 494 |
throw new ArgumentNullException("objectName", "The objectName property can't be empty"); |
426 | 495 |
|
427 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Delete, Timeout=_shortTimeout };
|
|
496 |
var request = new RestRequest { Path = container + "/" + objectName, Method = WebMethod.Delete, RetryPolicy = _retryPolicy,Timeout = _shortTimeout };
|
|
428 | 497 |
var response = _client.Request(request); |
429 | 498 |
|
430 | 499 |
if (response.StatusCode == HttpStatusCode.NotFound || response.StatusCode == HttpStatusCode.NoContent) |
b/trunk/Pithos.Network/Pithos.Network.csproj | ||
---|---|---|
72 | 72 |
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories> |
73 | 73 |
</PropertyGroup> |
74 | 74 |
<ItemGroup> |
75 |
<Reference Include="Hammock.ClientProfile"> |
|
76 |
<HintPath>..\packages\Hammock.1.2.6\lib\4.0\Hammock.ClientProfile.dll</HintPath> |
|
77 |
</Reference> |
|
78 | 75 |
<Reference Include="System" /> |
79 | 76 |
<Reference Include="System.ComponentModel.Composition" /> |
80 | 77 |
<Reference Include="System.Core" /> |
... | ... | |
89 | 86 |
<Compile Include="TimeoutRetryCondition.cs" /> |
90 | 87 |
</ItemGroup> |
91 | 88 |
<ItemGroup> |
89 |
<ProjectReference Include="..\hammock\src\net40\Hammock.ClientProfile\Hammock.ClientProfile.csproj"> |
|
90 |
<Project>{487B7E3C-9689-47BC-8785-73CCD92A3749}</Project> |
|
91 |
<Name>Hammock.ClientProfile</Name> |
|
92 |
</ProjectReference> |
|
92 | 93 |
<ProjectReference Include="..\Libraries\Json40r2\Source\Src\Newtonsoft.Json\Newtonsoft.Json.csproj"> |
93 | 94 |
<Project>{A9AE40FF-1A21-414A-9FE7-3BE13644CC6D}</Project> |
94 | 95 |
<Name>Newtonsoft.Json</Name> |
b/trunk/Pithos.Network/TimeoutRetryCondition.cs | ||
---|---|---|
13 | 13 |
{ |
14 | 14 |
get |
15 | 15 |
{ |
16 |
return r => |
|
17 |
(r.Exception != null && r.Exception is WebException |
|
18 |
&& (((WebException)r.Exception).Status == WebExceptionStatus.Timeout)); |
|
16 |
return r => |
|
17 |
{ |
|
18 |
var responseStatus = r.ResponseHttpStatusCode; |
|
19 |
if (r.Exception == null) |
|
20 |
return false; |
|
21 |
if (!(r.Exception is WebException)) |
|
22 |
return false; |
|
23 |
var exceptionStatus = ((WebException) r.Exception).Status; |
|
24 |
return (r.Exception != null |
|
25 |
&& (exceptionStatus == WebExceptionStatus.Timeout)); |
|
26 |
}; |
|
19 | 27 |
} |
20 | 28 |
} |
21 | 29 |
} |
b/trunk/Pithos.ShellExtensions/FileContext.cs | ||
---|---|---|
25 | 25 |
|
26 | 26 |
public FileContext() |
27 | 27 |
{ |
28 |
/* if (Process.GetProcessesByName("Pithos.Client.WPF").Length == 0) |
|
29 |
{ |
|
30 |
var appPath = (string)Registry.LocalMachine.GetValue(@"Software\Pithos\AppPath"); |
|
31 |
Process.Start(appPath); |
|
32 |
}*/ |
|
33 | 28 |
} |
34 | 29 |
|
35 | 30 |
public bool IsManaged |
b/trunk/Pithos.ShellExtensions/Pithos.ShellExtensions.csproj | ||
---|---|---|
102 | 102 |
<Compile Include="Menus\DisplayFlags.cs" /> |
103 | 103 |
<Compile Include="Menus\FileContextMenu.cs" /> |
104 | 104 |
<Compile Include="Menus\MenuItem.cs" /> |
105 |
<Compile Include="Overlays\AddedIcodOverlay.cs" /> |
|
105 | 106 |
<Compile Include="Overlays\ConflictIconOverlay.cs" /> |
106 | 107 |
<Compile Include="Overlays\IconOverlayBase.cs" /> |
107 | 108 |
<Compile Include="Overlays\ModifiedIconOverlay.cs" /> |
108 | 109 |
<Compile Include="Overlays\NormalIconOverlay.cs" /> |
109 | 110 |
<Compile Include="Overlays\SynchIconOverlay.cs" /> |
111 |
<Compile Include="Overlays\UnversionedIconOverlay.cs" /> |
|
112 |
<Compile Include="PithosHost.cs" /> |
|
110 | 113 |
<Compile Include="ProjectInstaller.cs"> |
111 | 114 |
<SubType>Component</SubType> |
112 | 115 |
</Compile> |
b/trunk/Pithos.ShellExtensions/Service References/PithosService/mex2.xsd | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8"?> |
|
1 |
<?xml version="1.0" encoding="utf-8"?>
|
|
2 | 2 |
<xs:schema xmlns:tns="http://schemas.datacontract.org/2004/07/Pithos.Interfaces" elementFormDefault="qualified" targetNamespace="http://schemas.datacontract.org/2004/07/Pithos.Interfaces" xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
3 | 3 |
<xs:import schemaLocation="http://localhost:30000/pithos/mex?xsd=xsd1" namespace="http://schemas.microsoft.com/2003/10/Serialization/" /> |
4 | 4 |
<xs:import schemaLocation="http://localhost:30000/pithos/mex?xsd=xsd4" namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays" /> |
... | ... | |
11 | 11 |
</xs:appinfo> |
12 | 12 |
</xs:annotation> |
13 | 13 |
</xs:enumeration> |
14 |
<xs:enumeration value="NA">
|
|
14 |
<xs:enumeration value="Unversioned">
|
|
15 | 15 |
<xs:annotation> |
16 | 16 |
<xs:appinfo> |
17 | 17 |
<EnumerationValue xmlns="http://schemas.microsoft.com/2003/10/Serialization/">-1</EnumerationValue> |
b/trunk/Pithos.ShellExtensions/ShellSettings.cs | ||
---|---|---|
7 | 7 |
using System.ComponentModel.Composition; |
8 | 8 |
using System.Diagnostics; |
9 | 9 |
using System.ServiceModel; |
10 |
using Microsoft.Win32; |
|
10 | 11 |
using Pithos.Interfaces; |
11 | 12 |
|
12 | 13 |
namespace Pithos.ShellExtensions |
... | ... | |
131 | 132 |
|
132 | 133 |
private IPithosSettings LoadSettings() |
133 | 134 |
{ |
135 |
|
|
134 | 136 |
try |
135 | 137 |
{ |
136 |
var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); |
|
137 |
|
|
138 |
var remoteAddress = new EndpointAddress("net.pipe://localhost/pithos/settings"); |
|
139 |
using (var client = new PithosService.SettingsServiceClient(binding, remoteAddress)) |
|
138 |
using (var client = PithosHost.GetSettingsClient()) |
|
140 | 139 |
{ |
141 | 140 |
return client.GetSettings(); |
142 | 141 |
} |
b/trunk/Pithos.ShellExtensions/ShellStatusChecker.cs | ||
---|---|---|
7 | 7 |
using System.ComponentModel.Composition; |
8 | 8 |
using System.Diagnostics; |
9 | 9 |
using System.ServiceModel; |
10 |
using Microsoft.Win32; |
|
10 | 11 |
using Pithos.Interfaces; |
11 | 12 |
|
12 | 13 |
namespace Pithos.ShellExtensions |
... | ... | |
30 | 31 |
|
31 | 32 |
try |
32 | 33 |
{ |
33 |
var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); |
|
34 |
|
|
35 |
var remoteAddress = new EndpointAddress("net.pipe://localhost/pithos/statuscache"); |
|
36 |
using (var client = new PithosService.StatusServiceClient(binding, remoteAddress)) |
|
34 |
using (var client = PithosHost.GetStatusClient()) |
|
37 | 35 |
{ |
38 | 36 |
var status = client.GetStatus(path); |
39 | 37 |
return status; |
... | ... | |
42 | 40 |
catch (Exception exc) |
43 | 41 |
{ |
44 | 42 |
Trace.TraceError(exc.ToString()); |
45 |
return FileOverlayStatus.NA;
|
|
43 |
return FileOverlayStatus.Unversioned;
|
|
46 | 44 |
} |
47 | 45 |
} |
48 | 46 |
|
b/trunk/Pithos.ShellExtensions/TestStatusChecker.cs | ||
---|---|---|
31 | 31 |
var status = Char.ConvertToUtf32(fileName, 0)%4; |
32 | 32 |
return (FileOverlayStatus)status; |
33 | 33 |
} |
34 |
return FileOverlayStatus.NA;
|
|
34 |
return FileOverlayStatus.Unversioned;
|
|
35 | 35 |
} |
36 | 36 |
|
37 | 37 |
|
b/trunk/Pithos.sln | ||
---|---|---|
36 | 36 |
EndProject |
37 | 37 |
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Caliburn.Micro.WPF", "..\..\..\Downloads\caliburnmicro\caliburnmicro_1f6100f2f0af\src\Caliburn.Micro.WPF\Caliburn.Micro.WPF.csproj", "{B633FE8C-B40E-4122-A763-F94C8B1A70F8}" |
38 | 38 |
EndProject |
39 |
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hammock.ClientProfile", "hammock\src\net40\Hammock.ClientProfile\Hammock.ClientProfile.csproj", "{487B7E3C-9689-47BC-8785-73CCD92A3749}" |
|
40 |
EndProject |
|
39 | 41 |
Global |
40 | 42 |
GlobalSection(SolutionConfigurationPlatforms) = preSolution |
41 | 43 |
Debug|Any CPU = Debug|Any CPU |
... | ... | |
257 | 259 |
{B633FE8C-B40E-4122-A763-F94C8B1A70F8}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU |
258 | 260 |
{B633FE8C-B40E-4122-A763-F94C8B1A70F8}.Test|Mixed Platforms.Build.0 = Release|Any CPU |
259 | 261 |
{B633FE8C-B40E-4122-A763-F94C8B1A70F8}.Test|x86.ActiveCfg = Release|Any CPU |
262 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|
263 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|
264 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU |
|
265 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU |
|
266 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Debug|x86.ActiveCfg = Debug|Any CPU |
|
267 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|
268 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Any CPU.Build.0 = Release|Any CPU |
|
269 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU |
|
270 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|Mixed Platforms.Build.0 = Release|Any CPU |
|
271 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Release|x86.ActiveCfg = Release|Any CPU |
|
272 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Test|Any CPU.ActiveCfg = Release|Any CPU |
|
273 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Test|Any CPU.Build.0 = Release|Any CPU |
|
274 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Test|Mixed Platforms.ActiveCfg = Release|Any CPU |
|
275 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Test|Mixed Platforms.Build.0 = Release|Any CPU |
|
276 |
{487B7E3C-9689-47BC-8785-73CCD92A3749}.Test|x86.ActiveCfg = Release|Any CPU |
|
260 | 277 |
EndGlobalSection |
261 | 278 |
GlobalSection(SolutionProperties) = preSolution |
262 | 279 |
HideSolutionNode = FALSE |
/dev/null | ||
---|---|---|
1 |
Hammock (http://github.com/danielcrenna/hammock) |
|
2 |
-------------------------------------- |
|
3 |
Copyright (c) 2010 Daniel Crenna and Jason Diller |
|
4 |
|
|
5 |
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated |
|
6 |
documentation files (the "Software"), to deal in the Software without restriction, including without limitation |
|
7 |
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and |
|
8 |
to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
|
9 |
|
|
10 |
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
|
11 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
12 |
|
|
13 |
Hammock for Silverlight and Windows Phone 7 |
|
14 |
-------------------------------------- |
|
15 |
This target optionally links to a port of SharpZipLib http://www.icsharpcode.net/opensource/sharpziplib as an independent |
|
16 |
module that does not derive from, and is not based on, SharpZipLib. As such it is compliant with the special |
|
17 |
exception of SharpZipLib's GNU General Public License and may be used in commercial, closed-source applications. |
|
18 |
As the independent module, this is compliant with Hammock's MIT X11 Licence. |
|
19 |
|
|
20 |
Hammock Extras |
|
21 |
-------------------------------------- |
|
22 |
The Extras project in source code provides an example serializer that includes JSON.NET, |
|
23 |
licensed under the MIT X11 License http://www.opensource.org/licenses/mit-license.php. |
/dev/null | ||
---|---|---|
1 |
<?xml version="1.0" encoding="utf-8"?> |
|
2 |
<?xml-stylesheet type="text/xsl" href="c:\program files (x86)\microsoft visual studio 10.0\team tools\static analysis tools\fxcop\Xml\CodeAnalysisReport.xsl"?> |
|
3 |
<FxCopReport Version="10.0"> |
|
4 |
<Targets> |
|
5 |
<Target Name="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\bin\lib\net40\Hammock.dll"> |
|
6 |
<Modules> |
|
7 |
<Module Name="hammock.dll"> |
|
8 |
<Namespaces> |
|
9 |
<Namespace Name="Hammock"> |
|
10 |
<Types> |
|
11 |
<Type Name="RestBase" Kind="Class" Accessibility="Public" ExternallyVisible="True"> |
|
12 |
<Members> |
|
13 |
<Member Name="#.ctor()" Kind="Method" Static="False" Accessibility="Family" ExternallyVisible="True"> |
|
14 |
<Messages> |
|
15 |
<Message TypeName="DoNotCallOverridableMethodsInConstructors" Category="Microsoft.Usage" CheckId="CA2214" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="NonBreaking"> |
|
16 |
<Issue Certainty="95" Level="CriticalWarning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestBase.cs" Line="89">'RestBase.RestBase()' contains a call chain that results in a call to a virtual method defined by the class. Review the following call stack for unintended consequences: 

RestBase..ctor()
RestBase.Initialize():Void
RestBase.set_Cookies(WebParameterCollection):Void</Issue> |
|
17 |
<Issue Certainty="95" Level="CriticalWarning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestBase.cs" Line="89">'RestBase.RestBase()' contains a call chain that results in a call to a virtual method defined by the class. Review the following call stack for unintended consequences: 

RestBase..ctor()
RestBase.Initialize():Void
RestBase.set_Headers(NameValueCollection):Void</Issue> |
|
18 |
<Issue Certainty="95" Level="CriticalWarning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestBase.cs" Line="89">'RestBase.RestBase()' contains a call chain that results in a call to a virtual method defined by the class. Review the following call stack for unintended consequences: 

RestBase..ctor()
RestBase.Initialize():Void
RestBase.set_Parameters(WebParameterCollection):Void</Issue> |
|
19 |
<Issue Certainty="95" Level="CriticalWarning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestBase.cs" Line="89">'RestBase.RestBase()' contains a call chain that results in a call to a virtual method defined by the class. Review the following call stack for unintended consequences: 

RestBase..ctor()
RestBase.Initialize():Void
RestBase.set_PostParameters(ICollection<HttpPostParameter>):Void</Issue> |
|
20 |
</Message> |
|
21 |
</Messages> |
|
22 |
</Member> |
|
23 |
</Members> |
|
24 |
</Type> |
|
25 |
<Type Name="RestClient" Kind="Class" Accessibility="Public" ExternallyVisible="True"> |
|
26 |
<Members> |
|
27 |
<Member Name="#_streamQuery" Kind="Field" Static="False" Accessibility="Private" ExternallyVisible="False"> |
|
28 |
<Messages> |
|
29 |
<Message TypeName="MarkAllNonSerializableFields" Category="Microsoft.Usage" CheckId="CA2235" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="NonBreaking"> |
|
30 |
<Issue Certainty="95" Level="Error">Field 'RestClient._streamQuery' is a member of type 'RestClient', which is serializable, but is of type 'WebQuery', which is not serializable. Add the NonSerializedAttribute to 'RestClient._streamQuery'.</Issue> |
|
31 |
</Message> |
|
32 |
</Messages> |
|
33 |
</Member> |
|
34 |
<Member Name="#BeginRequestWithTask(Hammock.RestRequest,Hammock.RestCallback,Hammock.Web.WebQuery,System.String,Hammock.Web.WebQueryAsyncResult&,System.Object)" Kind="Method" Static="False" Accessibility="Private" ExternallyVisible="False"> |
|
35 |
<Messages> |
|
36 |
<Message TypeName="Dispose objects before losing scope" Category="Microsoft.Reliability" CheckId="CA2000" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
37 |
<Issue Name="ExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="2064">In method 'RestClient.BeginRequestWithTask(RestRequest, RestCallback, WebQuery, string, out WebQueryAsyncResult, object)', object '<>g__initLocal3d' is not disposed along all exception paths. Call System.IDisposable.Dispose on object '<>g__initLocal3d' before all references to it are out of scope.</Issue> |
|
38 |
<Issue Name="NonExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="2032">In method 'RestClient.BeginRequestWithTask(RestRequest, RestCallback, WebQuery, string, out WebQueryAsyncResult, object)', call System.IDisposable.Dispose on object 'task' before all references to it are out of scope.</Issue> |
|
39 |
</Message> |
|
40 |
</Messages> |
|
41 |
</Member> |
|
42 |
<Member Name="#BeginRequestWithTask`1(Hammock.RestRequest,Hammock.RestCallback`1<!!0>,Hammock.Web.WebQuery,System.String,Hammock.Web.WebQueryAsyncResult&,System.Object)" Kind="Method" Static="False" Accessibility="Private" ExternallyVisible="False"> |
|
43 |
<Messages> |
|
44 |
<Message TypeName="Dispose objects before losing scope" Category="Microsoft.Reliability" CheckId="CA2000" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
45 |
<Issue Name="ExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="2126">In method 'RestClient.BeginRequestWithTask<T>(RestRequest, RestCallback<T>, WebQuery, string, out WebQueryAsyncResult, object)', object '<>g__initLocal45' is not disposed along all exception paths. Call System.IDisposable.Dispose on object '<>g__initLocal45' before all references to it are out of scope.</Issue> |
|
46 |
<Issue Name="NonExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="2095">In method 'RestClient.BeginRequestWithTask<T>(RestRequest, RestCallback<T>, WebQuery, string, out WebQueryAsyncResult, object)', call System.IDisposable.Dispose on object 'task' before all references to it are out of scope.</Issue> |
|
47 |
</Message> |
|
48 |
</Messages> |
|
49 |
</Member> |
|
50 |
<Member Name="#BuildBaseResponse(Hammock.Web.WebQueryResult)" Kind="Method" Static="True" Accessibility="Private" ExternallyVisible="False"> |
|
51 |
<Messages> |
|
52 |
<Message TypeName="Dispose objects before losing scope" Category="Microsoft.Reliability" CheckId="CA2000" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
53 |
<Issue Name="ExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="2519">In method 'RestClient.BuildBaseResponse(WebQueryResult)', object 'response' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'response' before all references to it are out of scope.</Issue> |
|
54 |
</Message> |
|
55 |
</Messages> |
|
56 |
</Member> |
|
57 |
<Member Name="#BuildBaseResponse`1(Hammock.Web.WebQueryResult)" Kind="Method" Static="True" Accessibility="Private" ExternallyVisible="False"> |
|
58 |
<Messages> |
|
59 |
<Message TypeName="Dispose objects before losing scope" Category="Microsoft.Reliability" CheckId="CA2000" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
60 |
<Issue Name="ExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="2528">In method 'RestClient.BuildBaseResponse<T>(WebQueryResult)', object 'response' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'response' before all references to it are out of scope.</Issue> |
|
61 |
</Message> |
|
62 |
</Messages> |
|
63 |
</Member> |
|
64 |
<Member Name="#BuildRateLimitingTask(Hammock.RestRequest,Hammock.Tasks.ITaskOptions,Hammock.RestCallback,Hammock.Web.WebQuery,System.String,System.Object)" Kind="Method" Static="False" Accessibility="Private" ExternallyVisible="False"> |
|
65 |
<Messages> |
|
66 |
<Message TypeName="Dispose objects before losing scope" Category="Microsoft.Reliability" CheckId="CA2000" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
67 |
<Issue Name="NonExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="2247">In method 'RestClient.BuildRateLimitingTask(RestRequest, ITaskOptions, RestCallback, WebQuery, string, object)', call System.IDisposable.Dispose on object '<>g__initLocal4b' before all references to it are out of scope.</Issue> |
|
68 |
</Message> |
|
69 |
</Messages> |
|
70 |
</Member> |
|
71 |
<Member Name="#CompleteWithMockWebResponse(System.IAsyncResult,System.IAsyncResult,Hammock.Web.Triplet`3<Hammock.RestRequest,Hammock.RestCallback,System.Object>)" Kind="Method" Static="False" Accessibility="Private" ExternallyVisible="False"> |
|
72 |
<Messages> |
|
73 |
<Message TypeName="Dispose objects before losing scope" Category="Microsoft.Reliability" CheckId="CA2000" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
74 |
<Issue Name="ExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="1017">In method 'RestClient.CompleteWithMockWebResponse(IAsyncResult, IAsyncResult, Triplet<RestRequest, RestCallback, object>)', object '<>g__initLocal10' is not disposed along all exception paths. Call System.IDisposable.Dispose on object '<>g__initLocal10' before all references to it are out of scope.</Issue> |
|
75 |
<Issue Name="ExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="1001">In method 'RestClient.CompleteWithMockWebResponse(IAsyncResult, IAsyncResult, Triplet<RestRequest, RestCallback, object>)', object 'm' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'm' before all references to it are out of scope.</Issue> |
|
76 |
</Message> |
|
77 |
<Message TypeName="Do not dispose objects multiple times" Category="Microsoft.Usage" CheckId="CA2202" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
78 |
<Issue Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="1008">Object 'stream' can be disposed more than once in method 'RestClient.CompleteWithMockWebResponse(IAsyncResult, IAsyncResult, Triplet<RestRequest, RestCallback, object>)'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 1008</Issue> |
|
79 |
</Message> |
|
80 |
</Messages> |
|
81 |
</Member> |
|
82 |
<Member Name="#CompleteWithMockWebResponse`1(System.IAsyncResult,System.IAsyncResult,Hammock.Web.Triplet`3<Hammock.RestRequest,Hammock.RestCallback`1<!!0>,System.Object>)" Kind="Method" Static="False" Accessibility="Private" ExternallyVisible="False"> |
|
83 |
<Messages> |
|
84 |
<Message TypeName="Dispose objects before losing scope" Category="Microsoft.Reliability" CheckId="CA2000" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
85 |
<Issue Name="ExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="953">In method 'RestClient.CompleteWithMockWebResponse<T>(IAsyncResult, IAsyncResult, Triplet<RestRequest, RestCallback<T>, object>)', object '<>g__initLocalf' is not disposed along all exception paths. Call System.IDisposable.Dispose on object '<>g__initLocalf' before all references to it are out of scope.</Issue> |
|
86 |
<Issue Name="ExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="937">In method 'RestClient.CompleteWithMockWebResponse<T>(IAsyncResult, IAsyncResult, Triplet<RestRequest, RestCallback<T>, object>)', object 'm' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'm' before all references to it are out of scope.</Issue> |
|
87 |
</Message> |
|
88 |
<Message TypeName="Do not dispose objects multiple times" Category="Microsoft.Usage" CheckId="CA2202" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
89 |
<Issue Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="944">Object 'stream' can be disposed more than once in method 'RestClient.CompleteWithMockWebResponse<T>(IAsyncResult, IAsyncResult, Triplet<RestRequest, RestCallback<T>, object>)'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.: Lines: 944</Issue> |
|
90 |
</Message> |
|
91 |
</Messages> |
|
92 |
</Member> |
|
93 |
<Member Name="#GetQueryFor(Hammock.RestBase,System.Uri)" Kind="Method" Static="False" Accessibility="Public" ExternallyVisible="True"> |
|
94 |
<Messages> |
|
95 |
<Message TypeName="Dispose objects before losing scope" Category="Microsoft.Reliability" CheckId="CA2000" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
96 |
<Issue Name="ExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestClient.cs" Line="2659">In method 'RestClient.GetQueryFor(RestBase, Uri)', object 'new BasicAuthWebQuery(info)' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'new BasicAuthWebQuery(info)' before all references to it are out of scope.</Issue> |
|
97 |
</Message> |
|
98 |
</Messages> |
|
99 |
</Member> |
|
100 |
</Members> |
|
101 |
</Type> |
|
102 |
<Type Name="RestRequest" Kind="Class" Accessibility="Public" ExternallyVisible="True"> |
|
103 |
<Members> |
|
104 |
<Member Name="#.ctor()" Kind="Method" Static="False" Accessibility="Public" ExternallyVisible="True"> |
|
105 |
<Messages> |
|
106 |
<Message TypeName="DoNotCallOverridableMethodsInConstructors" Category="Microsoft.Usage" CheckId="CA2214" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="NonBreaking"> |
|
107 |
<Issue Certainty="95" Level="CriticalWarning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestRequest.cs" Line="27">'RestRequest.RestRequest()' contains a call chain that results in a call to a virtual method defined by the class. Review the following call stack for unintended consequences: 

RestRequest..ctor()
RestRequest.Initialize():Void
RestRequest.set_ExpectHeaders(WebHeaderCollection):Void</Issue> |
|
108 |
</Message> |
|
109 |
</Messages> |
|
110 |
</Member> |
|
111 |
</Members> |
|
112 |
</Type> |
|
113 |
<Type Name="RestResponseBase" Kind="Class" Accessibility="Public" ExternallyVisible="True"> |
|
114 |
<Messages> |
|
115 |
<Message TypeName="ImplementIDisposableCorrectly" Category="Microsoft.Design" CheckId="CA1063" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="Breaking"> |
|
116 |
<Issue Name="ProvideDisposeBool" Certainty="95" Level="Error">Provide an overridable implementation of Dispose(bool) on 'RestResponseBase' or mark the type as sealed. A call to Dispose(false) should only clean up native resources. A call to Dispose(true) should clean up both managed and native resources.</Issue> |
|
117 |
</Message> |
|
118 |
</Messages> |
|
119 |
<Members> |
|
120 |
<Member Name="#Dispose()" Kind="Method" Static="False" Accessibility="Public" ExternallyVisible="True"> |
|
121 |
<Messages> |
|
122 |
<Message TypeName="ImplementIDisposableCorrectly" Category="Microsoft.Design" CheckId="CA1063" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="Breaking"> |
|
123 |
<Issue Name="DisposeImplementation" Certainty="95" Level="Error" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestResponse.cs" Line="287">Modify 'RestResponseBase.Dispose()' so that it calls Dispose(true), then calls GC.SuppressFinalize on the current object instance ('this' or 'Me' in Visual Basic), and then returns.</Issue> |
|
124 |
</Message> |
|
125 |
</Messages> |
|
126 |
</Member> |
|
127 |
<Member Name="#ReplaceContentStreamWithMemoryStream()" Kind="Method" Static="False" Accessibility="Private" ExternallyVisible="False"> |
|
128 |
<Messages> |
|
129 |
<Message TypeName="Dispose objects before losing scope" Category="Microsoft.Reliability" CheckId="CA2000" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
130 |
<Issue Name="ExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock" File="RestResponse.cs" Line="138">In method 'RestResponseBase.ReplaceContentStreamWithMemoryStream()', object 'stream' is not disposed along all exception paths. Call System.IDisposable.Dispose on object 'stream' before all references to it are out of scope.</Issue> |
|
131 |
</Message> |
|
132 |
</Messages> |
|
133 |
</Member> |
|
134 |
</Members> |
|
135 |
</Type> |
|
136 |
</Types> |
|
137 |
</Namespace> |
|
138 |
<Namespace Name="Hammock.Attributes.Specialized"> |
|
139 |
<Types> |
|
140 |
<Type Name="EntityAttribute" Kind="Class" Accessibility="Public" ExternallyVisible="True"> |
|
141 |
<Members> |
|
142 |
<Member Name="#.ctor()" Kind="Method" Static="False" Accessibility="Public" ExternallyVisible="True"> |
|
143 |
<Messages> |
|
144 |
<Message TypeName="DoNotCallOverridableMethodsInConstructors" Category="Microsoft.Usage" CheckId="CA2214" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="NonBreaking"> |
|
145 |
<Issue Certainty="95" Level="CriticalWarning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock\Attributes\Specialized" File="EntityAttribute.cs" Line="12">'EntityAttribute.EntityAttribute()' contains a call chain that results in a call to a virtual method defined by the class. Review the following call stack for unintended consequences: 

EntityAttribute..ctor()
EntityAttribute.set_ContentEncoding(Encoding):Void</Issue> |
|
146 |
</Message> |
|
147 |
</Messages> |
|
148 |
</Member> |
|
149 |
</Members> |
|
150 |
</Type> |
|
151 |
</Types> |
|
152 |
</Namespace> |
|
153 |
<Namespace Name="Hammock.Authentication.OAuth"> |
|
154 |
<Types> |
|
155 |
<Type Name="OAuthTools" Kind="Class" Accessibility="Public" ExternallyVisible="True"> |
|
156 |
<Members> |
|
157 |
<Member Name="#GetSignature(Hammock.Authentication.OAuth.OAuthSignatureMethod,Hammock.Authentication.OAuth.OAuthSignatureTreatment,System.String,System.String,System.String)" Kind="Method" Static="True" Accessibility="Public" ExternallyVisible="True"> |
|
158 |
<Messages> |
|
159 |
<Message TypeName="Dispose objects before losing scope" Category="Microsoft.Reliability" CheckId="CA2000" Status="Active" Created="2011-06-01 12:43:22Z" FixCategory="DependsOnFix"> |
|
160 |
<Issue Name="NonExceptionEdge" Certainty="75" Level="Warning" Path="L:\My Dropbox\_7_Source_Code\_1_Projects\hammock\src\net35\Hammock\Authentication\OAuth" File="OAuthTools.cs" Line="292">In method 'OAuthTools.GetSignature(OAuthSignatureMethod, OAuthSignatureTreatment, string, string, string)', call System.IDisposable.Dispose on object 'crypto' before all references to it are out of scope.</Issue> |
Also available in: Unified diff