+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Dataflow;
+
+namespace Pithos.Network
+{
+ class MD5BlockCalculator:IDisposable
+ {
+ private HashAlgorithm _hasher = HashAlgorithm.Create("md5");
+
+ private ActionBlock<Tuple<long, byte[],int>> _actionBlock;
+
+ private long _currentBlock = 0;
+
+ public MD5BlockCalculator()
+ {
+ _actionBlock=new ActionBlock<Tuple<long, byte[],int>>(t=> ProcessBlock(t));
+ }
+
+ private void ProcessBlock(Tuple<long,byte[],int> tuple)
+ {
+ if (tuple.Item1 == _currentBlock)
+ {
+ _hasher.TransformBlock(tuple.Item2, 0, tuple.Item3, null, 0);
+ Interlocked.Increment(ref _currentBlock);
+ }
+ else
+ {
+ _actionBlock.Post(tuple);
+ }
+ }
+
+ public void PostBlock(long blockIndex,byte[] buffer,int size)
+ {
+ _actionBlock.Post(Tuple.Create(blockIndex, buffer, size));
+ }
+
+ public async Task<string> GetHash()
+ {
+ _actionBlock.Complete();
+ await _actionBlock.Completion;
+ Debug.Assert(_actionBlock.InputCount == 0);
+ _hasher.TransformFinalBlock(new byte[0], 0, 0);
+ var hash=_hasher.Hash.ToHashString();
+ return hash;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing && _hasher!=null)
+ _hasher.Dispose();
+ _hasher = null;
+ }
+ }
+}