1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Security.Cryptography;
using Monodoc;
namespace macdoc
{
public class IndexUpdateManager
{
readonly string baseUserDir; // This is e.g. .config/MonoDoc, a user-specific place where we can write stuff
readonly IEnumerable<string> sourceFiles; // this is $prefix/monodoc/sources folder
Dictionary<string, string> md5sums;
const string sumFile = "index_freshness";
public event EventHandler UpdaterChange;
public IndexUpdateManager (IEnumerable<string> sourceFiles, string baseUserDir)
{
Console.WriteLine ("Going to verify [{0}]", sourceFiles.Aggregate ((e1, e2) => e1 + ", " + e2));
this.baseUserDir = baseUserDir;
this.sourceFiles = sourceFiles;
}
public Task<bool> CheckIndexIsFresh ()
{
return Task.Factory.StartNew (() => {
var path = Path.Combine (baseUserDir, sumFile);
// Two cases can trigger index creation/re-creation:
// 1- there is no search_index folder or no monodoc.index file (i.e. GetIndex or GetSearchIndex returns null)
// 2- one of the doc source we use is stale
if (AppDelegate.Root.GetIndex () == null || AppDelegate.Root.GetSearchIndex () == null) {
// force stale state
md5sums = new Dictionary<string, string> ();
} else {
if (File.Exists (path)) {
try {
md5sums = DeserializeDictionary (path);
} catch {}
}
if (md5sums == null)
md5sums = new Dictionary<string, string> ();
}
bool isFresh = true;
HashAlgorithm hasher = MD5.Create ();
foreach (var source in sourceFiles) {
var hash = StringHash (hasher, File.OpenRead (source));
string originalHash;
if (md5sums.TryGetValue (source, out originalHash))
isFresh &= originalHash.Equals (hash, StringComparison.OrdinalIgnoreCase);
else
isFresh = false;
md5sums[source] = hash;
}
Console.WriteLine ("We have a {0} fresh index", isFresh);
return IsFresh = isFresh;
});
}
string StringHash (HashAlgorithm hasher, Stream stream)
{
return hasher.ComputeHash (stream).Select (b => String.Format("{0:X2}", b)).Aggregate (string.Concat);
}
Dictionary<string, string> DeserializeDictionary (string path)
{
if (!File.Exists (path))
return new Dictionary<string, string> ();
return File.ReadAllLines (path)
.Where (l => !string.IsNullOrEmpty (l) && l[0] != '#') // Take non-empty, non-comment lines
.Select (l => l.Split ('='))
.Where (a => a != null && a.Length == 2)
.ToDictionary (t => t[0].Trim (), t => t[1].Trim ());
}
void SerializeDictionary (string path, Dictionary<string, string> dict)
{
File.WriteAllLines (path, dict.Select (kvp => string.Format ("{0} = {1}", kvp.Key, kvp.Value)));
}
public void PerformSearchIndexCreation ()
{
FireSearchIndexCreationEvent (true);
RootTree.MakeSearchIndex ();
RootTree.MakeIndex ();
IsFresh = true;
FireSearchIndexCreationEvent (false);
if (md5sums != null)
SerializeDictionary (Path.Combine (baseUserDir, sumFile), md5sums);
}
public void AdvertiseFreshIndex ()
{
FireSearchIndexCreationEvent (false);
}
void FireSearchIndexCreationEvent (bool status)
{
IsCreatingSearchIndex = status;
Thread.MemoryBarrier ();
var evt = UpdaterChange;
if (evt != null)
evt (this, EventArgs.Empty);
}
public bool IsCreatingSearchIndex {
get;
set;
}
public bool IsFresh {
get;
set;
}
}
}
|