/Horizon/Snapshots/SnapshotManagerForm.cs |
@@ -6,8 +6,11 @@ |
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; |
@@ -14,8 +17,13 @@ |
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 |
{ |
@@ -55,6 +63,12 @@ |
|
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 |
@@ -69,6 +83,10 @@ |
|
_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, |
@@ -96,6 +114,8 @@ |
|
_snapshotDatabase.SnapshotCreate -= SnapshotManager_SnapshotCreate; |
|
_horizonServiceBrowser.ServiceAdded -= OnHorizonServiceBrowserOnServiceAdded; |
_horizonServiceBrowser.Dispose(); |
_localCancellationTokenSource.Cancel(); |
|
base.Dispose(disposing); |
@@ -104,6 +124,16 @@ |
#endregion |
|
#region Event Handlers |
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) |
{ |
|
} |
|
private void contextMenuStrip1_Opened(object sender, EventArgs e) |
{ |
_horizonServiceBrowser.Browse("_horizon._tcp", "local"); |
} |
|
private void DataGridView1_MouseDown(object sender, MouseEventArgs e) |
{ |
var dataGridView = (DataGridView)sender; |
@@ -588,6 +618,10 @@ |
|
private async void SnapshotManagerForm_Load(object sender, EventArgs e) |
{ |
// Start browsing for network services. |
_horizonServiceBrowser.Browse("_horizon._tcp", "local"); |
|
// Load snapshots. |
toolStripProgressBar1.Minimum = 0; |
toolStripProgressBar1.Maximum = (int)await _snapshotDatabase.CountSnapshotsAsync(_cancellationToken); |
|
@@ -647,6 +681,77 @@ |
} |
} |
|
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); |
|
_discoveredHorizonNetworkShares.TryAdd(service.Name, service); |
|
var discoveredServiceMenuItem = new ToolStripMenuItem(service.Name, null, OnShareWithNodeClicked); |
discoveredServiceMenuItem.Tag = service; |
|
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(); |
@@ -1307,7 +1412,42 @@ |
#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) |
{ |
@@ -1410,6 +1550,48 @@ |
} |
} |
|
|
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 += (sender, args) => |
{ |
Log.Information($"{args.Data.Length} byte long message received from {args.Client.IpPort}"); |
}; |
|
try |
{ |
client.Connect(); |
|
var count = rows.Count; |
|
for (var i = 0; i < count && !cancellationToken.IsCancellationRequested; ++i) |
{ |
try |
{ |
var completeSnapshot = await _snapshotDatabase.GetCompleteSnapshot((string)rows[i].Cells["HashColumn"].Value, 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)); |
} |
} |
} |
finally |
{ |
client.Dispose(); |
} |
|
} |
|
private async Task RevertFile(IReadOnlyList<DataGridViewRow> rows, IProgress<DataGridViewRowProgress> progress, |
CancellationToken cancellationToken) |
{ |
@@ -1656,41 +1838,5 @@ |
} |
|
#endregion |
|
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) |
); |
} |
} |
} |