[1.2.0] Refactor Bot to ABot and refere MultiSourceBot, Webserver and Bot to it. Add MultiSourceBot. Rewrite Mqtt module so that it not need to watch the connection.

This commit is contained in:
BlubbFish 2019-05-27 17:23:31 +02:00
parent cf3413a3d7
commit 8932867ed9
8 changed files with 186 additions and 173 deletions

48
Bot-Utils/ABot.cs Normal file
View File

@ -0,0 +1,48 @@
using System;
using System.Threading;
namespace BlubbFish.Utils.IoT.Bots {
public abstract class ABot {
private Thread sig_thread;
private Boolean RunningProcess = true;
protected ProgramLogger logger = new ProgramLogger();
private void SetupShutdown(Object sender, ConsoleCancelEventArgs e) {
e.Cancel = true;
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.SetupShutdown: Signalhandler Windows INT recieved.");
this.RunningProcess = false;
}
protected void WaitForShutdown() {
if(Type.GetType("Mono.Runtime") != null) {
this.sig_thread = new Thread(delegate () {
Mono.Unix.UnixSignal[] signals = new Mono.Unix.UnixSignal[] {
new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGTERM),
new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGINT)
};
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Mono attached.");
while(true) {
Int32 i = Mono.Unix.UnixSignal.WaitAny(signals, -1);
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Mono INT recieved " + i + ".");
this.RunningProcess = false;
break;
}
});
this.sig_thread.Start();
} else {
Console.CancelKeyPress += new ConsoleCancelEventHandler(this.SetupShutdown);
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Windows attached.");
}
while(this.RunningProcess) {
Thread.Sleep(100);
}
}
public virtual void Dispose() {
if(this.sig_thread != null && this.sig_thread.IsAlive) {
this.sig_thread.Abort();
}
}
}
}

View File

@ -46,6 +46,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ABot.cs" />
<Compile Include="Bot.cs" /> <Compile Include="Bot.cs" />
<Compile Include="Events\CronEvent.cs" /> <Compile Include="Events\CronEvent.cs" />
<Compile Include="Events\ModulEventArgs.cs" /> <Compile Include="Events\ModulEventArgs.cs" />
@ -59,6 +60,7 @@
<Compile Include="Moduls\Mqtt.cs" /> <Compile Include="Moduls\Mqtt.cs" />
<Compile Include="Moduls\Overtaker.cs" /> <Compile Include="Moduls\Overtaker.cs" />
<Compile Include="Moduls\Statuspolling.cs" /> <Compile Include="Moduls\Statuspolling.cs" />
<Compile Include="MultiSourceBot.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Webserver.cs" /> <Compile Include="Webserver.cs" />
</ItemGroup> </ItemGroup>

View File

@ -1,57 +1,20 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Threading;
using BlubbFish.Utils.IoT.Bots.Moduls;
using BlubbFish.Utils.IoT.Bots.Events; using BlubbFish.Utils.IoT.Bots.Events;
using BlubbFish.Utils.IoT.Bots.Interfaces; using BlubbFish.Utils.IoT.Bots.Interfaces;
using BlubbFish.Utils.IoT.Bots.Moduls;
namespace BlubbFish.Utils.IoT.Bots { namespace BlubbFish.Utils.IoT.Bots {
public abstract class Bot<T> { public abstract class Bot<T> : ABot {
private Thread sig_thread; protected readonly Dictionary<String, AModul<T>> moduls = new Dictionary<String, AModul<T>>();
private Boolean RunningProcess = true;
protected ProgramLogger logger = new ProgramLogger();
protected readonly Dictionary<String, AModul<T>> moduls = new Dictionary<String, AModul<T>>();
protected void WaitForShutdown() {
if (Type.GetType("Mono.Runtime") != null) {
this.sig_thread = new Thread(delegate () {
Mono.Unix.UnixSignal[] signals = new Mono.Unix.UnixSignal[] {
new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGTERM),
new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGINT)
};
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Mono attached.");
while (true) {
Int32 i = Mono.Unix.UnixSignal.WaitAny(signals, -1);
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Mono INT recieved " + i + ".");
this.RunningProcess = false;
break;
}
});
this.sig_thread.Start();
} else {
Console.CancelKeyPress += new ConsoleCancelEventHandler(this.SetupShutdown);
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Windows attached.");
}
while (this.RunningProcess) {
Thread.Sleep(100);
}
}
private void SetupShutdown(Object sender, ConsoleCancelEventArgs e) {
e.Cancel = true;
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.SetupShutdown: Signalhandler Windows INT recieved.");
this.RunningProcess = false;
}
protected void ModulDispose() { protected void ModulDispose() {
foreach (KeyValuePair<String, AModul<T>> item in this.moduls) { foreach (KeyValuePair<String, AModul<T>> item in this.moduls) {
item.Value.Dispose(); item.Value.Dispose();
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.ModulDispose: Modul entladen: " + item.Key); Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.ModulDispose: Modul entladen: " + item.Key);
} }
if (this.sig_thread != null && this.sig_thread.IsAlive) { this.Dispose();
this.sig_thread.Abort();
}
} }
protected void ModulLoader(String @namespace, Object library) { protected void ModulLoader(String @namespace, Object library) {
@ -92,8 +55,6 @@ namespace BlubbFish.Utils.IoT.Bots {
} }
} }
protected void ModulUpdate(Object sender, ModulEventArgs e) { protected void ModulUpdate(Object sender, ModulEventArgs e) => Console.WriteLine(e.ToString());
Console.WriteLine(e.ToString());
}
} }
} }

View File

@ -54,9 +54,7 @@ namespace BlubbFish.Utils.IoT.Bots.Moduls {
protected abstract void LibUpadteThread(Object state); protected abstract void LibUpadteThread(Object state);
protected void HandleLibUpdate(Object sender, EventArgs e) { protected void HandleLibUpdate(Object sender, EventArgs e) => ThreadPool.QueueUserWorkItem(this.LibUpadteThread, e);
ThreadPool.QueueUserWorkItem(this.LibUpadteThread, e);
}
public abstract void Dispose(); public abstract void Dispose();

View File

@ -1,119 +1,102 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using BlubbFish.Utils.IoT.Bots.Events;
using BlubbFish.Utils.IoT.Bots.Events; using BlubbFish.Utils.IoT.Connector;
using BlubbFish.Utils.IoT.Connector; using BlubbFish.Utils.IoT.Events;
using BlubbFish.Utils.IoT.Events; using LitJson;
using LitJson;
namespace BlubbFish.Utils.IoT.Bots.Moduls {
namespace BlubbFish.Utils.IoT.Bots.Moduls { public abstract class Mqtt<T> : AModul<T>, IDisposable {
public abstract class Mqtt<T> : AModul<T>, IDisposable { protected ABackend mqtt;
protected readonly Thread connectionWatcher; protected Dictionary<String, AModul<T>> modules;
protected ABackend mqtt;
protected Dictionary<String, AModul<T>> modules; #region Constructor
public Mqtt(T lib, InIReader settings) : base(lib, settings) => this.Connect();
#region Constructor #endregion
public Mqtt(T lib, InIReader settings) : base(lib, settings) {
if (this.config.ContainsKey("settings")) { #region Connection
this.connectionWatcher = new Thread(this.ConnectionWatcherRunner); protected void Reconnect() {
this.connectionWatcher.Start(); if(!this.config.ContainsKey("settings")) {
} else { throw new ArgumentException("Setting section [settings] is missing!");
throw new ArgumentException("Setting section [settings] is missing!"); } else {
} this.Disconnect();
} this.Connect();
#endregion }
}
#region Watcher
protected void ConnectionWatcherRunner() { protected void Connect() {
while (true) { if(!this.config.ContainsKey("settings")) {
try { throw new ArgumentException("Setting section [settings] is missing!");
if (this.mqtt == null || !this.mqtt.IsConnected) { } else {
this.Reconnect(); this.mqtt = ABackend.GetInstance(this.config["settings"], ABackend.BackendType.Data);
} }
Thread.Sleep(10000); }
} catch (Exception) { }
} protected void Disconnect() => this.mqtt.Dispose();
} #endregion
protected void Reconnect() { #region AModul
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Moduls.Mqtt.Reconnect()"); public override void Interconnect(Dictionary<String, AModul<T>> moduls) => this.modules = moduls;
this.Disconnect();
this.Connect(); protected override void UpdateConfig() => this.Reconnect();
} #endregion
protected abstract void Connect(); protected Tuple<Boolean, MqttEvent> ChangeConfig(BackendEvent e, String topic) {
if (e.From.ToString().StartsWith(topic) && (e.From.ToString().EndsWith("/set") || e.From.ToString().EndsWith("/get"))) {
protected abstract void Disconnect(); Match m = new Regex("^"+ topic + "(\\w+)/[gs]et$|").Match(e.From.ToString());
#endregion if (!m.Groups[1].Success) {
return new Tuple<Boolean, MqttEvent>(false, null);
#region AModul }
public override void Interconnect(Dictionary<String, AModul<T>> moduls) { AModul<T> modul = null;
this.modules = moduls; foreach (KeyValuePair<String, AModul<T>> item in this.modules) {
} if (item.Key.ToLower() == m.Groups[1].Value) {
modul = item.Value;
protected override void UpdateConfig() { }
this.Reconnect(); }
} if (modul == null) {
#endregion return new Tuple<Boolean, MqttEvent>(false, null);
}
protected Tuple<Boolean, MqttEvent> ChangeConfig(BackendEvent e, String topic) { if (e.From.ToString().EndsWith("/get") && modul.HasConfig && modul.ConfigPublic) {
if (e.From.ToString().StartsWith(topic) && (e.From.ToString().EndsWith("/set") || e.From.ToString().EndsWith("/get"))) { String t = topic + m.Groups[1].Value;
Match m = new Regex("^"+ topic + "(\\w+)/[gs]et$|").Match(e.From.ToString()); String d = JsonMapper.ToJson(modul.GetConfig()).ToString();
if (!m.Groups[1].Success) { ((ADataBackend)this.mqtt).Send(t, d);
return new Tuple<Boolean, MqttEvent>(false, null); return new Tuple<Boolean, MqttEvent>(true, new MqttEvent(t, d));
} } else if (e.From.ToString().EndsWith("/set") && modul.HasConfig && modul.ConfigPublic) {
AModul<T> modul = null; try {
foreach (KeyValuePair<String, AModul<T>> item in this.modules) { JsonData a = JsonMapper.ToObject(e.Message);
if (item.Key.ToLower() == m.Groups[1].Value) { Dictionary<String, Dictionary<String, String>> newconf = new Dictionary<String, Dictionary<String, String>>();
modul = item.Value; foreach (String section in a.Keys) {
} Dictionary<String, String> sectiondata = new Dictionary<String, String>();
} foreach (String item in a[section].Keys) {
if (modul == null) { sectiondata.Add(item, a[section][item].ToString());
return new Tuple<Boolean, MqttEvent>(false, null); }
} newconf.Add(section, sectiondata);
if (e.From.ToString().EndsWith("/get") && modul.HasConfig && modul.ConfigPublic) { }
String t = topic + m.Groups[1].Value; modul.SetConfig(newconf);
String d = JsonMapper.ToJson(modul.GetConfig()).ToString(); return new Tuple<Boolean, MqttEvent>(true, new MqttEvent("New Config", "Write"));
((ADataBackend)this.mqtt).Send(t, d); } catch { }
return new Tuple<Boolean, MqttEvent>(true, new MqttEvent(t, d)); }
} else if (e.From.ToString().EndsWith("/set") && modul.HasConfig && modul.ConfigPublic) { }
try { return new Tuple<Boolean, MqttEvent>(false, null);
JsonData a = JsonMapper.ToObject(e.Message); }
Dictionary<String, Dictionary<String, String>> newconf = new Dictionary<String, Dictionary<String, String>>();
foreach (String section in a.Keys) { #region IDisposable Support
Dictionary<String, String> sectiondata = new Dictionary<String, String>(); private Boolean disposedValue = false;
foreach (String item in a[section].Keys) {
sectiondata.Add(item, a[section][item].ToString()); protected void Dispose(Boolean disposing) {
} if (!this.disposedValue) {
newconf.Add(section, sectiondata); if (disposing) {
} this.Disconnect();
modul.SetConfig(newconf); }
return new Tuple<Boolean, MqttEvent>(true, new MqttEvent("New Config", "Write")); this.disposedValue = true;
} catch (Exception) { } }
} }
}
return new Tuple<Boolean, MqttEvent>(false, null); public override void Dispose() {
} this.Dispose(true);
GC.SuppressFinalize(this);
#region IDisposable Support }
private Boolean disposedValue = false; #endregion
}
protected void Dispose(Boolean disposing) { }
if (!this.disposedValue) {
if (disposing) {
this.connectionWatcher.Abort();
while (this.connectionWatcher.ThreadState == ThreadState.Running) { Thread.Sleep(10); }
this.Disconnect();
}
this.disposedValue = true;
}
}
public override void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BlubbFish.Utils.IoT.Connector;
namespace BlubbFish.Utils.IoT.Bots {
public abstract class MultiSourceBot : ABot {
protected Dictionary<String, ABackend> sources;
protected Dictionary<String, String> settings;
protected MultiSourceBot(Dictionary<String, ABackend> sources, Dictionary<String, String> settings) {
this.sources = sources;
this.settings = settings;
}
}
}

View File

@ -1,4 +1,5 @@
using System.Reflection; using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// Allgemeine Informationen über eine Assembly werden über die folgenden // Allgemeine Informationen über eine Assembly werden über die folgenden
@ -9,9 +10,10 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("BlubbFish")] [assembly: AssemblyCompany("BlubbFish")]
[assembly: AssemblyProduct("Bot-Utils")] [assembly: AssemblyProduct("Bot-Utils")]
[assembly: AssemblyCopyright("Copyright © 2018 - 21.04.2019")] [assembly: AssemblyCopyright("Copyright © 2018 - 27.05.2019")]
[assembly: AssemblyTrademark("© BlubbFish")] [assembly: AssemblyTrademark("© BlubbFish")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("de-DE")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly // Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von // für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
@ -31,8 +33,8 @@ using System.Runtime.InteropServices;
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, // Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
// indem Sie "*" wie unten gezeigt eingeben: // indem Sie "*" wie unten gezeigt eingeben:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.9")] [assembly: AssemblyVersion("1.2.0")]
[assembly: AssemblyFileVersion("1.1.9")] [assembly: AssemblyFileVersion("1.2.0")]
/* /*
* 1.1.0 Remove Helper from Bot-Utils * 1.1.0 Remove Helper from Bot-Utils
@ -46,4 +48,5 @@ using System.Runtime.InteropServices;
* 1.1.7 Restrucutre loading, so that all is init and after the listener is started, REQUEST_URL_HOST gives now host and port * 1.1.7 Restrucutre loading, so that all is init and after the listener is started, REQUEST_URL_HOST gives now host and port
* 1.1.8 Add logger to Webserver Class * 1.1.8 Add logger to Webserver Class
* 1.1.9 Modify Output of SendFileResponse * 1.1.9 Modify Output of SendFileResponse
* 1.2.0 Refactor Bot to ABot and refere MultiSourceBot, Webserver and Bot to it. Add MultiSourceBot. Rewrite Mqtt module so that it not need to watch the connection.
*/ */

View File

@ -10,13 +10,12 @@ using BlubbFish.Utils.IoT.Events;
using LitJson; using LitJson;
namespace BlubbFish.Utils.IoT.Bots { namespace BlubbFish.Utils.IoT.Bots {
public abstract class Webserver public abstract class Webserver : ABot
{ {
protected Dictionary<String, String> config; protected Dictionary<String, String> config;
protected static InIReader requests; protected static InIReader requests;
protected HttpListener httplistener; protected HttpListener httplistener;
protected ABackend databackend; protected ABackend databackend;
protected ProgramLogger logger = new ProgramLogger();
public Webserver(ABackend backend, Dictionary<String, String> settings, InIReader requestslookup) { public Webserver(ABackend backend, Dictionary<String, String> settings, InIReader requestslookup) {
this.config = settings; this.config = settings;
@ -142,9 +141,10 @@ namespace BlubbFish.Utils.IoT.Bots {
return new Dictionary<String, String>(); return new Dictionary<String, String>();
} }
public void Dispose() { public override void Dispose() {
this.httplistener.Stop(); this.httplistener.Stop();
this.httplistener.Close(); this.httplistener.Close();
base.Dispose();
} }
protected abstract void Backend_MessageIncomming(Object sender, BackendEvent e); protected abstract void Backend_MessageIncomming(Object sender, BackendEvent e);