first commit

This commit is contained in:
BlubbFish 2026-08-02 23:33:31 +02:00
commit fd62224511
41 changed files with 2348 additions and 0 deletions

16
.gitignore vendored Normal file
View File

@ -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

97
BosServer.sln Normal file
View File

@ -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

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<ApplicationManifest>Adminrights.manifest</ApplicationManifest>
<Version>1.0.5</Version>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySqlConnector" Version="2.1.13" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj" />
<ProjectReference Include="..\..\Utils\ConnectorUserTelegram\ConnectorUserTelegram\ConnectorUserTelegram.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="config-example\settings.conf.example">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

90
BosServer/Database.cs Normal file
View File

@ -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<String, String> dbconfig;
private MySqlConnection Mysql;
public Boolean Debug {
get; private set;
}
public Database(Dictionary<String, String> 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<T>(String query, Dictionary<String, Object> 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<String, Object> item in param) {
_ = command.Parameters.AddWithValue(item.Key, item.Value);
}
using MySqlDataReader reader = command.ExecuteReader();
if(!reader.HasRows) {
return default;
}
ReadOnlyCollection<DbColumn> 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<String, Object> param) {
if(this.Mysql.State == System.Data.ConnectionState.Broken) {
this.Reconnect();
}
using MySqlCommand command = new MySqlCommand {
CommandText = query,
Connection = this.Mysql
};
foreach(KeyValuePair<String, Object> item in param) {
_ = command.Parameters.AddWithValue(item.Key, item.Value);
}
return command.ExecuteNonQuery();
}
public void Dispose() => this.Disconnect();
}
}

View File

@ -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;
}
}
}

11
BosServer/Program.cs Normal file
View File

@ -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);
}
}

238
BosServer/Webserver.cs Normal file
View File

@ -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<String, String> bosconf;
private readonly Database db;
public Webserver(String[] args, Boolean fileLogging, String configSearchPath, ABackend backend, Dictionary<String, String> 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<String, PocsagRecords>("BosServer.exe", null), "Anwendung Version "+ Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion + " gestartet.", null, this.bosconf["group"]);
this.WaitForShutdown();
this.SendTelegram("Anwendung", new Tuple<String, PocsagRecords>("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<Int64, String, Int64, String> 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<String, PocsagRecords>("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<String, PocsagRecords>("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<String, PocsagRecords>("BosServer.exe", null), "Hallo " + t.Item2 + ", https://xkcd.com/838/", null, t.Item3.ToString());
}
} else {
this.SendTelegram("Filter", new Tuple<String, PocsagRecords>("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<String, PocsagRecords>("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<String, String> 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<String, PocsagRecords> ric = this.ParseRic(address);
Tuple<Double, Double> 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<String, PocsagRecords> ric, String message, Tuple<Double, Double> 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(?<lon>.+?),(?<lat>.+?)#", "").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<String, PocsagRecords> 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<String, String> 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<Double, Double> ParseLocation(String message) {
Match m = Regex.Match(message, @"#C(?<lon>.+?),(?<lat>.+?)#");
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<Double, Double>(lat, lon);
}
}
return null;
}
private Tuple<String, PocsagRecords> ParseRic(String ric) {
PocsagRecords ric_data = this.db.DbGetSingleRow<PocsagRecords>("SELECT * FROM `PocsagRecords` WHERE `Address` = CONCAT(@ric,'*');", new Dictionary<String, Object>() { { "ric", ric } });
String text;
if(ric_data is null) {
text = ric;
} else {
List<String> text_parts = new List<String>();
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<String, PocsagRecords>(text, ric_data);
}
private void SaveDatabse(String address, String function, String message, Tuple<Double, Double> 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<String, Object>() {
{ "addr", address+function },
{ "message", message },
{ "ext", geo is null? null: "<extensions>" +
"<location>" +
"<country></country>" +
"<postalcode></postalcode>" +
"<locality></locality>" +
"<street></street>" +
"<lat>"+geo.Item1.ToString(CultureInfo.InvariantCulture)+"</lat>" +
"<lng>"+geo.Item2.ToString(CultureInfo.InvariantCulture)+"</lng>" +
"</location>" +
"<keywords/>" +
"</extensions>"}
});
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<String, Object>() {
{ "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();
}
}
}

View File

@ -0,0 +1,32 @@
[bosserver]
group=<telegram_group_id>
special=<telegram_personal_id>
special-ric=<pocsag_ric>;<send_also_to>;<personal_id>
path=upload
[filter]
filter1=address|1234
filter2=address|3456
filter4=message|<DC1>
filter5=message|<DC2>
filter6=message|<DC3>
[logging]
path=bosserver.log
debug=true
[webserver]
prefix=http://+:8080/
[backend]
type=Telegram
backendtype=User
telegram-key=<telegram_api_key>
default-chat=<telegram_group_id>
[mysql]
server=localhost
user=bosserver
pass=password_change_me
db=bosmon
save=false

View File

@ -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

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj" />
<ProjectReference Include="..\..\..\Utils\ConnectorDbMysql\ConnectorDbMysql\ConnectorDbMysql.csproj" />
<ProjectReference Include="..\..\..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj" />
<ProjectReference Include="..\..\BosServerDatatypes\BosServerDatatypes.csproj" />
</ItemGroup>
</Project>

View File

@ -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<String, String> bosconf;
//private List<TelegramStorage> mysqlTableMessage;
private List<PocsagRecords> mysqlTableRic;
//private List<PocsagParsed> pocsagTable;
private SortedDictionary<String, RicData> ricData;
//private List<String> influxTable;
//private readonly Dictionary<String, (String, RicDescription)> rics = new Dictionary<String, (String, RicDescription)>();
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<String>();
foreach(PocsagParsed item in this.pocsagTable) {
this.influxTable.Add(new Bosmon(item, true).ToInfluxString());
}
this.pocsagTable.Clear();
}*/
/*private void ParseMessage() {
this.pocsagTable = new List<PocsagParsed>();
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<String, RicData>();
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<String, String> 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(?<lon>[0-9\.]+),(?<lat>[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, @"<lat>(?<lat>[0-9\.]+)</lat>");
Match elon = Regex.Match(extensions, @"<lng>(?<lon>[0-9\.]+)</lng>");
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<PocsagRecords>("SELECT * FROM `PocsagRecords` WHERE `Address` = CONCAT(@ric,'*');", new Dictionary<String, Object>() { { "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<String> text_parts = new List<String>();
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<TelegramStorage>("SELECT * FROM `TelegramStorage`", new Dictionary<String, Object>());*/
private void LoadRicList() => this.mysqlTableRic = ((BlubbFish.Utils.IoT.Connector.Db.Mysql)this.mysql).LoadMultiRows<PocsagRecords>("SELECT * FROM `PocsagRecords`", new Dictionary<String, Object>());
public override void Dispose() {
if(this.mysql != null) {
this.mysql.Dispose();
}
base.Dispose();
}
}
}

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>BlubbFish.IoT.Pocsag.BosServerDatatypes</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Librarys\litjson\litjson\litjson.csproj" />
<ProjectReference Include="..\..\Utils\ConnectorStorageJson\ConnectorStorageJson\ConnectorStorageJson.csproj" />
</ItemGroup>
</Project>

View File

@ -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<String, String> _tags = ImmutableSortedDictionary<String, String>.Empty;
private ImmutableSortedDictionary<String, Object> _fields = ImmutableSortedDictionary<String, Object>.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<String, String> 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<String, Object> 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;
}
}

View File

@ -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;
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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));
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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));
}
}

View File

@ -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(?<lon>.+?),(?<lat>.+?)#", "").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));
}
}

View File

@ -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();
}
}
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>BlubbFish.IoT.Pocsag.BosServerHTTP</RootNamespace>
<ApplicationManifest>Adminrights.manifest</ApplicationManifest>
<Version>1.1.0</Version>
<Description>1.1.0 Rewrite to linux
1.0.0 Init</Description>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj" />
<ProjectReference Include="..\..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj" />
<ProjectReference Include="..\..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj" />
<ProjectReference Include="..\..\Utils\Utils\Utils\Utils.csproj" />
<ProjectReference Include="..\BosServerDatatypes\BosServerDatatypes.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="config-example\settings.conf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

73
BosServerHTTP/Program.cs Normal file
View File

@ -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<String, String> bosconf;
static void Main(String[] args) => new Program(args, true, "bshttp", null, null);
public Program(String[] args, Boolean fileLogging, String configSearchPath, ABackend backend, Dictionary<String, String> 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<AssemblyInformationalVersionAttribute>().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<String, String> 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);
}
}
}
}

View File

@ -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

View File

@ -0,0 +1,41 @@
#!/bin/bash
CSPROJFILE="BosServerHTTP.csproj"
VMAJOR=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 1)
VMINOR=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 2)
VBUILD=$(grep -e "<Version>" ../$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 <dev@blubbfish.net>"
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

View File

@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>BlubbFish.IoT.Pocsag.BosServerParser</RootNamespace>
<Version>1.1.2</Version>
<Description>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</Description>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj" />
<ProjectReference Include="..\..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj" />
<ProjectReference Include="..\..\Utils\ConnectorStorageJson\ConnectorStorageJson\ConnectorStorageJson.csproj" />
<ProjectReference Include="..\..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj" />
<ProjectReference Include="..\..\Utils\Utils\Utils\Utils.csproj" />
<ProjectReference Include="..\BosServerDatatypes\BosServerDatatypes.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="config-example\settings.conf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

170
BosServerParser/Program.cs Normal file
View File

@ -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<String, String> 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<Type> { 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<AssemblyInformationalVersionAttribute>().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(?<lon>.+?),(?<lat>.+?)#");
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<RicData>)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<String> text_parts = new List<String>();
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<String, String> 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<RicData>)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();
}
}
}

View File

@ -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|<DC1>
filter5=message|<DC2>
filter6=message|<DC3>

View File

@ -0,0 +1,43 @@
#!/bin/bash
CSPROJFILE="BosServerParser.csproj"
VMAJOR=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 1)
VMINOR=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 2)
VBUILD=$(grep -e "<Version>" ../$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 <dev@blubbfish.net>"
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

View File

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>BlubbFish.IoT.Pocsag.BosServerStorage</RootNamespace>
<Version>1.1.2</Version>
<Description>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</Description>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj" />
<ProjectReference Include="..\..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj" />
<ProjectReference Include="..\..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj" />
<ProjectReference Include="..\..\Utils\Utils\Utils\Utils.csproj" />
<ProjectReference Include="..\BosServerDatatypes\BosServerDatatypes.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="config-example\settings.conf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -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<String, String> 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<AssemblyInformationalVersionAttribute>().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();
}
}
}

View File

@ -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

View File

@ -0,0 +1,41 @@
#!/bin/bash
CSPROJFILE="BosServerStorage.csproj"
VMAJOR=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 1)
VMINOR=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 2)
VBUILD=$(grep -e "<Version>" ../$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 <dev@blubbfish.net>"
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

View File

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>BlubbFish.IoT.Pocsag.BosServerTelegram</RootNamespace>
<Version>1.1.0</Version>
<Description>
1.1.0 make it running on linux
1.0.0 Init
</Description>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Utils\Bot-Utils\Bot-Utils\Bot-Utils.csproj" />
<ProjectReference Include="..\..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj" />
<ProjectReference Include="..\..\Utils\ConnectorUserTelegram\ConnectorUserTelegram\ConnectorUserTelegram.csproj" />
<ProjectReference Include="..\..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj" />
<ProjectReference Include="..\..\Utils\Utils\Utils\Utils.csproj" />
<ProjectReference Include="..\BosServerDatatypes\BosServerDatatypes.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="config-example\settings.conf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -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<String, String> 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<AssemblyInformationalVersionAttribute>().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<Int64, String, Int64, String> 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();
}
}
}

View File

@ -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]

View File

@ -0,0 +1,41 @@
#!/bin/bash
CSPROJFILE="BosServerTelegram.csproj"
VMAJOR=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 1)
VMINOR=$(grep -e "<Version>" ../$CSPROJFILE | cut -d'>' -f 2 | cut -d'<' -f 1 | cut -d'.' -f 2)
VBUILD=$(grep -e "<Version>" ../$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 <dev@blubbfish.net>"
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