From 01140f1700d8b0fe08dc49e8eb985ff3d6d8e555 Mon Sep 17 00:00:00 2001 From: BlubbFish Date: Sun, 1 Apr 2018 11:38:33 +0000 Subject: [PATCH] =?UTF-8?q?[NF]=20Verbindungs=C3=BCberwachung=20eingebaut?= =?UTF-8?q?=20[NF]=20Globale=20Aktivierung=20des=20Plugins=20hinzugef?= =?UTF-8?q?=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BosmonMqtt/BosmonMqtt.csproj | 2 +- .../{ => Models}/PluginConfiguration.cs | 35 ++++- BosmonMqtt/MqttEventProcessor.cs | 142 ++++++++++++++---- BosmonMqtt/Plugin.cs | 3 +- BosmonMqtt/Views/Config.Designer.cs | 19 ++- BosmonMqtt/Views/Config.cs | 133 ++++++++++++---- BosmonMqtt/bin/Release/BosmonMqtt.dll | Bin 19456 -> 24064 bytes BosmonMqtt/bin/Release/M2Mqtt.dll | Bin 38912 -> 38912 bytes 8 files changed, 271 insertions(+), 63 deletions(-) rename BosmonMqtt/{ => Models}/PluginConfiguration.cs (76%) diff --git a/BosmonMqtt/BosmonMqtt.csproj b/BosmonMqtt/BosmonMqtt.csproj index 7d7219e..fc48278 100644 --- a/BosmonMqtt/BosmonMqtt.csproj +++ b/BosmonMqtt/BosmonMqtt.csproj @@ -51,7 +51,7 @@ - + UserControl diff --git a/BosmonMqtt/PluginConfiguration.cs b/BosmonMqtt/Models/PluginConfiguration.cs similarity index 76% rename from BosmonMqtt/PluginConfiguration.cs rename to BosmonMqtt/Models/PluginConfiguration.cs index b17a422..641d1a2 100644 --- a/BosmonMqtt/PluginConfiguration.cs +++ b/BosmonMqtt/Models/PluginConfiguration.cs @@ -2,18 +2,22 @@ using System; using System.Text; -namespace BlubbFish.BosmonMqtt { +namespace BlubbFish.BosmonMqtt.Models { internal class PluginConfiguration : BosMonConfiguration, IBosMonConfigurationTemplate { private String _server; private String _user; private String _pass; private String _topic; private Int32 _port; + private Boolean _enable; + public delegate void Change(Object sender, EventArgs e); + public event Change ConfigChanged; public PluginConfiguration(IBosMonConfigurationStorage storage) : base(storage) { this.PluginStorage = storage; } + #region öffentliche Eigenschaften public IBosMonConfigurationStorage PluginStorage { get; private set; } public String Server { @@ -69,6 +73,17 @@ namespace BlubbFish.BosmonMqtt { } } + public Boolean Enable { + get { + return this._enable; + } + set { + this._enable = value; + WriteConfiguration(); + } + } + #endregion + #region IBosMonConfigurationTemplate Config-Variablen public override void ReadConfiguration() { base.ReadConfiguration(); @@ -77,6 +92,7 @@ namespace BlubbFish.BosmonMqtt { this._pass = this.Storage.ReadString("pass", ""); this._topic = this.Storage.ReadString("topic", ""); this._port = this.Storage.ReadInteger("port", 1883); + this._enable = this.Storage.ReadBoolean("enable", false); } public override void WriteConfiguration() { this.Storage.Write("server", this._server); @@ -84,9 +100,11 @@ namespace BlubbFish.BosmonMqtt { this.Storage.Write("pass", this._pass); this.Storage.Write("topic", this._topic); this.Storage.Write("port", this._port); + this.Storage.Write("enable", this._enable); base.WriteConfiguration(); } #endregion + #region IBosMonConfigurationTemplate Member public override TKeyVal[] StringVariables { get { @@ -103,10 +121,17 @@ namespace BlubbFish.BosmonMqtt { public override TKeyVal[] IntVariables { get { return Merge(new TKeyVal[] { - new TKeyVal("port",1883) + new TKeyVal("port", 1883) }, base.IntVariables); } } + public override TKeyVal[] BoolVariables { + get { + return Merge(new TKeyVal[] { + new TKeyVal("enable", false) + }, base.BoolVariables); + } + } public override TKeyVal[] Sections { get { return new TKeyVal[] { @@ -115,7 +140,11 @@ namespace BlubbFish.BosmonMqtt { } } - + public void Saved() { + this.ConfigChanged?.Invoke(this, new EventArgs()); + } + + #endregion diff --git a/BosmonMqtt/MqttEventProcessor.cs b/BosmonMqtt/MqttEventProcessor.cs index ffc0c9e..866de84 100644 --- a/BosmonMqtt/MqttEventProcessor.cs +++ b/BosmonMqtt/MqttEventProcessor.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; using System.Text; +using System.Threading; +using BlubbFish.BosmonMqtt.Models; using BosMon.Data; using BosMon.Data.Telegrams; -using BosMon.Prefs; +using BosMon.Plugins; +using BosMon.Utils; using TelegramFilter.Filter; using uPLibrary.Networking.M2Mqtt; using uPLibrary.Networking.M2Mqtt.Messages; @@ -11,51 +14,133 @@ using uPLibrary.Networking.M2Mqtt.Messages; namespace BlubbFish.BosmonMqtt { class MqttEventProcessor : IDisposable { private PluginConfiguration pluginconfig; + private IBosMonHost pluginhost; private MqttClient client; private FilterList filter; private List pfilter = new List(); + Thread connectionWatcher; - public MqttEventProcessor(PluginConfiguration pluginconfiguration) { + public MqttEventProcessor(PluginConfiguration pluginconfiguration, IBosMonHost pluginHost) { this.pluginconfig = pluginconfiguration; + this.pluginhost = pluginHost; + this.Connect(); + if(this.pluginconfig.Enable) { + this.ConnectionWatcherStart(); + } + this.pluginconfig.ConfigChanged += this.Pluginconfig_ConfigChanged; + } + + private void ConnectionWatcherRunner() { + while(true) { + try { + Thread.Sleep(10000); + if(!this.client.IsConnected) { + this.Reconnect(); + } + } catch(Exception) { } + } + } + + private void ConnectionWatcherStart() { + if(this.connectionWatcher == null) { + this.connectionWatcher = new Thread(this.ConnectionWatcherRunner); + } + if(this.connectionWatcher.ThreadState == ThreadState.Running || this.connectionWatcher.ThreadState == ThreadState.WaitSleepJoin) { + return; + } + this.connectionWatcher.Start(); + this.Log("ConnectionWatcherStart", "Überwachungsthread gestartet."); + } + + private void ConnectionWatcherStop() { + if(this.connectionWatcher == null) { + return; + } + try { + this.connectionWatcher.Abort(); + Thread.Sleep(100); + this.connectionWatcher = null; + } catch (Exception) { } + this.Log("ConnectionWatcherStop", "Überwachungsthread gestoppt."); + } + + private void Pluginconfig_ConfigChanged(Object sender, EventArgs e) { + this.Reconnect(); + if (this.pluginconfig.Enable) { + this.ConnectionWatcherStart(); + } + if(!this.pluginconfig.Enable) { + this.ConnectionWatcherStop(); + } + } + + private void Reconnect() { + if (this.pluginconfig.Enable) { + this.Log("Reconnect", "Reconnect ausgelößt."); + } + this.Disconnect(); this.Connect(); } - public void Connect() { - try { - this.client = new MqttClient(this.pluginconfig.Server, this.pluginconfig.Port, false, null); - if (this.pluginconfig.User == "" || this.pluginconfig.Password == "") { - this.client.Connect("bosmon-" + Guid.NewGuid().ToString()); - } else { - this.client.Connect("bosmon-" + Guid.NewGuid().ToString(), this.pluginconfig.User, this.pluginconfig.Password); - } - this.client.Subscribe(new String[] { this.pluginconfig.Topic }, new Byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE }); - } catch (Exception) { + - } - this.filter = new FilterList(this.pluginconfig.PluginStorage.GetSection("filter")); - this.pfilter.Clear(); - foreach (FilterItem item in this.filter) { - if(item.GetType() == typeof(PocsagFilterItem)) { - this.pfilter.Add(item as PocsagFilterItem); + private void Connect() { + if (this.pluginconfig.Enable) { + try { + this.client = new MqttClient(this.pluginconfig.Server, this.pluginconfig.Port, false, null); + if (this.pluginconfig.User == "" || this.pluginconfig.Password == "") { + this.client.Connect("bosmon-" + Guid.NewGuid().ToString()); + } else { + this.client.Connect("bosmon-" + Guid.NewGuid().ToString(), this.pluginconfig.User, this.pluginconfig.Password); + } + this.client.Subscribe(new String[] { this.pluginconfig.Topic }, new Byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE }); + } catch (Exception) { + return; } + this.filter = new FilterList(this.pluginconfig.PluginStorage.GetSection("filter")); + foreach (FilterItem item in this.filter) { + if (item.GetType() == typeof(PocsagFilterItem)) { + this.pfilter.Add(item as PocsagFilterItem); + } + } + this.Log("Connect", "Erfolgreich verbunden."); } } + private void Disconnect() { + this.pfilter.Clear(); + if (this.client != null && this.client.IsConnected) { + this.client.Unsubscribe(new String[] { this.pluginconfig.Topic }); + this.client.Disconnect(); + this.Log("Disconnect", "Verbindung getrennt."); + } + this.client = null; + } + internal void TelegramEvent(Object sender, TelegramEventArgs e) { - Telegram t = e.Telegram as Telegram; - if (this.client != null && this.client.IsConnected && this.filter != null) { - if (t.Type == PocsagTelegram.TYPE_POCSAG) { - PocsagTelegram p = t as PocsagTelegram; - foreach (PocsagFilterItem item in this.pfilter) { - if((item.IsMatching(p) && item.Negated)) { - return; + if (this.pluginconfig.Enable) { + try { + Telegram t = e.Telegram as Telegram; + if (this.client != null && this.client.IsConnected && this.filter != null) { + if (t.Type == PocsagTelegram.TYPE_POCSAG) { + PocsagTelegram p = t as PocsagTelegram; + foreach (PocsagFilterItem item in this.pfilter) { + if ((item.IsMatching(p) && item.Negated)) { + return; + } + } + this.client.Publish(this.pluginconfig.Topic + p.Address + p.Func, Encoding.UTF8.GetBytes(p.Msg)); } } - this.client.Publish(this.pluginconfig.Topic + p.Address+p.Func, Encoding.UTF8.GetBytes(p.Msg)); - } + } catch (Exception) { } } } + private void Log(String method, String text) { + BosMonLog.Logger.WriteLine(LogSeverity.Info, "BosmonMqtt.MqttEventProcessor", method, text); + this.pluginhost.AddMessage(DateTime.Now.Ticks, MessageType.Message, "BosmonMqtt " + text); + } + #region IDisposable Support private Boolean disposedValue = false; @@ -63,7 +148,8 @@ namespace BlubbFish.BosmonMqtt { protected virtual void Dispose(Boolean disposing) { if (!this.disposedValue) { if (disposing) { - // TODO: verwalteten Zustand (verwaltete Objekte) entsorgen. + this.ConnectionWatcherStop(); + this.Disconnect(); } this.disposedValue = true; } diff --git a/BosmonMqtt/Plugin.cs b/BosmonMqtt/Plugin.cs index f483c25..136b246 100644 --- a/BosmonMqtt/Plugin.cs +++ b/BosmonMqtt/Plugin.cs @@ -1,4 +1,5 @@ using System; +using BlubbFish.BosmonMqtt.Models; using BlubbFish.BosmonMqtt.Views; using BosMon.Data.Processors; using BosMon.Exceptions; @@ -28,7 +29,7 @@ namespace BlubbFish.BosmonMqtt { this.pluginconfiguration = new PluginConfiguration(this.ConfigurationStorage); this.isInitialized = true; this._configView = new ConfigView(this.pluginconfiguration); - this._mqtteventprocessor = new MqttEventProcessor(this.pluginconfiguration); + this._mqtteventprocessor = new MqttEventProcessor(this.pluginconfiguration, this.PluginHost); } internal void Start() { diff --git a/BosmonMqtt/Views/Config.Designer.cs b/BosmonMqtt/Views/Config.Designer.cs index 22d5817..6297a92 100644 --- a/BosmonMqtt/Views/Config.Designer.cs +++ b/BosmonMqtt/Views/Config.Designer.cs @@ -38,6 +38,7 @@ this.label5 = new System.Windows.Forms.Label(); this.textTopic = new System.Windows.Forms.TextBox(); this.filterButton = new System.Windows.Forms.Button(); + this.boxEnable = new System.Windows.Forms.CheckBox(); this.groupBox1.SuspendLayout(); this.SuspendLayout(); // @@ -113,7 +114,7 @@ this.groupBox1.Controls.Add(this.label1); this.groupBox1.Controls.Add(this.textUser); this.groupBox1.Controls.Add(this.label3); - this.groupBox1.Location = new System.Drawing.Point(3, 3); + this.groupBox1.Location = new System.Drawing.Point(3, 30); this.groupBox1.Name = "groupBox1"; this.groupBox1.Size = new System.Drawing.Size(390, 250); this.groupBox1.TabIndex = 7; @@ -196,18 +197,31 @@ this.filterButton.UseVisualStyleBackColor = true; this.filterButton.Click += new System.EventHandler(this.Filter_Click); // + // boxEnable + // + this.boxEnable.AutoSize = true; + this.boxEnable.Location = new System.Drawing.Point(3, 7); + this.boxEnable.Name = "boxEnable"; + this.boxEnable.Size = new System.Drawing.Size(218, 17); + this.boxEnable.TabIndex = 8; + this.boxEnable.Text = "Aktiviert oder Deaktiviert das Mqtt-Plugin"; + this.boxEnable.UseVisualStyleBackColor = true; + this.boxEnable.CheckedChanged += new System.EventHandler(this.Enabled_Changed); + // // ConfigView // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoSize = true; this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.Controls.Add(this.boxEnable); this.Controls.Add(this.groupBox1); this.Name = "ConfigView"; - this.Size = new System.Drawing.Size(396, 256); + this.Size = new System.Drawing.Size(396, 283); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); this.ResumeLayout(false); + this.PerformLayout(); } @@ -228,5 +242,6 @@ private System.Windows.Forms.Label label7; private System.Windows.Forms.TextBox textPort; private System.Windows.Forms.Label label2; + private System.Windows.Forms.CheckBox boxEnable; } } \ No newline at end of file diff --git a/BosmonMqtt/Views/Config.cs b/BosmonMqtt/Views/Config.cs index 706e00a..3be155f 100644 --- a/BosmonMqtt/Views/Config.cs +++ b/BosmonMqtt/Views/Config.cs @@ -3,7 +3,8 @@ using System.Drawing; using System.Text; using System.Threading; using System.Windows.Forms; -using BosMon.Prefs; +using BlubbFish.BosmonMqtt.Models; +using BosMon.Gui; using BosMon.Utils; using TelegramFilter.Filter; using TelegramFilter.Gui; @@ -11,19 +12,19 @@ using uPLibrary.Networking.M2Mqtt; using uPLibrary.Networking.M2Mqtt.Messages; namespace BlubbFish.BosmonMqtt.Views { - internal partial class ConfigView : UserControl { + internal partial class ConfigView : UserControl, IPreferencesUserControl { private PluginConfiguration pluginconfig; private EditFilterListDlg filter; + private String _server; + private String _port; + private String _user; + private String _pass; + private String _topic; + private Boolean _enable; internal ConfigView(PluginConfiguration pluginconfiguration) { InitializeComponent(); this.pluginconfig = pluginconfiguration; - this.filter = new EditFilterListDlg(new FilterList(this.pluginconfig.PluginStorage.GetSection("filter"))); - this.textServer.Text = this.pluginconfig.Server; - this.textUser.Text = this.pluginconfig.User; - this.textPass.Text = this.pluginconfig.Password; - this.textTopic.Text = this.pluginconfig.Topic; - this.textPort.Text = this.pluginconfig.Port.ToString(); } private void Filter_Click(Object sender, EventArgs e) { @@ -31,30 +32,47 @@ namespace BlubbFish.BosmonMqtt.Views { } private void Settings_Changed(Object sender, EventArgs e) { - TextBox t = (TextBox)sender; + TextBox t = sender as TextBox; switch (t.Tag) { case "server": - this.pluginconfig.Server = t.Text; - break; - case "user": - this.pluginconfig.User = t.Text; - break; - case "pass": - this.pluginconfig.Password = t.Text; - break; - case "topic": - this.pluginconfig.Topic = t.Text; - t.BeginInvoke((Action)(() => { - t.Text = this.pluginconfig.Topic; - })); + this._server = t.Text; break; case "port": - if (Int32.TryParse(t.Text, out Int32 port)) { - this.pluginconfig.Port = port; + this._port = t.Text; + break; + case "user": + this._user = t.Text; + break; + case "pass": + this._pass = t.Text; + break; + case "topic": + this._topic = t.Text; + if (this._topic.Length > 0 && this._topic[0] != '/') { + this._topic = "/" + this._topic; } + if (this._topic.Length > 1 && this._topic[this._topic.Length - 1] != '/') { + this._topic = this._topic + "/"; + } + t.BeginInvoke((Action)(() => { + t.Text = this._topic; + })); break; } } + private void Enabled_Changed(Object sender, EventArgs e) { + CheckBox t = sender as CheckBox; + this._enable = t.Checked; + this.boxEnable.BeginInvoke((Action)(() => { + this.textServer.Enabled = this._enable; + this.textPort.Enabled = this._enable; + this.textUser.Enabled = this._enable; + this.textPass.Enabled = this._enable; + this.textTopic.Enabled = this._enable; + this.filterButton.Enabled = this._enable; + this.testButton.Enabled = this._enable; + })); + } private void Check_Numbers(Object sender, KeyPressEventArgs e) { e.Handled = !Char.IsDigit(e.KeyChar) && !Char.IsControl(e.KeyChar); @@ -66,23 +84,29 @@ namespace BlubbFish.BosmonMqtt.Views { this.labelStatus.Text = "Baue Verbindung auf."; this.labelStatus.ForeColor = Color.DarkOrange; })); - MqttClient client = new MqttClient(this.pluginconfig.Server, this.pluginconfig.Port, false, null); + if (!Int32.TryParse(this._port, out Int32 port)) { + this.labelStatus.BeginInvoke((Action)(() => { + this.labelStatus.Text = "Fehler beim Parsen des Ports."; + })); + throw new Exception(); + } + MqttClient client = new MqttClient(this._server, port, false, null); if (this.pluginconfig.User == "" || this.pluginconfig.Password == "") { client.Connect("bosmon-" + Guid.NewGuid().ToString()); } else { - client.Connect("bosmon-" + Guid.NewGuid().ToString(), this.pluginconfig.User, this.pluginconfig.Password); + client.Connect("bosmon-" + Guid.NewGuid().ToString(), this._user, this._pass); } this.labelStatus.BeginInvoke((Action)(() => { this.labelStatus.Text = "Subscribe Topic."; this.labelStatus.ForeColor = Color.DarkOrange; })); - client.Subscribe(new String[] { this.pluginconfig.Topic }, new Byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE }); + client.Subscribe(new String[] { this._topic }, new Byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE }); this.labelStatus.BeginInvoke((Action)(() => { this.labelStatus.Text = "Schicke Testnachricht."; this.labelStatus.ForeColor = Color.DarkOrange; })); client.MqttMsgPublishReceived += this.Client_MqttMsgPublishReceived; - client.Publish(this.pluginconfig.Topic, Encoding.UTF8.GetBytes("BosMon Connection Test")); + client.Publish(this._topic, Encoding.UTF8.GetBytes("BosMon Connection Test")); this.labelStatus.BeginInvoke((Action)(() => { this.labelStatus.Text = "Warte auf Testnachricht."; this.labelStatus.ForeColor = Color.DarkOrange; @@ -113,5 +137,58 @@ namespace BlubbFish.BosmonMqtt.Views { this._testMessageRecieved = true; } } + + public void LoadSettings() { + this.filter = new EditFilterListDlg(new FilterList(this.pluginconfig.PluginStorage.GetSection("filter"))); + this._server = this.pluginconfig.Server; + this._port = this.pluginconfig.Port.ToString(); + this._user = this.pluginconfig.User; + this._pass = this.pluginconfig.Password; + this._topic = this.pluginconfig.Topic; + this._enable = this.pluginconfig.Enable; + + this.textServer.BeginInvoke((Action)(() => { + this.textServer.Text = this._server; + })); + this.textPort.BeginInvoke((Action)(() => { + this.textPort.Text = this._port; + })); + this.textUser.BeginInvoke((Action)(() => { + this.textUser.Text = this._user; + })); + this.textPass.BeginInvoke((Action)(() => { + this.textPass.Text = this._pass; + })); + this.textTopic.BeginInvoke((Action)(() => { + this.textTopic.Text = this._topic; + })); + this.boxEnable.BeginInvoke((Action)(() => { + this.boxEnable.Checked = this._enable; + this.textServer.Enabled = this._enable; + this.textPort.Enabled = this._enable; + this.textUser.Enabled = this._enable; + this.textPass.Enabled = this._enable; + this.textTopic.Enabled = this._enable; + this.filterButton.Enabled = this._enable; + this.testButton.Enabled = this._enable; + })); + } + + public Boolean SaveSettings() { + if (Int32.TryParse(this._port, out Int32 port)) { + this.pluginconfig.Port = port; + } else { + return false; + } + this.pluginconfig.Server = this._server; + this.pluginconfig.User = this._user; + this.pluginconfig.Password = this._pass; + this.pluginconfig.Topic = this._topic; + this.pluginconfig.Enable = this._enable; + this.pluginconfig.Saved(); + return true; + } + + public void ResetSettings() { } } } diff --git a/BosmonMqtt/bin/Release/BosmonMqtt.dll b/BosmonMqtt/bin/Release/BosmonMqtt.dll index 79dd32ed0a9c1d7b68cf88081a65ee70283d2bbe..9a6500b0b1e7190f23259fe160275b3ff8f0266c 100644 GIT binary patch literal 24064 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 r&yM@0(x(IZ_<>^-F@s$PC>zB91WZ6I p!^ptEvkr(SFfarKy99ro@?nv6lDg}x*WXV5F&AsztT5pLI{aT2