Statistics
| Branch: | Revision:

root / trunk / Pithos.Network / TreeHash.cs @ 1caef52e

History | View | Annotate | Download (4.8 kB)

1
using System;
2
using System.Collections.Generic;
3
using System.IO;
4
using System.Text;
5
using System.Threading.Tasks;
6
using Newtonsoft.Json;
7
using System.Linq;
8
using Newtonsoft.Json.Linq;
9

    
10
namespace Pithos.Network
11
{
12
    public class TreeHash
13
    {
14
        private const string DEFAULT_HASH_ALGORITHM = "sha256";
15
        private const int DEFAULT_BLOCK_SIZE = 4*1024*1024;
16
        public string BlockHash { get; set; }
17
        public int BlockSize { get; set; }
18
        public long Bytes { get; set; }
19

    
20
        public Guid FileId { get; set; }
21

    
22
        private readonly Lazy<byte[]> _topHash;        
23
        public byte[] TopHash
24
        {
25
            get { return _topHash.Value; }
26
        }
27
        private readonly Lazy<string> _topHash2;        
28
        public string TopHash2
29
        {
30
            get { return _topHash2.Value; }
31
        }
32

    
33
        private IEnumerable<byte[]> _hashes;
34
        public IEnumerable<byte[]> Hashes
35
        {
36
            get { return _hashes; }
37
            set
38
            {
39
                _hashes = value;
40
                _topHash.Force();
41
            }
42
        }
43

    
44
        public TreeHash(string algorithm)
45
        {
46
            BlockHash = algorithm;
47
            _topHash = new Lazy<byte[]>(() => Signature.CalculateTopHash(_hashes, BlockHash));
48

    
49
            _topHash2 = new Lazy<string>(() =>
50
                                             {
51
                                                 var hashString = _hashes.Select(hash => hash.ToHashString())
52
                                                     .Aggregate(new StringBuilder(),
53
                                                                (builder, hash) => builder.Append(hash),
54
                                                                builder => builder.ToString());
55

    
56
                                                 return Signature.CalculateTopHash(hashString, BlockHash);
57
                                             });
58
        }
59

    
60
        //Returns a Json representation of the hashes, as required by Pithos
61
        public string ToJson()
62
        {
63
            var value = new JObject();
64
            //We avoid using JObject's dynamic features because they use exceptions to detect new properties.
65
            value["block_hash"] = BlockHash;
66
            //Create a string array for all the hashes           
67
            
68
            string[] hashes=null ;
69
            if (Hashes!=null)
70
                hashes= Hashes.Select(hash=>hash.ToHashString()).ToArray();
71
            value["hashes"]= new JArray(hashes);
72
            value["block_size"] = BlockSize;
73
            value["bytes"] = Bytes;
74
            
75
            var json = JsonConvert.SerializeObject(value, Formatting.None);
76
            return json;
77
        }
78

    
79
        //Saves the Json representation to a file
80
        public Task Save(string filePath)
81
        {
82
            var fileName = FileId.ToString("N");
83
            var path = Path.Combine(filePath, fileName);
84
            if (!Directory.Exists(filePath))
85
                Directory.CreateDirectory(filePath);
86

    
87
            return Task.Factory
88
                .StartNew<string>(ToJson)
89
                .ContinueWith(jsonTask=> 
90
                FileAsync.WriteAllText(path, jsonTask.Result)).Unwrap();
91
        }
92

    
93
        public static Task<TreeHash> LoadTreeHash(string dataPath,Guid fileId)
94
        {
95
            var fileName = fileId.ToString("N");
96
            var path = Path.Combine(dataPath, fileName);
97
            return FileAsync.ReadAllText(path).ContinueWith(loadTask =>
98
            {
99
                var json = loadTask.Result;
100
                var treeHash = Parse(json);
101
                treeHash.FileId = fileId;
102
                return treeHash;
103
            });
104
        }
105

    
106
        public static TreeHash Empty = new TreeHash(DEFAULT_HASH_ALGORITHM)
107
        {
108
            BlockSize = DEFAULT_BLOCK_SIZE,
109
            Bytes = 0
110
        };
111

    
112
        //Parse a json string and return a TreeHash
113
        //Returns an empty TreeHash if the string is null or empty
114
        public static TreeHash Parse(string json)
115
        {
116
            if (String.IsNullOrWhiteSpace(json))
117
                return Empty;
118

    
119
            var value = JsonConvert.DeserializeObject<JObject>(json);
120

    
121
            var blockHash = (string) value["block_hash"];
122
            var size = value.Value<int>("block_size");
123
            var bytes = value.Value<long>("bytes");
124
            var hashes = value.Value<JArray>("hashes");
125
            var hashValues = from JToken token in hashes
126
                             select token.Value<string>().ToBytes();
127

    
128
            var treeHash = new TreeHash(blockHash)
129
                               {
130
                                   BlockSize = size,
131
                                   Hashes = hashValues,
132
                                   Bytes = bytes
133
                               };
134
            return treeHash;
135
        }
136
    }
137
}