WingMan – Rev 2

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

namespace WingMan.Host
{
    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()
        {
            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, 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" });

            }
        }
    }
}