commit fd6222451186b4d3498b74df48f1391e897f901c Author: BlubbFish Date: Sun Aug 2 23:33:31 2026 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..86db463 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +.vs +settings.conf +BosServer/bin +BosServer/obj +BosServerConvert/BosServerConvert/bin +BosServerConvert/BosServerConvert/obj +BosServerDatatypes/bin +BosServerDatatypes/obj +BosServerHTTP/bin +BosServerHTTP/obj +BosServerParser/bin +BosServerParser/obj +BosServerStorage/bin +BosServerStorage/obj +BosServerTelegram/bin +BosServerTelegram/obj \ No newline at end of file diff --git a/BosServer.sln b/BosServer.sln new file mode 100644 index 0000000..e51d211 --- /dev/null +++ b/BosServer.sln @@ -0,0 +1,97 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31112.23 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BosServer", "BosServer\BosServer.csproj", "{44AE0A15-A009-46BF-9C25-321EA81B4D19}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot-Utils", "..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj", "{1C179ACF-CFEC-469D-858A-CFE711126A7B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "..\Utils\Utils\Utils\Utils.csproj", "{ACA6F04E-5CDF-450E-B07B-050B5C90C9AB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils-IoT", "..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj", "{970CB7FF-E203-47B9-B238-BA67745FAC9A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "litjson", "..\Librarys\litjson\litjson\litjson.csproj", "{E9E055F8-552B-4CC7-9B89-BDB5EB1BC60B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConnectorUserTelegram", "..\Utils\ConnectorUserTelegram\ConnectorUserTelegram\ConnectorUserTelegram.csproj", "{007521AC-F65A-4D34-AC50-9636FD9B2669}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BosServerHTTP", "BosServerHTTP\BosServerHTTP.csproj", "{F241EDBB-C92D-4906-9708-B5A4F4FF8FA4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConnectorDataMqtt", "..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj", "{7D854605-811D-43D4-8943-EDAC59294B32}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BosServerParser", "BosServerParser\BosServerParser.csproj", "{22E73F36-3B85-4909-833E-987B4C91E15E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BosServerDatatypes", "BosServerDatatypes\BosServerDatatypes.csproj", "{63065686-A0A4-4A3E-A69C-684CEA08AE44}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BosServerStorage", "BosServerStorage\BosServerStorage.csproj", "{F7C06F26-7BFB-4BDD-92CB-6F6E4E0A06D9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BosServerTelegram", "BosServerTelegram\BosServerTelegram.csproj", "{F302ED4C-3ADB-4728-9246-14C3B0BD3FCA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConnectorStorageJson", "..\Utils\ConnectorStorageJson\ConnectorStorageJson\ConnectorStorageJson.csproj", "{78390660-0287-4304-BF07-8A50B50B1B8C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {44AE0A15-A009-46BF-9C25-321EA81B4D19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44AE0A15-A009-46BF-9C25-321EA81B4D19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44AE0A15-A009-46BF-9C25-321EA81B4D19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44AE0A15-A009-46BF-9C25-321EA81B4D19}.Release|Any CPU.Build.0 = Release|Any CPU + {1C179ACF-CFEC-469D-858A-CFE711126A7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C179ACF-CFEC-469D-858A-CFE711126A7B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C179ACF-CFEC-469D-858A-CFE711126A7B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C179ACF-CFEC-469D-858A-CFE711126A7B}.Release|Any CPU.Build.0 = Release|Any CPU + {ACA6F04E-5CDF-450E-B07B-050B5C90C9AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ACA6F04E-5CDF-450E-B07B-050B5C90C9AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ACA6F04E-5CDF-450E-B07B-050B5C90C9AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ACA6F04E-5CDF-450E-B07B-050B5C90C9AB}.Release|Any CPU.Build.0 = Release|Any CPU + {970CB7FF-E203-47B9-B238-BA67745FAC9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {970CB7FF-E203-47B9-B238-BA67745FAC9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {970CB7FF-E203-47B9-B238-BA67745FAC9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {970CB7FF-E203-47B9-B238-BA67745FAC9A}.Release|Any CPU.Build.0 = Release|Any CPU + {E9E055F8-552B-4CC7-9B89-BDB5EB1BC60B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E9E055F8-552B-4CC7-9B89-BDB5EB1BC60B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E9E055F8-552B-4CC7-9B89-BDB5EB1BC60B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E9E055F8-552B-4CC7-9B89-BDB5EB1BC60B}.Release|Any CPU.Build.0 = Release|Any CPU + {007521AC-F65A-4D34-AC50-9636FD9B2669}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {007521AC-F65A-4D34-AC50-9636FD9B2669}.Debug|Any CPU.Build.0 = Debug|Any CPU + {007521AC-F65A-4D34-AC50-9636FD9B2669}.Release|Any CPU.ActiveCfg = Release|Any CPU + {007521AC-F65A-4D34-AC50-9636FD9B2669}.Release|Any CPU.Build.0 = Release|Any CPU + {F241EDBB-C92D-4906-9708-B5A4F4FF8FA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F241EDBB-C92D-4906-9708-B5A4F4FF8FA4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F241EDBB-C92D-4906-9708-B5A4F4FF8FA4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F241EDBB-C92D-4906-9708-B5A4F4FF8FA4}.Release|Any CPU.Build.0 = Release|Any CPU + {7D854605-811D-43D4-8943-EDAC59294B32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D854605-811D-43D4-8943-EDAC59294B32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D854605-811D-43D4-8943-EDAC59294B32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D854605-811D-43D4-8943-EDAC59294B32}.Release|Any CPU.Build.0 = Release|Any CPU + {22E73F36-3B85-4909-833E-987B4C91E15E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22E73F36-3B85-4909-833E-987B4C91E15E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22E73F36-3B85-4909-833E-987B4C91E15E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22E73F36-3B85-4909-833E-987B4C91E15E}.Release|Any CPU.Build.0 = Release|Any CPU + {63065686-A0A4-4A3E-A69C-684CEA08AE44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {63065686-A0A4-4A3E-A69C-684CEA08AE44}.Debug|Any CPU.Build.0 = Debug|Any CPU + {63065686-A0A4-4A3E-A69C-684CEA08AE44}.Release|Any CPU.ActiveCfg = Release|Any CPU + {63065686-A0A4-4A3E-A69C-684CEA08AE44}.Release|Any CPU.Build.0 = Release|Any CPU + {F7C06F26-7BFB-4BDD-92CB-6F6E4E0A06D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7C06F26-7BFB-4BDD-92CB-6F6E4E0A06D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7C06F26-7BFB-4BDD-92CB-6F6E4E0A06D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7C06F26-7BFB-4BDD-92CB-6F6E4E0A06D9}.Release|Any CPU.Build.0 = Release|Any CPU + {F302ED4C-3ADB-4728-9246-14C3B0BD3FCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F302ED4C-3ADB-4728-9246-14C3B0BD3FCA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F302ED4C-3ADB-4728-9246-14C3B0BD3FCA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F302ED4C-3ADB-4728-9246-14C3B0BD3FCA}.Release|Any CPU.Build.0 = Release|Any CPU + {78390660-0287-4304-BF07-8A50B50B1B8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78390660-0287-4304-BF07-8A50B50B1B8C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78390660-0287-4304-BF07-8A50B50B1B8C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78390660-0287-4304-BF07-8A50B50B1B8C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {32FD8D01-BD1F-4187-A3DF-BFB51FCB4F10} + EndGlobalSection +EndGlobal diff --git a/BosServer/Adminrights.manifest b/BosServer/Adminrights.manifest new file mode 100644 index 0000000..6250b4f --- /dev/null +++ b/BosServer/Adminrights.manifest @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/BosServer/BosServer.csproj b/BosServer/BosServer.csproj new file mode 100644 index 0000000..6b988d5 --- /dev/null +++ b/BosServer/BosServer.csproj @@ -0,0 +1,25 @@ + + + + Exe + netcoreapp3.1 + Adminrights.manifest + 1.0.5 + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/BosServer/Database.cs b/BosServer/Database.cs new file mode 100644 index 0000000..20397c3 --- /dev/null +++ b/BosServer/Database.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data.Common; +using System.Text; + +using BlubbFish.Utils; + +using MySqlConnector; + +namespace BosServer { + class Database { + private readonly Dictionary dbconfig; + private MySqlConnection Mysql; + + public Boolean Debug { + get; private set; + } + + public Database(Dictionary configuration) { + this.dbconfig = configuration; + if(!(this.dbconfig.ContainsKey("save") && Boolean.TryParse(this.dbconfig["save"], out Boolean savetodatavase))) { + savetodatavase = true; + } + this.Debug = !savetodatavase; + this.Connect(); + } + + private void Connect() { + this.Mysql = new MySqlConnection("Server=" + this.dbconfig["server"] + ";User ID=" + this.dbconfig["user"] + ";Password=" + this.dbconfig["pass"] + ";Database=" + this.dbconfig["db"]); + this.Mysql.Open(); + Console.WriteLine("BosServer.Database.Connect(): Database Server=" + this.dbconfig["server"] + ";User ID=" + this.dbconfig["user"] + ";Password=[xxx];Database=" + this.dbconfig["db"] + " connected"); + } + + private void Disconnect() { + this.Mysql.Close(); + this.Mysql = null; + Console.WriteLine("BosServer.Database.Disconnect(): Database Disconnect!"); + } + + private void Reconnect() { + Console.WriteLine("BosServer.Database.Reconnect(): Database Reconnect!"); + this.Disconnect(); + this.Connect(); + } + + public T DbGetSingleRow(String query, Dictionary param) where T : new() { + if(this.Mysql.State == System.Data.ConnectionState.Broken) { + this.Reconnect(); + } + using MySqlCommand command = new MySqlCommand { + CommandText = query, + Connection = this.Mysql + }; + foreach(KeyValuePair item in param) { + _ = command.Parameters.AddWithValue(item.Key, item.Value); + } + + using MySqlDataReader reader = command.ExecuteReader(); + if(!reader.HasRows) { + return default; + } + + ReadOnlyCollection cols = reader.GetColumnSchema(); + T ret = new T(); + _ = reader.Read(); + foreach(DbColumn item in cols) { + Object a = reader.GetValue((Int32)item.ColumnOrdinal); + ret.SetProperty(item.ColumnName, a.ToString()); + } + return ret; + } + + public Int32 DbInsert(String query, Dictionary param) { + if(this.Mysql.State == System.Data.ConnectionState.Broken) { + this.Reconnect(); + } + using MySqlCommand command = new MySqlCommand { + CommandText = query, + Connection = this.Mysql + }; + foreach(KeyValuePair item in param) { + _ = command.Parameters.AddWithValue(item.Key, item.Value); + } + return command.ExecuteNonQuery(); + } + + public void Dispose() => this.Disconnect(); + } +} diff --git a/BosServer/MysqlTables/PocsagRecords.cs b/BosServer/MysqlTables/PocsagRecords.cs new file mode 100644 index 0000000..53dc905 --- /dev/null +++ b/BosServer/MysqlTables/PocsagRecords.cs @@ -0,0 +1,21 @@ +using System; + +namespace BosServer.MysqlTables { + public class PocsagRecords { + public String Address { + get; set; + } + + public String Location { + get; set; + } + + public String ShortDescription { + get; set; + } + + public String LongDescription { + get; set; + } + } +} diff --git a/BosServer/Program.cs b/BosServer/Program.cs new file mode 100644 index 0000000..b4ecc6c --- /dev/null +++ b/BosServer/Program.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; + +using BlubbFish.Utils.IoT.Connector; + +namespace BosServer { + class Program { + public Program(String[] args) => _ = new Webserver(args, false, "boswatch", null, null); + static void Main(String[] args) => new Program(args); + } +} diff --git a/BosServer/Webserver.cs b/BosServer/Webserver.cs new file mode 100644 index 0000000..b9fa2d7 --- /dev/null +++ b/BosServer/Webserver.cs @@ -0,0 +1,238 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Text.RegularExpressions; + +using BlubbFish.Utils; +using BlubbFish.Utils.IoT.Bots; +using BlubbFish.Utils.IoT.Connector; +using BlubbFish.Utils.IoT.Events; + +using BosServer.MysqlTables; + +namespace BosServer { + internal class Webserver : AWebserverDataBackend { + private readonly Dictionary bosconf; + private readonly Database db; + + public Webserver(String[] args, Boolean fileLogging, String configSearchPath, ABackend backend, Dictionary settings) : base(args, fileLogging, configSearchPath, backend, settings) { + this.databackend.MessageSending += this.Backend_MessageSending; + this.bosconf = InIReader.GetInstance("settings").GetSection("bosserver"); + this.db = new Database(InIReader.GetInstance("settings").GetSection("mysql")); + + this.StartDataBackend(); + this.StartListen(); + + this.SendTelegram("Anwendung", new Tuple("BosServer.exe", null), "Anwendung Version "+ Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion + " gestartet.", null, this.bosconf["group"]); + this.WaitForShutdown(); + this.SendTelegram("Anwendung", new Tuple("BosServer.exe", null), "Anwendung wurde beendet... Ob das so soll?", null, this.bosconf["group"]); + + this.Dispose(); + } + + protected override void Backend_MessageIncomming(Object sender, BackendEvent message) { + try { + if(message.From is Tuple t) { + String task = message.Message.ToLower(); + if(task == "idea" || task == "leer") { + if(!(t.Item4 is null)) { + Match x = Regex.Match(t.Item4, @"^\[[A-Z]+\] ([0-9]+): .*?$"); + if(x.Success) { + if(t.Item1 == Int64.Parse(this.bosconf["special"])) { + if(this.AddFilter(x.Groups[1], task)) { + this.SendTelegram("Filter", new Tuple("BosServer.exe", null), "Hallo " + t.Item2 + ", die RIC " + x.Groups[1] + " wurde als \"" + task + "\" geflaggt, Nachrichten werden zukünftig gefiltert.", null, t.Item3.ToString()); + } else { + this.SendTelegram("Filter", new Tuple("BosServer.exe", null), "Hallo " + t.Item2 + ", das hinzufügen des Filters \"" + task + "\" für die RIC " + x.Groups[1] + " ist fehlgeschlagen.", null, t.Item3.ToString()); + } + } else { + this.SendTelegram("Filter", new Tuple("BosServer.exe", null), "Hallo " + t.Item2 + ", https://xkcd.com/838/", null, t.Item3.ToString()); + } + } else { + this.SendTelegram("Filter", new Tuple("BosServer.exe", null), "Hallo " + t.Item2 + ", ich kann die RIC in der zitierten Nachricht nicht finden.", null, t.Item3.ToString()); + } + } else { + this.SendTelegram("Filter", new Tuple("BosServer.exe", null), "Hallo " + t.Item2 + ", du hast keine Nachricht zitiert.", null, t.Item3.ToString()); + } + } else { + Console.WriteLine("=> Telegram-API [" + t.Item1.ToString() + "]: " + message.Message); + } + } + } catch(Exception e) { + Helper.WriteError("Backend_MessageIncomming(): " + e.Message + "\n\n" + e.StackTrace); + } + } + + private void Backend_MessageSending(Object sender, BackendEvent telegram) { + try { + Console.WriteLine("<= Telegram-API [" + telegram.From.ToString() + "]: " + telegram.Message); + } catch(Exception e) { + Helper.WriteError("Backend_MessageSending(): " + e.Message + "\n\n" + e.StackTrace); + } + } + + protected override Boolean SendWebserverResponse(HttpListenerContext cont) { + try { + if(cont.Request.Url.LocalPath.ToLower() == "/telegramin/"+ this.bosconf["path"] + "/input.xml") { + Dictionary post = cont.Request.GetPostParams(); + if(post.ContainsKey("function") && post.ContainsKey("flags") && post.ContainsKey("message") && post.ContainsKey("type") && post.ContainsKey("address")) { + String function = post["function"]; + String flags = post["flags"]; + String message = post["message"]; + String type = post["type"]; + String address = post["address"]; + + String function_str = this.ParseFunction(function); + Tuple ric = this.ParseRic(address); + Tuple geo = this.ParseLocation(message); + Boolean sendonline = this.ParseFilter(message, ric, address); + Boolean isprivate = this.ParsePrivate(address); + + this.SaveDatabse(address, function, message, geo); + + if(isprivate) { + this.SendTelegram(function_str, ric, message, geo, this.bosconf["special"]); + } + if(sendonline) { + this.SendTelegram(function_str, ric, message, geo, this.bosconf["group"]); + } + cont.Response.StatusCode = 200; + return true; + } + } + } catch(Exception e) { + Helper.WriteError("SendWebserverResponse(): 500 - " + e.Message + "\n\n" + e.StackTrace); + cont.Response.StatusCode = 500; + return false; + } + return cont.SendFileResponse(); + } + + private void SendTelegram(String function_str, Tuple ric, String message, Tuple geo, String chatid) { + Console.WriteLine("=> Telegram [" + function_str + "] " + ric.Item1 + ": " + message); + ((BlubbFish.Utils.IoT.Connector.User.Telegram)this.databackend).Send("[" + function_str + "] " + ric.Item1 + ": " + message, chatid); + if(!(geo is null)) { + String ric_str = !(ric.Item2 is null || ric.Item2.ShortDescription is null) && ric.Item2.ShortDescription != "" ? ric.Item2.ShortDescription : ric.Item1; + String without_coords = Regex.Replace(message, @"#C(?.+?),(?.+?)#", "").Trim(); + Console.WriteLine("=> Telegram {" + geo.Item1 + ", " + geo.Item2 + "} " + ric_str + ": " + without_coords); + ((BlubbFish.Utils.IoT.Connector.User.Telegram)this.databackend).SendLocationWithText(ric_str, without_coords, geo.Item1, geo.Item2, chatid); + } + } + + private Boolean ParsePrivate(String address) => this.bosconf["special-ric"].Split(";").Contains(address); + + private Boolean ParseFilter(String message, Tuple ric, String address) { + if(ric.Item2 != null && ric.Item2.LongDescription.ToLower() == "idea") { + return false; + } else if(ric.Item2 != null && ric.Item2.LongDescription.ToLower() == "leer") { + return false; + } else if(message == "" && ric.Item2 is null) { + return false; + } + foreach(KeyValuePair item in InIReader.GetInstance("settings").GetSection("filter")) { + String[] a = item.Value.Split("|"); + switch(a[0]) { + case "address": if(address.StartsWith(a[1])) { return false; } break; + case "message": if(message == a[1]) { return false; } break; + } + } + return true; + } + + private Tuple ParseLocation(String message) { + Match m = Regex.Match(message, @"#C(?.+?),(?.+?)#"); + if(m.Success) { + if(Double.TryParse(m.Groups["lat"].Value.Insert(2, "."), NumberStyles.Float, CultureInfo.InvariantCulture, out Double lat) && + Double.TryParse(m.Groups["lon"].Value.Insert(2, "."), NumberStyles.Float, CultureInfo.InvariantCulture, out Double lon)) { + return new Tuple(lat, lon); + } + } + return null; + } + + private Tuple ParseRic(String ric) { + PocsagRecords ric_data = this.db.DbGetSingleRow("SELECT * FROM `PocsagRecords` WHERE `Address` = CONCAT(@ric,'*');", new Dictionary() { { "ric", ric } }); + String text; + + if(ric_data is null) { + text = ric; + } else { + List text_parts = new List(); + if(!(ric_data.Location is null) && ric_data.Location != "") { + text_parts.Add(ric_data.Location); + } + if(!(ric_data.ShortDescription is null) && ric_data.ShortDescription != "") { + text_parts.Add(ric_data.ShortDescription); + } + if(!(ric_data.LongDescription is null) && ric_data.LongDescription != "") { + text_parts.Add("(" + ric_data.LongDescription + ")"); + } + text = String.Join(" ", text_parts); + } + return new Tuple(text, ric_data); + } + + private void SaveDatabse(String address, String function, String message, Tuple geo) { + if(!this.db.Debug) { + Int32 rows = this.db.DbInsert("INSERT INTO `TelegramStorage` (`Timestamp`,`Type`,`Source`,`Flags`,`Address`,`Message`,`Extensions`) " + + "VALUES (UNIX_TIMESTAMP(), 4, 258292335, 0, @addr, @message, @ext);", + new Dictionary() { + { "addr", address+function }, + { "message", message }, + { "ext", geo is null? null: "" + + "" + + "" + + "" + + "" + + "" + + ""+geo.Item1.ToString(CultureInfo.InvariantCulture)+"" + + ""+geo.Item2.ToString(CultureInfo.InvariantCulture)+"" + + "" + + "" + + ""} + }); + if(rows == 0) { + Helper.WriteError("=> Database Nachricht [" + address + function + "] " + message + " konnte nicht hinzugefügt werden!"); + } else { + Console.WriteLine("=> Database [" + address + function + "] " + message + " gespeichert"); + } + } else { + Helper.WriteError("=> Database INSERT INTO `TelegramStorage` was not saved in db."); + } + } + + private Boolean AddFilter(Group ric, String task) { + if(!this.db.Debug) { + Int32 rows = this.db.DbInsert("INSERT INTO `PocsagRecords` (`Address`,`Location`,`ShortDescription`,`LongDescription`) " + + "VALUES (@ric,'','',@task);", + new Dictionary() { + { "ric", ric+"*" }, + { "task", task.ToUpper() } + }); + if(rows == 1) { + return true; + } else { + Helper.WriteError("=> Database Filter [" + ric + "*] " + task + " konnte nicht hinzugefügt werden!"); + } + } else { + Helper.WriteError("=> Database NSERT INTO `PocsagRecords` was not saved in db."); + } + return false; + } + + private String ParseFunction(String function) => function switch { + "a" => "EIL", + "b" => "ZEIT", + "c" => "PROBE", + "d" => "ENDE", + _ => "" + }; + + public override void Dispose() { + this.db.Dispose(); + base.Dispose(); + } + } +} diff --git a/BosServer/config-example/settings.conf.example b/BosServer/config-example/settings.conf.example new file mode 100644 index 0000000..df5cf40 --- /dev/null +++ b/BosServer/config-example/settings.conf.example @@ -0,0 +1,32 @@ +[bosserver] +group= +special= +special-ric=;; +path=upload + +[filter] +filter1=address|1234 +filter2=address|3456 +filter4=message| +filter5=message| +filter6=message| + +[logging] +path=bosserver.log +debug=true + +[webserver] +prefix=http://+:8080/ + +[backend] +type=Telegram +backendtype=User +telegram-key= +default-chat= + +[mysql] +server=localhost +user=bosserver +pass=password_change_me +db=bosmon +save=false \ No newline at end of file diff --git a/BosServerConvert/BosServerConvert.sln b/BosServerConvert/BosServerConvert.sln new file mode 100644 index 0000000..5901502 --- /dev/null +++ b/BosServerConvert/BosServerConvert.sln @@ -0,0 +1,61 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31112.23 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BosServerConvert", "BosServerConvert\BosServerConvert.csproj", "{CEBBF847-6041-4557-B2FD-FBDCE7CDEE50}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils-IoT", "..\..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj", "{E2B3A4E8-A404-46E9-8FCA-E7183A61EAB3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "..\..\Utils\Utils\Utils\Utils.csproj", "{6EFF890D-4C1D-495F-9BC6-EC1DB4CC5325}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "litjson", "..\..\Librarys\litjson\litjson\litjson.csproj", "{E94D6477-77C9-4722-9306-1C9EF1C86C99}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConnectorDbMysql", "..\..\Utils\ConnectorDbMysql\ConnectorDbMysql\ConnectorDbMysql.csproj", "{BC10C8C2-6108-486E-94DE-453720E84868}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot-Utils", "..\..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj", "{AF055E18-51B7-46A0-A0B6-C0E6EED4D95A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BosServerDatatypes", "..\BosServerDatatypes\BosServerDatatypes.csproj", "{48851AED-A7A2-43A6-8B90-E9917D16DC19}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CEBBF847-6041-4557-B2FD-FBDCE7CDEE50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CEBBF847-6041-4557-B2FD-FBDCE7CDEE50}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CEBBF847-6041-4557-B2FD-FBDCE7CDEE50}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CEBBF847-6041-4557-B2FD-FBDCE7CDEE50}.Release|Any CPU.Build.0 = Release|Any CPU + {E2B3A4E8-A404-46E9-8FCA-E7183A61EAB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2B3A4E8-A404-46E9-8FCA-E7183A61EAB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2B3A4E8-A404-46E9-8FCA-E7183A61EAB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2B3A4E8-A404-46E9-8FCA-E7183A61EAB3}.Release|Any CPU.Build.0 = Release|Any CPU + {6EFF890D-4C1D-495F-9BC6-EC1DB4CC5325}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6EFF890D-4C1D-495F-9BC6-EC1DB4CC5325}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6EFF890D-4C1D-495F-9BC6-EC1DB4CC5325}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6EFF890D-4C1D-495F-9BC6-EC1DB4CC5325}.Release|Any CPU.Build.0 = Release|Any CPU + {E94D6477-77C9-4722-9306-1C9EF1C86C99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E94D6477-77C9-4722-9306-1C9EF1C86C99}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E94D6477-77C9-4722-9306-1C9EF1C86C99}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E94D6477-77C9-4722-9306-1C9EF1C86C99}.Release|Any CPU.Build.0 = Release|Any CPU + {BC10C8C2-6108-486E-94DE-453720E84868}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC10C8C2-6108-486E-94DE-453720E84868}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC10C8C2-6108-486E-94DE-453720E84868}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC10C8C2-6108-486E-94DE-453720E84868}.Release|Any CPU.Build.0 = Release|Any CPU + {AF055E18-51B7-46A0-A0B6-C0E6EED4D95A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF055E18-51B7-46A0-A0B6-C0E6EED4D95A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF055E18-51B7-46A0-A0B6-C0E6EED4D95A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF055E18-51B7-46A0-A0B6-C0E6EED4D95A}.Release|Any CPU.Build.0 = Release|Any CPU + {48851AED-A7A2-43A6-8B90-E9917D16DC19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {48851AED-A7A2-43A6-8B90-E9917D16DC19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {48851AED-A7A2-43A6-8B90-E9917D16DC19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {48851AED-A7A2-43A6-8B90-E9917D16DC19}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EC08A76A-6496-4AFF-AB3C-D83912F25618} + EndGlobalSection +EndGlobal diff --git a/BosServerConvert/BosServerConvert/BosServerConvert.csproj b/BosServerConvert/BosServerConvert/BosServerConvert.csproj new file mode 100644 index 0000000..addfd80 --- /dev/null +++ b/BosServerConvert/BosServerConvert/BosServerConvert.csproj @@ -0,0 +1,15 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + diff --git a/BosServerConvert/BosServerConvert/Program.cs b/BosServerConvert/BosServerConvert/Program.cs new file mode 100644 index 0000000..5665fbb --- /dev/null +++ b/BosServerConvert/BosServerConvert/Program.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +using BlubbFish.IoT.Pocsag.BosServerDatatypes.Influx; +using BlubbFish.IoT.Pocsag.BosServerDatatypes.Json; +using BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt; +using BlubbFish.IoT.Pocsag.BosServerDatatypes.MysqlTables; +using BlubbFish.Utils; +using BlubbFish.Utils.IoT.Bots; +using BlubbFish.Utils.IoT.Connector; + +using LitJson; + +namespace BosServerConvert { + class Program : ABot { + private readonly ABackend mysql; + private readonly Dictionary bosconf; + + //private List mysqlTableMessage; + private List mysqlTableRic; + //private List pocsagTable; + private SortedDictionary ricData; + //private List influxTable; + //private readonly Dictionary rics = new Dictionary(); + + + static void Main(String[] args) => new Program(args, false, "bsconvert"); + public Program(String[] args, Boolean fileLogging, String configSearchPath) : base(args, fileLogging, configSearchPath) { + this.mysql = ABackend.GetInstance(InIReader.GetInstance("settings").GetSection("storage")); + this.bosconf = InIReader.GetInstance("settings").GetSection("bosserverparser"); + + Console.WriteLine("Wait for mysql"); + while(!this.mysql.IsConnected) { + System.Threading.Thread.Sleep(100); + } + Console.WriteLine("Mysql is now connected."); + Console.WriteLine("\n\n"); + + Console.WriteLine("Load data from mysql..."); + DateTime start = DateTime.Now; + this.LoadRicList(); + DateTime stop = DateTime.Now; + Console.WriteLine("Takes " + (stop - start).TotalSeconds + "s"); + Console.WriteLine("Mysql items: " + this.mysqlTableRic.Count + "\n\n"); + + Console.WriteLine("Parse data..."); + start = DateTime.Now; + this.ParseRics(); + stop = DateTime.Now; + Console.WriteLine("Takes " + (stop - start).TotalSeconds + "s"); + Console.WriteLine("Pocsag items: " + this.ricData.Count + "\n\n"); + + Console.WriteLine("Write to output file..."); + start = DateTime.Now; + this.WriteFileRics(); + stop = DateTime.Now; + Console.WriteLine("Takes " + (stop - start).TotalSeconds + "s"); + Console.WriteLine("\n\n"); + + /*Console.WriteLine("Load data from mysql..."); + DateTime start = DateTime.Now; + this.LoadMessageList(); + DateTime stop = DateTime.Now; + Console.WriteLine("Takes " + (stop - start).TotalSeconds + "s"); + Console.WriteLine("Mysql items: " + this.mysqlTableMessage.Count + "\n\n"); + + Console.WriteLine("Parse data..."); + start = DateTime.Now; + this.ParseMessage(); + stop = DateTime.Now; + Console.WriteLine("Takes " + (stop - start).TotalSeconds + "s"); + Console.WriteLine("Pocsag items: " + this.pocsagTable.Count + "\n\n"); + + Console.WriteLine("Convert to Influx..."); + start = DateTime.Now; + this.GenerateInflux(); + stop = DateTime.Now; + Console.WriteLine("Takes " + (stop - start).TotalSeconds + "s"); + Console.WriteLine("Influx items: " + this.influxTable.Count + "\n\n"); + + Console.WriteLine("Write to output file..."); + start = DateTime.Now; + this.WriteFileMessage(); + stop = DateTime.Now; + Console.WriteLine("Takes " + (stop - start).TotalSeconds + "s"); + Console.WriteLine("\n\n");*/ + + this.Dispose(); + } + + /*private void WriteFileMessage() { + StreamWriter file = new StreamWriter(this.bosconf["outputfile"], false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)) { + AutoFlush = true + }; + + foreach(String item in this.influxTable) { + file.Write(item+"\n"); + } + + file.Flush(); + file.Close(); + file.Dispose(); + }*/ + + private void WriteFileRics() { + JsonWriter m = new JsonWriter(); + m.PrettyPrint = true; + JsonMapper.ToJson(this.ricData, m); + File.WriteAllText("ric.json", m.ToString()); + } + + /*private void GenerateInflux() { + this.influxTable = new List(); + foreach(PocsagParsed item in this.pocsagTable) { + this.influxTable.Add(new Bosmon(item, true).ToInfluxString()); + } + this.pocsagTable.Clear(); + }*/ + + /*private void ParseMessage() { + this.pocsagTable = new List(); + Int32 time = 0; + Int32 often = 0; + foreach(TelegramStorage item in this.mysqlTableMessage) { + if(item.Address.Length != 8) { + Console.Error.WriteLine("item " + item + " is not valied"); + continue; + } + if(time != item.Timestamp) { + time = item.Timestamp; + often = 0; + } else { + often++; + } + PocsagHttp p = new PocsagHttp(item.Address.Substring(7, 1), item.Flags.ToString(), item.Message, item.Type.ToString(), item.Address.Substring(0, 7), item.Timestamp+0.01*often); + + String funktion = this.ParseFunction(p.Function); + (String name, RicDescription ric) = this.ParseRic(p.Address); + GeoData geo = this.ParseLocation(p.Message, item.Extensions); + Boolean sendonline = this.ParseFilter(p.Message, ric, p.Address); + Boolean isprivate = this.ParsePrivate(p.Address); + + this.pocsagTable.Add(new PocsagParsed(p, funktion, name, ric, geo, sendonline, isprivate, p.Date)); + } + this.mysqlTableMessage.Clear(); + }*/ + + private void ParseRics() { + this.ricData = new SortedDictionary(); + foreach(PocsagRecords item in this.mysqlTableRic) { + if(!this.ricData.ContainsKey(item.Address)) { + this.ricData.Add(item.Address.Substring(0,7), new RicData(item.Location, item.ShortDescription, item.LongDescription)); + } + } + this.mysqlTableRic.Clear(); + } + + /*private Boolean ParsePrivate(String address) => this.bosconf["special-ric"].Split(";").Contains(address);*/ + + /*private Boolean ParseFilter(String message, RicDescription ric, String address) { + if(ric != null && ric.LongDescription.ToLower() == "idea") { + return false; + } else if(ric != null && ric.LongDescription.ToLower() == "leer") { + return false; + } else if(message == "" && ric is null) { + return false; + } + foreach(KeyValuePair item in InIReader.GetInstance("settings").GetSection("filter")) { + String[] a = item.Value.Split("|"); + switch(a[0]) { + case "address": + if(address.StartsWith(a[1])) { + return false; + } + break; + case "message": + if(message == a[1]) { + return false; + } + break; + } + } + return true; + }*/ + + /*private GeoData ParseLocation(String message, String extensions) { + Match m = Regex.Match(message, @"#C(?[0-9\.]+),(?[0-9\.]+)#"); + if(m.Success) { + if(Double.TryParse(m.Groups["lat"].Value.Insert(2, "."), NumberStyles.Float, CultureInfo.InvariantCulture, out Double lat) && + Double.TryParse(m.Groups["lon"].Value.Insert(2, "."), NumberStyles.Float, CultureInfo.InvariantCulture, out Double lon)) { + return new GeoData(lat, lon); + } + } else { + Match elat = Regex.Match(extensions, @"(?[0-9\.]+)"); + Match elon = Regex.Match(extensions, @"(?[0-9\.]+)"); + if(elat.Success && elon.Success) { + if(Double.TryParse(elat.Groups["lat"].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out Double lat) && + Double.TryParse(elon.Groups["lon"].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out Double lon)) { + return new GeoData(lat, lon); + } + } + } + return null; + }*/ + + /*private (String, RicDescription) ParseRic(String ric) { + if(this.rics.ContainsKey(ric)) { + return this.rics[ric]; + } else { + PocsagRecords ric_data = ((BlubbFish.Utils.IoT.Connector.Db.Mysql)this.mysql).LoadSingleRow("SELECT * FROM `PocsagRecords` WHERE `Address` = CONCAT(@ric,'*');", new Dictionary() { { "ric", ric } }); + RicDescription desc = null; + String text; + + if(ric_data is null) { + text = ric; + } else { + desc = new RicDescription(ric_data.Address, ric_data.Location, ric_data.ShortDescription, ric_data.LongDescription); + List text_parts = new List(); + if(!(ric_data.Location is null) && ric_data.Location != "") { + text_parts.Add(ric_data.Location); + } + if(!(ric_data.ShortDescription is null) && ric_data.ShortDescription != "") { + text_parts.Add(ric_data.ShortDescription); + } + if(!(ric_data.LongDescription is null) && ric_data.LongDescription != "") { + text_parts.Add("(" + ric_data.LongDescription + ")"); + } + text = String.Join(" ", text_parts); + } + this.rics.Add(ric, (text, desc)); + return (text, desc); + } + }*/ + + /*private String ParseFunction(String function) => function switch { + "a" => "EIL", + "b" => "ZEIT", + "c" => "PROBE", + "d" => "ENDE", + _ => "" + };*/ + + /*private void LoadMessageList() => this.mysqlTableMessage = ((BlubbFish.Utils.IoT.Connector.Db.Mysql)this.mysql).LoadMultiRows("SELECT * FROM `TelegramStorage`", new Dictionary());*/ + + private void LoadRicList() => this.mysqlTableRic = ((BlubbFish.Utils.IoT.Connector.Db.Mysql)this.mysql).LoadMultiRows("SELECT * FROM `PocsagRecords`", new Dictionary()); + + public override void Dispose() { + if(this.mysql != null) { + this.mysql.Dispose(); + } + base.Dispose(); + } + } +} diff --git a/BosServerDatatypes/BosServerDatatypes.csproj b/BosServerDatatypes/BosServerDatatypes.csproj new file mode 100644 index 0000000..98e0d2e --- /dev/null +++ b/BosServerDatatypes/BosServerDatatypes.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + BlubbFish.IoT.Pocsag.BosServerDatatypes + + + + + + + + diff --git a/BosServerDatatypes/Influx/AInfluxMessage.cs b/BosServerDatatypes/Influx/AInfluxMessage.cs new file mode 100644 index 0000000..b6ea92f --- /dev/null +++ b/BosServerDatatypes/Influx/AInfluxMessage.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Reflection; +using System.Text; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Influx { + public abstract class AInfluxMessage { + public String ToInfluxString() { + Type measurementType = this.GetType(); + PropertyInfoColumn[] cache = measurementType.GetProperties().Select(property => new PropertyInfoColumn { Column = (Column)property.GetCustomAttribute(typeof(Column)), Property = property }).Where(propertyInfo => propertyInfo.Column != null).ToArray(); + + Measurement measurementAttribute = (Measurement)measurementType.GetCustomAttribute(typeof(Measurement)); + PropertyInfoColumn measurementColumn = cache.SingleOrDefault(p => p.Column.IsMeasurement); + + PointData point = new PointData(measurementAttribute.Name); + foreach(PropertyInfoColumn propertyInfo in cache) { + if(propertyInfo.Column.IsMeasurement) { + continue; + } + Object value = propertyInfo.Property.GetValue(this); + if(value == null) { + continue; + } + String name = propertyInfo.Column.Name; + if(propertyInfo.Column.IsTag && !String.IsNullOrEmpty(value.ToString())) { + point.Tag(name, value.ToString()); + } else if(propertyInfo.Column.IsTimestamp) { + if(value is DateTime date) { + point.Timestamp(date); + } + } else { + point.PutField(name, value); + } + } + return point.ToLineProtocol(); + } + } + + internal class PropertyInfoColumn { + internal PropertyInfo Property; + internal Column Column; + } + + public class PointData { + private static readonly DateTime EpochStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + private readonly String _measurementName; + private ImmutableSortedDictionary _tags = ImmutableSortedDictionary.Empty; + private ImmutableSortedDictionary _fields = ImmutableSortedDictionary.Empty; + private BigInteger _time; + + public PointData(String measurementName) => this._measurementName = measurementName; + + internal void PutField(String name, Object value) => this._fields = this._fields.Add(name, value); + internal void Tag(String name, String value) => this._tags = this._tags.Add(name, value); + + internal void Timestamp(DateTime timestamp) => this._time = timestamp.ToUniversalTime().Subtract(EpochStart).Ticks * 100; + internal String ToLineProtocol() { + StringBuilder sb = new StringBuilder(); + + this.EscapeKey(sb, this._measurementName, false); + this.AppendTags(sb); + if(!this.AppendFields(sb)) { + return ""; + } + this.AppendTime(sb); + return sb.ToString(); + } + + private void AppendTags(StringBuilder sb) { + foreach(KeyValuePair keyValue in this._tags) { + _ = sb.Append(','); + this.EscapeKey(sb, keyValue.Key); + _ = sb.Append('='); + this.EscapeKey(sb, keyValue.Value); + } + + _ = sb.Append(' '); + } + private Boolean AppendFields(StringBuilder sb) { + Boolean appended = false; + + foreach(KeyValuePair keyValue in this._fields) { + String key = keyValue.Key; + Object value = keyValue.Value; + + if(this.IsNotDefined(value)) { + continue; + } + + this.EscapeKey(sb, key); + _ = sb.Append('='); + + if(value is Double || value is Single) { + _ = sb.Append(((IConvertible)value).ToString(CultureInfo.InvariantCulture)); + } else if(value is UInt32 || value is UInt64 || value is UInt16) { + _ = sb.Append(((IConvertible)value).ToString(CultureInfo.InvariantCulture)); + _ = sb.Append('u'); + } else if(value is Byte || value is Int32 || value is Int64 || value is SByte || value is Int16) { + _ = sb.Append(((IConvertible)value).ToString(CultureInfo.InvariantCulture)); + _ = sb.Append('i'); + } else if(value is Boolean b) { + _ = sb.Append(b ? "true" : "false"); + } else if(value is String s) { + _ = sb.Append('"'); + this.EscapeValue(sb, s); + _ = sb.Append('"'); + } else if(value is IConvertible c) { + _ = sb.Append(c.ToString(CultureInfo.InvariantCulture)); + } else { + _ = sb.Append('"'); + this.EscapeValue(sb, value.ToString()); + _ = sb.Append('"'); + } + + _ = sb.Append(','); + appended = true; + } + + if(appended) { + _ = sb.Remove(sb.Length - 1, 1); + } + + return appended; + } + private void AppendTime(StringBuilder sb) { + _ = sb.Append(' '); + _ = sb.Append(this._time.ToString(CultureInfo.InvariantCulture)); + } + + private void EscapeKey(StringBuilder sb, String key, Boolean escapeEqual = true) { + foreach(Char c in key) { + switch(c) { + case '\n': + _ = sb.Append("\\n"); + continue; + case '\r': + _ = sb.Append("\\r"); + continue; + case '\t': + _ = sb.Append("\\t"); + continue; + case ' ': + case ',': + _ = sb.Append("\\"); + break; + case '=': + if(escapeEqual) { + _ = sb.Append("\\"); + } + + break; + } + + _ = sb.Append(c); + } + } + private void EscapeValue(StringBuilder sb, String value) { + foreach(Char c in value) { + switch(c) { + case '\\': + case '\"': + _ = sb.Append("\\"); + break; + } + + _ = sb.Append(c); + } + } + private Boolean IsNotDefined(Object value) => value == null + || value is Double d && (Double.IsInfinity(d) || Double.IsNaN(d)) + || value is Single f && (Single.IsInfinity(f) || Single.IsNaN(f)); + } + + [AttributeUsage(AttributeTargets.Class)] + public sealed class Measurement : Attribute { + public String Name { + get; + } + + public Measurement(String name) => this.Name = name; + } + + [AttributeUsage(AttributeTargets.Property)] + public sealed class Column : Attribute { + public String Name { + get; + } + + public Boolean IsMeasurement { + get; set; + } + + public Boolean IsTag { + get; set; + } + + public Boolean IsTimestamp { + get; set; + } + + public Column() { + } + + public Column(String name) => this.Name = name; + } +} \ No newline at end of file diff --git a/BosServerDatatypes/Influx/Bosmon.cs b/BosServerDatatypes/Influx/Bosmon.cs new file mode 100644 index 0000000..97a3ab6 --- /dev/null +++ b/BosServerDatatypes/Influx/Bosmon.cs @@ -0,0 +1,86 @@ +using System; + +using BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Influx { + [Measurement("bosmon")] + public class Bosmon : AInfluxMessage { + + [Column("address", IsTag = true)] + public UInt64 Address { + get; + } + + [Column("function", IsTag = true)] + public String Function { + get; + } + + [Column("sendonline", IsTag = true)] + public Boolean SendOnline { + get; + } + + [Column("isprivate", IsTag = true)] + public Boolean Isprivate { + get; + } + + [Column("withgeo", IsTag = true)] + public Boolean Withgeo { + get; + } + + [Column("art")] + public String Art { + get; + } + + [Column("name")] + public String Name { + get; + } + + [Column("text")] + public String Text { + get; + } + + [Column(IsTimestamp = true)] + public DateTime Time { + get; + } + + [Column("latitude")] + public Double Lat { + get; + } + + [Column("longitude")] + public Double Lon { + get; + } + + public Bosmon(PocsagParsed p, Boolean parseTime = false) { + if(UInt64.TryParse(p.Raw.Address, out UInt64 adress)) { + this.Address = adress; + } + this.Function = p.Raw.Function; + this.SendOnline = p.Sendonline; + this.Isprivate = p.Isprivate; + this.Art = p.Funktion; + this.Name = p.Name; + this.Text = p.Raw.Message; + this.Time = parseTime ? p.Date : DateTime.Now; + if(p.Geo != null) { + this.Lat = p.Geo.Latitude; + this.Lon = p.Geo.Longitude; + this.Withgeo = true; + } else { + this.Lat = 0; + this.Lon = 0; + this.Withgeo = false; + } + } + } +} diff --git a/BosServerDatatypes/Json/RicData.cs b/BosServerDatatypes/Json/RicData.cs new file mode 100644 index 0000000..fdb8ab3 --- /dev/null +++ b/BosServerDatatypes/Json/RicData.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using BlubbFish.Utils.IoT.Connector.Storage; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Json { + public class RicData : AJsonDatatype { + public RicData() { } + public RicData(String location, String shortdescription, String longdescription) { + this.Location = location; + this.ShortDescription = shortdescription; + this.LongDescription = longdescription; + } + public String Location { + get; + set; + } + public String ShortDescription { + get; + set; + } + public String LongDescription { + get; + set; + } + } +} diff --git a/BosServerDatatypes/Mqtt/AMqttMessage.cs b/BosServerDatatypes/Mqtt/AMqttMessage.cs new file mode 100644 index 0000000..1cfd10a --- /dev/null +++ b/BosServerDatatypes/Mqtt/AMqttMessage.cs @@ -0,0 +1,78 @@ +using System; +using System.Reflection; + +using LitJson; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt { + public abstract class AMqttMessage { + public String Datatype { + get; + protected set; + } + + public DateTime Date { + get; + protected set; + } + + protected AMqttMessage(String datatype) { + this.Datatype = datatype; + this.Date = DateTime.Now; + } + + protected AMqttMessage(String datatype, JsonData json) { + this.Datatype = datatype; + this.Date = DateTime.Parse(json.ToString(), new System.Globalization.CultureInfo("en-US", false)); + } + + public virtual String ToJson() => JsonMapper.ToJson(this); + + public static Boolean CheckJson(String message, Type t) { + try { + return CheckJson(JsonMapper.ToObject(message), t); + } catch { + return false; + } + } + + public static Boolean CheckJson(JsonData json, Type t) { + try { + foreach(PropertyInfo p_info in t.GetProperties()) { + if(p_info.Name == "Item") { + continue; + } + if(p_info.CanRead) { + if(p_info.PropertyType == typeof(String)) { + if(!(json.ContainsKey(p_info.Name) && json[p_info.Name] != null && json[p_info.Name].IsString)) { + return false; + } + } else if(p_info.PropertyType == typeof(DateTime)) { + if(!(json.ContainsKey(p_info.Name) && json[p_info.Name] != null && json[p_info.Name].IsString)) { + return false; + } + } else if(p_info.PropertyType == typeof(Boolean)) { + if(!(json.ContainsKey(p_info.Name) && json[p_info.Name] != null && json[p_info.Name].IsBoolean)) { + return false; + } + } else if(p_info.PropertyType == typeof(Double)) { + if(!(json.ContainsKey(p_info.Name) && json[p_info.Name] != null && (json[p_info.Name].IsInt || json[p_info.Name].IsDouble || json[p_info.Name].IsLong))) { + return false; + } + } else if(p_info.PropertyType.BaseType == typeof(AMqttMessage)) { + if(json.ContainsKey(p_info.Name) && (json[p_info.Name] == null || json[p_info.Name].IsObject)) { + if(json[p_info.Name] != null && !CheckJson(json[p_info.Name], p_info.PropertyType)) { + return false; + } + } + } else { + return false; + } + } + } + return true; + } catch { + return false; + } + } + } +} \ No newline at end of file diff --git a/BosServerDatatypes/Mqtt/AddFilter.cs b/BosServerDatatypes/Mqtt/AddFilter.cs new file mode 100644 index 0000000..04b8428 --- /dev/null +++ b/BosServerDatatypes/Mqtt/AddFilter.cs @@ -0,0 +1,31 @@ +using System; + +using LitJson; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt { + public class AddFilter : AMqttMessage { + public String Ric { + get; + } + public String Task { + get; + } + public String Sender { + get; + } + + public AddFilter(String ric, String task, String sender) : base("add-filter") { + this.Ric = ric; + this.Task = task; + this.Sender = sender; + } + + public AddFilter(JsonData json) : base("add-filter", json["Date"]) { + this.Ric = json["Ric"].ToString(); + this.Task = json["Task"].ToString(); + this.Sender = json["Sender"].ToString(); + } + + public static AddFilter ConvertJson(String message) => new AddFilter(JsonMapper.ToObject(message)); + } +} diff --git a/BosServerDatatypes/Mqtt/GeoData.cs b/BosServerDatatypes/Mqtt/GeoData.cs new file mode 100644 index 0000000..415feb1 --- /dev/null +++ b/BosServerDatatypes/Mqtt/GeoData.cs @@ -0,0 +1,22 @@ +using System; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt { + public class GeoData : AMqttMessage { + public Double Latitude { + get; + } + public Double Longitude { + get; + } + + public GeoData(Double latitude, Double longitude) : base("geo-data") { + this.Latitude = latitude; + this.Longitude = longitude; + } + + public GeoData(LitJson.JsonData json) : base("geo-data", json["Date"]) { + this.Latitude = Double.Parse(json["Latitude"].ToString().Replace(',', '.'), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture); + this.Longitude = Double.Parse(json["Longitude"].ToString().Replace(',', '.'), System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture); + } + } +} diff --git a/BosServerDatatypes/Mqtt/InfluxStorage.cs b/BosServerDatatypes/Mqtt/InfluxStorage.cs new file mode 100644 index 0000000..9f34515 --- /dev/null +++ b/BosServerDatatypes/Mqtt/InfluxStorage.cs @@ -0,0 +1,25 @@ +using System; + +using LitJson; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt { + public class InfluxStorage : AMqttMessage { + public String Text { + get; + } + + public InfluxStorage(String text) : base("bosmon") => this.Text = text; + + public InfluxStorage(JsonData json) : base("bosmon", json["Date"]) => this.Text = ""; + + public override String ToString() => this.Text; + + public static InfluxStorage ConvertJson(String _) => new InfluxStorage(""); + + public override String ToJson() => this.Text; + + public static new Boolean CheckJson(String _1, Type _2) => false; + + public static new Boolean CheckJson(JsonData _1, Type _2) => false; + } +} diff --git a/BosServerDatatypes/Mqtt/Message.cs b/BosServerDatatypes/Mqtt/Message.cs new file mode 100644 index 0000000..161cb5d --- /dev/null +++ b/BosServerDatatypes/Mqtt/Message.cs @@ -0,0 +1,19 @@ +using System; + +using LitJson; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt { + public class Message : AMqttMessage { + public String Text { + get; + } + + public Message(String text) : base("message") => this.Text = text; + + public Message(JsonData json) : base("message", json["Date"]) => this.Text = json["Text"].ToString(); + + public override String ToString() => this.Text; + + public static Message ConvertJson(String message) => new Message(JsonMapper.ToObject(message)); + } +} diff --git a/BosServerDatatypes/Mqtt/PocsagHttp.cs b/BosServerDatatypes/Mqtt/PocsagHttp.cs new file mode 100644 index 0000000..799fb41 --- /dev/null +++ b/BosServerDatatypes/Mqtt/PocsagHttp.cs @@ -0,0 +1,51 @@ +using System; + +using LitJson; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt { + public class PocsagHttp : AMqttMessage { + public String Function { + get; + } + public String Flags { + get; + } + public String Message { + get; + } + public String Type { + get; + } + public String Address { + get; + } + + + public PocsagHttp(String function, String flags, String message, String type, String address) : base("pocsag-http") { + this.Function = function; + this.Flags = flags; + this.Message = message; + this.Type = type; + this.Address = address; + } + + public PocsagHttp(JsonData json) : base("pocsag-http", json["Date"]) { + this.Function = json["Function"].ToString(); + this.Flags = json["Flags"].ToString(); + this.Message = json["Message"].ToString(); + this.Type = json["Type"].ToString(); + this.Address = json["Address"].ToString(); + } + + public PocsagHttp(String function, String flags, String message, String type, String address, Double timestamp) : base("pocsag-http") { + this.Function = function; + this.Flags = flags; + this.Message = message; + this.Type = type; + this.Address = address; + this.Date = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timestamp).ToLocalTime(); + } + + public static PocsagHttp ConvertJson(String message) => new PocsagHttp(JsonMapper.ToObject(message)); + } +} diff --git a/BosServerDatatypes/Mqtt/PocsagParsed.cs b/BosServerDatatypes/Mqtt/PocsagParsed.cs new file mode 100644 index 0000000..19b3c13 --- /dev/null +++ b/BosServerDatatypes/Mqtt/PocsagParsed.cs @@ -0,0 +1,68 @@ +using System; + +using LitJson; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt { + public class PocsagParsed : AMqttMessage { + public PocsagHttp Raw { + get; + } + public String Funktion { + get; + } + public String Name { + get; + } + public RicDescription Ric { + get; + } + public GeoData Geo { + get; + } + public Boolean Sendonline { + get; + } + public Boolean Isprivate { + get; + } + + public PocsagParsed(PocsagHttp raw, String funktion, String name, RicDescription ric, GeoData geo, Boolean sendonline, Boolean isprivate) : base("pocsag-parsed") { + this.Raw = raw; + this.Funktion = funktion; + this.Name = name; + this.Ric = ric; + this.Geo = geo; + this.Sendonline = sendonline; + this.Isprivate = isprivate; + } + + public PocsagParsed(JsonData json) : base("pocsag-parsed", json["Date"]) { + this.Raw = new PocsagHttp(json["Raw"]); + this.Funktion = json["Funktion"].ToString(); + this.Name = json["Name"].ToString(); + this.Ric = json["Ric"] is null ? null : new RicDescription(json["Ric"]); + this.Geo = json["Geo"] is null ? null : new GeoData(json["Geo"]); + this.Sendonline = (Boolean)json["Sendonline"]; + this.Isprivate = (Boolean)json["Isprivate"]; + } + + public PocsagParsed(PocsagHttp raw, String funktion, String name, RicDescription ric, GeoData geo, Boolean sendonline, Boolean isprivate, DateTime date) : base("pocsag-parsed") { + this.Raw = raw; + this.Funktion = funktion; + this.Name = name; + this.Ric = ric; + this.Geo = geo; + this.Sendonline = sendonline; + this.Isprivate = isprivate; + this.Date = date; + } + + public override String ToString() => "[" + this.Funktion + "] " + this.Name + ": " + this.Raw.Message; + + public String ToTextString() => System.Text.RegularExpressions.Regex.Replace(this.Raw.Message, @"#C(?.+?),(?.+?)#", "").Trim(); + + public String ToTitleString() => this.Ric is RicDescription && this.Ric.ShortDescription != "" ? this.Ric.ShortDescription : this.Name; + + public static PocsagParsed ConvertJson(String message) => new PocsagParsed(JsonMapper.ToObject(message)); + } +} diff --git a/BosServerDatatypes/Mqtt/RicDescription.cs b/BosServerDatatypes/Mqtt/RicDescription.cs new file mode 100644 index 0000000..9831c72 --- /dev/null +++ b/BosServerDatatypes/Mqtt/RicDescription.cs @@ -0,0 +1,37 @@ +using System; + +using LitJson; + +namespace BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt { + public class RicDescription : AMqttMessage { + public String Address { + get; + } + + public String Location { + get; + } + + public String ShortDescription { + get; + } + + public String LongDescription { + get; + } + + public RicDescription(String address, String location, String shortdescription, String longdescription) : base("ric-description") { + this.Address = address; + this.Location = location; + this.ShortDescription = shortdescription; + this.LongDescription = longdescription; + } + + public RicDescription(JsonData json) : base("ric-description", json["Date"]) { + this.Address = json["Address"].ToString(); + this.Location = json["Location"].ToString(); + this.ShortDescription = json["ShortDescription"].ToString(); + this.LongDescription = json["LongDescription"].ToString(); + } + } +} diff --git a/BosServerHTTP/Adminrights.manifest b/BosServerHTTP/Adminrights.manifest new file mode 100644 index 0000000..6250b4f --- /dev/null +++ b/BosServerHTTP/Adminrights.manifest @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/BosServerHTTP/BosServerHTTP.csproj b/BosServerHTTP/BosServerHTTP.csproj new file mode 100644 index 0000000..dca17a7 --- /dev/null +++ b/BosServerHTTP/BosServerHTTP.csproj @@ -0,0 +1,28 @@ + + + + Exe + netcoreapp3.1 + BlubbFish.IoT.Pocsag.BosServerHTTP + Adminrights.manifest + 1.1.0 + 1.1.0 Rewrite to linux +1.0.0 Init + true + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/BosServerHTTP/Program.cs b/BosServerHTTP/Program.cs new file mode 100644 index 0000000..d418b67 --- /dev/null +++ b/BosServerHTTP/Program.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Reflection; + +using BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt; +using BlubbFish.Utils; +using BlubbFish.Utils.IoT.Bots; +using BlubbFish.Utils.IoT.Connector; +using BlubbFish.Utils.IoT.Events; + +namespace BlubbFish.IoT.Pocsag.BosServerHTTP { + class Program : AWebserverDataBackend { + private readonly Dictionary bosconf; + + static void Main(String[] args) => new Program(args, true, "bshttp", null, null); + + public Program(String[] args, Boolean fileLogging, String configSearchPath, ABackend backend, Dictionary settings) : base(args, fileLogging, configSearchPath, backend, settings) { + this.databackend.MessageSending += this.Backend_MessageSending; + this.bosconf = InIReader.GetInstance("settings").GetSection("bosserverhttp"); + + this.StartDataBackend(); + this.StartListen(); + + this.SendMqtt(new Message("Anwendung BosServerHTTP Version " + Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion + " gestartet.")); + this.WaitForShutdown(); + this.SendMqtt(new Message("Anwendung BosServerHTTP wurde beendet... Ob das so soll?")); + + this.Dispose(); + } + + protected override Boolean SendWebserverResponse(HttpListenerContext cont) { + try { + Console.WriteLine("<= HTTP " + cont.Request.Url.PathAndQuery); + if(cont.Request.Url.LocalPath.ToLower() == "/telegramin/" + this.bosconf["path"] + "/input.xml") { + Dictionary post = cont.Request.GetPostParams(); + if(post.ContainsKey("function") && post.ContainsKey("flags") && post.ContainsKey("message") && post.ContainsKey("type") && post.ContainsKey("address")) { + Console.WriteLine("=> HTTP 200 - Ok"); + this.SendMqtt(new PocsagHttp(post["function"], post["flags"], post["message"], post["type"], post["address"])); + cont.Response.StatusCode = 200; + return true; + } + } + } catch(Exception e) { + Helper.WriteError("=> HTTP SendWebserverResponse(): 500 - " + e.Message + "\n\n" + e.StackTrace); + cont.Response.StatusCode = 500; + return false; + } + Helper.WriteError("=> HTTP 404 - " + cont.Request.Url.PathAndQuery + " not found!"); + cont.Response.StatusCode = 404; + return false; + } + + protected override void Backend_MessageIncomming(Object sender, BackendEvent message) { + } + + private void Backend_MessageSending(Object sender, BackendEvent e) { + try { + Console.WriteLine("=> MQTT [" + e.From.ToString() + "]: " + e.Message); + } catch(Exception ex) { + Helper.WriteError("Backend_MessageSending(): " + ex.Message + "\n\n" + ex.StackTrace); + } + } + + private void SendMqtt(AMqttMessage msg) { + try { + ((Utils.IoT.Connector.Data.Mqtt)this.databackend).Send(this.bosconf["topic"] + "/" + msg.Datatype, msg.ToJson()); + } catch(Exception e) { + Helper.WriteError("SendMqtt(): " + e.Message + "\n\n" + e.StackTrace); + } + } + } +} diff --git a/BosServerHTTP/config-example/settings.conf.example b/BosServerHTTP/config-example/settings.conf.example new file mode 100644 index 0000000..e9a9a08 --- /dev/null +++ b/BosServerHTTP/config-example/settings.conf.example @@ -0,0 +1,15 @@ +[logging] +path=/var/log/bshttp.log +debug=true + +[webserver] +prefix=http://+:8080/ + +[backend] +type=Mqtt +backendtype=Data +server=ilocalhost + +[bosserverhttp] +path=upload +topic=bosmon \ No newline at end of file diff --git a/BosServerHTTP/dpkg/create-builds.sh b/BosServerHTTP/dpkg/create-builds.sh new file mode 100644 index 0000000..1e4f093 --- /dev/null +++ b/BosServerHTTP/dpkg/create-builds.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +CSPROJFILE="BosServerHTTP.csproj" +VMAJOR=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 1) +VMINOR=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 2) +VBUILD=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 3) + +mkdir -p ../deb +mkdir -p ../Builds + +export NAME=bshttp +export MAINAINER="BlubbFish " +export VERSION="$VMAJOR.$VMINOR-$VBUILD" +export DESCRIPTION="bshttp recieves web reqests and post them in mqtt" +export DEPENDENCIES="dotnet-runtime-8.0 (>= 8.0.0)" +export LOGFILE="/var/log/bshttp.log" + +export EXEPATH=BosServerHTTP.dll +export RUNNER=/usr/share/dotnet/dotnet +export COPYEXEC="../bin/Release/netcoreapp3.1/*.dll ../bin/Release/netcoreapp3.1/BosServerHTTP.deps.json ../bin/Release/netcoreapp3.1/BosServerHTTP.runtimeconfig.json" + +export COPYCONFIG="../bin/Release/netcoreapp3.1/config-example/*.conf" +export CONFIGREPLACEASK=settings.conf + +cd ../deb +export PLATFORM=armhf +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/control-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/pre-post-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/service-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/logrotate-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/build-deb.sh | bash + +export PLATFORM=amd64 +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/control-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/build-deb.sh | bash + +cd .. +rm deb -rf + +cp Builds/* ../../Builds/ +rm Builds -rf \ No newline at end of file diff --git a/BosServerParser/BosServerParser.csproj b/BosServerParser/BosServerParser.csproj new file mode 100644 index 0000000..57b21d8 --- /dev/null +++ b/BosServerParser/BosServerParser.csproj @@ -0,0 +1,31 @@ + + + + Exe + netcoreapp3.1 + BlubbFish.IoT.Pocsag.BosServerParser + 1.1.2 + 1.1.2 Correct file path +1.1.1 Prettiefy Json file. +1.1.0 Rewrite to store data in json instead of mysql +1.0.1 Bugfix Dispose also StorageBackend +1.0.0 Init + true + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/BosServerParser/Program.cs b/BosServerParser/Program.cs new file mode 100644 index 0000000..57cd259 --- /dev/null +++ b/BosServerParser/Program.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; + +using BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt; +using BlubbFish.IoT.Pocsag.BosServerDatatypes.Json; +using BlubbFish.Utils; +using BlubbFish.Utils.IoT.Bots; +using BlubbFish.Utils.IoT.Connector; +using BlubbFish.Utils.IoT.Events; + +namespace BlubbFish.IoT.Pocsag.BosServerParser { + class Program : ABot { + private readonly ABackend bmqtt; + private readonly ABackend bjson; + private readonly Dictionary bosconf; + + static void Main(String[] args) => new Program(args, true, "bsparser"); + + public Program(String[] args, Boolean fileLogging, String configSearchPath) : base(args, fileLogging, configSearchPath) { + this.bmqtt = ABackend.GetInstance(InIReader.GetInstance("settings").GetSection("backend")); + this.bjson = ABackend.GetStorageInstance(InIReader.GetInstance("settings").GetSection("storage"),new List { typeof(RicData) }); + this.bosconf = InIReader.GetInstance("settings").GetSection("bosserverparser"); + + this.bmqtt.MessageIncomming += this.Mqtt_MessageIncomming; + this.bmqtt.MessageSending += this.Mqtt_MessageSending; + + this.SendMqtt(new Message("Anwendung BosServerParser Version " + Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion + " gestartet.")); + this.WaitForShutdown(); + this.SendMqtt(new Message("Anwendung BosServerParser wurde beendet... Ob das so soll?")); + + this.Dispose(); + } + + private void Mqtt_MessageIncomming(Object sender, BackendEvent mqtt) { + try { + Console.WriteLine("<= MQTT [" + mqtt.From.ToString() + "]: " + mqtt.Message); + if(AMqttMessage.CheckJson(mqtt.Message, typeof(PocsagHttp))) { + PocsagHttp p = PocsagHttp.ConvertJson(mqtt.Message); + + String funktion = this.ParseFunction(p.Function); + (String name, RicDescription ric) = this.ParseRic(p.Address); + GeoData geo = this.ParseLocation(p.Message); + Boolean sendonline = this.ParseFilter(p.Message, ric, p.Address); + Boolean isprivate = this.ParsePrivate(p.Address); + + this.SendMqtt(new PocsagParsed(p, funktion, name, ric, geo, sendonline, isprivate)); + } else if(AMqttMessage.CheckJson(mqtt.Message, typeof(AddFilter))) { + AddFilter filter = AddFilter.ConvertJson(mqtt.Message); + if(this.InsertFilter(filter)) { + this.SendMqtt(new Message("Hallo " + filter.Sender + ", die RIC " + filter.Ric + " wurde als \"" + filter.Task + "\" geflaggt, Nachrichten werden zukünftig gefiltert.")); + } else { + this.SendMqtt(new Message("Hallo " + filter.Sender + ", das hinzufügen des Filters \"" + filter.Task + "\" für die RIC " + filter.Ric + " ist fehlgeschlagen.")); + } + } + } catch(Exception ex) { + Helper.WriteError("Backend_MessageIncomming(): " + ex.Message + "\n\n" + ex.StackTrace); + } + } + + private void Mqtt_MessageSending(Object sender, BackendEvent mqtt) { + try { + Console.WriteLine("=> MQTT [" + mqtt.From.ToString() + "]: " + mqtt.Message); + } catch(Exception ex) { + Helper.WriteError("Backend_MessageSending(): " + ex.Message + "\n\n" + ex.StackTrace); + } + } + + private void SendMqtt(AMqttMessage msg) { + try { + ((Utils.IoT.Connector.Data.Mqtt)this.bmqtt).Send(this.bosconf["topic"] + "/" + msg.Datatype, msg.ToJson()); + } catch(Exception e) { + Helper.WriteError("SendMqtt(): " + e.Message + "\n\n" + e.StackTrace); + } + } + + private String ParseFunction(String function) => function switch { + "a" => "EIL", + "b" => "ZEIT", + "c" => "PROBE", + "d" => "ENDE", + _ => "" + }; + + private GeoData ParseLocation(String message) { + Match m = Regex.Match(message, @"#C(?.+?),(?.+?)#"); + if(m.Success) { + if(Double.TryParse(m.Groups["lat"].Value.Insert(2, "."), NumberStyles.Float, CultureInfo.InvariantCulture, out Double lat) && + Double.TryParse(m.Groups["lon"].Value.Insert(2, "."), NumberStyles.Float, CultureInfo.InvariantCulture, out Double lon)) { + return new GeoData(lat, lon); + } + } + return null; + } + + private (String, RicDescription) ParseRic(String ric) { + RicData ric_data = ((Utils.IoT.Connector.Storage.Json)this.bjson).Get(ric); + RicDescription desc = null; + String text; + + if(ric_data is null) { + text = ric; + } else { + desc = new RicDescription(ric, ric_data.Location, ric_data.ShortDescription, ric_data.LongDescription); + List text_parts = new List(); + if(!(ric_data.Location is null) && ric_data.Location != "") { + text_parts.Add(ric_data.Location); + } + if(!(ric_data.ShortDescription is null) && ric_data.ShortDescription != "") { + text_parts.Add(ric_data.ShortDescription); + } + if(!(ric_data.LongDescription is null) && ric_data.LongDescription != "") { + text_parts.Add("(" + ric_data.LongDescription + ")"); + } + text = String.Join(" ", text_parts); + } + return (text, desc); + } + + private Boolean ParseFilter(String message, RicDescription ric, String address) { + if(ric != null && ric.LongDescription.ToLower() == "idea") { + return false; + } else if(ric != null && ric.LongDescription.ToLower() == "leer") { + return false; + } else if(message == "" && ric is null) { + return false; + } + foreach(KeyValuePair item in InIReader.GetInstance("settings").GetSection("filter")) { + String[] a = item.Value.Split("|"); + switch(a[0]) { + case "address": + if(address.StartsWith(a[1])) { + return false; + } + break; + case "message": + if(message == a[1]) { + return false; + } + break; + } + } + return true; + } + + private Boolean ParsePrivate(String address) => this.bosconf["special-ric"].Split(";").Contains(address); + + private Boolean InsertFilter(AddFilter filter) { + try { + return ((Utils.IoT.Connector.Storage.Json)this.bjson).Put(new RicData("", "BosServer", filter.Task.ToUpper()), filter.Ric); + } catch { + Helper.WriteError("=> Database Filter [" + filter.Ric + "*] " + filter.Task + " konnte nicht hinzugefügt werden!"); + } + return false; + } + + public override void Dispose() { + if(this.bmqtt != null) { + this.bmqtt.Dispose(); + } + if(this.bjson != null) { + this.bjson.Dispose(); + } + base.Dispose(); + } + } +} diff --git a/BosServerParser/config-example/settings.conf.example b/BosServerParser/config-example/settings.conf.example new file mode 100644 index 0000000..706b3b8 --- /dev/null +++ b/BosServerParser/config-example/settings.conf.example @@ -0,0 +1,26 @@ +[logging] +path=/var/log/bsparser.log +debug=true + +[backend] +type=Mqtt +backendtype=Data +server=localhost +topic=bosmon/pocsag-http;bosmon/add-filter + +[storage] +type=Json +backendtype=Storage +path=/var/lib/bsparser/ric.json + +[bosserverparser] +topic=bosmon +special-ric=0000001;0000002 + +[filter] +filter1=address|9999999 +filter2=address|0000001 +filter3=address|0000014 +filter4=message| +filter5=message| +filter6=message| \ No newline at end of file diff --git a/BosServerParser/dpkg/create-builds.sh b/BosServerParser/dpkg/create-builds.sh new file mode 100644 index 0000000..5b0d131 --- /dev/null +++ b/BosServerParser/dpkg/create-builds.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +CSPROJFILE="BosServerParser.csproj" +VMAJOR=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 1) +VMINOR=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 2) +VBUILD=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 3) + +mkdir -p ../deb +mkdir -p ../Builds + +export NAME=bsparser +export MAINAINER="BlubbFish " +export VERSION="$VMAJOR.$VMINOR-$VBUILD" +export DESCRIPTION="bsparser parsed pocsag messages" +export DEPENDENCIES="dotnet-runtime-8.0 (>= 8.0.0)" +export LOGFILE="/var/log/bsparser.log" + +export EXEPATH=BosServerParser.dll +export RUNNER=/usr/share/dotnet/dotnet +export COPYEXEC="../bin/Release/netcoreapp3.1/*.dll ../bin/Release/netcoreapp3.1/BosServerParser.deps.json ../bin/Release/netcoreapp3.1/BosServerParser.runtimeconfig.json" + +export COPYCONFIG="../bin/Release/netcoreapp3.1/config-example/*.conf" +export CONFIGREPLACEASK=settings.conf + +export DATADIR="/var/lib/bsparser" + +cd ../deb +export PLATFORM=armhf +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/control-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/pre-post-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/service-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/logrotate-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/build-deb.sh | bash + +export PLATFORM=amd64 +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/control-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/build-deb.sh | bash + +cd .. +rm deb -rf + +cp Builds/* ../../Builds/ +rm Builds -rf \ No newline at end of file diff --git a/BosServerStorage/BosServerStorage.csproj b/BosServerStorage/BosServerStorage.csproj new file mode 100644 index 0000000..d455df4 --- /dev/null +++ b/BosServerStorage/BosServerStorage.csproj @@ -0,0 +1,29 @@ + + + + Exe + netcoreapp3.1 + BlubbFish.IoT.Pocsag.BosServerStorage + 1.1.2 + 1.1.2 Fix searchpath for config +1.1.1 Fix InvariantGlobalization, so Linux will start the app +1.1.0 Rewrite from Mysql to Influx +1.0.0 Init + true + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/BosServerStorage/Program.cs b/BosServerStorage/Program.cs new file mode 100644 index 0000000..828661f --- /dev/null +++ b/BosServerStorage/Program.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +using BlubbFish.IoT.Pocsag.BosServerDatatypes.Influx; +using BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt; +using BlubbFish.Utils; +using BlubbFish.Utils.IoT.Bots; +using BlubbFish.Utils.IoT.Connector; +using BlubbFish.Utils.IoT.Events; + +namespace BlubbFish.IoT.Pocsag.BosServerStorage { + class Program : ABot { + private readonly ABackend mqtt; + private readonly Dictionary bosconf; + + static void Main(String[] args) => new Program(args, true, "bsstorage"); + + public Program(String[] args, Boolean fileLogging, String configSearchPath) : base(args, fileLogging, configSearchPath) { + this.mqtt = ABackend.GetInstance(InIReader.GetInstance("settings").GetSection("backend")); + this.mqtt.MessageIncomming += this.Mqtt_MessageIncomming; + this.mqtt.MessageSending += this.Mqtt_MessageSending; + + this.bosconf = InIReader.GetInstance("settings").GetSection("bosserverstorage"); + + this.SendMqtt(new Message("Anwendung BosServerStorage Version " + Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion + " gestartet.")); + this.WaitForShutdown(); + this.SendMqtt(new Message("Anwendung BosServerStorage wurde beendet... Ob das so soll?")); + + this.Dispose(); + } + + private void Mqtt_MessageSending(Object sender, BackendEvent mqtt) { + try { + Console.WriteLine("=> MQTT [" + mqtt.From.ToString() + "]: " + mqtt.Message); + } catch(Exception ex) { + Helper.WriteError("Backend_MessageSending(): " + ex.Message + "\n\n" + ex.StackTrace); + } + } + + private void Mqtt_MessageIncomming(Object sender, BackendEvent mqtt) { + try { + Console.WriteLine("<= MQTT [" + mqtt.From.ToString() + "]: " + mqtt.Message); + if(AMqttMessage.CheckJson(mqtt.Message, typeof(PocsagParsed))) { + this.SendMqtt(new InfluxStorage(new Bosmon(PocsagParsed.ConvertJson(mqtt.Message)).ToInfluxString())); + } + } catch(Exception ex) { + Helper.WriteError("Backend_MessageIncomming(): " + ex.Message + "\n\n" + ex.StackTrace); + } + } + + private void SendMqtt(AMqttMessage msg) { + try { + ((Utils.IoT.Connector.Data.Mqtt)this.mqtt).Send(this.bosconf["topic"] + "/" + msg.Datatype, msg.ToJson()); + } catch(Exception e) { + Helper.WriteError("SendMqtt(): " + e.Message + "\n\n" + e.StackTrace); + } + } + + public override void Dispose() { + if(this.mqtt != null) { + this.mqtt.Dispose(); + } + base.Dispose(); + } + } +} diff --git a/BosServerStorage/config-example/settings.conf.example b/BosServerStorage/config-example/settings.conf.example new file mode 100644 index 0000000..f12f3da --- /dev/null +++ b/BosServerStorage/config-example/settings.conf.example @@ -0,0 +1,12 @@ +[logging] +path=/var/log/bsstorage.log +debug=true + +[backend] +type=Mqtt +backendtype=Data +server=localhost +topic=bosmon/pocsag-parsed + +[bosserverstorage] +topic=bosmon \ No newline at end of file diff --git a/BosServerStorage/dpkg/create-builds.sh b/BosServerStorage/dpkg/create-builds.sh new file mode 100644 index 0000000..02bab13 --- /dev/null +++ b/BosServerStorage/dpkg/create-builds.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +CSPROJFILE="BosServerStorage.csproj" +VMAJOR=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 1) +VMINOR=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 2) +VBUILD=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 3) + +mkdir -p ../deb +mkdir -p ../Builds + +export NAME=bsstorage +export MAINAINER="BlubbFish " +export VERSION="$VMAJOR.$VMINOR-$VBUILD" +export DESCRIPTION="bsstorage converts parsed pocsag messages to influx format" +export DEPENDENCIES="dotnet-runtime-8.0 (>= 8.0.0)" +export LOGFILE="/var/log/bsstorage.log" + +export EXEPATH=BosServerStorage.dll +export RUNNER=/usr/share/dotnet/dotnet +export COPYEXEC="../bin/Release/netcoreapp3.1/*.dll ../bin/Release/netcoreapp3.1/BosServerStorage.deps.json ../bin/Release/netcoreapp3.1/BosServerStorage.runtimeconfig.json" + +export COPYCONFIG="../bin/Release/netcoreapp3.1/config-example/*.conf" +export CONFIGREPLACEASK=settings.conf + +cd ../deb +export PLATFORM=armhf +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/control-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/pre-post-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/service-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/logrotate-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/build-deb.sh | bash + +export PLATFORM=amd64 +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/control-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/build-deb.sh | bash + +cd .. +rm deb -rf + +cp Builds/* ../../Builds/ +rm Builds -rf \ No newline at end of file diff --git a/BosServerTelegram/BosServerTelegram.csproj b/BosServerTelegram/BosServerTelegram.csproj new file mode 100644 index 0000000..873b9ea --- /dev/null +++ b/BosServerTelegram/BosServerTelegram.csproj @@ -0,0 +1,30 @@ + + + + Exe + netcoreapp3.1 + BlubbFish.IoT.Pocsag.BosServerTelegram + 1.1.0 + + 1.1.0 make it running on linux + 1.0.0 Init + + true + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/BosServerTelegram/Program.cs b/BosServerTelegram/Program.cs new file mode 100644 index 0000000..604df1c --- /dev/null +++ b/BosServerTelegram/Program.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text.RegularExpressions; + +using BlubbFish.IoT.Pocsag.BosServerDatatypes.Mqtt; +using BlubbFish.Utils; +using BlubbFish.Utils.IoT.Bots; +using BlubbFish.Utils.IoT.Connector; +using BlubbFish.Utils.IoT.Events; + +namespace BlubbFish.IoT.Pocsag.BosServerTelegram { + class Program : ABot { + private readonly ABackend bmqtt; + private readonly ABackend btelegram; + private readonly Dictionary bosconf; + + static void Main(String[] args) => new Program(args, false, "bstelegram"); + + public Program(String[] args, Boolean fileLogging, String configSearchPath) : base(args, fileLogging, configSearchPath) { + this.bmqtt = ABackend.GetInstance(InIReader.GetInstance("settings").GetSection("backend")); + this.bmqtt.MessageIncomming += this.Mqtt_MessageIncomming; + this.bmqtt.MessageSending += this.Mqtt_MessageSending; + + this.btelegram = ABackend.GetInstance(InIReader.GetInstance("settings").GetSection("usernotification")); + this.btelegram.MessageIncomming += this.Telegram_MessageIncomming; + this.btelegram.MessageSending += this.Telegram_MessageSending; + + this.bosconf = InIReader.GetInstance("settings").GetSection("bosservertelegram"); + + this.SendMqtt(new Message("Anwendung BosServerTelegram Version " + Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion + " gestartet.")); + this.WaitForShutdown(); + this.SendMqtt(new Message("Anwendung BosServerTelegram wurde beendet... Ob das so soll?")); + + System.Threading.Thread.Sleep(5000); + this.Dispose(); + } + + private void Telegram_MessageSending(Object sender, BackendEvent telegram) { + try { + Console.WriteLine("=> Telegram [" + telegram.From.ToString() + "]: " + telegram.Message); + } catch(Exception e) { + Helper.WriteError("Backend_MessageSending(): " + e.Message + "\n\n" + e.StackTrace); + } + } + + private void Mqtt_MessageSending(Object sender, BackendEvent mqtt) { + try { + Console.WriteLine("=> MQTT [" + mqtt.From.ToString() + "]: " + mqtt.Message); + } catch(Exception e) { + Helper.WriteError("Backend_MessageSending(): " + e.Message + "\n\n" + e.StackTrace); + } + } + + private void Telegram_MessageIncomming(Object sender, BackendEvent telegram) { + try { + if(telegram.From is Tuple t) { + Console.WriteLine("<= Telegram-API [" + t.Item1.ToString() + "]: " + telegram.Message); + String task = telegram.Message.ToLower(); + if(task == "idea" || task == "leer") { + if(!(t.Item4 is null)) { + Match x = Regex.Match(t.Item4, @"^\[[A-Z]+\] ([0-9]+): .*?$"); + if(x.Success) { + if(t.Item1 == Int64.Parse(this.bosconf["special"])) { + this.SendMqtt(new AddFilter(x.Groups[1].ToString(), task, t.Item2)); + } else { + this.SendTelegram(new Message("Hallo " + t.Item2 + ", https://xkcd.com/838/"), t.Item3.ToString()); + } + } else { + this.SendTelegram(new Message("Hallo " + t.Item2 + ", ich kann die RIC in der zitierten Nachricht nicht finden."), t.Item3.ToString()); + } + } else { + this.SendTelegram(new Message("Hallo " + t.Item2 + ", du hast keine Nachricht zitiert."), t.Item3.ToString()); + } + } + } + } catch(Exception e) { + Helper.WriteError("Backend_MessageIncomming(): " + e.Message + "\n\n" + e.StackTrace); + } + } + + private void Mqtt_MessageIncomming(Object sender, BackendEvent mqtt) { + try { + Console.WriteLine("<= MQTT [" + mqtt.From.ToString() + "]: " + mqtt.Message); + if(AMqttMessage.CheckJson(mqtt.Message, typeof(PocsagParsed))) { + PocsagParsed p = PocsagParsed.ConvertJson(mqtt.Message); + if(p.Isprivate) { + this.SendTelegram(p, this.bosconf["special"]); + } + if(p.Sendonline) { + this.SendTelegram(p, this.bosconf["group"]); + } + } else if(AMqttMessage.CheckJson(mqtt.Message, typeof(Message))) { + this.SendTelegram(Message.ConvertJson(mqtt.Message), this.bosconf["group"]); + } + } catch(Exception e) { + Helper.WriteError("Backend_MessageIncomming(): " + e.Message + "\n\n" + e.StackTrace); + } + } + + private void SendMqtt(AMqttMessage msg) { + try { + ((Utils.IoT.Connector.Data.Mqtt)this.bmqtt).Send(this.bosconf["topic"] + "/" + msg.Datatype, msg.ToJson()); + } catch(Exception e) { + Helper.WriteError("SendMqtt(): " + e.Message + "\n\n" + e.StackTrace); + } + } + + private void SendTelegram(AMqttMessage msg, String target) { + ((Utils.IoT.Connector.User.Telegram)this.btelegram).Send(msg.ToString(), target); + if(msg is PocsagParsed p && p.Geo is GeoData) { + ((Utils.IoT.Connector.User.Telegram)this.btelegram).SendLocationWithText(p.ToTitleString(), p.ToTextString(), p.Geo.Latitude, p.Geo.Longitude, target); + } + } + + public override void Dispose() { + if(this.bmqtt != null) { + this.bmqtt.Dispose(); + } + if(this.btelegram != null) { + this.btelegram.Dispose(); + } + base.Dispose(); + } + } +} diff --git a/BosServerTelegram/config-example/settings.conf.example b/BosServerTelegram/config-example/settings.conf.example new file mode 100644 index 0000000..c01807e --- /dev/null +++ b/BosServerTelegram/config-example/settings.conf.example @@ -0,0 +1,20 @@ +[logging] +path=/var/log/bstelegram.log +debug=true + +[backend] +type=Mqtt +backendtype=Data +server=localhost +topic=bosmon/pocsag-parsed;bosmon/message + +[usernotification] +type=Telegram +backendtype=User +telegram-key=[api_key] +default-chat=[chatgruppe] + +[bosservertelegram] +topic=bosmon +group=[chatgruppe] +special=[chat_person] \ No newline at end of file diff --git a/BosServerTelegram/dpkg/create-builds.sh b/BosServerTelegram/dpkg/create-builds.sh new file mode 100644 index 0000000..004f589 --- /dev/null +++ b/BosServerTelegram/dpkg/create-builds.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +CSPROJFILE="BosServerTelegram.csproj" +VMAJOR=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 1) +VMINOR=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 2) +VBUILD=$(grep -e "" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 3) + +mkdir -p ../deb +mkdir -p ../Builds + +export NAME=bstelegram +export MAINAINER="BlubbFish " +export VERSION="$VMAJOR.$VMINOR-$VBUILD" +export DESCRIPTION="bstelegram sends parsed pocsag messages to to telegram chat" +export DEPENDENCIES="dotnet-runtime-8.0 (>= 8.0.0)" +export LOGFILE="/var/log/bstelegram.log" + +export EXEPATH=BosServerTelegram.dll +export RUNNER=/usr/share/dotnet/dotnet +export COPYEXEC="../bin/Release/netcoreapp3.1/*.dll ../bin/Release/netcoreapp3.1/BosServerTelegram.deps.json ../bin/Release/netcoreapp3.1/BosServerTelegram.runtimeconfig.json" + +export COPYCONFIG="../bin/Release/netcoreapp3.1/config-example/*.conf" +export CONFIGREPLACEASK=settings.conf + +cd ../deb +export PLATFORM=armhf +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/control-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/pre-post-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/service-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/logrotate-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/build-deb.sh | bash + +export PLATFORM=amd64 +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/control-build.sh | bash +curl -s https://git.blubbfish.net/vs_utils/CI-Scripts/raw/branch/master/deb/build-deb.sh | bash + +cd .. +rm deb -rf + +cp Builds/* ../../Builds/ +rm Builds -rf \ No newline at end of file