/trunk/Hush/Hush.cs |
@@ -8,13 +8,11 @@ |
using System.Threading; |
using System.Threading.Tasks; |
using System.Windows.Forms; |
using Hush.Chat; |
using Hush.Communication; |
using Hush.Discovery; |
using Hush.Lobby; |
using Hush.Properties; |
using Hush.Utilities; |
using MQTTnet.Extensions.ManagedClient; |
using MQTTnet.Server; |
using WingMan.Communication; |
|
namespace Hush |
@@ -21,12 +19,6 @@ |
{ |
public partial class Hush : Form |
{ |
private static TaskScheduler FormTaskScheduler { get; set; } |
private static CancellationTokenSource FormCancellationTokenSource { get; set; } |
private static MqttCommunication MqttCommunication { get; set; } |
private static ChatMessageSynchronizer ChatMessageSynchronizer { get; set; } |
private static Discovery.Discovery Discovery { get; set; } |
|
public Hush() |
{ |
InitializeComponent(); |
@@ -40,27 +32,194 @@ |
Settings.Default.PropertyChanged += DefaultOnPropertyChanged; |
|
// Set up discovery. |
Discovery = new Discovery.Discovery(Constants.AssemblyName, FormCancellationTokenSource.Token, |
Discovery = new Discovery.Discovery(Constants.ASSEMBLY_NAME, FormCancellationTokenSource, |
FormTaskScheduler); |
Discovery.OnPortMapFailed += OnDiscoveryPortMapFailed; |
|
// Bind to MQTT events. |
MqttCommunication = new MqttCommunication(FormTaskScheduler, FormCancellationTokenSource.Token); |
MqttCommunication.OnClientConnectionFailed += MqttOnClientConnectionFailed; |
MqttCommunication.OnClientAuthenticationFailed += MqttOnClientAuthenticationFailed; |
MqttCommunication.OnClientConnected += MqttOnClientConnected; |
MqttCommunication.OnClientDisconnected += MqttOnClientDisconnected; |
MqttCommunication.OnServerClientConnected += MqttCommunicationOnOnServerClientConnected; |
MqttCommunication.OnServerClientDisconnected += MqttOnServerClientDisconnected; |
//mqttCommunication. |
|
// Start message synchronizer. |
ChatMessageSynchronizer = new ChatMessageSynchronizer(Constants.MqttTopic, MqttCommunication, |
FormTaskScheduler, |
// Start lobby message synchronizer. |
LobbyMessageSynchronizer = new LobbyMessageSynchronizer(MqttCommunication, FormTaskScheduler, |
FormCancellationTokenSource.Token); |
ChatMessageSynchronizer.OnMessageReceived += OnMessageReceived; |
LobbyMessageSynchronizer.OnLobbyMessageReceived += OnLobbyMessageReceived; |
} |
|
private static TaskScheduler FormTaskScheduler { get; set; } |
private static CancellationTokenSource FormCancellationTokenSource { get; set; } |
private static MqttCommunication MqttCommunication { get; set; } |
private static LobbyMessageSynchronizer LobbyMessageSynchronizer { get; set; } |
private static Discovery.Discovery Discovery { get; set; } |
|
private void OnDiscoveryPortMapFailed(object sender, DiscoveryFailedEventArgs args) |
{ |
notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning; |
notifyIcon1.BalloonTipTitle = Strings.Network_warning; |
notifyIcon1.BalloonTipText = Strings.Failed_to_create_automatic_NAT_port_mapping; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
private void OnLobbyMessageReceived(object sender, LobbyMessageReceivedEventArgs e) |
{ |
LobbyTextBox.AppendText($"{e.Nick} : {e.Message}{Environment.NewLine}"); |
} |
|
private async void DefaultOnPropertyChanged(object sender, PropertyChangedEventArgs e) |
{ |
if (e.PropertyName == "LaunchOnBoot") |
LaunchOnBoot.Set(Settings.Default.LaunchOnBoot); |
|
if (e.PropertyName == "Start") |
await ToggleStart(); |
} |
|
private async Task ToggleStart() |
{ |
switch (Settings.Default.Mode) |
{ |
case "Server": |
await StopServer(); |
|
if (!Settings.Default.Start) |
break; |
|
try |
{ |
await StartServer(); |
} |
catch (ToolTippedException ex) |
{ |
notifyIcon1.BalloonTipIcon = ex.Icon; |
notifyIcon1.BalloonTipTitle = ex.Title; |
notifyIcon1.BalloonTipText = ex.Body; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
break; |
case "Client": |
await StopClient(); |
|
if (!Settings.Default.Start) |
break; |
|
try |
{ |
await StartClient(); |
} |
catch (ToolTippedException ex) |
{ |
notifyIcon1.BalloonTipIcon = ex.Icon; |
notifyIcon1.BalloonTipTitle = ex.Title; |
notifyIcon1.BalloonTipText = ex.Body; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
break; |
} |
|
startToolStripMenuItem.Checked = Settings.Default.Start; |
} |
|
private async Task StopClient() |
{ |
// Stop the client if it is already started. |
await MqttCommunication.Stop(); |
} |
|
private async Task StopServer() |
{ |
// Remove UPnP and Pmp mappings. |
await Task.Delay(0, FormCancellationTokenSource.Token).ContinueWith(async _ => |
{ |
await Discovery.DeleteMapping(DiscoveryType.Upnp, MqttCommunication.Port); |
await Discovery.DeleteMapping(DiscoveryType.Pmp, MqttCommunication.Port); |
}, |
FormCancellationTokenSource.Token, TaskContinuationOptions.LongRunning, FormTaskScheduler); |
|
// Stop the MQTT server if it is running. |
await MqttCommunication.Stop(); |
} |
|
private async Task StartClient() |
{ |
if (!IPAddress.TryParse(Settings.Default.Address, out var address)) |
try |
{ |
address = Dns.GetHostAddresses(Settings.Default.Address).FirstOrDefault(); |
} |
catch |
{ |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, |
$"{Strings.Unable_to_determine_address} {Settings.Default.Address}"); |
} |
|
if (!uint.TryParse(Settings.Default.Port, out var port)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, |
$"{Strings.Unable_to_determine_port} {Settings.Default.Port}"); |
|
|
if (string.IsNullOrEmpty(Settings.Default.Nick)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_nickname_set); |
|
if (string.IsNullOrEmpty(Settings.Default.Password)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_password_set); |
|
if (!await MqttCommunication |
.Start(MqttCommunicationType.Client, address, (int) port, Settings.Default.Nick, |
Settings.Default.Password, |
new[] {"lobby"})) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.Unable_to_start_client); |
} |
|
private async Task StartServer() |
{ |
if (!IPAddress.TryParse(Settings.Default.Address, out var address)) |
try |
{ |
address = Dns.GetHostAddresses(Settings.Default.Address).FirstOrDefault(); |
} |
catch |
{ |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, |
$"{Strings.Unable_to_determine_address} {Settings.Default.Address}"); |
} |
|
if (!uint.TryParse(Settings.Default.Port, out var port)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, |
$"{Strings.Unable_to_determine_port} {Settings.Default.Port}"); |
|
|
if (string.IsNullOrEmpty(Settings.Default.Nick)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_nickname_set); |
|
if (string.IsNullOrEmpty(Settings.Default.Password)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_password_set); |
|
// Try to reserve port: try UPnP followed by PMP. |
await Task.Delay(0, FormCancellationTokenSource.Token).ContinueWith(async _ => |
{ |
if (!await Discovery.CreateMapping(DiscoveryType.Upnp, (int) port)) |
await Discovery.CreateMapping(DiscoveryType.Pmp, (int) port); |
}, |
FormCancellationTokenSource.Token, TaskContinuationOptions.LongRunning, FormTaskScheduler); |
|
// Start the MQTT server. |
if (!await MqttCommunication |
.Start(MqttCommunicationType.Server, address, (int) port, Settings.Default.Nick, |
Settings.Default.Password, new[] {"lobby"})) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.Unable_to_start_server); |
} |
|
private void DefaultOnSettingsSaving(object sender, CancelEventArgs e) |
{ |
} |
|
private void DefaultOnSettingsLoaded(object sender, SettingsLoadedEventArgs e) |
{ |
LaunchOnBoot.Set(Settings.Default.LaunchOnBoot); |
} |
|
/// <summary> |
/// Clean up any resources being used. |
/// </summary> |
@@ -67,9 +226,6 @@ |
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> |
protected override void Dispose(bool disposing) |
{ |
// Unbind message synchronizer. |
ChatMessageSynchronizer.OnMessageReceived -= OnMessageReceived; |
|
// Unbind settings handlers. |
Settings.Default.SettingsLoaded -= DefaultOnSettingsLoaded; |
Settings.Default.SettingsSaving -= DefaultOnSettingsSaving; |
@@ -79,7 +235,14 @@ |
base.Dispose(disposing); |
} |
|
#region Overrides |
private void OnMouseDown(object sender, MouseEventArgs e) |
{ |
if (e.Button == MouseButtons.Left) |
{ |
Natives.ReleaseCapture(); |
Natives.SendMessage(Handle, Natives.WM_NCLBUTTONDOWN, Natives.HT_CAPTION, 0); |
} |
} |
|
protected override void OnPaintBackground(PaintEventArgs e) |
{ |
@@ -164,113 +327,12 @@ |
base.WndProc(ref m); |
} |
|
#endregion |
|
#region Event Handlers |
|
private void MqttOnServerClientDisconnected(object sender, |
MqttClientDisconnectedEventArgs mqttClientDisconnectedEventArgs) |
private void OnMouseEnter(object sender, EventArgs e) |
{ |
notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning; |
notifyIcon1.BalloonTipTitle = Strings.Network_warning; |
notifyIcon1.BalloonTipText = $"{Strings.Client_disconnected}"; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
|
private void MqttCommunicationOnOnServerClientConnected(object sender, |
MqttClientConnectedEventArgs mqttClientConnectedEventArgs) |
{ |
notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning; |
notifyIcon1.BalloonTipTitle = Strings.Network_warning; |
notifyIcon1.BalloonTipText = $"{Strings.Client_connected}"; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
private void MqttOnClientDisconnected(object sender, |
MQTTnet.Client.MqttClientDisconnectedEventArgs mqttClientDisconnectedEventArgs) |
{ |
notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning; |
notifyIcon1.BalloonTipTitle = Strings.Network_warning; |
notifyIcon1.BalloonTipText = $"{Strings.Client_disconnected}"; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
private void MqttOnClientConnected(object sender, |
MQTTnet.Client.MqttClientConnectedEventArgs mqttClientConnectedEventArgs) |
{ |
notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning; |
notifyIcon1.BalloonTipTitle = Strings.Network_warning; |
notifyIcon1.BalloonTipText = $"{Strings.Client_connected}"; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
private void MqttOnClientAuthenticationFailed(object sender, |
MqttAuthenticationFailureEventArgs mqttAuthenticationFailureEventArgs) |
{ |
notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning; |
notifyIcon1.BalloonTipTitle = Strings.Network_warning; |
notifyIcon1.BalloonTipText = $"{Strings.Failed_to_authenticate_to_server}"; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
private void MqttOnClientConnectionFailed(object sender, |
MqttManagedProcessFailedEventArgs mqttManagedProcessFailedEventArgs) |
{ |
notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning; |
notifyIcon1.BalloonTipTitle = Strings.Network_warning; |
notifyIcon1.BalloonTipText = |
$"{Strings.Failed_to_connect_to_server} {mqttManagedProcessFailedEventArgs.Exception.Message}"; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
private void OnDiscoveryPortMapFailed(object sender, DiscoveryFailedEventArgs args) |
{ |
notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning; |
notifyIcon1.BalloonTipTitle = Strings.Network_warning; |
notifyIcon1.BalloonTipText = Strings.Failed_to_create_automatic_NAT_port_mapping; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
private void OnMessageReceived(object sender, ChatMessageReceivedEventArgs e) |
{ |
var message = $"{e.Nick} : {e.Message}{Environment.NewLine}"; |
chatTextBox.AppendText(message); |
} |
|
private async void DefaultOnPropertyChanged(object sender, PropertyChangedEventArgs e) |
{ |
if (string.Equals(e.PropertyName, "LaunchOnBoot")) |
LaunchOnBoot.Set(Settings.Default.LaunchOnBoot); |
|
if (string.Equals(e.PropertyName, "Start")) |
await ToggleStart(); |
} |
|
private void DefaultOnSettingsSaving(object sender, CancelEventArgs e) |
{ |
} |
|
private void DefaultOnSettingsLoaded(object sender, SettingsLoadedEventArgs e) |
{ |
LaunchOnBoot.Set(Settings.Default.LaunchOnBoot); |
} |
|
private void OnMouseDown(object sender, MouseEventArgs e) |
{ |
if (e.Button == MouseButtons.Left) |
{ |
DllImports.ReleaseCapture(); |
DllImports.SendMessage(Handle, DllImports.WM_NCLBUTTONDOWN, DllImports.HT_CAPTION, 0); |
} |
} |
|
private void HushFocus(object sender, EventArgs e) |
{ |
Opacity = .75; |
} |
|
private void HushUnfocus(object sender, EventArgs e) |
private void OnMouseLeave(object sender, EventArgs e) |
{ |
Opacity = .33; |
} |
@@ -287,22 +349,18 @@ |
|
private async void MessageTextBoxOnKeyDown(object sender, KeyEventArgs e) |
{ |
// Prevent the enter key to be passed to the text box or we get a nasty ding. |
if (e.KeyCode == Keys.Enter) |
e.SuppressKeyPress = true; |
// Do not send messages if the communication is not running. |
if (!MqttCommunication.Running) |
return; |
|
if (e.KeyCode != Keys.Enter) |
return; |
|
// Do not send messages if the communication is not running. |
if (!MqttCommunication.Running) |
return; |
|
if (string.IsNullOrEmpty(messageTextBox.Text)) |
return; |
|
// Send the message |
await ChatMessageSynchronizer.Broadcast($"{messageTextBox.Text}"); |
await LobbyMessageSynchronizer.Broadcast($"{messageTextBox.Text}\n"); |
|
messageTextBox.Text = string.Empty; |
} |
@@ -350,148 +408,5 @@ |
|
Settings.Default.Port = toolStripMenuItem.Text; |
} |
|
#endregion |
|
private async Task ToggleStart() |
{ |
switch (Settings.Default.Mode) |
{ |
case "Server": |
await StopServer(); |
|
if (!Settings.Default.Start) |
break; |
|
try |
{ |
await StartServer(); |
} |
catch (ToolTippedException ex) |
{ |
notifyIcon1.BalloonTipIcon = ex.Icon; |
notifyIcon1.BalloonTipTitle = ex.Title; |
notifyIcon1.BalloonTipText = ex.Body; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
break; |
case "Client": |
await StopClient(); |
|
if (!Settings.Default.Start) |
break; |
|
try |
{ |
await StartClient(); |
} |
catch (ToolTippedException ex) |
{ |
notifyIcon1.BalloonTipIcon = ex.Icon; |
notifyIcon1.BalloonTipTitle = ex.Title; |
notifyIcon1.BalloonTipText = ex.Body; |
notifyIcon1.ShowBalloonTip(1000); |
} |
|
break; |
} |
|
startToolStripMenuItem.Checked = Settings.Default.Start; |
} |
|
private async Task StopClient() |
{ |
// Stop the client if it is already started. |
await MqttCommunication.Stop(); |
} |
|
private async Task StopServer() |
{ |
// Remove UPnP and Pmp mappings. |
await Task.Delay(0, FormCancellationTokenSource.Token).ContinueWith(async _ => |
{ |
await Discovery.DeleteMapping(DiscoveryType.Upnp, MqttCommunication.Port); |
await Discovery.DeleteMapping(DiscoveryType.Pmp, MqttCommunication.Port); |
}, |
FormCancellationTokenSource.Token, TaskContinuationOptions.LongRunning, FormTaskScheduler); |
|
// Stop the MQTT server if it is running. |
await MqttCommunication.Stop(); |
} |
|
private async Task StartClient() |
{ |
if (!IPAddress.TryParse(Settings.Default.Address, out var address)) |
try |
{ |
var getHostAddresses = await Dns.GetHostAddressesAsync(Settings.Default.Address); |
if (!getHostAddresses.Any()) |
throw new Exception(); |
|
address = getHostAddresses.FirstOrDefault(); |
} |
catch |
{ |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, |
$"{Strings.Unable_to_determine_address} {Settings.Default.Address}"); |
} |
|
if (!uint.TryParse(Settings.Default.Port, out var port)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, |
$"{Strings.Unable_to_determine_port} {Settings.Default.Port}"); |
|
|
if (string.IsNullOrEmpty(Settings.Default.Nick)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_nickname_set); |
|
if (string.IsNullOrEmpty(Settings.Default.Password)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_password_set); |
|
if (!await MqttCommunication |
.Start(MqttCommunicationType.Client, address, (int) port, Settings.Default.Nick, |
Settings.Default.Password, |
new[] {Constants.MqttTopic})) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.Unable_to_start_client); |
} |
|
private async Task StartServer() |
{ |
if (!IPAddress.TryParse(Settings.Default.Address, out var address)) |
try |
{ |
address = Dns.GetHostAddresses(Settings.Default.Address).FirstOrDefault(); |
} |
catch |
{ |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, |
$"{Strings.Unable_to_determine_address} {Settings.Default.Address}"); |
} |
|
if (!uint.TryParse(Settings.Default.Port, out var port)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, |
$"{Strings.Unable_to_determine_port} {Settings.Default.Port}"); |
|
|
if (string.IsNullOrEmpty(Settings.Default.Nick)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_nickname_set); |
|
if (string.IsNullOrEmpty(Settings.Default.Password)) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.No_password_set); |
|
// Try to reserve port: try UPnP followed by PMP. |
await Task.Delay(0, FormCancellationTokenSource.Token).ContinueWith(async _ => |
{ |
if (!await Discovery.CreateMapping(DiscoveryType.Upnp, (int) port)) |
await Discovery.CreateMapping(DiscoveryType.Pmp, (int) port); |
}, |
FormCancellationTokenSource.Token, TaskContinuationOptions.LongRunning, FormTaskScheduler); |
|
// Start the MQTT server. |
if (!await MqttCommunication |
.Start(MqttCommunicationType.Server, address, (int) port, Settings.Default.Nick, |
Settings.Default.Password, new[] {Constants.MqttTopic})) |
throw new ToolTippedException(ToolTipIcon.Error, Strings.Network_error, Strings.Unable_to_start_server); |
} |
} |
} |