PageRenderTime 42ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/source/samples/ObviousCode.Interlace.BitTunnel/Knock/KnockServer/MountedFileCache.cs

https://bitbucket.org/VahidN/interlace
C# | 433 lines | 317 code | 113 blank | 3 comment | 52 complexity | 83bf10806bf800e62dc0654504592abd MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. using KnockServer.Events;
  7. using ObviousCode.Interlace.BitTunnelLibrary.File;
  8. using TelexplorerServer.Mounting;
  9. using ObviousCode.Interlace.BitTunnel.Connectivity;
  10. using ObviousCode.Interlace.BitTunnelLibrary.Events;
  11. using System.Threading;
  12. namespace KnockServer
  13. {
  14. public class MountedFileCache
  15. {
  16. public event EventHandler PromptRequested;
  17. public event EventHandler<MountDeletedEventArgs> FileMountDeleted;
  18. public event EventHandler<MountDeletedEventArgs> DirectoryMountDeleted;
  19. Dictionary<string, FileSystemWatcher> _watchers;
  20. Dictionary<string, List<string>> _relevantFiles;
  21. Dictionary<string, List<string>> _relevantDirectories;
  22. Dictionary<string, FileDescriptor> _cachedDescriptors;
  23. List<string> _cachedDirectories;
  24. string AllFilesTag = "all-files";
  25. private static MountedFileCache _cache;
  26. private MountedFileCache()
  27. {
  28. _watchers = new Dictionary<string, FileSystemWatcher>();
  29. _relevantDirectories = new Dictionary<string, List<string>>();
  30. _relevantFiles = new Dictionary<string, List<string>>();
  31. _cachedDescriptors = new Dictionary<string, FileDescriptor>();
  32. _cachedDirectories = new List<string>();
  33. }
  34. public static MountedFileCache Cache
  35. {
  36. get
  37. {
  38. if (_cache == null) _cache = new MountedFileCache();
  39. return _cache;
  40. }
  41. }
  42. public ClientInstance Client { private get; set; }
  43. public ServerInstance Server { private get; set; }
  44. public bool AddFile(FileDescriptor file)
  45. {
  46. return AddFile(file, false);
  47. }
  48. private bool AddFile(FileDescriptor file, bool force)
  49. {
  50. bool hashed = false;
  51. Exception hashException = null;
  52. int loops = 0;
  53. if (!force && (ContainsFile(file)))
  54. {
  55. Console.WriteLine("{0} already mounted. Ignoring.", file.FileFullName);
  56. return false;
  57. }
  58. //Hashing operations
  59. Console.WriteLine("Preparing \"{0}\"", file.FileFullName);
  60. file.HashGenerationCompleted += new EventHandler(delegate(object sender, EventArgs e)
  61. {
  62. hashed = true;
  63. });
  64. file.HashGenerationFailed += new EventHandler<ExceptionEventArgs>(delegate(object sender, ExceptionEventArgs e)
  65. {
  66. hashException = e.ThrownException;
  67. });
  68. file.GenerateHash();
  69. Console.Write("Hashing ..");
  70. while (!hashed && hashException == null)
  71. {
  72. if (loops++ % 10 == 0)
  73. {
  74. Console.Write(".");
  75. }
  76. Thread.Sleep(100);
  77. }
  78. Console.WriteLine();
  79. if (hashException != null)
  80. {
  81. Console.WriteLine(hashException.Message);
  82. Console.WriteLine("Unable to hash {0}. Ignoring", file.FileName);
  83. return false;
  84. }
  85. if(_cachedDescriptors.Count(d => d.Value.Hash == file.Hash) > 0)
  86. {
  87. Console.WriteLine("Identically hashed file already mounted. Ignoring.");
  88. return false;
  89. }
  90. //Caching operations
  91. EnsureRequiredWatcherExists(file.DirectoryName);
  92. EnsureRelevantFileListExists(file.DirectoryName);
  93. if (!_relevantFiles[file.DirectoryName].Contains(file.FileFullName))
  94. {
  95. _relevantFiles[file.DirectoryName].Add(file.FileFullName);
  96. }
  97. //mounting
  98. bool fileAvailable = false;
  99. EventHandler<FileListModificationEventArgs> handler = delegate(object sender, FileListModificationEventArgs e)
  100. {
  101. StringBuilder builder = new StringBuilder();
  102. foreach (FileModificationDescriptor item in e.Modifications)
  103. {
  104. if (item.Mode == FileModificationMode.New)
  105. {
  106. builder.AppendFormat("Available File: \"{0}\"{1}", item.FileFullName, Environment.NewLine);
  107. }
  108. }
  109. Console.Write(builder.ToString());
  110. _cachedDescriptors[e.Modifications[0].FileFullName] = e.Modifications[0].ToFileDescriptor();
  111. fileAvailable = true;
  112. };
  113. Client.FileListUpdateReceived += new EventHandler<FileListModificationEventArgs>(handler);
  114. Client.AddFiles(new FileDescriptor[] { file });
  115. DateTime then = DateTime.Now;
  116. while (!fileAvailable && ((TimeSpan)(DateTime.Now - then)).TotalSeconds < 30)
  117. {
  118. Thread.Sleep(100);
  119. }
  120. if (!fileAvailable)
  121. {
  122. ConsoleColor oldColour = Console.ForegroundColor;
  123. Console.ForegroundColor = ConsoleColor.Red;
  124. Console.WriteLine("File Add Request not responded after 30 seconds. Check network and consider restarting.");
  125. Console.WriteLine("Terminating request ...");
  126. Console.ForegroundColor = oldColour;
  127. return false;
  128. }
  129. Client.FileListUpdateReceived -= new EventHandler<FileListModificationEventArgs>(handler);
  130. return true;
  131. }
  132. public bool AddDirectory(DirectoryInfo directory)
  133. {
  134. if (directory.Parent != null)
  135. {
  136. EnsureRequiredWatcherExists(directory.Parent.FullName);
  137. EnsureRelevantDirectoryListExists(directory.Parent.FullName);
  138. if (!_relevantDirectories[directory.Parent.FullName].Contains(directory.FullName))//it shouldn't
  139. {
  140. _relevantDirectories[directory.Parent.FullName].Add(directory.FullName);
  141. }
  142. else throw new InvalidOperationException();
  143. _relevantDirectories[directory.Parent.FullName].Add(directory.FullName);
  144. }
  145. EnsureRelevantFileListExists(directory.FullName);
  146. foreach (FileInfo file in directory.GetFiles())
  147. {
  148. AddFile(FileDescriptor.Create(file, false));
  149. }
  150. _relevantFiles[directory.FullName].Insert(0, AllFilesTag);
  151. _cachedDirectories.Add(directory.FullName);
  152. return true;
  153. }
  154. public FileDescriptor GetFileDescriptor(string path)
  155. {
  156. return (_cachedDescriptors.ContainsKey(path)) ? _cachedDescriptors[path] : (FileDescriptor)null;
  157. }
  158. private void RenameFile(string oldFileName, string newFileName)
  159. {
  160. FileDescriptor descriptor = GetFileDescriptor(oldFileName);
  161. descriptor.FileFullName = newFileName;
  162. if (descriptor == null) return;
  163. bool fileRenamed = false;
  164. EventHandler<FileListModificationEventArgs> handler = delegate(object sender, FileListModificationEventArgs e)
  165. {
  166. StringBuilder builder = new StringBuilder();
  167. if (e.Modifications[0].Mode == FileModificationMode.Renamed)
  168. {
  169. Console.Write("Renamed File: \"{0}\"{1}", e.Modifications[0].FileFullName, Environment.NewLine);
  170. _cachedDescriptors.Remove(oldFileName);
  171. _cachedDescriptors[e.Modifications[0].FileFullName] = e.Modifications[0].ToFileDescriptor();
  172. fileRenamed = true;
  173. }
  174. };
  175. Client.FileListUpdateReceived += new EventHandler<FileListModificationEventArgs>(handler);
  176. Client.RenameFiles(new FileDescriptor[] { descriptor });
  177. DateTime then = DateTime.Now;
  178. while (!fileRenamed && ((TimeSpan)(DateTime.Now - then)).TotalSeconds < 30)
  179. {
  180. Thread.Sleep(100);
  181. }
  182. if (!fileRenamed)
  183. {
  184. ConsoleColor oldColour = Console.ForegroundColor;
  185. Console.ForegroundColor = ConsoleColor.Red;
  186. Console.WriteLine("File Rename Request not responded after 30 seconds. Check network and consider restarting.");
  187. Console.WriteLine("Terminating request ...");
  188. Console.ForegroundColor = oldColour;
  189. return;
  190. }
  191. Client.FileListUpdateReceived -= new EventHandler<FileListModificationEventArgs>(handler);
  192. }
  193. private void RemoveFile(string path)
  194. {
  195. FileDescriptor descriptor = GetFileDescriptor(path);
  196. if (descriptor == null) return;
  197. if (_relevantFiles[descriptor.DirectoryName].Contains(descriptor.FileFullName))//it should
  198. {
  199. _relevantFiles.Remove(path);
  200. }
  201. else throw new InvalidOperationException();
  202. if (_relevantFiles[descriptor.DirectoryName].Count == 0)
  203. {
  204. _relevantFiles.Remove(descriptor.DirectoryName);
  205. }
  206. FileDescriptor toRemove = GetFileDescriptor(path);
  207. _cachedDescriptors.Remove(path);
  208. bool fileRemoved = false;
  209. EventHandler<FileListModificationEventArgs> handler = delegate(object sender, FileListModificationEventArgs e)
  210. {
  211. StringBuilder builder = new StringBuilder();
  212. foreach (FileModificationDescriptor item in e.Modifications)
  213. {
  214. if (item.Mode == FileModificationMode.Remove)
  215. {
  216. builder.AppendFormat("Removed File: \"{0}\"{1}", item.FileFullName, Environment.NewLine);
  217. }
  218. }
  219. Console.Write(builder.ToString());
  220. _cachedDescriptors[e.Modifications[0].FileFullName] = e.Modifications[0].ToFileDescriptor();
  221. fileRemoved = true;
  222. };
  223. Client.FileListUpdateReceived += new EventHandler<FileListModificationEventArgs>(handler);
  224. Client.RemoveFiles(new FileDescriptor[] { toRemove });
  225. DateTime then = DateTime.Now;
  226. while (!fileRemoved && ((TimeSpan)(DateTime.Now - then)).TotalSeconds < 30)
  227. {
  228. Thread.Sleep(100);
  229. }
  230. if (!fileRemoved)
  231. {
  232. ConsoleColor oldColour = Console.ForegroundColor;
  233. Console.ForegroundColor = ConsoleColor.Red;
  234. Console.WriteLine("File Remove Request not responded after 30 seconds. Check network and consider restarting.");
  235. Console.WriteLine("Terminating request ...");
  236. Console.ForegroundColor = oldColour;
  237. return;
  238. }
  239. Client.FileListUpdateReceived -= new EventHandler<FileListModificationEventArgs>(handler);
  240. }
  241. private bool ContainsFile(FileDescriptor file)
  242. {
  243. if (_relevantFiles.ContainsKey(file.DirectoryName))
  244. {
  245. return (
  246. _relevantFiles[file.DirectoryName].Contains(AllFilesTag)
  247. || _relevantFiles[file.DirectoryName].Contains(file.FileFullName));
  248. }
  249. return false;
  250. }
  251. internal bool ContainsDirectory(string fullName)
  252. {
  253. return _cachedDirectories.Contains(fullName);
  254. }
  255. private void EnsureRelevantDirectoryListExists(string directoryName)
  256. {
  257. if (!_relevantDirectories.ContainsKey(directoryName))
  258. {
  259. _relevantDirectories[directoryName] = new List<string>();
  260. }
  261. }
  262. private void EnsureRelevantFileListExists(string directoryName)
  263. {
  264. if (!_relevantFiles.ContainsKey(directoryName))
  265. {
  266. _relevantFiles[directoryName] = new List<string>();
  267. }
  268. }
  269. private void EnsureRequiredWatcherExists(string watcherKey)
  270. {
  271. if (!_watchers.ContainsKey(watcherKey))
  272. {
  273. FileSystemWatcher watcher = new FileSystemWatcher(watcherKey);
  274. watcher.Created += new FileSystemEventHandler(FileSystemWatcher_ItemCreated);
  275. watcher.Deleted += new FileSystemEventHandler(FileSystemWatcher_ItemDeleted);
  276. watcher.Renamed += new RenamedEventHandler(FileSystemWatcher_ItemRenamed);
  277. watcher.EnableRaisingEvents = true;
  278. _watchers[watcherKey] = watcher;
  279. }
  280. }
  281. void FileSystemWatcher_ItemRenamed(object sender, RenamedEventArgs e)
  282. {
  283. RenameFile(e.OldFullPath, e.FullPath);
  284. if (PromptRequested != null)
  285. {
  286. PromptRequested(this, EventArgs.Empty);
  287. }
  288. }
  289. void FileSystemWatcher_ItemDeleted(object sender, FileSystemEventArgs e)
  290. {
  291. RemoveFile(e.FullPath);
  292. if (PromptRequested != null)
  293. {
  294. PromptRequested(this, EventArgs.Empty);
  295. }
  296. }
  297. void FileSystemWatcher_ItemCreated(object sender, FileSystemEventArgs e)
  298. {
  299. AddFile(FileDescriptor.Create(e.FullPath, false), true);
  300. if (PromptRequested != null)
  301. {
  302. PromptRequested(this, EventArgs.Empty);
  303. }
  304. }
  305. public int DirectoryCount
  306. {
  307. get
  308. {
  309. return _cachedDirectories.Count;
  310. }
  311. }
  312. public IEnumerable<string> DirectoryNames
  313. {
  314. get
  315. {
  316. return _cachedDirectories;
  317. }
  318. }
  319. }
  320. }