Horizon

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ HEAD  →  ?path2? @ 1
/Horizon/Snapshots/SnapshotManagerForm.cs
@@ -6,11 +6,8 @@
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@@ -17,13 +14,7 @@
using Horizon.Database;
using Horizon.Utilities;
using Microsoft.WindowsAPICodePack.Dialogs;
using Mono.Zeroconf;
using Mono.Zeroconf.Providers.Bonjour;
using Newtonsoft.Json;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Utilities.Net;
using Serilog;
using WatsonTcp;
 
namespace Horizon.Snapshots
{
@@ -35,6 +26,12 @@
 
#endregion
 
#region Public Events & Delegates
 
public event EventHandler<PreviewRetrievedEventArgs> PreviewRetrieved;
 
#endregion
 
#region Private Delegates, Events, Enums, Properties, Indexers and Fields
 
private readonly MainForm _mainForm;
@@ -43,7 +40,7 @@
 
private HexViewForm _hexViewForm;
 
private SnapshotNoteForm _snapshotNoteForm;
private SnapshotNoteForm _snapshotNote;
 
private SnapshotPreviewForm _snapshotPreviewForm;
 
@@ -57,19 +54,14 @@
 
private readonly CancellationToken _localCancellationToken;
 
private readonly Mono.Zeroconf.ServiceBrowser _horizonServiceBrowser;
 
private IResolvableService _resolvedService;
 
private readonly ConcurrentDictionary<string, Service> _discoveredHorizonNetworkShares;
 
#endregion
 
#region Constructors, Destructors and Finalizers
 
private SnapshotManagerForm()
public SnapshotManagerForm()
{
InitializeComponent();
Utilities.WindowState.FormTracker.Track(this);
 
dataGridView1.Columns["TimeColumn"].ValueType = typeof(DateTime);
 
@@ -77,10 +69,6 @@
 
_localCancellationTokenSource = new CancellationTokenSource();
_localCancellationToken = _localCancellationTokenSource.Token;
 
_discoveredHorizonNetworkShares = new ConcurrentDictionary<string, Service>();
_horizonServiceBrowser = new Mono.Zeroconf.ServiceBrowser();
_horizonServiceBrowser.ServiceAdded += OnHorizonServiceBrowserOnServiceAdded;
}
 
public SnapshotManagerForm(MainForm mainForm, SnapshotDatabase snapshotDatabase,
@@ -89,7 +77,6 @@
_mainForm = mainForm;
_snapshotDatabase = snapshotDatabase;
_snapshotDatabase.SnapshotCreate += SnapshotManager_SnapshotCreate;
_snapshotDatabase.SnapshotTransferReceived += _snapshotDatabase_SnapshotTransferReceived;
 
_cancellationTokenSource =
CancellationTokenSource.CreateLinkedTokenSource(_cancellationToken, cancellationToken);
@@ -108,10 +95,7 @@
}
 
_snapshotDatabase.SnapshotCreate -= SnapshotManager_SnapshotCreate;
_snapshotDatabase.SnapshotTransferReceived -= _snapshotDatabase_SnapshotTransferReceived;
 
_horizonServiceBrowser.ServiceAdded -= OnHorizonServiceBrowserOnServiceAdded;
_horizonServiceBrowser.Dispose();
_localCancellationTokenSource.Cancel();
 
base.Dispose(disposing);
@@ -120,14 +104,6 @@
#endregion
 
#region Event Handlers
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
}
 
private void contextMenuStrip1_Opened(object sender, EventArgs e)
{
}
 
private void DataGridView1_MouseDown(object sender, MouseEventArgs e)
{
var dataGridView = (DataGridView)sender;
@@ -234,9 +210,9 @@
}
});
 
await Task.Run(() => RetrieveFileStream(rows, progress, _cancellationToken), _cancellationToken);
await Task.Run(() => RetriveFileStream(rows, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -255,7 +231,7 @@
}
}
 
private async Task RetrieveFileStream(IReadOnlyList<DataGridViewRow> rows,
private async Task RetriveFileStream(IReadOnlyList<DataGridViewRow> rows,
IProgress<DataGridViewRowProgress> progress,
CancellationToken cancellationToken)
{
@@ -265,10 +241,10 @@
{
try
{
var hash = (string)rows[i].Cells["HashColumn"].Value;
var fileStream = await _snapshotDatabase.RetrieveFileStream(
(string)rows[i].Cells["HashColumn"].Value,
cancellationToken);
 
var fileStream = await _snapshotDatabase.RetrieveFileStreamAsync(hash, cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccessRetrieveFileStream(rows[i], i, fileStream));
}
catch (Exception exception)
@@ -280,7 +256,7 @@
 
private void SnapshotManagerForm_Resize(object sender, EventArgs e)
{
if (_snapshotPreviewForm is { Visible: true })
if (_snapshotPreviewForm != null)
{
_snapshotPreviewForm.WindowState = WindowState;
}
@@ -297,10 +273,18 @@
Process.Start("explorer.exe", $"/select, \"{(string)row.Cells["PathColumn"].Value}\"");
}
 
private void DataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
private async void DataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
var dataGridView = (DataGridView)sender;
 
if (_snapshotPreviewForm == null)
{
_snapshotPreviewForm = new SnapshotPreviewForm(this, _snapshotDatabase);
_snapshotPreviewForm.Owner = this;
_snapshotPreviewForm.Closing += SnapshotPreviewForm_Closing;
_snapshotPreviewForm.Show();
}
 
var row = GetSelectedDataGridViewRows(dataGridView).FirstOrDefault();
if (row == null)
{
@@ -309,26 +293,27 @@
 
var hash = (string)row.Cells["HashColumn"].Value;
 
if (_snapshotPreviewForm is { Visible: true })
var snapshotPreview =
await Task.Run(async () => await _snapshotDatabase.RetrievePreview(hash, _cancellationToken),
_cancellationToken);
 
if (snapshotPreview == null)
{
_snapshotPreviewForm.Close();
return;
}
 
_snapshotPreviewForm = new SnapshotPreviewForm(this, hash, _snapshotDatabase, _cancellationToken);
_snapshotPreviewForm.Owner = this;
_snapshotPreviewForm.Closing += SnapshotPreviewForm_Closing;
_snapshotPreviewForm.Show();
PreviewRetrieved?.Invoke(this, new PreviewRetrievedEventArgs(snapshotPreview));
}
 
private void SnapshotPreviewForm_Closing(object sender, CancelEventArgs e)
{
if (_snapshotPreviewForm is { Visible: false })
if (_snapshotPreviewForm == null)
{
return;
}
 
_snapshotPreviewForm.Closing -= SnapshotPreviewForm_Closing;
_snapshotPreviewForm.Dispose();
_snapshotPreviewForm = null;
}
 
private async void NoneToolStripMenuItem_Click(object sender, EventArgs e)
@@ -366,7 +351,7 @@
 
await Task.Run(() => RemoveColorFiles(rows, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -411,7 +396,7 @@
 
await Task.Run(() => ColorFiles(rows, color, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -458,7 +443,7 @@
 
await Task.Run(() => DeleteFiles(rows, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -500,7 +485,6 @@
dataGridView.Rows[index].Cells["HashColumn"].Value = snapshotCreateSuccessEventArgs.Hash;
dataGridView.Rows[index].DefaultCellStyle.BackColor = snapshotCreateSuccessEventArgs.Color;
 
dataGridView.Rows[index].Selected = true;
dataGridView.Sort(dataGridView.Columns["TimeColumn"], ListSortDirection.Descending);
});
break;
@@ -510,33 +494,6 @@
}
}
 
 
private void _snapshotDatabase_SnapshotTransferReceived(object sender, SnapshotCreateEventArgs e)
{
switch (e)
{
case SnapshotCreateSuccessEventArgs snapshotCreateSuccessEventArgs:
dataGridView1.InvokeIfRequired(dataGridView =>
{
var index = dataGridView.Rows.Add();
 
dataGridView.Rows[index].Cells["TimeColumn"].Value =
DateTime.Parse(snapshotCreateSuccessEventArgs.Time);
dataGridView.Rows[index].Cells["NameColumn"].Value = snapshotCreateSuccessEventArgs.Name;
dataGridView.Rows[index].Cells["PathColumn"].Value = snapshotCreateSuccessEventArgs.Path;
dataGridView.Rows[index].Cells["HashColumn"].Value = snapshotCreateSuccessEventArgs.Hash;
dataGridView.Rows[index].DefaultCellStyle.BackColor = snapshotCreateSuccessEventArgs.Color;
 
dataGridView.Rows[index].Selected = true;
dataGridView.Sort(dataGridView.Columns["TimeColumn"], ListSortDirection.Descending);
});
break;
case SnapshotCreateFailureEventArgs snapshotCreateFailure:
Log.Warning(snapshotCreateFailure.Exception, "Could not create snapshot.");
break;
}
}
 
private void RevertToThisToolStripMenuItem_Click(object sender, EventArgs e)
{
_mainForm.InvokeIfRequired(async form =>
@@ -602,7 +559,7 @@
 
await Task.Run(() => RevertFile(rows, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -631,45 +588,25 @@
 
private async void SnapshotManagerForm_Load(object sender, EventArgs e)
{
// Start browsing for network services.
_horizonServiceBrowser.Browse("_horizon._tcp", "local");
 
int count;
try
{
count = (int)await _snapshotDatabase.CountSnapshotsAsync(_cancellationToken);
}
catch (Exception exception)
{
Log.Error(exception, "Could not count snapshots.");
return;
}
 
if (count == 0)
{
return;
}
 
// Load snapshots.
toolStripProgressBar1.Minimum = 0;
toolStripProgressBar1.Maximum = count;
toolStripProgressBar1.Maximum = (int)await _snapshotDatabase.CountSnapshots(_cancellationToken);
 
var snapshotQueue = new ConcurrentQueue<Snapshot>();
var snapshotsQueuedTaskCompletionSource = new TaskCompletionSource<object>();
 
void IdleHandler(object idleHandlerSender, EventArgs idleHandlerArgs)
async void IdleHandler(object idleHandlerSender, EventArgs idleHandlerArgs)
{
await snapshotsQueuedTaskCompletionSource.Task;
 
try
{
if (snapshotQueue.IsEmpty)
if (!snapshotQueue.TryDequeue(out var snapshot))
{
Application.Idle -= IdleHandler;
 
dataGridView1.Sort(dataGridView1.Columns["TimeColumn"], ListSortDirection.Descending);
toolStripStatusLabel1.Text = "Done.";
}
 
if (!snapshotQueue.TryDequeue(out var snapshot))
{
return;
}
 
@@ -692,15 +629,16 @@
Log.Error(exception, "Could not update data grid view.");
}
}
 
Application.Idle += IdleHandler;
try
{
await foreach (var snapshot in _snapshotDatabase.LoadSnapshotsAsync(_cancellationToken).WithCancellation(_cancellationToken))
foreach (var snapshot in await _snapshotDatabase.LoadSnapshots(_cancellationToken))
{
snapshotQueue.Enqueue(snapshot);
}
 
Application.Idle += IdleHandler;
snapshotsQueuedTaskCompletionSource.TrySetResult(new { });
}
catch (Exception exception)
{
@@ -710,96 +648,20 @@
}
}
 
private void OnHorizonServiceBrowserOnServiceAdded(object o, Mono.Zeroconf.ServiceBrowseEventArgs args)
{
_resolvedService = args.Service;
 
Log.Information("Found Service: {0}", _resolvedService.Name);
 
_resolvedService.Resolved += OnServiceOnResolved;
 
_resolvedService.Resolve();
 
_resolvedService.Resolved -= OnServiceOnResolved;
}
 
private void OnServiceOnResolved(object o, ServiceResolvedEventArgs args)
{
var service = (Service) args.Service;
 
Log.Information("Resolved Service: {0} - {1}:{2} ({3} TXT record entries)", service.FullName, service.HostEntry.AddressList[0], service.UPort, service.TxtRecord.Count);
 
// Do not add discovered services more than once.
if (!_discoveredHorizonNetworkShares.TryAdd(service.Name, service))
{
return;
}
var discoveredServiceMenuItem = new ToolStripMenuItem(service.Name, null, OnShareWithNodeClicked);
discoveredServiceMenuItem.Tag = service;
 
this.InvokeIfRequired(form =>
{
form.shareToToolStripMenuItem.DropDownItems.Add(discoveredServiceMenuItem);
});
}
 
private async void OnShareWithNodeClicked(object sender, EventArgs e)
{
var toolStripMenuItem = (ToolStripMenuItem)sender;
 
var service = (Service)toolStripMenuItem.Tag;
 
var rows = GetSelectedDataGridViewRows(dataGridView1);
 
var count = rows.Count;
 
toolStripProgressBar1.Minimum = 0;
toolStripProgressBar1.Maximum = count;
 
var progress = new Progress<DataGridViewRowProgress>(rowProgress =>
{
if (rowProgress is DataGridViewRowProgressFailure rowProgressFailure)
{
Log.Error(rowProgressFailure.Exception, "Unable to transfer data.");
 
toolStripStatusLabel1.Text =
$"Could not transfer {rowProgress.Row.Cells["NameColumn"].Value}...";
toolStripProgressBar1.Value = rowProgress.Index + 1;
 
statusStrip1.Update();
 
return;
}
 
toolStripStatusLabel1.Text =
$"Transferred {rowProgress.Row.Cells["NameColumn"].Value}...";
toolStripProgressBar1.Value = rowProgress.Index + 1;
 
statusStrip1.Update();
});
 
await Task.Run(() => TransferFiles(rows, service, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
}
}
 
private void SnapshotManagerForm_Closing(object sender, FormClosingEventArgs e)
{
_cancellationTokenSource.Cancel();
 
if (_snapshotPreviewForm is { Visible: true })
if (_snapshotPreviewForm != null)
{
_snapshotPreviewForm.Close();
_snapshotPreviewForm = null;
}
 
if (_hexViewForm is { Visible: true })
if (_hexViewForm != null)
{
_hexViewForm.Close();
_hexViewForm = null;
}
}
 
@@ -814,20 +676,31 @@
e.Effect = DragDropEffects.None;
}
 
private void CreateSnapshots(IReadOnlyList<string> files, Bitmap screenCapture, TrackedFolders.TrackedFolders trackedFolders, IProgress<CreateSnapshotProgress> progress, CancellationToken cancellationToken)
private async void DataGridView1_DragDrop(object sender, DragEventArgs e)
{
Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = 512 }, async file =>
if (!e.Data.GetDataPresent(DataFormats.FileDrop))
{
return;
}
 
var files = (string[])e.Data.GetData(DataFormats.FileDrop);
 
toolStripProgressBar1.Minimum = 0;
toolStripProgressBar1.Maximum = files.Length;
toolStripStatusLabel1.Text = "Snapshotting files...";
 
var screenCapture = ScreenCapture.Capture((CaptureMode)_mainForm.Configuration.CaptureMode);
for (var i = 0; i < files.Length; ++i)
{
var color = Color.Empty;
if (_mainForm.TrackedFolders.TryGet(file, out var folder))
if (_mainForm.TrackedFolders.TryGet(files[i], out var folder))
{
color = folder.Color;
}
 
var fileInfo = File.GetAttributes(file);
if (fileInfo.HasFlag(FileAttributes.Directory))
if (Directory.Exists(files[i]))
{
foreach (var directoryFile in Directory.GetFiles(file, "*.*", SearchOption.AllDirectories))
foreach (var directoryFile in Directory.GetFiles(files[i], "*.*", SearchOption.AllDirectories))
{
var name = Path.GetFileName(directoryFile);
var path = Path.Combine(Path.GetDirectoryName(directoryFile), name);
@@ -834,78 +707,61 @@
 
try
{
await _snapshotDatabase.CreateSnapshotAsync(name, path, screenCapture, color, _cancellationToken);
await _snapshotDatabase.CreateSnapshot(name, path, screenCapture, color,
_cancellationToken);
 
progress.Report(new CreateSnapshotProgressSuccess(file));
toolStripProgressBar1.Value = i + 1;
toolStripStatusLabel1.Text = $"Snapshot taken of {files[i]}.";
statusStrip1.Update();
}
catch (SQLiteException exception)
{
if (exception.ResultCode == SQLiteErrorCode.Constraint)
{
Log.Information(exception, "Snapshot already exists.");
 
toolStripProgressBar1.Value = i + 1;
toolStripStatusLabel1.Text = "Snapshot already exists.";
statusStrip1.Update();
}
}
catch (Exception exception)
{
progress.Report(new CreateSnapshotProgressFailure(file, exception));
Log.Warning(exception, "Could not create snapshot.");
}
}
 
return;
continue;
}
 
var fileName = Path.GetFileName(file);
var fileName = Path.GetFileName(files[i]);
var pathName = Path.Combine(Path.GetDirectoryName(files[i]), fileName);
 
var pathName = Path.Combine(Path.GetDirectoryName(file), fileName);
 
try
{
await _snapshotDatabase.CreateSnapshotAsync(fileName, pathName, screenCapture, color,
await _snapshotDatabase.CreateSnapshot(fileName, pathName, screenCapture, color,
_cancellationToken);
 
progress.Report(new CreateSnapshotProgressSuccess(file));
toolStripProgressBar1.Value = i + 1;
toolStripStatusLabel1.Text = $"Snapshot taken of {files[i]}.";
statusStrip1.Update();
}
catch (SQLiteException exception)
{
if (exception.ResultCode == SQLiteErrorCode.Constraint)
{
Log.Information(exception, "Snapshot already exists.");
 
toolStripProgressBar1.Value = i + 1;
toolStripStatusLabel1.Text = "Snapshot already exists.";
statusStrip1.Update();
}
}
catch (Exception exception)
{
progress.Report(new CreateSnapshotProgressFailure(file, exception));
Log.Warning(exception, "Could not create snapshot");
}
});
}
private async void DataGridView1_DragDrop(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent(DataFormats.FileDrop))
{
return;
}
 
var files = (string[])e.Data.GetData(DataFormats.FileDrop);
 
toolStripProgressBar1.Minimum = 0;
toolStripProgressBar1.Maximum = files.Length;
toolStripStatusLabel1.Text = "Snapshotting files...";
 
var screenCapture = ScreenCapture.Capture((CaptureMode)_mainForm.Configuration.CaptureMode);
 
var progress = new Progress<CreateSnapshotProgress>(createSnapshotProgress =>
{
switch (createSnapshotProgress)
{
case CreateSnapshotProgressSuccess createSnapshotProgressSuccess:
toolStripStatusLabel1.Text = $"Snapshot taken of {createSnapshotProgressSuccess.File}.";
break;
case CreateSnapshotProgressFailure createSnapshotProgressFailure:
if (createSnapshotProgressFailure.Exception is SQLiteException { ResultCode: SQLiteErrorCode.Constraint })
{
toolStripStatusLabel1.Text = $"Snapshot of file {createSnapshotProgressFailure.File} already exists.";
break;
}
 
toolStripStatusLabel1.Text = $"Could not snapshot file {createSnapshotProgressFailure.File}";
Log.Warning(createSnapshotProgressFailure.Exception, $"Could not snapshot file {createSnapshotProgressFailure.File}");
break;
}
 
toolStripProgressBar1.Increment(1);
statusStrip1.Update();
});
 
await Task.Factory.StartNew( () =>
{
CreateSnapshots(files, screenCapture, _mainForm.TrackedFolders, progress, _cancellationToken);
}, _cancellationToken);
}
 
private async void FileToolStripMenuItem_Click(object sender, EventArgs e)
@@ -927,7 +783,7 @@
 
try
{
await _snapshotDatabase.CreateSnapshotAsync(fileName, pathName, screenCapture, color,
await _snapshotDatabase.CreateSnapshot(fileName, pathName, screenCapture, color,
_cancellationToken);
}
catch (SQLiteException exception)
@@ -964,7 +820,7 @@
 
try
{
await _snapshotDatabase.CreateSnapshotAsync(name, path, screenCapture, color, _cancellationToken);
await _snapshotDatabase.CreateSnapshot(name, path, screenCapture, color, _cancellationToken);
}
catch (SQLiteException exception)
{
@@ -1036,7 +892,7 @@
 
await Task.Run(() => RelocateFiles(rows, directory, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -1043,8 +899,13 @@
}
}
 
private void NoteToolStripMenuItem_Click(object sender, EventArgs e)
private async void NoteToolStripMenuItem_Click(object sender, EventArgs e)
{
if (_snapshotNote != null)
{
return;
}
 
var row = GetSelectedDataGridViewRows(dataGridView1).FirstOrDefault();
if (row == null)
{
@@ -1051,21 +912,29 @@
return;
}
 
var hash = (string)row.Cells["HashColumn"].Value;
try
{
var snapshotPreview = await _snapshotDatabase.RetrievePreview(
(string)row.Cells["HashColumn"].Value, _cancellationToken);
 
if (_snapshotNoteForm is { Visible: true })
if (snapshotPreview == null)
{
return;
}
 
_snapshotNote = new SnapshotNoteForm(this, snapshotPreview);
_snapshotNote.Owner = this;
_snapshotNote.SaveNote += SnapshotNote_SaveNote;
_snapshotNote.Closing += SnapshotNote_Closing;
_snapshotNote.Show();
}
catch (Exception exception)
{
_snapshotNoteForm.Close();
Log.Error(exception, "Could not open notes form.");
}
 
_snapshotNoteForm = new SnapshotNoteForm(hash, _snapshotDatabase, _cancellationToken);
_snapshotNoteForm.Owner = this;
_snapshotNoteForm.SaveNote += SnapshotNoteFormSaveNoteForm;
_snapshotNoteForm.Closing += SnapshotNoteForm_Closing;
_snapshotNoteForm.Show();
}
 
private async void SnapshotNoteFormSaveNoteForm(object sender, SaveNoteEventArgs e)
private async void SnapshotNote_SaveNote(object sender, SaveNoteEventArgs e)
{
var rows = GetSelectedDataGridViewRows(dataGridView1);
 
@@ -1098,7 +967,7 @@
 
await Task.Run(() => UpdateNote(rows, e.Note, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -1105,19 +974,19 @@
}
}
 
private void SnapshotNoteForm_Closing(object sender, CancelEventArgs e)
private void SnapshotNote_Closing(object sender, CancelEventArgs e)
{
if (_snapshotNoteForm is { Visible: false })
if (_snapshotNote == null)
{
return;
}
 
_snapshotNoteForm.SaveNote -= SnapshotNoteFormSaveNoteForm;
_snapshotNoteForm.Closing -= SnapshotNoteForm_Closing;
_snapshotNoteForm.Dispose();
_snapshotNote.Closing -= SnapshotNote_Closing;
_snapshotNote.Close();
_snapshotNote = null;
}
 
private void ViewHexToolStripMenuItem_Click(object sender, EventArgs e)
private async void ViewHexToolStripMenuItem_Click(object sender, EventArgs e)
{
var rows = GetSelectedDataGridViewRows(dataGridView1);
var row = rows.FirstOrDefault();
@@ -1128,32 +997,33 @@
 
var hash = (string)row.Cells["HashColumn"].Value;
 
if (_hexViewForm is { Visible: true })
using (var memoryStream = await _snapshotDatabase.RetrieveFileStream(hash, _cancellationToken))
{
_hexViewForm.Close();
if (memoryStream == null)
{
return;
}
 
if (_hexViewForm != null)
{
_hexViewForm.UpdateData(memoryStream.ToArray());
_hexViewForm.Activate();
return;
}
 
_hexViewForm = new HexViewForm(_snapshotDatabase, hash, memoryStream.ToArray());
_hexViewForm.Owner = this;
_hexViewForm.Closing += HexViewForm_Closing;
_hexViewForm.SaveData += HexViewForm_SaveData;
 
_hexViewForm.Show();
}
 
_hexViewForm = new HexViewForm(hash, _snapshotDatabase, _cancellationToken);
_hexViewForm.Owner = this;
_hexViewForm.Closing += HexViewForm_Closing;
_hexViewForm.SaveData += HexViewForm_SaveData;
_hexViewForm.Show();
}
 
private async void HexViewForm_SaveData(object sender, SaveDataEventArgs e)
{
string hash;
var hash = await _snapshotDatabase.UpdateFile(e.Hash, e.Data, _cancellationToken);
 
try
{
hash = await _snapshotDatabase.UpdateFileAsync(e.Hash, e.Data, _cancellationToken);
}
catch (Exception exception)
{
Log.Error(exception, "Could not update snapshot data.");
return;
}
 
if (string.IsNullOrEmpty(hash))
{
return;
@@ -1188,7 +1058,7 @@
 
private void HexViewForm_Closing(object sender, CancelEventArgs e)
{
if (_hexViewForm is { Visible: false })
if (_hexViewForm == null)
{
return;
}
@@ -1195,7 +1065,8 @@
 
_hexViewForm.SaveData -= HexViewForm_SaveData;
_hexViewForm.Closing -= HexViewForm_Closing;
_hexViewForm.Dispose();
_hexViewForm.Close();
_hexViewForm = null;
}
 
private async void FileToolStripMenuItem2_Click(object sender, EventArgs e)
@@ -1250,7 +1121,7 @@
 
await Task.Run(() => SaveFilesTo(rows, directory, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -1307,7 +1178,7 @@
await Task.Run(() => SaveDirectoryTo(rows, basePath, dialog.FileName, progress, _cancellationToken),
_cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -1381,7 +1252,7 @@
 
await Task.Run(() => RecomputeHashes(rows, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -1421,7 +1292,7 @@
 
await Task.Run(() => NormalizeDateTime(rows, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -1431,42 +1302,7 @@
#endregion
 
#region Private Methods
private void DataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
DataGridView dataGridView = sender as DataGridView;
foreach (DataGridViewCell cell in dataGridView.Rows[e.RowIndex].Cells)
{
if (cell.Selected == false) { continue; }
var bgColorCell = Color.White;
if (cell.Style.BackColor != Color.Empty) { bgColorCell = cell.Style.BackColor; }
else if (cell.InheritedStyle.BackColor != Color.Empty) { bgColorCell = cell.InheritedStyle.BackColor; }
cell.Style.SelectionBackColor = MixColor(bgColorCell, Color.FromArgb(0, 150, 255), 10, 4);
}
}
 
//Mix two colors
//Example: Steps=10 & Position=4 makes Color2 mix 40% into Color1
/// <summary>
/// Mix two colors.
/// </summary>
/// <param name="Color1"></param>
/// <param name="Color2"></param>
/// <param name="Steps"></param>
/// <param name="Position"></param>
/// <example>Steps=10 & Positon=4 makes Color2 mix 40% into Color1</example>
/// <remarks>https://stackoverflow.com/questions/38337849/transparent-selectionbackcolor-for-datagridview-cell</remarks>
/// <returns></returns>
public static Color MixColor(Color Color1, Color Color2, int Steps, int Position)
{
if (Position <= 0 || Steps <= 1) { return Color1; }
if (Position >= Steps) { return Color2; }
return Color.FromArgb(
Color1.R + ((Color2.R - Color1.R) / Steps * Position),
Color1.G + ((Color2.G - Color1.G) / Steps * Position),
Color1.B + ((Color2.B - Color1.B) / Steps * Position)
);
}
 
private async Task DeleteFiles(IReadOnlyList<DataGridViewRow> rows, IProgress<DataGridViewRowProgress> progress,
CancellationToken cancellationToken)
{
@@ -1476,10 +1312,9 @@
{
try
{
var hash = (string)rows[index].Cells["HashColumn"].Value;
await _snapshotDatabase.RemoveFile((string)rows[index].Cells["HashColumn"].Value,
cancellationToken);
 
await _snapshotDatabase.RemoveFileAsync(hash, cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[index], index));
}
catch (Exception exception)
@@ -1493,14 +1328,7 @@
{
var hashes = rows.Select(row => (string)row.Cells["HashColumn"].Value);
 
try
{
await _snapshotDatabase.RemoveFileFastAsync(hashes, cancellationToken);
}
catch (Exception exception)
{
Log.Error(exception, "Failed to remove files.");
}
await _snapshotDatabase.RemoveFileFast(hashes, cancellationToken);
}
 
private async Task UpdateNote(IReadOnlyList<DataGridViewRow> rows, string note,
@@ -1512,10 +1340,9 @@
{
try
{
var hash = (string)rows[i].Cells["HashColumn"].Value;
await _snapshotDatabase.UpdateNote((string)rows[i].Cells["HashColumn"].Value, note,
cancellationToken);
 
await _snapshotDatabase.UpdateNoteAsync(hash, note,cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
}
catch (Exception exception)
@@ -1527,12 +1354,12 @@
 
private static List<DataGridViewRow> GetSelectedDataGridViewRows(DataGridView dataGridView)
{
return dataGridView.SelectedRows.OfType<DataGridViewRow>().Where(row => row.Visible).ToList();
return dataGridView.SelectedRows.OfType<DataGridViewRow>().ToList();
}
 
private static List<DataGridViewRow> GetAllDataGridViewRows(DataGridView dataGridView)
{
return dataGridView.Rows.OfType<DataGridViewRow>().Where(row => row.Visible).ToList();
return dataGridView.Rows.OfType<DataGridViewRow>().ToList();
}
 
private async Task RemoveColorFiles(IReadOnlyList<DataGridViewRow> rows,
@@ -1545,10 +1372,9 @@
{
try
{
var hash = (string)rows[i].Cells["HashColumn"].Value;
await _snapshotDatabase.RemoveColor((string)rows[i].Cells["HashColumn"].Value,
cancellationToken);
 
await _snapshotDatabase.RemoveColorAsync(hash, cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
}
catch (Exception exception)
@@ -1567,10 +1393,9 @@
{
try
{
var hash = (string)rows[i].Cells["HashColumn"].Value;
await _snapshotDatabase.UpdateColor((string)rows[i].Cells["HashColumn"].Value, color,
cancellationToken);
 
await _snapshotDatabase.UpdateColorAsync(hash, color, cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
}
catch (Exception exception)
@@ -1580,79 +1405,6 @@
}
}
 
private async Task TransferFiles(IReadOnlyList<DataGridViewRow> rows, Service service,
IProgress<DataGridViewRowProgress> progress, CancellationToken cancellationToken)
{
var client = new WatsonTcpClient($"{service.HostEntry.AddressList[0]}", service.UPort);
client.Events.MessageReceived += Events_MessageReceived;
client.Events.ServerConnected += Events_ServerConnected;
client.Events.ServerDisconnected += Events_ServerDisconnected;
client.Events.ExceptionEncountered += Events_ExceptionEncountered;
 
try
{
client.Connect();
 
var count = rows.Count;
 
for (var i = 0; i < count && !cancellationToken.IsCancellationRequested; ++i)
{
try
{
var hash = (string)rows[i].Cells["HashColumn"].Value;
 
var completeSnapshot =
await _snapshotDatabase.GenerateTransferSnapshotAsync(hash, cancellationToken);
 
var jsonSnapshot = JsonConvert.SerializeObject(completeSnapshot);
 
await client.SendAsync(jsonSnapshot, null, cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
}
catch (Exception exception)
{
progress.Report(new DataGridViewRowProgressFailure(rows[i], i, exception));
}
}
}
catch (Exception exception) when (exception is TimeoutException || exception is SocketException)
{
Log.Error(exception, "Client threw exception.");
}
finally
{
client.Events.MessageReceived -= Events_MessageReceived;
client.Events.ServerConnected -= Events_ServerConnected;
client.Events.ServerDisconnected -= Events_ServerDisconnected;
client.Events.ExceptionEncountered -= Events_ExceptionEncountered;
 
client.Dispose();
}
 
}
 
private void Events_ExceptionEncountered(object sender, ExceptionEventArgs e)
{
Log.Error(e.Exception, $"Client threw exception.");
}
 
private void Events_ServerDisconnected(object sender, DisconnectionEventArgs e)
{
Log.Information($"{e.Client?.IpPort} connected to server due to: {e.Reason}.");
}
 
private void Events_MessageReceived(object sender, MessageReceivedEventArgs e)
{
Log.Information($"{e.Data?.Length} byte long message received from {e.Client?.IpPort}");
}
 
private void Events_ServerConnected(object sender, WatsonTcp.ConnectionEventArgs e)
{
Log.Information($"{e.Client?.IpPort} connected to server.");
}
 
private async Task RevertFile(IReadOnlyList<DataGridViewRow> rows, IProgress<DataGridViewRowProgress> progress,
CancellationToken cancellationToken)
{
@@ -1662,11 +1414,10 @@
{
try
{
var path = (string)rows[i].Cells["NameColumn"].Value;
var hash = (string)rows[i].Cells["HashColumn"].Value;
await _snapshotDatabase.RevertFile((string)rows[i].Cells["NameColumn"].Value,
(string)rows[i].Cells["HashColumn"].Value,
cancellationToken, _mainForm.Configuration.AtomicOperations);
 
await _snapshotDatabase.RevertFileAsync(path, hash, cancellationToken, _mainForm.Configuration.AtomicOperations);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
}
catch (Exception exception)
@@ -1685,12 +1436,12 @@
{
try
{
var hash = (string)rows[i].Cells["HashColumn"].Value;
var fileInfo = new FileInfo((string)rows[i].Cells["NameColumn"].Value);
var file = fileInfo.Name;
var path = Path.Combine(directory, file);
 
await _snapshotDatabase.SaveFileAsync(path, hash, cancellationToken);
await _snapshotDatabase.SaveFile(path, (string)rows[i].Cells["HashColumn"].Value,
cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
}
@@ -1711,10 +1462,10 @@
{
try
{
var hash = (string)rows[i].Cells["HashColumn"].Value;
var path = Path.Combine(directory, (string)rows[i].Cells["NameColumn"].Value);
 
await _snapshotDatabase.RelocateFileAsync(hash, path, cancellationToken);
await _snapshotDatabase.RelocateFile((string)rows[i].Cells["HashColumn"].Value, path,
cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
}
@@ -1735,26 +1486,29 @@
{
try
{
var hash = (string)rows[i].Cells["HashColumn"].Value;
 
using var memoryStream = await _snapshotDatabase.RetrieveFileStreamAsync(hash, cancellationToken);
if (memoryStream == null)
using (var memoryStream =
await _snapshotDatabase.RetrieveFileStream((string)rows[i].Cells["HashColumn"].Value,
cancellationToken))
{
continue;
}
if (memoryStream == null)
{
continue;
}
 
using var md5 = MD5.Create();
using (var md5 = MD5.Create())
{
var recomputedHash = md5.ComputeHash(memoryStream);
var hashHex = BitConverter.ToString(recomputedHash).Replace("-", "")
.ToLowerInvariant();
 
var recomputedHash = md5.ComputeHash(memoryStream);
var hashHex = BitConverter.ToString(recomputedHash).Replace("-", "")
.ToLowerInvariant();
await _snapshotDatabase.UpdateHashAsync(hash, hashHex,
cancellationToken);
await _snapshotDatabase.UpdateHash((string)rows[i].Cells["HashColumn"].Value, hashHex,
cancellationToken);
 
rows[i].Cells["HashColumn"].Value = hashHex;
rows[i].Cells["HashColumn"].Value = hashHex;
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
}
}
}
catch (Exception exception)
{
@@ -1794,9 +1548,8 @@
var newPath = Path.Combine(targetPath, rootPath, relPath);
 
var hash = (string)rows[i].Cells["HashColumn"].Value;
await _snapshotDatabase.SaveFile(newPath, hash, cancellationToken);
 
await _snapshotDatabase.SaveFileAsync(newPath, hash, cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
 
if (!store.Contains(rowPath))
@@ -1821,10 +1574,9 @@
{
try
{
var hash = (string)rows[i].Cells["HashColumn"].Value;
await _snapshotDatabase.NormalizeTime((string)rows[i].Cells["HashColumn"].Value,
cancellationToken);
 
await _snapshotDatabase.NormalizeTimeAsync(hash, cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
}
catch (Exception exception)
@@ -1869,7 +1621,7 @@
 
await Task.Run(() => DeleteScreenshots(rows, progress, _cancellationToken), _cancellationToken);
 
if (_cancellationToken.IsCancellationRequested)
if (!_cancellationToken.IsCancellationRequested)
{
toolStripProgressBar1.Value = toolStripProgressBar1.Maximum;
toolStripStatusLabel1.Text = "Done.";
@@ -1886,10 +1638,9 @@
{
try
{
var hash = (string)rows[i].Cells["HashColumn"].Value;
await _snapshotDatabase.DeleteScreenshot((string)rows[i].Cells["HashColumn"].Value,
cancellationToken);
 
await _snapshotDatabase.DeleteScreenshotAsync(hash, cancellationToken);
 
progress.Report(new DataGridViewRowProgressSuccess(rows[i], i));
}
catch (Exception exception)
@@ -1901,16 +1652,40 @@
 
#endregion
 
private void copyHashToolStripMenuItem_Click(object sender, EventArgs e)
private void DataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
var row = GetSelectedDataGridViewRows(dataGridView1).FirstOrDefault();
if (row == null)
DataGridView dataGridView = sender as DataGridView;
foreach (DataGridViewCell cell in dataGridView.Rows[e.RowIndex].Cells)
{
return;
if (cell.Selected == false) { continue; }
var bgColorCell = Color.White;
if (cell.Style.BackColor != Color.Empty) { bgColorCell = cell.Style.BackColor; }
else if (cell.InheritedStyle.BackColor != Color.Empty) { bgColorCell = cell.InheritedStyle.BackColor; }
cell.Style.SelectionBackColor = MixColor(bgColorCell, Color.FromArgb(0, 150, 255), 10, 4);
}
}
 
Clipboard.SetText($"{row.Cells["HashColumn"].Value}");
//Mix two colors
//Example: Steps=10 & Position=4 makes Color2 mix 40% into Color1
/// <summary>
/// Mix two colors.
/// </summary>
/// <param name="Color1"></param>
/// <param name="Color2"></param>
/// <param name="Steps"></param>
/// <param name="Position"></param>
/// <example>Steps=10 & Positon=4 makes Color2 mix 40% into Color1</example>
/// <remarks>https://stackoverflow.com/questions/38337849/transparent-selectionbackcolor-for-datagridview-cell</remarks>
/// <returns></returns>
public static Color MixColor(Color Color1, Color Color2, int Steps, int Position)
{
if (Position <= 0 || Steps <= 1) { return Color1; }
if (Position >= Steps) { return Color2; }
return Color.FromArgb(
Color1.R + ((Color2.R - Color1.R) / Steps * Position),
Color1.G + ((Color2.G - Color1.G) / Steps * Position),
Color1.B + ((Color2.B - Color1.B) / Steps * Position)
);
}
}
}