WingMan – Rev

Subversion Repositories:
Rev:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet;
using MQTTnet.Extensions.ManagedClient;
using WingMan.Communication;

namespace WingMan.MouseKey
{
    public class MouseKeyBindingsSynchronizer
    {
        public delegate void MouseKeyBindingsSynchronized(object sender, MouseKeyBindingsSynchronizedEventArgs e);
        public event MouseKeyBindingsSynchronized OnMouseKeyBindingsSynchronized;

        private MouseKeyBindings MouseKeyBindings { get; set; }

        private ConcurrentDictionary<string, List<MouseKeyBindingExchange>> SynchronizedMouseKeyBindings { get; set; }

        private MQTTCommunication MQTTCommunication { get; set; }

        private CancellationTokenSource SynchronizationCancellationTokenSource { get; set; }

        public MouseKeyBindingsSynchronizer(MouseKeyBindings mouseKeyBindings, MQTTCommunication MQTTCommunication)
        {
            MouseKeyBindings = mouseKeyBindings;
            this.MQTTCommunication = MQTTCommunication;

            SynchronizedMouseKeyBindings = new ConcurrentDictionary<string, List<MouseKeyBindingExchange>>();

            MQTTCommunication.OnMessageReceived += MqttCommunicationOnOnMessageReceived;

            SynchronizationCancellationTokenSource = new CancellationTokenSource();

            Task.Run(Synchronize, SynchronizationCancellationTokenSource.Token);
        }

        private void MqttCommunicationOnOnMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
        {
            if (e.ApplicationMessage.Topic != "exchange")
                return;

            using (var memoryStream = new MemoryStream(e.ApplicationMessage.Payload))
            {
                memoryStream.Position = 0L;

                var mouseKeyBindingsExchange = (MouseKeyBindingsExchange)MouseKeyBindingsExchange.XmlSerializer.Deserialize(memoryStream);

                if (SynchronizedMouseKeyBindings.TryGetValue(mouseKeyBindingsExchange.Nick, out var mouseKeyBinding) &&
                    mouseKeyBinding.SequenceEqual(mouseKeyBindingsExchange.ExchangeBindings))
                    return;

                // Nick does not exist so the bindings will be added.
                SynchronizedMouseKeyBindings.AddOrUpdate(mouseKeyBindingsExchange.Nick,
                    mouseKeyBindingsExchange.ExchangeBindings, (s, list) => mouseKeyBindingsExchange.ExchangeBindings);

                OnMouseKeyBindingsSynchronized?.Invoke(sender,
                    new MouseKeyBindingsSynchronizedEventArgs(
                        mouseKeyBindingsExchange.ExchangeBindings));
            }
        }

        private async Task Synchronize()
        {
            do
            {
                await Task.Delay(1000).ConfigureAwait(false);

                if (!MouseKeyBindings.Bindings.Any())
                    continue;

                using (var memoryStream = new MemoryStream())
                {
                    MouseKeyBindingsExchange.XmlSerializer.Serialize(memoryStream, new MouseKeyBindingsExchange(MQTTCommunication.Nick, MouseKeyBindings));

                    memoryStream.Position = 0L;

                    await MQTTCommunication.Broadcast("exchange", memoryStream.ToArray()).ConfigureAwait(false);
                }

            } while (!SynchronizationCancellationTokenSource.Token.IsCancellationRequested);
        }
    }
}