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 |
} |