/trunk/WingMan/Bindings/KeyBindingsSynchronizer.cs |
@@ -0,0 +1,103 @@ |
using System; |
using System.Collections.Concurrent; |
using System.Collections.Generic; |
using System.IO; |
using System.Linq; |
using System.Threading; |
using System.Threading.Tasks; |
using MQTTnet; |
using WingMan.Communication; |
|
namespace WingMan.Bindings |
{ |
public class KeyBindingsSynchronizer : IDisposable |
{ |
public delegate void MouseKeyBindingsSynchronized(object sender, KeyBindingsSynchronizerEventArgs e); |
|
public KeyBindingsSynchronizer(LocalKeyBindings localKeyBindings, MqttCommunication mqttCommunication, |
TaskScheduler taskScheduler, CancellationToken cancellationToken) |
{ |
LocalKeyBindings = localKeyBindings; |
MqttCommunication = mqttCommunication; |
CancellationToken = cancellationToken; |
TaskScheduler = taskScheduler; |
|
SynchronizedMouseKeyBindings = new ConcurrentDictionary<string, List<KeyBinding>>(); |
|
MqttCommunication.OnMessageReceived += MqttCommunicationOnMessageReceived; |
|
Task.Run(PeriodicSynchronize, CancellationToken); |
} |
|
private LocalKeyBindings LocalKeyBindings { get; } |
|
private ConcurrentDictionary<string, List<KeyBinding>> SynchronizedMouseKeyBindings { get; } |
|
private MqttCommunication MqttCommunication { get; } |
|
private CancellationToken CancellationToken { get; } |
private TaskScheduler TaskScheduler { get; } |
|
public void Dispose() |
{ |
MqttCommunication.OnMessageReceived -= MqttCommunicationOnMessageReceived; |
} |
|
public event MouseKeyBindingsSynchronized OnMouseKeyBindingsSynchronized; |
|
private async void MqttCommunicationOnMessageReceived(object sender, |
MqttApplicationMessageReceivedEventArgs e) |
{ |
if (e.ApplicationMessage.Topic != "exchange") |
return; |
|
using (var memoryStream = new MemoryStream(e.ApplicationMessage.Payload)) |
{ |
memoryStream.Position = 0L; |
|
var mouseKeyBindingsExchange = |
(KeyBindingExchange) KeyBindingExchange.XmlSerializer.Deserialize(memoryStream); |
|
// Do not add own bindings. |
if (string.Equals(mouseKeyBindingsExchange.Nick, MqttCommunication.Nick)) |
return; |
|
if (SynchronizedMouseKeyBindings.TryGetValue(mouseKeyBindingsExchange.Nick, out var mouseKeyBinding) && |
mouseKeyBinding.SequenceEqual(mouseKeyBindingsExchange.KeyBindings)) |
return; |
|
await Task.Delay(0) |
.ContinueWith( |
_ => OnMouseKeyBindingsSynchronized?.Invoke(sender, |
new KeyBindingsSynchronizerEventArgs( |
mouseKeyBindingsExchange)), |
CancellationToken, TaskContinuationOptions.None, TaskScheduler); |
|
// Nick does not exist so the bindings will be added. |
SynchronizedMouseKeyBindings.AddOrUpdate(mouseKeyBindingsExchange.Nick, |
mouseKeyBindingsExchange.KeyBindings, (s, list) => mouseKeyBindingsExchange.KeyBindings); |
} |
} |
|
private async Task PeriodicSynchronize() |
{ |
do |
{ |
await Task.Delay(1000, CancellationToken); |
|
if (!MqttCommunication.Running) |
continue; |
|
using (var memoryStream = new MemoryStream()) |
{ |
KeyBindingExchange.XmlSerializer.Serialize(memoryStream, |
new KeyBindingExchange(MqttCommunication.Nick, LocalKeyBindings.Bindings)); |
|
memoryStream.Position = 0L; |
|
await MqttCommunication.Broadcast("exchange", memoryStream.ToArray()); |
} |
} while (!CancellationToken.IsCancellationRequested); |
} |
} |
} |