[NF] Add Bot-Utils and rewrite code

This commit is contained in:
BlubbFish 2018-06-07 20:49:54 +00:00
parent cbd94ef2ea
commit e1a2634f9d
13 changed files with 492 additions and 2 deletions

View File

@ -7,10 +7,12 @@
<ProjectGuid>{BB7BFCB5-3DB0-49E1-802A-3CE3EECC59F9}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Bot_Utils</RootNamespace>
<RootNamespace>BlubbFish.Utils.IoT.Bots</RootNamespace>
<AssemblyName>Bot-Utils</AssemblyName>
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@ -29,6 +31,9 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
@ -40,8 +45,37 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Bot.cs" />
<Compile Include="Events\CronEvent.cs" />
<Compile Include="Events\ModulEventArgs.cs" />
<Compile Include="Events\SenmlEvent.cs" />
<Compile Include="Events\MqttEvent.cs" />
<Compile Include="Events\OvertakerEvent.cs" />
<Compile Include="Events\StatusPollingEvent.cs" />
<Compile Include="Helper.cs" />
<Compile Include="Interfaces\IForceLoad.cs" />
<Compile Include="Moduls\AModul.cs" />
<Compile Include="Moduls\Mqtt.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Mono.Posix">
<Version>5.4.0.201</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Librarys\litjson\litjson\litjson_4.7.1.csproj">
<Project>{91a14cd2-2940-4500-8193-56d37edddbaa}</Project>
<Name>litjson_4.7.1</Name>
</ProjectReference>
<ProjectReference Include="..\IoT\Utils-IoT.csproj">
<Project>{b870e4d5-6806-4a0b-b233-8907eedc5afc}</Project>
<Name>Utils-IoT</Name>
</ProjectReference>
<ProjectReference Include="..\Utils\Utils.csproj">
<Project>{fac8ce64-bf13-4ece-8097-aeb5dd060098}</Project>
<Name>Utils</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

90
Bot.cs Normal file
View File

@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using BlubbFish.Utils.IoT.Bots.Moduls;
using BlubbFish.Utils.IoT.Bots.Events;
using BlubbFish.Utils.IoT.Bots.Interfaces;
namespace BlubbFish.Utils.IoT.Bots {
public abstract class Bot {
private Thread sig_thread;
private Boolean RunningProcess = true;
protected ProgramLogger logger = new ProgramLogger();
protected readonly Dictionary<String, Object> moduls = new Dictionary<String, Object>();
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("Signalhandler Mono attached.");
while (true) {
Int32 i = Mono.Unix.UnixSignal.WaitAny(signals, -1);
Console.WriteLine("Signalhandler Mono INT recieved " + i + ".");
this.RunningProcess = false;
break;
}
});
this.sig_thread.Start();
} else {
Console.CancelKeyPress += new ConsoleCancelEventHandler(this.SetupShutdown);
Console.WriteLine("Signalhandler Windows attached.");
}
while (this.RunningProcess) {
Thread.Sleep(100);
}
}
private void SetupShutdown(Object sender, ConsoleCancelEventArgs e) {
e.Cancel = true;
Console.WriteLine("Signalhandler Windows INT recieved.");
this.RunningProcess = false;
}
protected void ModulDispose<T>() {
foreach (KeyValuePair<String, Object> item in this.moduls) {
((AModul<T>)item.Value).Dispose();
Console.WriteLine("Modul entladen: " + item.Key);
}
if (this.sig_thread != null && this.sig_thread.IsAlive) {
this.sig_thread.Abort();
}
}
protected void ModulLoader<T>(String @namespace, Object library) {
Assembly asm = Assembly.GetEntryAssembly();
foreach (Type item in asm.GetTypes()) {
if (item.Namespace == @namespace) {
Type t = item;
String name = t.Name;
if (InIReader.ConfigExist(name.ToLower())) {
this.moduls.Add(name, (AModul<T>)t.GetConstructor(new Type[] { typeof(T), typeof(InIReader) }).Invoke(new Object[] { library, InIReader.GetInstance(name.ToLower()) }));
Console.WriteLine("Load Modul " + name);
} else if (t.HasInterface(typeof(IForceLoad))) {
this.moduls.Add(name, (AModul<T>)t.GetConstructor(new Type[] { typeof(T), typeof(InIReader) }).Invoke(new Object[] { library, null }));
Console.WriteLine("Load Modul Forced " + name);
}
}
}
}
protected void ModulInterconnect<T>() {
foreach (KeyValuePair<String, Object> item in this.moduls) {
((AModul<T>)item.Value).Interconnect(this.moduls);
}
}
protected void ModulEvents<T>() {
foreach (KeyValuePair<String, Object> item in this.moduls) {
((AModul<T>)item.Value).Update += this.ModulUpdate;
}
}
protected void ModulUpdate(Object sender, ModulEventArgs e) {
Console.WriteLine(e.ToString());
}
}
}

16
Events/CronEvent.cs Normal file
View File

@ -0,0 +1,16 @@
using System;
namespace BlubbFish.Utils.IoT.Bots.Events {
public class CronEvent : ModulEventArgs {
public CronEvent() {
}
public CronEvent(String addr, String prop, String value) {
this.Address = addr;
this.Property = prop;
this.Value = value;
this.Source = "Cronjob";
}
}
}

15
Events/ModulEventArgs.cs Normal file
View File

@ -0,0 +1,15 @@
using System;
namespace BlubbFish.Utils.IoT.Bots.Events {
public class ModulEventArgs : EventArgs {
public ModulEventArgs() {
}
public String Address { get; protected set; }
public String Property { get; protected set; }
public String Value { get; protected set; }
public String Source { get; protected set; }
public override String ToString() {
return this.Source + ": " + this.Address + " set " + this.Property + " to " + this.Value;
}
}
}

16
Events/MqttEvent.cs Normal file
View File

@ -0,0 +1,16 @@
using System;
namespace BlubbFish.Utils.IoT.Bots.Events {
public class MqttEvent : ModulEventArgs {
public MqttEvent() {
}
public MqttEvent(String topic, String text) {
this.Address = topic;
this.Value = text;
this.Source = "MQTT";
}
public override String ToString() {
return this.Source + ": on " + this.Address + " set " + this.Value;
}
}
}

16
Events/OvertakerEvent.cs Normal file
View File

@ -0,0 +1,16 @@
using System;
namespace BlubbFish.Utils.IoT.Bots.Events {
public class OvertakerEvent : ModulEventArgs {
public OvertakerEvent() {
}
public OvertakerEvent(String addr, String prop, String value) {
this.Address = addr;
this.Property = prop;
this.Value = value;
this.Source = "Overtaker";
}
}
}

16
Events/SenmlEvent.cs Normal file
View File

@ -0,0 +1,16 @@
using System;
namespace BlubbFish.Utils.IoT.Bots.Events {
public class SenmlEvent : ModulEventArgs {
public SenmlEvent() {
}
public SenmlEvent(String topic, String text) {
this.Address = topic;
this.Value = text;
this.Source = "Senml";
}
public override String ToString() {
return this.Source + ": on " + this.Address + " set " + this.Value;
}
}
}

View File

@ -0,0 +1,18 @@
using System;
namespace BlubbFish.Utils.IoT.Bots.Events {
public class StatusPollingEvent : ModulEventArgs {
public StatusPollingEvent() {
}
public StatusPollingEvent(String text, String node) {
this.Value = text;
this.Address = node;
this.Source = "POLLING";
}
public override String ToString() {
return this.Source + ": " + this.Value + " on " + this.Address;
}
}
}

79
Helper.cs Normal file
View File

@ -0,0 +1,79 @@
using System;
using System.Reflection;
namespace BlubbFish.Utils.IoT.Bots {
public static class Helper {
#region PropertyHelper
public static Boolean HasProperty(this Object o, String type) {
Type t = o.GetType();
foreach (PropertyInfo item in t.GetProperties()) {
if (item.Name == type) {
return true;
}
}
return false;
}
public static Object GetProperty(this Object o, String name) {
PropertyInfo prop = o.GetType().GetProperty(name);
if (prop.CanRead) {
return prop.GetValue(o);
}
return null;
}
public static void SetProperty(this Object o, String name, String value) {
PropertyInfo prop = o.GetType().GetProperty(name);
if (prop.CanWrite) {
if (prop.PropertyType == typeof(Boolean) && Boolean.TryParse(value, out Boolean vb)) {
prop.SetValue(o, vb);
} else if (prop.PropertyType == typeof(Int32) && Int32.TryParse(value, out Int32 v32)) {
prop.SetValue(o, v32);
} else if (prop.PropertyType == typeof(Single) && Single.TryParse(value, out Single vs)) {
prop.SetValue(o, vs);
} else if (prop.PropertyType == typeof(Double) && Double.TryParse(value, out Double vd)) {
prop.SetValue(o, vd);
} else if (prop.PropertyType == typeof(Int64) && Int64.TryParse(value, out Int64 v64)) {
prop.SetValue(o, v64);
}
}
}
#endregion
#region InterfaceHelper
public static Boolean HasInterface(this Type o, Type interf) {
foreach (Type item in o.GetInterfaces()) {
if (item == interf) {
return true;
}
}
return false;
}
public static Boolean HasAbstract(this Type o, Type type) {
if (o.BaseType == type) {
return true;
}
return false;
}
#endregion
#region StringHelper
public static String ToUpperLower(this String s) {
if (s.Length == 0) {
return "";
}
if (s.Length == 1) {
return s.ToUpper();
}
return s[0].ToString().ToUpper() + s.Substring(1).ToLower();
}
public static void WriteError(String text) {
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine("ERROR: " + text);
Console.ResetColor();
}
#endregion
}
}

4
Interfaces/IForceLoad.cs Normal file
View File

@ -0,0 +1,4 @@
namespace BlubbFish.Utils.IoT.Bots.Interfaces {
public interface IForceLoad {
}
}

70
Moduls/AModul.cs Normal file
View File

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using BlubbFish.Utils.IoT.Bots.Events;
namespace BlubbFish.Utils.IoT.Bots.Moduls {
public abstract class AModul<T> {
protected T library;
private readonly InIReader settings;
protected Dictionary<String, Dictionary<String, String>> config = new Dictionary<String, Dictionary<String, String>>();
public Boolean HasConfig { get; private set; }
public Boolean ConfigPublic { get; private set; }
public delegate void ModulEvent(Object sender, ModulEventArgs e);
public abstract event ModulEvent Update;
public AModul(T lib, InIReader settings) {
this.HasConfig = false;
this.ConfigPublic = false;
this.library = lib;
this.settings = settings;
this.ParseConfig();
}
private void ParseConfig() {
if (this.settings != null) {
this.HasConfig = true;
foreach (String item in this.settings.GetSections(false)) {
this.config.Add(item, this.settings.GetSection(item));
}
if (this.config.ContainsKey("modul")) {
this.ConfigPublic = this.config["modul"].ContainsKey("config") && this.config["modul"]["config"].ToLower() == "public";
}
}
}
public Dictionary<String, Dictionary<String, String>> GetConfig() {
if (this.HasConfig && this.ConfigPublic) {
Dictionary<String, Dictionary<String, String>> ret = new Dictionary<String, Dictionary<String, String>>(this.config);
if (ret.ContainsKey("modul")) {
ret.Remove("modul");
}
return ret;
}
return new Dictionary<String, Dictionary<String, String>>();
}
public virtual void Interconnect(Dictionary<String, Object> moduls) { }
public virtual void SetInterconnection(String param, Action<Object> hook, Object data) { }
public abstract void Dispose();
public void SetConfig(Dictionary<String, Dictionary<String, String>> newconf) {
if (this.HasConfig && this.ConfigPublic) {
if (newconf.ContainsKey("modul")) {
newconf.Remove("modul");
}
if (this.config.ContainsKey("modul")) {
newconf.Add("modul", this.config["modul"]);
}
this.config = newconf;
this.settings.SetSections(this.config);
this.UpdateConfig();
}
}
protected abstract void UpdateConfig();
}
}

116
Moduls/Mqtt.cs Normal file
View File

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

Binary file not shown.