using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using System.Linq; using Newtonsoft.Json.Linq; namespace Pithos.Network { public class TreeHash { private const string DEFAULT_HASH_ALGORITHM = "sha256"; private const int DEFAULT_BLOCK_SIZE = 4*1024*1024; public string BlockHash { get; set; } public int BlockSize { get; set; } public long Bytes { get; set; } public Guid FileId { get; set; } private readonly Lazy _topHash; public byte[] TopHash { get { return _topHash.Value; } } private readonly Lazy _topHash2; public string TopHash2 { get { return _topHash2.Value; } } private IEnumerable _hashes; public IEnumerable Hashes { get { return _hashes; } set { _hashes = value; _topHash.Force(); } } public TreeHash(string algorithm) { BlockHash = algorithm; _topHash = new Lazy(() => { // //Cast the hashes to an IList or create a new list out of the hashes var hashMap = (_hashes as IList)??_hashes.ToList(); return Signature.CalculateTopHash(hashMap, BlockHash); }); } //Returns a Json representation of the hashes, as required by Pithos public string ToJson() { var value = new JObject(); //We avoid using JObject's dynamic features because they use exceptions to detect new properties. value["block_hash"] = BlockHash; //Create a string array for all the hashes string[] hashes=null ; if (Hashes!=null) hashes= Hashes.Select(hash=>hash.ToHashString()).ToArray(); value["hashes"]= new JArray(hashes); value["block_size"] = BlockSize; value["bytes"] = Bytes; var json = JsonConvert.SerializeObject(value, Formatting.None); return json; } //Saves the Json representation to a file public Task Save(string filePath) { var fileName = FileId.ToString("N"); var path = Path.Combine(filePath, fileName); if (!Directory.Exists(filePath)) Directory.CreateDirectory(filePath); return Task.Factory .StartNew(ToJson) .ContinueWith(jsonTask=> FileAsync.WriteAllText(path, jsonTask.Result)).Unwrap(); } public static Task LoadTreeHash(string dataPath,Guid fileId) { var fileName = fileId.ToString("N"); var path = Path.Combine(dataPath, fileName); return FileAsync.ReadAllText(path).ContinueWith(loadTask => { var json = loadTask.Result; var treeHash = Parse(json); treeHash.FileId = fileId; return treeHash; }); } public static TreeHash Empty = new TreeHash(DEFAULT_HASH_ALGORITHM) { BlockSize = DEFAULT_BLOCK_SIZE, Bytes = 0 }; //Parse a json string and return a TreeHash //Returns an empty TreeHash if the string is null or empty public static TreeHash Parse(string json) { if (String.IsNullOrWhiteSpace(json)) return Empty; var value = JsonConvert.DeserializeObject(json); var blockHash = (string) value["block_hash"]; var size = value.Value("block_size"); var bytes = value.Value("bytes"); var hashes = value.Value("hashes"); var hashValues = from JToken token in hashes select token.Value().ToBytes(); var treeHash = new TreeHash(blockHash) { BlockSize = size, Hashes = hashValues, Bytes = bytes }; return treeHash; } } }