WingMan

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 1  →  ?path2? @ 2
File deleted
/trunk/WingMan/Form1.cs
File deleted
\ No newline at end of file
/trunk/WingMan/Form1.resx
File deleted
/trunk/WingMan/Form1.Designer.cs
/trunk/WingMan/Communication/MQTTClient.cs
@@ -1,9 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Serialization;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;
@@ -12,32 +16,49 @@
{
public class MQTTClient : IDisposable
{
private WingManForm WingManForm { get; set; }
private IManagedMqttClient Client { get; set; }
public bool ClientRunning { get; set; }
 
public string Nick { get; set; }
 
public MQTTClient()
{
Client = new MqttFactory().CreateManagedMqttClient();
}
 
public async Task Start(IPAddress ipAddress, int port)
public MQTTClient(WingManForm wingManForm) : this()
{
WingManForm = wingManForm;
}
 
public async Task Start(IPAddress ipAddress, int port, string nick)
{
Nick = nick;
 
var clientOptions = new MqttClientOptionsBuilder()
.WithTcpServer(ipAddress.ToString(), port);
 
// Setup and start a managed MQTT client.
var options = new ManagedMqttClientOptionsBuilder()
.WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
.WithClientOptions(new MqttClientOptionsBuilder()
.WithTcpServer(ipAddress.ToString(), port)
.WithTls().Build())
.WithClientOptions(clientOptions.Build())
.Build();
 
BindHandlers();
 
await Client.SubscribeAsync(
new TopicFilterBuilder()
.WithTopic("lobby")
.WithTopic("exchange")
.Build()
);
 
await Client.SubscribeAsync(
new TopicFilterBuilder()
.WithTopic("exchange")
.Build()
);
 
await Client.StartAsync(options);
 
ClientRunning = true;
@@ -45,14 +66,52 @@
 
private void ClientOnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
{
if (e.ApplicationMessage.Topic == "lobby")
{
using (var memoryStream = new MemoryStream(e.ApplicationMessage.Payload))
{
memoryStream.Position = 0L;
 
var lobbyMessage = (LobbyMessage)LobbyMessage.XmlSerializer.Deserialize(memoryStream);
 
UpdateLobbyMessage(lobbyMessage.Nick, lobbyMessage.Message);
}
return;
}
}
 
private void ClientOnConnected(object sender, MqttClientConnectedEventArgs e)
{
LogActivity(Properties.Strings.Client_connected);
}
 
private void ClientOnDisconnected(object sender, MqttClientDisconnectedEventArgs e)
{
LogActivity(Properties.Strings.Client_disconnected, e.Exception.Message);
}
 
private void ClientOnConnectingFailed(object sender, MqttManagedProcessFailedEventArgs e)
{
LogActivity(Properties.Strings.Client_connection_failed, e.Exception.Message);
}
 
private void UpdateLobbyMessage(string client, string message)
{
WingManForm.LobbyTextBox.Invoke((MethodInvoker)delegate
{
WingManForm.LobbyTextBox.AppendText($"{client} : {message}" + Environment.NewLine);
});
}
 
private void LogActivity(params string[] messages)
{
WingManForm.ActivityTextBox.Invoke((MethodInvoker) delegate
{
WingManForm.ActivityTextBox.Text =
string.Join(" : ", messages) + Environment.NewLine + WingManForm.ActivityTextBox.Text;
});
}
 
public async Task Stop()
{
UnbindHandlers();
@@ -74,6 +133,8 @@
public void BindHandlers()
{
Client.Connected += ClientOnConnected;
Client.Disconnected += ClientOnDisconnected;
Client.ConnectingFailed += ClientOnConnectingFailed;
Client.ApplicationMessageReceived += ClientOnApplicationMessageReceived;
}
 
@@ -80,7 +141,33 @@
public void UnbindHandlers()
{
Client.Connected -= ClientOnConnected;
Client.Disconnected -= ClientOnDisconnected;
Client.ConnectingFailed -= ClientOnConnectingFailed;
Client.ApplicationMessageReceived -= ClientOnApplicationMessageReceived;
}
 
public async Task BroadcastLobbyMessage(string text)
{
using (var memoryStream = new MemoryStream())
{
LobbyMessage.XmlSerializer.Serialize(memoryStream, new LobbyMessage()
{
Message = text,
Nick = Nick
});
 
memoryStream.Position = 0L;
 
await Client.PublishAsync(new ManagedMqttApplicationMessage
{
ApplicationMessage = new MqttApplicationMessage
{
Payload = memoryStream.ToArray(),
Topic = "lobby"
}
});
 
}
}
}
}
/trunk/WingMan/Communication/MQTTServer.cs
@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using MQTTnet;
using MQTTnet.Server;
 
@@ -11,8 +13,10 @@
{
public class MQTTServer
{
private WingManForm WingManForm { get; set; }
private IMqttServer Server { get; set; }
public bool ServerRunning { get; set; }
public string Nick { get; set; }
 
public MQTTServer()
{
@@ -19,22 +23,147 @@
Server = new MqttFactory().CreateMqttServer();
}
 
public MQTTServer(WingManForm wingManForm) : this()
{
WingManForm = wingManForm;
}
 
public async Task Stop()
{
UnbindHandlers();
 
await Server.StopAsync().ConfigureAwait(false);
 
ServerRunning = false;
}
 
public async Task Start(IPAddress ipAddress, int port)
public async Task Start(IPAddress ipAddress, int port, string nick)
{
Nick = nick;
 
var optionsBuilder = new MqttServerOptionsBuilder()
.WithDefaultEndpointBoundIPAddress(ipAddress)
.WithSubscriptionInterceptor(MQTTSubscriptionIntercept)
.WithDefaultEndpointPort(port);
 
BindHandlers();
 
await Server.StartAsync(optionsBuilder.Build()).ConfigureAwait(false);
 
ServerRunning = true;
}
 
private void MQTTSubscriptionIntercept(MqttSubscriptionInterceptorContext context)
{
if (context.TopicFilter.Topic != "lobby" &&
context.TopicFilter.Topic != "exchange")
{
context.AcceptSubscription = false;
context.CloseConnection = true;
return;
}
 
context.AcceptSubscription = true;
context.CloseConnection = false;
}
 
private void ServerOnClientUnsubscribedTopic(object sender, MqttClientUnsubscribedTopicEventArgs e)
{
LogActivity(Properties.Strings.Client_unsubscribed_from_topic, e.ClientId, e.TopicFilter);
}
 
private void ServerOnClientSubscribedTopic(object sender, MqttClientSubscribedTopicEventArgs e)
{
LogActivity(Properties.Strings.Client_subscribed_to_topic, e.ClientId, e.TopicFilter.Topic);
}
 
private void ServerOnClientDisconnected(object sender, MqttClientDisconnectedEventArgs e)
{
LogActivity(Properties.Strings.Client_disconnected, e.ClientId);
}
 
private void ServerOnClientConnected(object sender, MqttClientConnectedEventArgs e)
{
LogActivity(Properties.Strings.Client_connected, e.ClientId);
}
 
private void ServerOnStopped(object sender, EventArgs e)
{
LogActivity(Properties.Strings.Server_stopped);
}
 
private void ServerOnStarted(object sender, EventArgs e)
{
LogActivity(Properties.Strings.Server_started);
}
 
private void BindHandlers()
{
Server.Started += ServerOnStarted;
Server.Stopped += ServerOnStopped;
Server.ClientConnected += ServerOnClientConnected;
Server.ClientDisconnected += ServerOnClientDisconnected;
Server.ClientSubscribedTopic += ServerOnClientSubscribedTopic;
Server.ClientUnsubscribedTopic += ServerOnClientUnsubscribedTopic;
Server.ApplicationMessageReceived += ServerOnApplicationMessageReceived;
}
 
private void ServerOnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
{
using (var memoryStream = new MemoryStream(e.ApplicationMessage.Payload))
{
memoryStream.Position = 0L;
 
var lobbyMessage = (LobbyMessage)LobbyMessage.XmlSerializer.Deserialize(memoryStream);
 
UpdateLobbyMessage(lobbyMessage.Nick, lobbyMessage.Message);
}
}
 
private void UnbindHandlers()
{
Server.Started -= ServerOnStarted;
Server.Stopped -= ServerOnStopped;
Server.ClientConnected -= ServerOnClientConnected;
Server.ClientDisconnected -= ServerOnClientDisconnected;
Server.ClientSubscribedTopic -= ServerOnClientSubscribedTopic;
Server.ClientUnsubscribedTopic -= ServerOnClientUnsubscribedTopic;
Server.ApplicationMessageReceived -= ServerOnApplicationMessageReceived;
}
 
private void UpdateLobbyMessage(string client, string message)
{
WingManForm.LobbyTextBox.Invoke((MethodInvoker)delegate
{
WingManForm.LobbyTextBox.AppendText($"{client} : {message}" + Environment.NewLine);
});
}
 
private void LogActivity(params string[] messages)
{
WingManForm.ActivityTextBox.Invoke((MethodInvoker) delegate
{
WingManForm.ActivityTextBox.Text =
string.Join(" : ", messages) + Environment.NewLine + WingManForm.ActivityTextBox.Text;
});
}
 
public async Task BroadcastLobbyMessage(string text)
{
using (var memoryStream = new MemoryStream())
{
LobbyMessage.XmlSerializer.Serialize(memoryStream, new LobbyMessage()
{
Message = text,
Nick = Nick
});
 
memoryStream.Position = 0L;
 
await Server.PublishAsync(
new MqttApplicationMessage { Payload = memoryStream.ToArray(), Topic = "lobby" });
 
}
}
}
}
/trunk/WingMan/LobbyMessage.cs
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
 
namespace WingMan
{
public class LobbyMessage
{
public string Message { get; set; }
public string Nick { get; set; }
 
[XmlIgnore] public static XmlSerializer XmlSerializer = new XmlSerializer(typeof(LobbyMessage));
}
}
/trunk/WingMan/Program.cs
@@ -16,7 +16,7 @@
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
Application.Run(new WingManForm());
}
}
}
/trunk/WingMan/Properties/Strings.Designer.cs
@@ -61,6 +61,33 @@
}
/// <summary>
/// Looks up a localized string similar to Client connected.
/// </summary>
internal static string Client_connected {
get {
return ResourceManager.GetString("Client_connected", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Client connection failed.
/// </summary>
internal static string Client_connection_failed {
get {
return ResourceManager.GetString("Client_connection_failed", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Client disconnected.
/// </summary>
internal static string Client_disconnected {
get {
return ResourceManager.GetString("Client_disconnected", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Client started.
/// </summary>
internal static string Client_started {
@@ -70,6 +97,24 @@
}
/// <summary>
/// Looks up a localized string similar to Client subscribed to topic.
/// </summary>
internal static string Client_subscribed_to_topic {
get {
return ResourceManager.GetString("Client_subscribed_to_topic", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Client unsubscribed from topic.
/// </summary>
internal static string Client_unsubscribed_from_topic {
get {
return ResourceManager.GetString("Client_unsubscribed_from_topic", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Connect.
/// </summary>
internal static string Connect {
/trunk/WingMan/Properties/Strings.resx
@@ -117,9 +117,24 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Client_connected" xml:space="preserve">
<value>Client connected</value>
</data>
<data name="Client_connection_failed" xml:space="preserve">
<value>Client connection failed</value>
</data>
<data name="Client_disconnected" xml:space="preserve">
<value>Client disconnected</value>
</data>
<data name="Client_started" xml:space="preserve">
<value>Client started</value>
</data>
<data name="Client_subscribed_to_topic" xml:space="preserve">
<value>Client subscribed to topic</value>
</data>
<data name="Client_unsubscribed_from_topic" xml:space="preserve">
<value>Client unsubscribed from topic</value>
</data>
<data name="Connect" xml:space="preserve">
<value>Connect</value>
</data>
/trunk/WingMan/WingMan.csproj
@@ -41,6 +41,9 @@
<Reference Include="MQTTnet.Extensions.ManagedClient, Version=2.8.4.0, Culture=neutral, PublicKeyToken=b69712f52770c0a7, processorArchitecture=MSIL">
<HintPath>..\packages\MQTTnet.Extensions.ManagedClient.2.8.4\lib\net452\MQTTnet.Extensions.ManagedClient.dll</HintPath>
</Reference>
<Reference Include="Open.Nat, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f22a6a4582336c76, processorArchitecture=MSIL">
<HintPath>..\packages\Open.NAT.2.1.0.0\lib\net45\Open.Nat.dll</HintPath>
</Reference>
<Reference Include="SimWinKeyboard, Version=1.0.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\SimWinKeyboard.1.0.2\lib\net20\SimWinKeyboard.dll</HintPath>
</Reference>
@@ -61,11 +64,12 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Communication\MQTTClient.cs" />
<Compile Include="Form1.cs">
<Compile Include="LobbyMessage.cs" />
<Compile Include="WingManForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
<Compile Include="WingManForm.Designer.cs">
<DependentUpon>WingManForm.cs</DependentUpon>
</Compile>
<Compile Include="Communication\MQTTServer.cs" />
<Compile Include="Program.cs" />
@@ -75,8 +79,8 @@
<DesignTime>True</DesignTime>
<DependentUpon>Strings.resx</DependentUpon>
</Compile>
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
<EmbeddedResource Include="WingManForm.resx">
<DependentUpon>WingManForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
/trunk/WingMan/WingManForm.Designer.cs
@@ -0,0 +1,480 @@
namespace WingMan
{
partial class WingManForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
 
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
 
#region Windows Form Designer generated code
 
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.button2 = new System.Windows.Forms.Button();
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.listBox1 = new System.Windows.Forms.ListBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.button5 = new System.Windows.Forms.Button();
this.LobbySayTextBox = new System.Windows.Forms.TextBox();
this.LobbyTextBox = new System.Windows.Forms.TextBox();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.button3 = new System.Windows.Forms.Button();
this.button4 = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.textBox2 = new System.Windows.Forms.TextBox();
this.listBox2 = new System.Windows.Forms.ListBox();
this.groupBox4 = new System.Windows.Forms.GroupBox();
this.label5 = new System.Windows.Forms.Label();
this.Nick = new System.Windows.Forms.TextBox();
this.HostButton = new System.Windows.Forms.Button();
this.label4 = new System.Windows.Forms.Label();
this.ConnectButton = new System.Windows.Forms.Button();
this.Port = new System.Windows.Forms.TextBox();
this.label3 = new System.Windows.Forms.Label();
this.Address = new System.Windows.Forms.TextBox();
this.statusStrip = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.groupBox5 = new System.Windows.Forms.GroupBox();
this.ActivityTextBox = new System.Windows.Forms.TextBox();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.groupBox4.SuspendLayout();
this.statusStrip.SuspendLayout();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.groupBox5.SuspendLayout();
this.tabPage2.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
//
this.groupBox1.Controls.Add(this.comboBox1);
this.groupBox1.Controls.Add(this.button2);
this.groupBox1.Controls.Add(this.button1);
this.groupBox1.Controls.Add(this.label1);
this.groupBox1.Controls.Add(this.textBox1);
this.groupBox1.Controls.Add(this.listBox1);
this.groupBox1.Location = new System.Drawing.Point(12, 10);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(256, 296);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Wing (Them)";
//
// comboBox1
//
this.comboBox1.FormattingEnabled = true;
this.comboBox1.Location = new System.Drawing.Point(8, 24);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(240, 21);
this.comboBox1.TabIndex = 5;
//
// button2
//
this.button2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button2.Location = new System.Drawing.Point(168, 264);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 4;
this.button2.Text = "Unbind";
this.button2.UseVisualStyleBackColor = true;
//
// button1
//
this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button1.Location = new System.Drawing.Point(88, 264);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 3;
this.button1.Text = "Bind";
this.button1.UseVisualStyleBackColor = true;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(8, 232);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(54, 13);
this.label1.TabIndex = 2;
this.label1.Text = "Bound To";
//
// textBox1
//
this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.textBox1.Location = new System.Drawing.Point(72, 228);
this.textBox1.Name = "textBox1";
this.textBox1.ReadOnly = true;
this.textBox1.Size = new System.Drawing.Size(172, 20);
this.textBox1.TabIndex = 1;
//
// listBox1
//
this.listBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.listBox1.FormattingEnabled = true;
this.listBox1.Location = new System.Drawing.Point(8, 56);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(240, 132);
this.listBox1.TabIndex = 0;
//
// groupBox2
//
this.groupBox2.Controls.Add(this.button5);
this.groupBox2.Controls.Add(this.LobbySayTextBox);
this.groupBox2.Controls.Add(this.LobbyTextBox);
this.groupBox2.Location = new System.Drawing.Point(276, 10);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(256, 296);
this.groupBox2.TabIndex = 1;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Lobby";
//
// button5
//
this.button5.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button5.Location = new System.Drawing.Point(208, 264);
this.button5.Name = "button5";
this.button5.Size = new System.Drawing.Size(40, 20);
this.button5.TabIndex = 2;
this.button5.UseVisualStyleBackColor = true;
//
// LobbySayTextBox
//
this.LobbySayTextBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.LobbySayTextBox.Location = new System.Drawing.Point(8, 264);
this.LobbySayTextBox.Name = "LobbySayTextBox";
this.LobbySayTextBox.Size = new System.Drawing.Size(192, 20);
this.LobbySayTextBox.TabIndex = 1;
this.LobbySayTextBox.KeyDown += new System.Windows.Forms.KeyEventHandler(this.LobbySayTextBoxKeyDown);
//
// LobbyTextBox
//
this.LobbyTextBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.LobbyTextBox.Location = new System.Drawing.Point(8, 16);
this.LobbyTextBox.Multiline = true;
this.LobbyTextBox.Name = "LobbyTextBox";
this.LobbyTextBox.ReadOnly = true;
this.LobbyTextBox.Size = new System.Drawing.Size(240, 240);
this.LobbyTextBox.TabIndex = 0;
//
// groupBox3
//
this.groupBox3.Controls.Add(this.button3);
this.groupBox3.Controls.Add(this.button4);
this.groupBox3.Controls.Add(this.label2);
this.groupBox3.Controls.Add(this.textBox2);
this.groupBox3.Controls.Add(this.listBox2);
this.groupBox3.Location = new System.Drawing.Point(540, 10);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(256, 296);
this.groupBox3.TabIndex = 2;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Helm (You)";
//
// button3
//
this.button3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button3.Location = new System.Drawing.Point(168, 264);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(75, 23);
this.button3.TabIndex = 6;
this.button3.Text = "Remove";
this.button3.UseVisualStyleBackColor = true;
//
// button4
//
this.button4.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button4.Location = new System.Drawing.Point(88, 264);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(75, 23);
this.button4.TabIndex = 5;
this.button4.Text = "Add";
this.button4.UseVisualStyleBackColor = true;
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(24, 232);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(35, 13);
this.label2.TabIndex = 4;
this.label2.Text = "Name";
//
// textBox2
//
this.textBox2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.textBox2.Location = new System.Drawing.Point(72, 228);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(172, 20);
this.textBox2.TabIndex = 3;
//
// listBox2
//
this.listBox2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.listBox2.FormattingEnabled = true;
this.listBox2.Location = new System.Drawing.Point(8, 16);
this.listBox2.Name = "listBox2";
this.listBox2.Size = new System.Drawing.Size(240, 184);
this.listBox2.TabIndex = 1;
//
// groupBox4
//
this.groupBox4.Controls.Add(this.label5);
this.groupBox4.Controls.Add(this.Nick);
this.groupBox4.Controls.Add(this.HostButton);
this.groupBox4.Controls.Add(this.label4);
this.groupBox4.Controls.Add(this.ConnectButton);
this.groupBox4.Controls.Add(this.Port);
this.groupBox4.Controls.Add(this.label3);
this.groupBox4.Controls.Add(this.Address);
this.groupBox4.Location = new System.Drawing.Point(8, 8);
this.groupBox4.Name = "groupBox4";
this.groupBox4.Size = new System.Drawing.Size(344, 112);
this.groupBox4.TabIndex = 3;
this.groupBox4.TabStop = false;
this.groupBox4.Text = "Connection";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(16, 52);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(29, 13);
this.label5.TabIndex = 8;
this.label5.Text = "Nick";
//
// Nick
//
this.Nick.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Nick.Location = new System.Drawing.Point(56, 48);
this.Nick.Name = "Nick";
this.Nick.Size = new System.Drawing.Size(176, 20);
this.Nick.TabIndex = 7;
//
// HostButton
//
this.HostButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.HostButton.Location = new System.Drawing.Point(136, 80);
this.HostButton.Name = "HostButton";
this.HostButton.Size = new System.Drawing.Size(75, 23);
this.HostButton.TabIndex = 6;
this.HostButton.Text = "Host";
this.HostButton.UseVisualStyleBackColor = true;
this.HostButton.Click += new System.EventHandler(this.HostButtonClickAsync);
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(240, 24);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(26, 13);
this.label4.TabIndex = 3;
this.label4.Text = "Port";
//
// ConnectButton
//
this.ConnectButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.ConnectButton.Location = new System.Drawing.Point(56, 80);
this.ConnectButton.Name = "ConnectButton";
this.ConnectButton.Size = new System.Drawing.Size(75, 23);
this.ConnectButton.TabIndex = 5;
this.ConnectButton.Text = "Connect";
this.ConnectButton.UseVisualStyleBackColor = true;
this.ConnectButton.Click += new System.EventHandler(this.ConnectButtonClickAsync);
//
// Port
//
this.Port.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Port.Location = new System.Drawing.Point(272, 20);
this.Port.Name = "Port";
this.Port.Size = new System.Drawing.Size(60, 20);
this.Port.TabIndex = 2;
this.Port.Text = "43335";
this.Port.Click += new System.EventHandler(this.PortTextBoxClick);
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(8, 24);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(45, 13);
this.label3.TabIndex = 1;
this.label3.Text = "Address";
//
// Address
//
this.Address.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.Address.Location = new System.Drawing.Point(56, 20);
this.Address.Name = "Address";
this.Address.Size = new System.Drawing.Size(176, 20);
this.Address.TabIndex = 0;
this.Address.Text = "0.0.0.0";
this.Address.Click += new System.EventHandler(this.AddressTextBoxClick);
//
// statusStrip
//
this.statusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripStatusLabel});
this.statusStrip.Location = new System.Drawing.Point(0, 428);
this.statusStrip.Name = "statusStrip";
this.statusStrip.Size = new System.Drawing.Size(800, 22);
this.statusStrip.TabIndex = 4;
this.statusStrip.Text = "statusStrip1";
//
// toolStripStatusLabel
//
this.toolStripStatusLabel.Name = "toolStripStatusLabel";
this.toolStripStatusLabel.Size = new System.Drawing.Size(0, 17);
//
// tabControl1
//
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Location = new System.Drawing.Point(0, 64);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(800, 360);
this.tabControl1.TabIndex = 5;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.groupBox5);
this.tabPage1.Controls.Add(this.groupBox4);
this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(792, 334);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Connection";
this.tabPage1.UseVisualStyleBackColor = true;
//
// groupBox5
//
this.groupBox5.Controls.Add(this.ActivityTextBox);
this.groupBox5.Location = new System.Drawing.Point(8, 128);
this.groupBox5.Name = "groupBox5";
this.groupBox5.Size = new System.Drawing.Size(776, 200);
this.groupBox5.TabIndex = 5;
this.groupBox5.TabStop = false;
this.groupBox5.Text = "Activity";
//
// ActivityTextBox
//
this.ActivityTextBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.ActivityTextBox.Location = new System.Drawing.Point(8, 16);
this.ActivityTextBox.Multiline = true;
this.ActivityTextBox.Name = "ActivityTextBox";
this.ActivityTextBox.Size = new System.Drawing.Size(760, 176);
this.ActivityTextBox.TabIndex = 4;
//
// tabPage2
//
this.tabPage2.Controls.Add(this.groupBox1);
this.tabPage2.Controls.Add(this.groupBox2);
this.tabPage2.Controls.Add(this.groupBox3);
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(792, 334);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Bindings";
this.tabPage2.UseVisualStyleBackColor = true;
//
// WingManForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.tabControl1);
this.Controls.Add(this.statusStrip);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MaximumSize = new System.Drawing.Size(816, 488);
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(816, 488);
this.Name = "WingManForm";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.Text = "WingManForm";
this.groupBox1.ResumeLayout(false);
this.groupBox1.PerformLayout();
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.groupBox3.PerformLayout();
this.groupBox4.ResumeLayout(false);
this.groupBox4.PerformLayout();
this.statusStrip.ResumeLayout(false);
this.statusStrip.PerformLayout();
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.groupBox5.ResumeLayout(false);
this.groupBox5.PerformLayout();
this.tabPage2.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
 
}
 
#endregion
 
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.GroupBox groupBox3;
private System.Windows.Forms.ListBox listBox1;
private System.Windows.Forms.ListBox listBox2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox LobbySayTextBox;
public System.Windows.Forms.TextBox LobbyTextBox;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.Button button5;
private System.Windows.Forms.GroupBox groupBox4;
private System.Windows.Forms.Button HostButton;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Button ConnectButton;
private System.Windows.Forms.TextBox Port;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox Address;
private System.Windows.Forms.StatusStrip statusStrip;
private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel;
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox Nick;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.GroupBox groupBox5;
public System.Windows.Forms.TextBox ActivityTextBox;
private System.Windows.Forms.TabPage tabPage2;
}
}
 
/trunk/WingMan/WingManForm.cs
@@ -0,0 +1,208 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using WingMan.Communication;
using WingMan.Host;
 
namespace WingMan
{
public partial class WingManForm : Form
{
private MQTTServer MQTTServer { get; set; }
 
private MQTTClient MQTTClient { get; set; }
 
private SemaphoreSlim MQTTServerSemaphore {get; set;} = new SemaphoreSlim(1, 1);
 
private SemaphoreSlim MQTTClientSemaphore { get; set; } = new SemaphoreSlim(1, 1);
 
public WingManForm()
{
InitializeComponent();
 
MQTTClient = new MQTTClient(this);
MQTTServer = new MQTTServer(this);
}
 
private void AddressTextBoxClick(object sender, EventArgs e)
{
Address.BackColor = Color.Empty;
}
 
private void PortTextBoxClick(object sender, EventArgs e)
{
Port.BackColor = Color.Empty;
}
 
private async void HostButtonClickAsync(object sender, EventArgs e)
{
// Stop the MQTT server if it is running.
if (MQTTServer.ServerRunning)
{
await StopServer();
toolStripStatusLabel.Text = Properties.Strings.Server_stopped;
HostButton.BackColor = Color.Empty;
 
ConnectButton.Enabled = true;
return;
}
 
if (!ValidateAddressPort(out var ipAddress, out var port, out var nick))
return;
 
// Start the MQTT server.
await StartServer(ipAddress, port, nick);
toolStripStatusLabel.Text = Properties.Strings.Server_started;
HostButton.BackColor = Color.Aquamarine;
 
ConnectButton.Enabled = false;
}
 
private bool ValidateAddressPort(out IPAddress address, out int port, out string nick)
{
address = IPAddress.Any;
port = 0;
nick = string.Empty;
 
if (string.IsNullOrEmpty(Address.Text) &&
string.IsNullOrEmpty(Port.Text) &&
string.IsNullOrEmpty(Nick.Text))
{
Address.BackColor = Color.LightPink;
Port.BackColor = Color.LightPink;
Nick.BackColor = Color.LightPink;
return false;
}
 
if (!IPAddress.TryParse(Address.Text, out address))
{
Address.BackColor = Color.LightPink;
return false;
}
 
if (!uint.TryParse(Port.Text, out var uPort))
{
Port.BackColor = Color.LightPink;
return false;
}
 
port = (int) uPort;
 
if (string.IsNullOrEmpty(Nick.Text))
{
Nick.BackColor = Color.LightPink;
return false;
}
 
nick = Nick.Text;
 
Address.BackColor = Color.Empty;
Port.BackColor = Color.Empty;
Nick.BackColor = Color.Empty;
 
return true;
}
 
private async Task StartServer(IPAddress ipAddress, int port, string nick)
{
await MQTTServerSemaphore.WaitAsync();
try
{
await MQTTServer.Start(ipAddress, port, nick);
}
finally
{
MQTTServerSemaphore.Release();
}
}
 
private async Task StopServer()
{
await MQTTServerSemaphore.WaitAsync();
try
{
await MQTTServer.Stop();
}
finally
{
MQTTServerSemaphore.Release();
}
}
 
private async void ConnectButtonClickAsync(object sender, EventArgs e)
{
if (MQTTClient.ClientRunning)
{
await StopClient();
ConnectButton.Text = Properties.Strings.Connect;
ConnectButton.BackColor = Color.Empty;
 
HostButton.Enabled = true;
return;
}
 
if (!ValidateAddressPort(out var ipAddress, out var port, out var nick))
return;
 
await StartClient(ipAddress, port, nick);
 
toolStripStatusLabel.Text = Properties.Strings.Client_started;
ConnectButton.Text = Properties.Strings.Disconnect;
ConnectButton.BackColor = Color.Aquamarine;
 
HostButton.Enabled = false;
}
 
private async Task StopClient()
{
await MQTTClientSemaphore.WaitAsync();
try
{
await MQTTClient.Stop();
}
finally
{
MQTTClientSemaphore.Release();
}
}
 
private async Task StartClient(IPAddress ipAddress, int port, string nick)
{
await MQTTClientSemaphore.WaitAsync();
try
{
await MQTTClient.Start(ipAddress, port, nick);
}
finally
{
MQTTClientSemaphore.Release();
}
}
 
private async void LobbySayTextBoxKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode != Keys.Enter)
return;
 
if (MQTTServer.ServerRunning)
{
await MQTTServer.BroadcastLobbyMessage(LobbySayTextBox.Text);
}
 
if (MQTTClient.ClientRunning)
{
await MQTTClient.BroadcastLobbyMessage(LobbySayTextBox.Text);
}
 
}
}
}
/trunk/WingMan/WingManForm.resx
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
 
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="statusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>
/trunk/WingMan/packages.config
@@ -3,6 +3,7 @@
<package id="MonoGame.EasyInput" version="1.0.0" targetFramework="net452" />
<package id="MQTTnet" version="2.8.4" targetFramework="net452" />
<package id="MQTTnet.Extensions.ManagedClient" version="2.8.4" targetFramework="net452" />
<package id="Open.NAT" version="2.1.0.0" targetFramework="net452" />
<package id="SimWinKeyboard" version="1.0.2" targetFramework="net452" />
<package id="SimWinMouse" version="1.0.2" targetFramework="net452" />
</packages>