WingMan – Rev 2

Subversion Repositories:
Rev:
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;

namespace WingMan.Communication
{
    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 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(clientOptions.Build())
                .Build();

            BindHandlers();

            await Client.SubscribeAsync(
                new TopicFilterBuilder()
                    .WithTopic("lobby")
                    .Build()
                );

            await Client.SubscribeAsync(
                new TopicFilterBuilder()
                    .WithTopic("exchange")
                    .Build()
            );

            await Client.StartAsync(options);

            ClientRunning = true;
        }

        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();

            await Client.StopAsync();

            ClientRunning = false;
        }

        public void Dispose()
        {
            UnbindHandlers();

            Client.StopAsync().Wait();

            Client?.Dispose();
        }

        public void BindHandlers()
        {
            Client.Connected += ClientOnConnected;
            Client.Disconnected += ClientOnDisconnected;
            Client.ConnectingFailed += ClientOnConnectingFailed;
            Client.ApplicationMessageReceived += ClientOnApplicationMessageReceived;
        }

        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"
                    }
                });

            }
        }
    }
}