diff --git a/Bot-Utils/ABot.cs b/Bot-Utils/ABot.cs index 661ca64..7965a80 100644 --- a/Bot-Utils/ABot.cs +++ b/Bot-Utils/ABot.cs @@ -4,68 +4,39 @@ using System.Threading; namespace BlubbFish.Utils.IoT.Bots { public abstract class ABot { - #if !NETCOREAPP - private Thread sig_thread; - #endif 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; + private void ConsoleCancelEvent(Object sender, ConsoleCancelEventArgs e) { + e.Cancel = true; + Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.ConsoleCancelEvent()"); + this.RunningProcess = false; } #if NETCOREAPP - private void Default_Unloading(AssemblyLoadContext obj) { - Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.SetupShutdown: Signalhandler Windows NETCORE recieved."); - this.RunningProcess = false; - Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Shutdown."); - this.Dispose(); - } + private void Unloading(AssemblyLoadContext obj) => this.RunningProcess = false; + + private void ProcessExit(Object sender, EventArgs e) => this.RunningProcess = false; #endif - protected void WaitForShutdown() { - if(Type.GetType("Mono.Runtime") != null) { - #if !NETCOREAPP - 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(); - #endif - } else { - #if NETCOREAPP - AssemblyLoadContext.Default.Unloading += this.Default_Unloading; - Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Netcore attached."); - #endif - Console.CancelKeyPress += new ConsoleCancelEventHandler(this.SetupShutdown); - Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Windows attached."); - } - while(this.RunningProcess) { - Thread.Sleep(100); - } - Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Shutdown."); + protected void WaitForShutdown() { + #if NETCOREAPP + AssemblyLoadContext.Default.Unloading += this.Unloading; + AppDomain.CurrentDomain.ProcessExit += this.ProcessExit; + Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Attach Unloading and ProcessExit."); + #endif + Console.CancelKeyPress += new ConsoleCancelEventHandler(this.ConsoleCancelEvent); + Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Attach ConsoleCancelEvent."); + while(this.RunningProcess) { + Thread.Sleep(100); + } + Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Shutdown."); } - - public virtual void Dispose() { - #if !NETCOREAPP - if(this.sig_thread != null && this.sig_thread.IsAlive) { - this.sig_thread.Abort(); - } - #endif + Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.Dispose: Shutdown."); + this.RunningProcess = false; } } } diff --git a/Bot-Utils/Bot-Utils.csproj b/Bot-Utils/Bot-Utils.csproj index eb2da40..09cf5ba 100644 --- a/Bot-Utils/Bot-Utils.csproj +++ b/Bot-Utils/Bot-Utils.csproj @@ -5,17 +5,18 @@ BlubbFish.Utils.IoT.Bots Bot-Utils Bots.IoT.Utils.BlubbFish - 1.2.4 + 1.2.5 de-DE Bot-Utils are helpers for programming a bot BlubbFish BlubbFish - Copyright © BlubbFish 2018 - 18.01.2022 + Copyright © BlubbFish 2018 - 20.01.2022 LICENSE http://git.blubbfish.net/vs_utils/Bot-Utils http://git.blubbfish.net/vs_utils/Bot-Utils.git git + 1.2.5 - 2022-01-20 - Better linux handling 1.2.4 - 2022-01-18 - Config enabled module loading 1.2.3 - 2022-01-09 - Tiny Refactoring 1.2.2 - 2021-08-22 - Going to netcore diff --git a/Bot-Utils/Bot.cs b/Bot-Utils/Bot.cs index 073265b..06c0553 100644 --- a/Bot-Utils/Bot.cs +++ b/Bot-Utils/Bot.cs @@ -11,6 +11,7 @@ namespace BlubbFish.Utils.IoT.Bots { protected void ModulDispose() { foreach (KeyValuePair> item in this.moduls) { + Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.ModulDispose: Entlade Modul: " + item.Key); item.Value.Dispose(); Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.ModulDispose: Modul entladen: " + item.Key); } diff --git a/Bot-Utils/Moduls/CronJob.cs b/Bot-Utils/Moduls/CronJob.cs index cc00e69..d7fe418 100644 --- a/Bot-Utils/Moduls/CronJob.cs +++ b/Bot-Utils/Moduls/CronJob.cs @@ -1,170 +1,162 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text.RegularExpressions; -using System.Threading; -using BlubbFish.Utils.IoT.Bots.Interfaces; - -namespace BlubbFish.Utils.IoT.Bots.Moduls { - public abstract class CronJob : AModul, IDisposable, IForceLoad { - protected readonly List, Object>> internalCron = new List, Object>>(); - protected Thread thread; - protected DateTime crontime; - - protected readonly Dictionary cron_named = new Dictionary { - { "@yearly", "0 0 1 1 *" }, - { "@annually", "0 0 1 1 *" }, - { "@monthly", "0 0 1 * *" }, - { "@weekly", "0 0 * * 0" }, - { "@daily", "0 0 * * *" }, - { "@hourly", "0 * * * *" } - }; - - #region Constructor - public CronJob(T lib, InIReader settings) : base(lib, settings) { - this.crontime = DateTime.Now; - this.thread = new Thread(this.Runner); - this.thread.Start(); - } - #endregion - - #region Cronjobrunner - protected void Runner() { - Thread.Sleep(DateTime.Now.AddMinutes(1).AddSeconds(DateTime.Now.Second * -1).AddMilliseconds(DateTime.Now.Millisecond * -1) - DateTime.Now); - while (true) { - if (this.crontime.Minute != DateTime.Now.Minute) { - this.crontime = DateTime.Now; - if (this.config.Count != 0) { - foreach (KeyValuePair> item in this.config) { - if (item.Value.ContainsKey("cron") && item.Value.ContainsKey("set") && this.ParseCronString(item.Value["cron"])) { - this.SetValues(item.Value["set"]); - } - } - } - foreach (Tuple, Object> item in this.internalCron) { - if (this.ParseCronString(item.Item1)) { - item.Item2?.Invoke(item.Item3); - } - } - } - Thread.Sleep(100); - } - } - - protected abstract void SetValues(String value); - #endregion - - #region CronFunctions - protected Boolean ParseCronString(String cronstring) { - cronstring = cronstring.Trim(); - if (this.cron_named.ContainsKey(cronstring)) { - cronstring = this.cron_named[cronstring]; - } - String[] value = cronstring.Split(' '); - if (value.Length != 5) { - return false; - } - if (!this.CheckDateStr(this.crontime.ToString("mm"), value[0], "0-59")) { - return false; - } - if (!this.CheckDateStr(this.crontime.ToString("HH"), value[1], "0-23")) { - return false; - } - if (!this.CheckDateStr(this.crontime.ToString("MM"), value[3], "1-12")) { - return false; - } - if (value[2] != "*" && value[4] != "*") { - if (!this.CheckDateStr(this.crontime.ToString("dd"), value[2], "1-31") && !this.CheckDateStr(((Int32)this.crontime.DayOfWeek).ToString(), value[4], "0-7")) { - return false; - } - } else { - if (!this.CheckDateStr(this.crontime.ToString("dd"), value[2], "1-31")) { - return false; - } - if (!this.CheckDateStr(((Int32)this.crontime.DayOfWeek).ToString(), value[4], "0-7")) { - return false; - } - } - return true; - } - protected Boolean CheckDateStr(String date, String cron, String limit) { - cron = cron.ToLower(); - for (Int32 i = 0; i <= 6; i++) { - cron = cron.Replace(DateTime.Parse("2015-01-" + (4 + i) + "T00:00:00").ToString("ddd", CultureInfo.CreateSpecificCulture("en-US")), i.ToString()); - cron = cron.Replace(DateTime.Parse("2015-01-" + (4 + i) + "T00:00:00").ToString("dddd", CultureInfo.CreateSpecificCulture("en-US")), i.ToString()); - } - for (Int32 i = 1; i <= 12; i++) { - cron = cron.Replace(DateTime.Parse("2015-" + i + "-01T00:00:00").ToString("MMM", CultureInfo.CreateSpecificCulture("en-US")), i.ToString()); - cron = cron.Replace(DateTime.Parse("2015-" + i + "-01T00:00:00").ToString("MMMM", CultureInfo.CreateSpecificCulture("en-US")), i.ToString()); - } - if (cron.Contains("*")) { - cron = cron.Replace("*", limit); - } - if (cron.Contains("-")) { - MatchCollection m = new Regex("(\\d+)-(\\d+)").Matches(cron); - foreach (Match p in m) { - List s = new List(); - for (Int32 i = Math.Min(Int32.Parse(p.Groups[1].Value), Int32.Parse(p.Groups[2].Value)); i <= Math.Max(Int32.Parse(p.Groups[1].Value), Int32.Parse(p.Groups[2].Value)); i++) { - s.Add(i.ToString()); - } - cron = cron.Replace(p.Groups[0].Value, String.Join(",", s)); - } - } - Int32 match = 0; - if (cron.Contains("/")) { - Match m = new Regex("/(\\d+)").Match(cron); - cron = cron.Replace(m.Groups[0].Value, ""); - match = Int32.Parse(m.Groups[1].Value); - } - Dictionary ret = new Dictionary(); - if (!cron.Contains(",")) { - ret.Add(Int32.Parse(cron), ""); - } else { - foreach (String item in cron.Split(',')) { - if (!ret.ContainsKey(Int32.Parse(item))) { - ret.Add(Int32.Parse(item), ""); - } - } - } - if (match != 0) { - Dictionary r = new Dictionary(); - foreach (KeyValuePair item in ret) { - if (item.Key % match == 0) { - r.Add(item.Key, ""); - } - } - ret = r; - } - return ret.ContainsKey(Int32.Parse(date)); - } - #endregion - - #region AModul - public override void SetInterconnection(String cron, Action hook, Object data) => this.internalCron.Add(new Tuple, Object>(cron, hook, data)); - - protected override void UpdateConfig() { } - #endregion - - #region IDisposable Support - private Boolean disposedValue = false; - - protected virtual void Dispose(Boolean disposing) { - if (!this.disposedValue) { - if (disposing) { - if (this.thread != null) { - this.thread.Abort(); - while (this.thread.ThreadState == ThreadState.Running) { Thread.Sleep(100); } - } - } - this.thread = null; - this.disposedValue = true; - } - } - - public override void Dispose() { - this.Dispose(true); - GC.SuppressFinalize(this); - } - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.RegularExpressions; +using System.Threading; + +using BlubbFish.Utils.IoT.Bots.Interfaces; + +namespace BlubbFish.Utils.IoT.Bots.Moduls { + public abstract class CronJob : AModul, IForceLoad { + protected readonly List, Object>> internalCron = new List, Object>>(); + protected Thread thread; + protected Boolean threadRunning = false; + protected DateTime crontime; + + protected readonly Dictionary cron_named = new Dictionary { + { "@yearly", "0 0 1 1 *" }, + { "@annually", "0 0 1 1 *" }, + { "@monthly", "0 0 1 * *" }, + { "@weekly", "0 0 * * 0" }, + { "@daily", "0 0 * * *" }, + { "@hourly", "0 * * * *" } + }; + + #region Constructor + public CronJob(T lib, InIReader settings) : base(lib, settings) { + this.crontime = DateTime.Now; + this.thread = new Thread(this.Runner); + this.threadRunning = true; + this.thread.Start(); + } + #endregion + + #region Cronjobrunner + protected void Runner() { + DateTime nextminute = DateTime.Now.AddMinutes(1).AddSeconds(DateTime.Now.Second * -1).AddMilliseconds(DateTime.Now.Millisecond * -1); + while(nextminute > DateTime.Now && this.threadRunning) { + Thread.Sleep(100); + } + while (this.threadRunning) { + if (this.crontime.Minute != DateTime.Now.Minute) { + this.crontime = DateTime.Now; + if (this.config.Count != 0) { + foreach (KeyValuePair> item in this.config) { + if (item.Value.ContainsKey("cron") && item.Value.ContainsKey("set") && this.ParseCronString(item.Value["cron"])) { + this.SetValues(item.Value["set"]); + } + } + } + foreach (Tuple, Object> item in this.internalCron) { + if (this.ParseCronString(item.Item1)) { + item.Item2?.Invoke(item.Item3); + } + } + } + Thread.Sleep(100); + } + } + + protected abstract void SetValues(String value); + #endregion + + #region CronFunctions + protected Boolean ParseCronString(String cronstring) { + cronstring = cronstring.Trim(); + if (this.cron_named.ContainsKey(cronstring)) { + cronstring = this.cron_named[cronstring]; + } + String[] value = cronstring.Split(' '); + if (value.Length != 5) { + return false; + } + if (!this.CheckDateStr(this.crontime.ToString("mm"), value[0], "0-59")) { + return false; + } + if (!this.CheckDateStr(this.crontime.ToString("HH"), value[1], "0-23")) { + return false; + } + if (!this.CheckDateStr(this.crontime.ToString("MM"), value[3], "1-12")) { + return false; + } + if (value[2] != "*" && value[4] != "*") { + if (!this.CheckDateStr(this.crontime.ToString("dd"), value[2], "1-31") && !this.CheckDateStr(((Int32)this.crontime.DayOfWeek).ToString(), value[4], "0-7")) { + return false; + } + } else { + if (!this.CheckDateStr(this.crontime.ToString("dd"), value[2], "1-31")) { + return false; + } + if (!this.CheckDateStr(((Int32)this.crontime.DayOfWeek).ToString(), value[4], "0-7")) { + return false; + } + } + return true; + } + protected Boolean CheckDateStr(String date, String cron, String limit) { + cron = cron.ToLower(); + for (Int32 i = 0; i <= 6; i++) { + cron = cron.Replace(DateTime.Parse("2015-01-" + (4 + i) + "T00:00:00").ToString("ddd", CultureInfo.CreateSpecificCulture("en-US")), i.ToString()); + cron = cron.Replace(DateTime.Parse("2015-01-" + (4 + i) + "T00:00:00").ToString("dddd", CultureInfo.CreateSpecificCulture("en-US")), i.ToString()); + } + for (Int32 i = 1; i <= 12; i++) { + cron = cron.Replace(DateTime.Parse("2015-" + i + "-01T00:00:00").ToString("MMM", CultureInfo.CreateSpecificCulture("en-US")), i.ToString()); + cron = cron.Replace(DateTime.Parse("2015-" + i + "-01T00:00:00").ToString("MMMM", CultureInfo.CreateSpecificCulture("en-US")), i.ToString()); + } + if (cron.Contains("*")) { + cron = cron.Replace("*", limit); + } + if (cron.Contains("-")) { + MatchCollection m = new Regex("(\\d+)-(\\d+)").Matches(cron); + foreach (Match p in m) { + List s = new List(); + for (Int32 i = Math.Min(Int32.Parse(p.Groups[1].Value), Int32.Parse(p.Groups[2].Value)); i <= Math.Max(Int32.Parse(p.Groups[1].Value), Int32.Parse(p.Groups[2].Value)); i++) { + s.Add(i.ToString()); + } + cron = cron.Replace(p.Groups[0].Value, String.Join(",", s)); + } + } + Int32 match = 0; + if (cron.Contains("/")) { + Match m = new Regex("/(\\d+)").Match(cron); + cron = cron.Replace(m.Groups[0].Value, ""); + match = Int32.Parse(m.Groups[1].Value); + } + Dictionary ret = new Dictionary(); + if (!cron.Contains(",")) { + ret.Add(Int32.Parse(cron), ""); + } else { + foreach (String item in cron.Split(',')) { + if (!ret.ContainsKey(Int32.Parse(item))) { + ret.Add(Int32.Parse(item), ""); + } + } + } + if (match != 0) { + Dictionary r = new Dictionary(); + foreach (KeyValuePair item in ret) { + if (item.Key % match == 0) { + r.Add(item.Key, ""); + } + } + ret = r; + } + return ret.ContainsKey(Int32.Parse(date)); + } + #endregion + + #region AModul + public override void SetInterconnection(String cron, Action hook, Object data) => this.internalCron.Add(new Tuple, Object>(cron, hook, data)); + + protected override void UpdateConfig() { } + + public override void Dispose() { + this.threadRunning = false; + while(this.thread != null && this.thread.IsAlive) { + Thread.Sleep(10); + } + this.thread = null; + } + #endregion + } +} diff --git a/Bot-Utils/Moduls/Mqtt.cs b/Bot-Utils/Moduls/Mqtt.cs index b3d5f13..5af54d3 100644 --- a/Bot-Utils/Moduls/Mqtt.cs +++ b/Bot-Utils/Moduls/Mqtt.cs @@ -7,7 +7,7 @@ using BlubbFish.Utils.IoT.Events; using LitJson; namespace BlubbFish.Utils.IoT.Bots.Moduls { - public abstract class Mqtt : AModul, IDisposable { + public abstract class Mqtt : AModul { protected ABackend mqtt; protected Dictionary> modules; @@ -34,6 +34,8 @@ namespace BlubbFish.Utils.IoT.Bots.Moduls { public override void Interconnect(Dictionary> moduls) => this.modules = moduls; protected override void UpdateConfig() => this.Reconnect(); + + public override void Dispose() => this.Disconnect(); #endregion protected Tuple ChangeConfig(BackendEvent e, String topic) { @@ -74,23 +76,5 @@ namespace BlubbFish.Utils.IoT.Bots.Moduls { } return new Tuple(false, null); } - - #region IDisposable Support - private Boolean disposedValue = false; - - protected void Dispose(Boolean disposing) { - if (!this.disposedValue) { - if (disposing) { - this.Disconnect(); - } - this.disposedValue = true; - } - } - - public override void Dispose() { - this.Dispose(true); - GC.SuppressFinalize(this); - } - #endregion } } diff --git a/Bot-Utils/Moduls/Overtaker.cs b/Bot-Utils/Moduls/Overtaker.cs index 25da35e..5a23261 100644 --- a/Bot-Utils/Moduls/Overtaker.cs +++ b/Bot-Utils/Moduls/Overtaker.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; namespace BlubbFish.Utils.IoT.Bots.Moduls { - public abstract class Overtaker : AModul, IDisposable { + public abstract class Overtaker : AModul { protected readonly Dictionary> events = new Dictionary>(); #region Constructor @@ -62,23 +62,8 @@ namespace BlubbFish.Utils.IoT.Bots.Moduls { #region AModul public override void Interconnect(Dictionary> moduls) { } protected override void UpdateConfig() => this.ParseIni(); - #endregion - - #region IDisposable Support - private Boolean disposedValue = false; - - protected virtual void Dispose(Boolean disposing) { - if (!this.disposedValue) { - if (disposing) { - } - this.disposedValue = true; - } + public override void Dispose() { } - - public override void Dispose() { - this.Dispose(true); - GC.SuppressFinalize(this); - } - #endregion + #endregion } } diff --git a/Bot-Utils/Moduls/Statuspolling.cs b/Bot-Utils/Moduls/Statuspolling.cs index 3df061a..780746c 100644 --- a/Bot-Utils/Moduls/Statuspolling.cs +++ b/Bot-Utils/Moduls/Statuspolling.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using BlubbFish.Utils.IoT.Bots.Interfaces; namespace BlubbFish.Utils.IoT.Bots.Moduls { - public abstract class Statuspolling : AModul, IDisposable, IForceLoad { + public abstract class Statuspolling : AModul, IForceLoad { #region Constructor public Statuspolling(T lib, InIReader settings) : base(lib, settings) { } @@ -31,22 +31,7 @@ namespace BlubbFish.Utils.IoT.Bots.Moduls { } } protected override void UpdateConfig() { } - #endregion - - #region IDisposable Support - private Boolean disposedValue = false; - - protected virtual void Dispose(Boolean disposing) { - if (!this.disposedValue) { - if (disposing) { - } - this.disposedValue = true; - } - } - - public override void Dispose() { - this.Dispose(true); - GC.SuppressFinalize(this); + public override void Dispose() { } #endregion } diff --git a/Changelog.md b/Changelog.md index c972304..84e4201 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,15 @@ # Changelog +## 1.2.5 - 2022-01-20 - Better linux handling +### New Features +* Add ProcessExit Handler in ABot +* Add Output in ModulDispose +### Bugfixes +* Eleminate Hangs in Cronjob, when in startup phase it not blocks shutdown +### Changes +* Reweite ABot, remove Mono Code +* Codingstyle + ## 1.2.4 - 2022-01-18 - Config enabled module loading ### New Features * Modules can have an enabled=true|false in config, so that also enables or disables moduleloading.