private void EncodeThread()
{
for (;;)
{
Thread.Sleep(1000 * 1);
if (this.EncodeState == ManagerState.Stop) return;
UploadItem item = null;
try
{
lock (_thisLock)
{
if (_settings.UploadItems.Count > 0)
{
item = _settings.UploadItems
.Where(n => n.State == UploadState.ComputeHash || n.State == UploadState.Encoding || n.State == UploadState.ParityEncoding)
.Where(n => n.Priority != 0)
.OrderBy(n => -n.Priority)
.Where(n => !_workingPaths.Contains(n.FilePath))
.FirstOrDefault();
if (item != null)
{
_workingPaths.Add(item.FilePath);
}
}
}
}
catch (Exception)
{
return;
}
if (item == null) continue;
try
{
if (item.Groups.Count == 0 && item.Keys.Count == 0)
{
if (item.Type == UploadType.Upload)
{
item.State = UploadState.Encoding;
KeyCollection keys = null;
byte[] cryptoKey = null;
try
{
using (var stream = new UnbufferedFileStream(item.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read, FileOptions.None, _bufferManager))
using (ProgressStream hashProgressStream = new ProgressStream(stream, (object sender, long readSize, long writeSize, out bool isStop) =>
{
isStop = (this.EncodeState == ManagerState.Stop || !_settings.UploadItems.Contains(item));
item.EncodeOffset = Math.Min(readSize, stream.Length);
}, 1024 * 1024, true))
using (ProgressStream encodingProgressStream = new ProgressStream(stream, (object sender, long readSize, long writeSize, out bool isStop) =>
{
isStop = (this.EncodeState == ManagerState.Stop || !_settings.UploadItems.Contains(item));
item.EncodeOffset = Math.Min(readSize, stream.Length);
}, 1024 * 1024, true))
{
if (stream.Length == 0) throw new InvalidOperationException("Stream Length");
item.Length = stream.Length;
item.EncodeLength = stream.Length;
item.State = UploadState.ComputeHash;
if (item.HashAlgorithm == HashAlgorithm.Sha256)
{
cryptoKey = Sha256.ComputeHash(hashProgressStream);
}
stream.Seek(0, SeekOrigin.Begin);
item.EncodeOffset = 0;
item.State = UploadState.Encoding;
keys = _cacheManager.Encoding(encodingProgressStream, item.CompressionAlgorithm, item.CryptoAlgorithm, cryptoKey, item.BlockLength, item.HashAlgorithm);
}
}
catch (StopIoException)
{
continue;
}
lock (_thisLock)
{
if (!_settings.UploadItems.Contains(item))
{
foreach (var key in keys)
{
_cacheManager.Unlock(key);
}
continue;
}
foreach (var key in keys)
{
item.UploadKeys.Add(key);
item.LockedKeys.Add(key);
}
item.EncodeOffset = 0;
item.EncodeLength = 0;
item.CryptoKey = cryptoKey;
item.Keys.AddRange(keys);
}
}
else if (item.Type == UploadType.Share)
{
item.State = UploadState.ComputeHash;
KeyCollection keys = null;
try
{
using (var stream = new UnbufferedFileStream(item.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read, FileOptions.None, _bufferManager))
using (ProgressStream hashProgressStream = new ProgressStream(stream, (object sender, long readSize, long writeSize, out bool isStop) =>
{
isStop = (this.EncodeState == ManagerState.Stop || !_settings.UploadItems.Contains(item));
item.EncodeOffset = Math.Min(readSize, stream.Length);
}, 1024 * 1024, true))
{
if (stream.Length == 0) throw new InvalidOperationException("Stream Length");
item.Length = stream.Length;
item.EncodeLength = stream.Length;
keys = _cacheManager.Share(hashProgressStream, stream.Name, item.HashAlgorithm, item.BlockLength);
}
}
catch (StopIoException)
{
continue;
}
if (keys.Count == 1)
{
lock (_thisLock)
{
if (!_settings.UploadItems.Contains(item))
{
foreach (var key in keys)
{
_cacheManager.Unlock(key);
}
continue;
}
item.EncodeOffset = 0;
item.EncodeLength = 0;
item.UploadKeys.Add(keys[0]);
item.Keys.Add(keys[0]);
item.State = UploadState.Encoding;
}
}
else
{
var groups = new List<Group>();
for (int i = 0, remain = keys.Count; 0 < remain; i++, remain -= 256)
{
var tempKeys = keys.GetRange(i * 256, Math.Min(remain, 256));
var group = new Group();
group.CorrectionAlgorithm = CorrectionAlgorithm.None;
group.InformationLength = tempKeys.Count;
group.BlockLength = item.BlockLength;
group.Length = tempKeys.Sum(n => (long)_cacheManager.GetLength(n));
group.Keys.AddRange(tempKeys);
groups.Add(group);
}
lock (_thisLock)
{
if (!_settings.UploadItems.Contains(item))
{
foreach (var key in keys)
{
_cacheManager.Unlock(key);
}
continue;
}
item.EncodeOffset = 0;
item.EncodeLength = 0;
foreach (var key in keys)
{
item.UploadKeys.Add(key);
}
item.Groups.AddRange(groups);
item.State = UploadState.Encoding;
}
}
}
}
else if (item.Groups.Count == 0 && item.Keys.Count == 1)
{
lock (_thisLock)
{
if (!_settings.UploadItems.Contains(item)) continue;
Metadata metadata = null;
{
if (item.Type == UploadType.Upload)
{
metadata = new Metadata(item.Depth, item.Keys[0], item.CompressionAlgorithm, item.CryptoAlgorithm, item.CryptoKey);
}
else if (item.Type == UploadType.Share)
{
if (item.Depth == 1)
{
metadata = new Metadata(item.Depth, item.Keys[0], CompressionAlgorithm.None, CryptoAlgorithm.None, null);
}
else
{
metadata = new Metadata(item.Depth, item.Keys[0], item.CompressionAlgorithm, item.CryptoAlgorithm, item.CryptoKey);
}
}
item.Keys.Clear();
}
item.Seed = new Seed(metadata);
item.Seed.Name = item.Name;
item.Seed.Length = item.Length;
item.Seed.CreationTime = item.CreationTime;
item.Seed.Keywords.AddRange(item.Keywords);
if (item.DigitalSignature != null)
{
item.Seed.CreateCertificate(item.DigitalSignature);
}
foreach (var key in item.UploadKeys)
{
_connectionsManager.Upload(key);
}
{
if (item.Type == UploadType.Upload)
{
_cacheManager.SetSeed(item.Seed.Clone(), item.RetainKeys.ToArray());
}
else if (item.Type == UploadType.Share)
{
_cacheManager.SetSeed(item.Seed.Clone(), item.FilePath, item.RetainKeys.ToArray());
}
item.RetainKeys.Clear();
}
foreach (var key in item.LockedKeys)
{
_cacheManager.Unlock(key);
}
item.LockedKeys.Clear();
item.State = UploadState.Uploading;
this.CheckState(item);
}
}
else if (item.Keys.Count > 0)
{
item.State = UploadState.ParityEncoding;
item.EncodeLength = item.Groups.Sum(n =>
{
long sumLength = 0;
for (int i = 0; i < n.InformationLength; i++)
{
if (_cacheManager.Contains(n.Keys[i]))
{
sumLength += (long)_cacheManager.GetLength(n.Keys[i]);
}
}
return sumLength;
}) + item.Keys.Sum(n =>
{
if (_cacheManager.Contains(n))
{
return (long)_cacheManager.GetLength(n);
}
return 0;
});
var length = Math.Min(item.Keys.Count, 128);
var keys = new KeyCollection(item.Keys.Take(length));
Group group = null;
try
{
using (var tokenSource = new CancellationTokenSource())
{
var task = _cacheManager.ParityEncoding(keys, item.HashAlgorithm, item.BlockLength, item.CorrectionAlgorithm, tokenSource.Token);
while (!task.IsCompleted)
{
if ((this.EncodeState == ManagerState.Stop || !_settings.UploadItems.Contains(item))) tokenSource.Cancel();
Thread.Sleep(1000);
}
group = task.Result;
}
}
catch (Exception)
{
continue;
}
lock (_thisLock)
{
if (!_settings.UploadItems.Contains(item))
{
foreach (var key in group.Keys.Skip(group.InformationLength))
{
_cacheManager.Unlock(key);
}
continue;
}
foreach (var key in group.Keys.Skip(group.InformationLength))
{
item.UploadKeys.Add(key);
item.LockedKeys.Add(key);
}
foreach (var key in group.Keys.Skip(group.Keys.Count - group.InformationLength))
{
item.RetainKeys.Add(key);
}
item.Groups.Add(group);
item.EncodeOffset = item.Groups.Sum(n =>
{
long sumLength = 0;
for (int i = 0; i < n.InformationLength; i++)
{
if (_cacheManager.Contains(n.Keys[i]))
{
sumLength += (long)_cacheManager.GetLength(n.Keys[i]);
}
}
return sumLength;
});
item.Keys.RemoveRange(0, length);
}
}
else if (item.Groups.Count > 0 && item.Keys.Count == 0)
{
item.State = UploadState.Encoding;
var index = new Index();
if (item.Type == UploadType.Upload)
{
index.Groups.AddRange(item.Groups);
index.CompressionAlgorithm = item.CompressionAlgorithm;
index.CryptoAlgorithm = item.CryptoAlgorithm;
index.CryptoKey = item.CryptoKey;
}
else if (item.Type == UploadType.Share)
{
index.Groups.AddRange(item.Groups);
if (item.Depth != 1)
{
index.CompressionAlgorithm = item.CompressionAlgorithm;
index.CryptoAlgorithm = item.CryptoAlgorithm;
index.CryptoKey = item.CryptoKey;
}
}
byte[] cryptoKey = null;
KeyCollection keys = null;
try
{
using (var stream = index.Export(_bufferManager))
using (ProgressStream hashProgressStream = new ProgressStream(stream, (object sender, long readSize, long writeSize, out bool isStop) =>
{
isStop = (this.EncodeState == ManagerState.Stop || !_settings.UploadItems.Contains(item));
item.EncodeOffset = Math.Min(readSize, stream.Length);
}, 1024 * 1024, true))
using (ProgressStream encodingProgressStream = new ProgressStream(stream, (object sender, long readSize, long writeSize, out bool isStop) =>
{
isStop = (this.EncodeState == ManagerState.Stop || !_settings.UploadItems.Contains(item));
item.EncodeOffset = Math.Min(readSize, stream.Length);
}, 1024 * 1024, true))
{
item.EncodeLength = stream.Length;
item.State = UploadState.ComputeHash;
if (item.HashAlgorithm == HashAlgorithm.Sha256)
{
cryptoKey = Sha256.ComputeHash(hashProgressStream);
}
stream.Seek(0, SeekOrigin.Begin);
item.EncodeOffset = 0;
item.State = UploadState.Encoding;
keys = _cacheManager.Encoding(encodingProgressStream, item.CompressionAlgorithm, item.CryptoAlgorithm, cryptoKey, item.BlockLength, item.HashAlgorithm);
}
}
catch (StopIoException)
{
continue;
}
lock (_thisLock)
{
if (!_settings.UploadItems.Contains(item))
{
foreach (var key in keys)
{
_cacheManager.Unlock(key);
}
continue;
}
foreach (var key in keys)
{
item.UploadKeys.Add(key);
item.LockedKeys.Add(key);
}
item.EncodeOffset = 0;
item.EncodeLength = 0;
item.CryptoKey = cryptoKey;
item.Keys.AddRange(keys);
item.Depth++;
item.Groups.Clear();
}
}
}
catch (Exception e)
{
item.State = UploadState.Error;
Log.Error(e);
}
finally
{
_workingPaths.Remove(item.FilePath);
}
}
}