3using System.Diagnostics;
6using System.Net.NetworkInformation;
7using System.Reflection;
8using System.Runtime.ExceptionServices;
11using System.Security.Cryptography.X509Certificates;
13using System.Text.RegularExpressions;
14using System.Threading.Tasks;
16using System.Xml.Schema;
168 private const int MaxChunkSize = 4096;
170 private static readonly LinkedList<KeyValuePair<string, int>> ports =
new LinkedList<KeyValuePair<string, int>>();
171 private static readonly Dictionary<int, EventHandlerAsync> serviceCommandByNr =
new Dictionary<int, EventHandlerAsync>();
172 private static readonly Dictionary<EventHandlerAsync, int> serviceCommandNrByCallback =
new Dictionary<EventHandlerAsync, int>();
173 private static readonly Dictionary<string, DateTime> lastUnauthorizedAccess =
new Dictionary<string, DateTime>();
174 private static readonly DateTime startTime = DateTime.Now;
176 private static byte[] emergencyMemory =
new byte[1024 * 1024];
190 private static PepClient pepClient =
null;
194 private static GeoClient geoClient =
null;
196 private static X509Certificate2 certificate =
null;
197 private static DateTime checkCertificate = DateTime.MinValue;
198 private static DateTime checkIp = DateTime.MinValue;
207 private static Scheduler scheduler =
null;
208 private readonly
static RandomNumberGenerator rnd = RandomNumberGenerator.Create();
209 private static AsyncMutex gatewayRunning =
null;
210 private static AsyncMutex startingServer =
null;
212 private static StreamWriter exceptionFile =
null;
216 private static Dictionary<string, string> defaultPageByHostName =
null;
221 private static DateTime wafTimestamp = DateTime.MinValue;
222 private static string instance;
223 private static string appDataFolder;
224 private static string runtimeFolder;
225 private static string rootFolder;
226 private static string reportsFolder;
227 private static string applicationName;
228 private static string exceptionFolder =
null;
229 private static string exceptionFileName =
null;
230 private static int nextServiceCommandNr = 128;
231 private static int beforeUninstallCommandNr = 0;
232 private static bool firstStart =
true;
233 private static bool registered =
false;
234 private static bool connected =
false;
235 private static bool immediateReconnect;
236 private static bool consoleOutput;
237 private static bool loopbackIntefaceAvailable;
238 private static bool configuring =
false;
239 private static bool exportExceptions =
false;
240 private static bool stopped =
false;
254 public static Task<bool>
Start(
bool ConsoleOutput)
256 return Start(ConsoleOutput,
true,
string.Empty);
265 public static Task<bool>
Start(
bool ConsoleOutput,
bool LoopbackIntefaceAvailable)
267 return Start(ConsoleOutput, LoopbackIntefaceAvailable,
string.Empty);
277 public static async Task<bool>
Start(
bool ConsoleOutput,
bool LoopbackIntefaceAvailable,
string InstanceName)
279 bool FirstStart = firstStart;
285 gatewayRunning =
new AsyncMutex(
false,
"Waher.IoTGateway.Running" + Suffix);
286 if (!await gatewayRunning.
WaitOne(1000))
289 startingServer =
new AsyncMutex(
false,
"Waher.IoTGateway.Starting" + Suffix);
290 if (!await startingServer.
WaitOne(1000))
294 gatewayRunning =
null;
297 startingServer =
null;
304 consoleOutput = ConsoleOutput;
305 loopbackIntefaceAvailable = LoopbackIntefaceAvailable;
307 appDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
309 if (!appDataFolder.EndsWith(
new string(Path.DirectorySeparatorChar, 1)))
310 appDataFolder += Path.DirectorySeparatorChar;
312 appDataFolder +=
"IoT Gateway";
317 if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && !Directory.Exists(appDataFolder))
318 appDataFolder = appDataFolder.Replace(
"/usr/share",
"/usr/local/share");
319 else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && !Directory.Exists(appDataFolder))
320 appDataFolder = appDataFolder.Replace(
"/usr/share",
"/var/lib");
322 appDataFolder += Path.DirectorySeparatorChar;
323 rootFolder = appDataFolder +
"Root" + Path.DirectorySeparatorChar;
324 reportsFolder = appDataFolder +
"Reports" + Path.DirectorySeparatorChar;
330 appDataFolder +
"Events" + Path.DirectorySeparatorChar +
"Event Log %YEAR%-%MONTH%-%DAY%T%HOUR%.xml",
331 appDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"EventXmlToHtml.xslt", 7));
334 Assert.UnauthorizedAccess += Assert_UnauthorizedAccess;
345 if (!Directory.Exists(rootFolder))
347 string s = Path.Combine(runtimeFolder,
"Root");
348 if (Directory.Exists(s))
350 CopyFolder(runtimeFolder, appDataFolder,
"*.config", CopyOptions.IfNewer);
351 CopyFolders(s, rootFolder, CopyOptions.IfNewer);
352 CopyFolders(Path.Combine(runtimeFolder,
"Graphics"), Path.Combine(appDataFolder,
"Graphics"), CopyOptions.IfNewer);
353 CopyFolders(Path.Combine(runtimeFolder,
"Transforms"), Path.Combine(appDataFolder,
"Transforms"), CopyOptions.IfNewer);
357 string[] ManifestFiles = Directory.GetFiles(runtimeFolder,
"*.manifest", SearchOption.TopDirectoryOnly);
358 Dictionary<string, CopyOptions> ContentOptions =
new Dictionary<string, CopyOptions>();
361 for (i = 0; i < 2; i++)
363 foreach (
string ManifestFile
in ManifestFiles)
365 string FileName = Path.GetFileName(ManifestFile);
366 bool GatewayFile = FileName.StartsWith(
"Waher.IoTGateway", StringComparison.CurrentCultureIgnoreCase);
368 if ((i == 0 && GatewayFile) || (i == 1 && !GatewayFile))
370 CheckContentFiles(ManifestFile, ContentOptions);
372 if (ManifestFile.EndsWith(
"Waher.Utility.Install.manifest"))
373 CheckInstallUtilityFiles(ManifestFile);
388 Task T = Task.Run(() =>
398 if (!File.Exists(GatewayConfigFileName))
408 bool TrustClientCertificates =
false;
409 Dictionary<int, KeyValuePair<ClientCertificates, bool>> PortSpecificMTlsSettings =
null;
410 TimeSpan CleanupTime =
new TimeSpan(4, 15, 0);
411 bool Http2Enabled =
true;
412 int Http2InitialStreamWindowSize = 2500000;
413 int Http2InitialConnectionWindowSize = 5000000;
414 int Http2MaxFrameSize = 16384;
415 int Http2MaxConcurrentStreams = 100;
416 int Http2HeaderTableSize = 8192;
417 bool Http2NoRfc7540Priorities =
false;
418 bool Http2Profiling =
false;
419 bool HttpSniffersPerEndpoint =
false;
424 foreach (XmlNode N
in Config.DocumentElement.ChildNodes)
426 if (N is XmlElement E)
430 case "ApplicationName":
431 applicationName = E.InnerText;
435 defaultPageByHostName ??=
new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
436 defaultPageByHostName[
XML.
Attribute(E,
"host")] = E.InnerText;
441 TrustClientCertificates =
XML.
Attribute(E,
"trustCertificates",
false);
443 foreach (XmlNode N2
in E.ChildNodes)
445 if (N2.LocalName ==
"Port" &&
int.TryParse(N2.InnerText, out
int PortNumber))
447 XmlElement E2 = (XmlElement)N2;
449 bool TrustClientCertificatesPort =
XML.
Attribute(E2,
"trustCertificates", TrustClientCertificates);
451 PortSpecificMTlsSettings ??=
new Dictionary<int, KeyValuePair<ClientCertificates, bool>>();
452 PortSpecificMTlsSettings[PortNumber] =
new KeyValuePair<ClientCertificates, bool>(ClientCertificatesPort, TrustClientCertificatesPort);
457 case "Http2Settings":
458 Http2Enabled =
XML.
Attribute(E,
"enabled", Http2Enabled);
459 Http2InitialStreamWindowSize =
XML.
Attribute(E,
"initialWindowSize", Http2InitialStreamWindowSize);
460 Http2InitialConnectionWindowSize =
XML.
Attribute(E,
"initialConnectionWindowSize", Http2InitialConnectionWindowSize);
461 Http2MaxFrameSize =
XML.
Attribute(E,
"maxFrameSize", Http2MaxFrameSize);
462 Http2MaxConcurrentStreams =
XML.
Attribute(E,
"maxConcurrentStreams", Http2MaxConcurrentStreams);
463 Http2HeaderTableSize =
XML.
Attribute(E,
"headerTableSize", Http2HeaderTableSize);
464 Http2NoRfc7540Priorities =
XML.
Attribute(E,
"noRfc7540Priorities", Http2NoRfc7540Priorities);
465 Http2Profiling =
XML.
Attribute(E,
"profiling", Http2Profiling);
466 HttpSniffersPerEndpoint =
XML.
Attribute(E,
"sniffersPerEndpoint",
false);
469 case "ContentEncodings":
470 foreach (XmlNode N2
in E.ChildNodes)
472 if (N2.LocalName ==
"ContentEncoding")
474 XmlElement E2 = (XmlElement)N2;
481 if (Encoding is
null)
491 case "ExportExceptions":
492 exceptionFolder = Path.Combine(appDataFolder,
XML.
Attribute(E,
"folder",
"Exceptions"));
494 if (!Directory.Exists(exceptionFolder))
495 Directory.CreateDirectory(exceptionFolder);
497 DateTime UtcNow = DateTime.UtcNow;
498 string[] ExceptionFiles = Directory.GetFiles(exceptionFolder,
"*.txt", SearchOption.TopDirectoryOnly);
499 foreach (
string ExceptionFile
in ExceptionFiles)
503 DateTime TP = File.GetLastWriteTimeUtc(ExceptionFile);
504 if ((UtcNow - TP).TotalDays > 90)
505 File.Delete(ExceptionFile);
508 string XmlFile = Path.ChangeExtension(ExceptionFile,
"xml");
509 if (!File.Exists(XmlFile))
513 File.Delete(ExceptionFile);
523 ExceptionFiles = Directory.GetFiles(exceptionFolder,
"*.xml", SearchOption.TopDirectoryOnly);
524 foreach (
string ExceptionFile
in ExceptionFiles)
528 DateTime TP = File.GetLastWriteTimeUtc(ExceptionFile);
529 if ((UtcNow - TP).TotalDays > 90)
530 File.Delete(ExceptionFile);
544 UtcNow = DateTime.UtcNow;
546 exceptionFileName = Path.Combine(exceptionFolder, UtcNow.Year.ToString(
"D4") +
"-" + UtcNow.Month.ToString(
"D2") +
"-" + UtcNow.Day.ToString(
"D2") +
547 " " + UtcNow.Hour.ToString(
"D2") +
"." + UtcNow.Minute.ToString(
"D2") +
"." + UtcNow.Second.ToString(
"D2") +
".txt");
551 if (!File.Exists(exceptionFileName))
553 exceptionFile = File.CreateText(exceptionFileName);
556 await Task.Delay(1000);
560 exceptionFile =
null;
561 await Task.Delay(1000);
564 while (exceptionFile is
null && --MaxTries > 0);
566 exportExceptions = !(exceptionFile is
null);
568 if (exportExceptions)
570 exceptionFile.Write(
"Start of export: ");
571 exceptionFile.WriteLine(DateTime.UtcNow.ToString());
573 AppDomain.CurrentDomain.FirstChanceException += (Sender, e) =>
575 if (!(exceptionFile is
null))
581 if (e.Exception is SystemException &&
582 (e.Exception is StackOverflowException ||
583 e.Exception is OutOfMemoryException ||
584 e.Exception is AccessViolationException))
586 emergencyMemory =
null;
587 GC.GetTotalMemory(
true);
593 string StackTrace = e.Exception.StackTrace;
595 if (!exportExceptions || StackTrace.Contains(
"FirstChanceExceptionEventArgs"))
598 StringBuilder sb =
new StringBuilder();
600 sb.AppendLine(
new string(
'-', 80));
603 if (!(e.Exception is
null))
604 sb.AppendLine(e.Exception.GetType().FullName);
606 sb.AppendLine(
"null");
609 sb.AppendLine(DateTime.UtcNow.ToString());
611 if (!(e.Exception is
null))
616 sb.AppendLine(e.Exception.Message);
618 sb.AppendLine(StackTrace);
623 LinkedList<Exception> Exceptions =
new LinkedList<Exception>();
624 Exceptions.AddLast(e.Exception);
626 while (!(Exceptions.First is
null))
628 Exception ex = Exceptions.First.Value;
629 Exceptions.RemoveFirst();
632 sb.AppendLine(ex.Message);
637 if (ex is AggregateException ex2)
639 foreach (Exception ex3
in ex2.InnerExceptions)
640 Exceptions.AddLast(ex3);
642 else if (!(ex.InnerException is
null))
643 Exceptions.AddLast(ex.InnerException);
648 exceptionFile.Write(sb.ToString());
649 exceptionFile.Flush();
652 if (firstChanceExceptions?.HasSniffers ??
false)
653 firstChanceExceptions.
Exception(e.Exception);
663 if (!(DatabaseProvider is
null))
664 throw new Exception(
"Database provider already initiated.");
669 DatabaseProvider =
null;
671 if (DatabaseProvider is
null)
672 throw new Exception(
"Database provider not defined. Make sure the GetDatabaseProvider event has an appropriate event handler.");
674 internalProvider = DatabaseProvider;
680 await DatabaseProvider.
Start();
688 foreach (XmlNode N2
in E.ChildNodes)
690 if (N2.LocalName ==
"Port")
692 XmlElement E2 = (XmlElement)N2;
694 if (!
string.IsNullOrEmpty(Protocol) &&
int.TryParse(E2.InnerText, out
int Port2))
695 ports.AddLast(
new KeyValuePair<string, int>(Protocol, Port2));
704 List<LoginInterval> LoginIntervals =
new List<LoginInterval>();
706 bool LastMaxInterval =
false;
708 foreach (XmlNode N2
in E.ChildNodes)
710 if (N2 is XmlElement E2 && E2.LocalName ==
"Interval")
714 Log.
Error(
"Only the last login auditor interval can be the empty 'eternal' interval.",
722 Log.
Error(
"Number of attempts must be positive when defining an interval for the LoginAuditor",
727 if (!E2.HasAttribute(
"interval"))
729 LoginIntervals.Add(
new LoginInterval(NrAttempts, TimeSpan.MaxValue));
730 LastMaxInterval =
true;
741 if (Interval <= LastInterval)
743 Log.
Error(
"Login Auditor intervals must be specified in an increasing order.",
749 LastInterval = Interval;
754 return LoginIntervals.ToArray();
758 List<RemoteEndpointIntervals> EndpointExceptions =
new List<RemoteEndpointIntervals>();
760 foreach (XmlNode N2
in E.ChildNodes)
762 if (N2 is XmlElement E2 && E2.LocalName ==
"Exception")
767 if (ExceptionIntervals.Length == 0)
770 loginAuditor =
new LoginAuditor(
"Login Auditor", LoginIntervals);
772 if (ExceptionIntervals.Length == 0)
779 if (LoginIntervals.Length == 0)
782 loginAuditor =
new LoginAuditor(
"Login Auditor", EndpointExceptions.ToArray(), LoginIntervals);
788 static IEventSink[] ParseSinks(XmlElement E, ref TimeSpan CleanupTime)
792 foreach (XmlNode N2
in E.ChildNodes)
794 if (!(N2 is XmlElement E2) || E2.NamespaceURI != E.NamespaceURI)
799 switch (E2.LocalName)
801 case "TextFileEventSink":
804 int DeleteAfterDays =
XML.
Attribute(E2,
"deleteAfterDays", 7);
809 case "XmlFileEventSink":
812 DeleteAfterDays =
XML.
Attribute(E2,
"deleteAfterDays", 7);
814 string TransformFileName =
XML.
Attribute(E2,
"transformFileName");
815 if (
string.IsNullOrEmpty(TransformFileName))
816 TransformFileName = appDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"EventXmlToHtml.xslt";
818 Sinks.Add(
new XmlFileEventSink(SinkId, FileName, TransformFileName, DeleteAfterDays));
821 case "MqttEventSink":
832 if (
string.IsNullOrEmpty(UserName))
846 case "PipeEventSink":
853 case "SocketEventSink":
862 case "SyslogEventSink":
872 if (certificate is
null)
875 Separation, SinkId));
879 Sinks.Add(
new SyslogEventSink(Host, Port, certificate, Name, applicationName,
880 Separation, SinkId));
885 Sinks.Add(
new SyslogEventSink(Host, Port,
false, Name, applicationName,
886 Separation, SinkId));
890 case "WebHookEventSink":
894 int MaxSecondsUsed =
XML.
Attribute(E2,
"maxSecondsUsed", 0);
895 int MaxSecondsUnused =
XML.
Attribute(E2,
"maxSecondsUnused", 0);
896 bool CollectOnType =
XML.
Attribute(E2,
"collectOnType",
false);
897 bool CollectOnLevel =
XML.
Attribute(E2,
"collectOnLevel",
false);
898 bool CollectOnEventId =
XML.
Attribute(E2,
"collectOnEventId",
false);
899 bool CollectOnObject =
XML.
Attribute(E2,
"collectOnObject",
false);
900 bool CollectOnActor =
XML.
Attribute(E2,
"collectOnActor",
false);
901 bool CollectOnFacility =
XML.
Attribute(E2,
"collectOnFacility",
false);
902 bool CollectOnModule =
XML.
Attribute(E2,
"collectOnModule",
false);
905 MaxSecondsUnused, CollectOnType, CollectOnLevel,
906 CollectOnEventId, CollectOnObject, CollectOnActor,
907 CollectOnFacility, CollectOnModule));
910 case "XmppEventSink":
914 Sinks.Add(
new XmppEventSink(SinkId, xmppClient, Jid,
false));
927 string EventIdsString =
XML.
Attribute(E2,
"eventIds").Trim();
930 if (
string.IsNullOrEmpty(EventIdsString))
933 EventIds = EventIdsString.Split(
',', StringSplitOptions.RemoveEmptyEntries);
935 IEventSink[] ChildSinks = ParseSinks(E2, ref CleanupTime);
937 switch (ChildSinks.Length)
943 Sinks.Add(
new EventFilter(SinkId, ChildSinks[0], Debug, Informational, Notice, Warning,
944 Error, Critical, Alert, Emergency,
null, EventIds));
948 Sinks.Add(
new EventFilter(SinkId,
new EventSinks(SinkId, ChildSinks), Debug, Informational, Notice, Warning,
949 Error, Critical, Alert, Emergency,
null, EventIds));
957 DeleteAfterDays =
XML.
Attribute(E2,
"deleteAfterDays", 7);
959 Sinks.Add(
new EventQueue(SinkId, QueueName, DeleteAfterDays, CleanupTime));
960 CleanupTime = CleanupTime.Add(TimeSpan.FromMinutes(2));
970 return Sinks.ToArray();
973 foreach (
IEventSink Sink
in ParseSinks(E, ref CleanupTime))
981 if (DatabaseProvider is
null)
984 Database.CollectionRepaired += Database_CollectionRepaired;
986 await RepairIfInproperShutdown();
989 CleanupTime = CleanupTime.Add(TimeSpan.FromMinutes(2));
1030 LinkedList<SystemConfiguration> NewConfigurations =
null;
1031 Dictionary<string, Type> SystemConfigurationTypes =
new Dictionary<string, Type>();
1032 Dictionary<string, SystemConfiguration> SystemConfigurations =
new Dictionary<string, SystemConfiguration>();
1033 bool Configured =
true;
1034 bool CheckDeferredConfigurations =
false;
1039 if (SystemConfigurationType.IsAbstract || SystemConfigurationType.IsInterface || SystemConfigurationType.IsGenericTypeDefinition)
1042 SystemConfigurationTypes[SystemConfigurationType.FullName] = SystemConfigurationType;
1049 if (SystemConfigurations.ContainsKey(s))
1054 SystemConfigurationTypes.Remove(s);
1063 NewConfigurations ??=
new LinkedList<SystemConfiguration>();
1073 NewConfigurations ??=
new LinkedList<SystemConfiguration>();
1083 foreach (KeyValuePair<string, Type> P
in SystemConfigurationTypes)
1088 SystemConfiguration.Complete =
false;
1089 SystemConfiguration.Created = DateTime.Now;
1100 NewConfigurations ??=
new LinkedList<SystemConfiguration>();
1103 CheckDeferredConfigurations =
true;
1112 NewConfigurations ??=
new LinkedList<SystemConfiguration>();
1119 catch (Exception ex)
1127 SystemConfigurations.Values.CopyTo(configurations, 0);
1128 Array.Sort(configurations, (c1, c2) => c1.
Priority - c2.Priority);
1131 LinkedList<HttpResource> SetupResources =
null;
1137 if (loopbackIntefaceAvailable)
1138 Log.
Notice(
"System needs to be configured. This is done by navigating to the loopback interface using a browser on this machine.");
1140 Log.
Notice(
"System needs to be configured. This is done by navigating to the machine using a browser on another machine in the same network.");
1144 ResourceOverride =
"/Starting.md",
1145 ResourceOverrideFilter =
"(?<!Login)[.]md(\\?[.]*)?$",
1149 webServer.
Register(
"/Starting.md", StartingMd);
1150 webServer.CustomError += WebServer_CustomError;
1152 SetupResources =
new LinkedList<HttpResource>();
1158 SetupResources.AddLast(webServer.
Register(
"/", GoToDefaultPage));
1166 Path.Combine(runtimeFolder,
"Graphics",
"Emoji1.zip"), Path.Combine(appDataFolder,
"Graphics"));
1171 MarkdownToHtmlConverter.EmojiSource = emoji1_24x24;
1172 MarkdownToHtmlConverter.RootFolder = rootFolder;
1179 if (!(webServer is
null))
1180 await Configuration.
InitSetup(webServer);
1183 bool ReloadConfigurations;
1187 ReloadConfigurations =
false;
1191 bool NeedsCleanup =
false;
1195 CurrentConfiguration = Configuration;
1197 if (!(webServer is
null))
1198 webServer.ResourceOverride = Configuration.
Resource;
1202 if (!(startingServer is
null))
1206 startingServer =
null;
1212 ReloadConfigurations =
true;
1214 NeedsCleanup =
true;
1217 DateTime StartConfig = DateTime.UtcNow;
1225 await RepairIfInproperShutdown();
1231 catch (Exception ex)
1237 if (NeedsCleanup && !(webServer is
null))
1240 if (ReloadConfigurations)
1248 if (!(webServer is
null) && SystemConfigurations.TryGetValue(s, out
SystemConfiguration OldConfiguration))
1254 if (!(webServer is
null))
1268 SystemConfigurations.Values.CopyTo(configurations, 0);
1269 Array.Sort(configurations, (c1, c2) => c1.Priority - c2.Priority);
1274 if (DateTime.UtcNow.Subtract(StartConfig).TotalSeconds > 2)
1278 while (ReloadConfigurations);
1280 configuring =
false;
1283 if (!(webServer is
null))
1285 webServer.ResourceOverride =
"/Starting.md";
1288 if (!(SetupResources is
null))
1299 if (!(certificate is
null))
1307 if (!(certificate is
null))
1315 webServer.
Register(
"/Starting.md", StartingMd);
1316 webServer.ResourceOverride =
"/Starting.md";
1317 webServer.LoginAuditor = loginAuditor;
1319 webServer.CustomError += WebServer_CustomError;
1325 await Configuration.
InitSetup(webServer);
1329 await RepairIfInproperShutdown();
1333 await Configuration.
InitSetup(webServer);
1335 catch (Exception ex)
1343 if (CheckDeferredConfigurations)
1351 catch (Exception ex)
1359 Http2InitialConnectionWindowSize, Http2MaxFrameSize, Http2MaxConcurrentStreams,
1360 Http2HeaderTableSize,
false, Http2NoRfc7540Priorities, Http2Profiling,
true);
1362 webServer.ConnectionProfiled += WebServer_ConnectionProfiled;
1363 webServer.OnTryGetLocalResourceFileName += (
string Resource,
string Host, out
string FileName) =>
1370 InternetContent.LocalDomainCheck += InternetContent_LocalDomainCheck;
1372 await WriteWebServerOpenPorts();
1373 webServer.OnNetworkChanged += async (Sender, e) =>
1377 await WriteWebServerOpenPorts();
1379 catch (Exception ex)
1396 JwtFactory.ValidateAudience += (sender, e) =>
1398 foreach (
string Audience
in e.Audience)
1402 e.Acceptable =
true;
1413 LoginMasterFileName = Path.Combine(rootFolder,
"MasterOAuth.md")
1432 webServer.
Register(httpxProxy =
new HttpxProxy(
"/HttpxProxy", xmppClient, MaxChunkSize));
1433 webServer.
Register(
"/", GoToDefaultPage);
1442 webServer.
Register(
new WebResources.Ping());
1450 mcpSniffers =
new XmlFileSnifferSet(appDataFolder +
"MCP" + Path.DirectorySeparatorChar +
1451 "Sniffers",
"MCP Log %YEAR%-%MONTH%-%DAY%T%HOUR%.xml", TimeSpan.FromHours(8),
1452 appDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"SnifferXmlToHtml.xslt",
1455 webServer.
Register(
new Mcp.Content.InternetContentMcpServer(
"/MCP/Content",
Icons,
null, mcpSniffers));
1456 webServer.
Register(
new Mcp.Events.EventLogMcpServer(
"/MCP/EventLog",
Icons,
null, mcpSniffers));
1457 webServer.
Register(
new Mcp.Files.FileStorageMcpServer(
"/MCP/Files",
1458 Path.Combine(appDataFolder,
"MCP",
"Files"),
Icons,
null, mcpSniffers));
1460 if (emoji1_24x24 is
null)
1463 Path.Combine(runtimeFolder,
"Graphics",
"Emoji1.zip"), Path.Combine(appDataFolder,
"Graphics"));
1466 MarkdownToHtmlConverter.EmojiSource = emoji1_24x24;
1467 MarkdownToHtmlConverter.RootFolder = rootFolder;
1472 XmlElement DefaultHttpResponseHeaders = Config.DocumentElement[
"DefaultHttpResponseHeaders"];
1473 if (!(DefaultHttpResponseHeaders is
null))
1475 foreach (XmlNode N
in DefaultHttpResponseHeaders.ChildNodes)
1477 if (N is XmlElement E && E.LocalName ==
"DefaultHttpResponseHeader")
1487 XmlElement FileFolders = Config.DocumentElement[
"FileFolders"];
1488 if (!(FileFolders is
null))
1490 foreach (XmlNode N
in FileFolders.ChildNodes)
1492 if (N is XmlElement E && E.LocalName ==
"FileFolder")
1500 foreach (XmlNode N2
in E.ChildNodes)
1502 if (N2 is XmlElement E2 && E2.LocalName ==
"DefaultHttpResponseHeader")
1507 FileFolder.AddDefaultResponseHeader(HeaderKey, HeaderValue);
1514 XmlElement VanityResources = Config.DocumentElement[
"VanityResources"];
1515 if (!(VanityResources is
null))
1517 foreach (XmlNode N
in VanityResources.ChildNodes)
1519 if (N is XmlElement E && E.LocalName ==
"VanityResource")
1528 catch (Exception ex)
1530 Log.
Error(
"Unable to register vanity resource: " + ex.Message,
1531 new KeyValuePair<string, object>(
"RegEx", RegEx),
1532 new KeyValuePair<string, object>(
"Url", Url));
1538 XmlElement Redirections = Config.DocumentElement[
"Redirections"];
1539 if (!(Redirections is
null))
1541 foreach (XmlNode N
in Redirections.ChildNodes)
1543 if (N is XmlElement E && E.LocalName ==
"Redirection")
1547 bool IncludeSubPaths =
XML.
Attribute(E,
"includeSubPaths",
false);
1554 catch (Exception ex)
1556 Log.
Error(
"Unable to register redirection: " + ex.Message,
1557 new KeyValuePair<string, object>(
"Resource", Resource),
1558 new KeyValuePair<string, object>(
"Location", Location),
1559 new KeyValuePair<string, object>(
"IncludeSubPaths", IncludeSubPaths),
1560 new KeyValuePair<string, object>(
"Permanent", Permanent));
1566 XmlElement ReverseProxy = Config.DocumentElement[
"ReverseProxy"];
1567 if (!(ReverseProxy is
null))
1569 foreach (XmlNode N
in ReverseProxy.ChildNodes)
1571 if (!(N is XmlElement E))
1574 switch (E.LocalName)
1576 case "ProxyResource":
1577 string LocalResource =
XML.
Attribute(E,
"localResource");
1578 string RemoteDomain =
XML.
Attribute(E,
"remoteDomain");
1579 string RemoteFolder =
XML.
Attribute(E,
"remoteFolder");
1582 bool UseSession =
XML.
Attribute(E,
"useSession",
false);
1591 TimeSpan.FromMilliseconds(TimeoutMs), UseSession));
1600 catch (Exception ex)
1602 Log.
Error(
"Unable to register reverse proxy: " + ex.Message,
1603 new KeyValuePair<string, object>(
"LocalResource", LocalResource),
1604 new KeyValuePair<string, object>(
"RemoteDomain", RemoteDomain),
1605 new KeyValuePair<string, object>(
"Encrypted", Encrypted),
1606 new KeyValuePair<string, object>(
"RemotePort", RemotePort),
1607 new KeyValuePair<string, object>(
"RemoteFolder", RemoteFolder),
1608 new KeyValuePair<string, object>(
"UseSession", UseSession),
1609 new KeyValuePair<string, object>(
"TimeoutMs", TimeoutMs));
1628 "/", RemoteDomain, RemotePort, RemoteFolder, Encrypted,
1629 TimeSpan.FromMilliseconds(TimeoutMs), UseSession));
1634 "/", RemoteDomain, RemotePort, RemoteFolder, Encrypted,
1635 TimeSpan.FromMilliseconds(TimeoutMs), UseSession,
1639 catch (Exception ex)
1641 Log.
Error(
"Unable to register reverse proxy: " + ex.Message,
1642 new KeyValuePair<string, object>(
"LocalDomain", LocalDomain),
1643 new KeyValuePair<string, object>(
"RemoteDomain", RemoteDomain),
1644 new KeyValuePair<string, object>(
"Encrypted", Encrypted),
1645 new KeyValuePair<string, object>(
"RemotePort", RemotePort),
1646 new KeyValuePair<string, object>(
"RemoteFolder", RemoteFolder),
1647 new KeyValuePair<string, object>(
"UseSession", UseSession),
1648 new KeyValuePair<string, object>(
"TimeoutMs", TimeoutMs));
1655 await LoadScriptResources();
1657 httpxServer =
new HttpxServer(xmppClient, webServer, MaxChunkSize);
1661 httpxProxy.IbbClient = ibbClient;
1662 httpxServer.IbbClient = ibbClient;
1664 httpxProxy.Socks5Proxy = socksProxy;
1665 httpxServer.Socks5Proxy = socksProxy;
1667 if (xmppCredentials.
Sniffer || HttpSniffersPerEndpoint)
1671 Sniffer =
new XmlFileSniffer(appDataFolder +
"HTTP" + Path.DirectorySeparatorChar +
1672 "HTTP Log %YEAR%-%MONTH%-%DAY%T%HOUR%.xml",
1673 appDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"SnifferXmlToHtml.xslt",
1675 webServer.
Add(Sniffer);
1677 if (HttpSniffersPerEndpoint)
1680 xmlFileSnifferCache.Removed += XmlFileSnifferCache_Removed;
1682 webServer.GetCustomSniffers += GetCustomHttpSniffers;
1693 catch (Exception ex)
1717 await RepairIfInproperShutdown();
1733 catch (Exception ex)
1748 avatarClient =
new AvatarClient(xmppClient, pepClient);
1767 concentratorServer.SensorServer.AssignAuthority += SensorServer_AssignAuthority;
1769 ProvisionedMeteringNode.QrCodeUrlRequested += ProvisionedMeteringNode_QrCodeUrlRequested;
1772 DeleteOldDataSourceEvents(
null);
1776 string BinaryFolder = AppDomain.CurrentDomain.BaseDirectory;
1777 string[] LanguageFiles = Directory.GetFiles(BinaryFolder,
"*.lng", SearchOption.AllDirectories);
1780 if (LanguageFiles.Length > 0)
1784 foreach (
string LanguageFile
in LanguageFiles)
1790 FileName = LanguageFile;
1791 if (FileName.StartsWith(BinaryFolder))
1792 FileName = FileName[BinaryFolder.Length..];
1794 DateTime LastWriteTime = File.GetLastWriteTimeUtc(LanguageFile);
1797 if (LastWriteTime > LastImportedTime)
1806 using (XmlReader r =
new XmlNodeReader(Doc))
1814 catch (XmlException ex)
1819 catch (Exception ex)
1826 foreach (
string UnhandledException
in Directory.GetFiles(appDataFolder,
"UnhandledException*.txt", SearchOption.TopDirectoryOnly))
1831 File.Delete(UnhandledException);
1833 StringBuilder sb =
new StringBuilder();
1835 sb.AppendLine(
"Unhandled Exception");
1836 sb.AppendLine(
"=======================");
1838 sb.AppendLine(
"```");
1840 sb.AppendLine(
"```");
1844 catch (Exception ex)
1856 StringBuilder sb =
new StringBuilder();
1858 sb.AppendLine(
"Unable to start all modules. The following modules failed to load:");
1861 foreach (
IModule Module
in FailedModules)
1864 sb.Append(Module.GetType().FullName);
1872 await ProcessServiceConfigurations(
false);
1874 if (!(NewConfigurations is
null))
1878 StringBuilder sb =
new StringBuilder();
1880 sb.AppendLine(
"New System Configuration");
1881 sb.AppendLine(
"=============================");
1883 sb.AppendLine(
"A new system configuration is available.");
1884 sb.AppendLine(
"It has been set to simplified configuration, to not stop processing.");
1885 sb.AppendLine(
"You should review the configuration however, as soon as possible.");
1887 sb.Append(
"[Click here to review the new system configuration](http");
1895 sb.AppendLine(
").");
1901 catch (Exception ex)
1907 if (!(webServer is
null))
1909 webServer.ResourceOverride =
null;
1910 webServer.ResourceOverrideFilter =
null;
1912 if (webServer.
GetPorts(
true,
true).Length == 0)
1913 ScheduleEvent(AttemptReopenPorts, DateTime.Now.AddMinutes(1),
null);
1916 if (!(startingServer is
null))
1920 startingServer =
null;
1927 catch (Exception ex)
1931 if (!(startingServer is
null))
1935 startingServer =
null;
1938 if (!(gatewayRunning is
null))
1942 gatewayRunning =
null;
1945 ExceptionDispatchInfo.Capture(ex).Throw();
1957 if (File.Exists(WafFile))
1961 DateTime LastUpdated = File.GetLastWriteTimeUtc(WafFile);
1963 if (LastUpdated > wafTimestamp)
1968 webServer.WebApplicationFirewall = Waf;
1969 Log.
Informational(
"Web Application Firewall configuration loaded.", WafFile);
1974 Log.
Informational(
"Web Application Firewall configuration reloaded due to file change.", WafFile);
1977 wafTimestamp = LastUpdated;
1980 catch (Exception ex)
1987 private static void AttemptReopenPorts(
object _)
1991 if (webServer.
GetPorts(
true,
true).Length == 0)
1992 ScheduleEvent(AttemptReopenPorts, DateTime.Now.AddMinutes(1),
null);
1997 int i, c = e.
Sniffers?.Length ?? 0;
1999 for (i = 0; i < c; i++)
2005 if (!(xmlFileSnifferCache?.TryGetValue(RemoteIp, out
XmlFileSniffer Cached) ??
false))
2007 Cached =
new XmlFileSniffer(appDataFolder +
"HTTP" + Path.DirectorySeparatorChar +
2008 RemoteIp.Replace(
':',
'_') + Path.DirectorySeparatorChar +
2009 "HTTP Log %YEAR%-%MONTH%-%DAY%T%HOUR%.xml",
2010 appDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"SnifferXmlToHtml.xslt",
2013 Cached.OnBeforeWrite += (sender, e2) =>
2015 xmlFileSnifferCache?.
Ping(RemoteIp);
2018 xmlFileSnifferCache?.
Add(RemoteIp, Cached);
2025 return Task.CompletedTask;
2030 await e.
Value.DisposeAsync();
2033 private static Task ProvisionedMeteringNode_QrCodeUrlRequested(
object Sender,
GetQrCodeUrlEventArgs e)
2035 StringBuilder Link =
new StringBuilder();
2036 Link.Append(
"https://");
2043 Link.Append(
"/QR/");
2044 Link.Append(WebUtility.UrlEncode(e.
Text));
2045 Link.Append(
"?w=400&h=400&q=2");
2047 e.Url = Link.ToString();
2049 return Task.CompletedTask;
2054 if (
string.IsNullOrEmpty(webServer?.ResourceOverride))
2065 StringBuilder sb =
new StringBuilder();
2067 sb.AppendLine(
"Title: Starting");
2068 sb.AppendLine(
"Description: The starting page will be displayed while the service is being started.");
2069 sb.AppendLine(
"Cache-Control: max-age=0, no-cache, no-store");
2070 sb.AppendLine(
"Refresh: 2");
2072 sb.AppendLine(
"============================================================================================================================================");
2074 sb.AppendLine(
"Starting Service");
2075 sb.AppendLine(
"====================");
2077 sb.AppendLine(
"Please wait while the service is being started. This page will update automatically.");
2079 Markdown = sb.ToString();
2087 Response.ContentType =
"text/html; charset=utf-8";
2088 await Response.
Write(
true,
System.Text.Encoding.UTF8.GetBytes(Html));
2100 private class ModuleStartOrder : IComparer<IModule>
2106 int c1 = this.ModuleCategory(x);
2107 int c2 = this.ModuleCategory(y);
2113 return this.dependencyOrder.Compare(x, y);
2116 private int ModuleCategory(
IModule x)
2118 if (x is Persistence.LifeCycle.DatabaseModule)
2120 else if (x is Runtime.Transactions.TransactionModule)
2123 return int.MaxValue;
2129 private static async Task RepairIfInproperShutdown()
2132 Type ProviderType = DatabaseProvider.GetType();
2133 PropertyInfo AutoRepairReportFolder = ProviderType.GetProperty(
"AutoRepairReportFolder");
2134 AutoRepairReportFolder?.SetValue(DatabaseProvider, Path.Combine(
AppDataFolder,
"Backup"));
2136 MethodInfo MI = ProviderType.GetMethod(
"RepairIfInproperShutdown",
new Type[] { typeof(
string) });
2140 Task T = MI.Invoke(DatabaseProvider,
new object[] {
AppDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"DbStatXmlToHtml.xslt" }) as Task;
2142 if (T is Task<
string[]> StringArrayTask)
2143 DatabaseConfiguration.RepairedCollections = await StringArrayTask;
2144 else if (!(T is
null))
2149 private static async Task WriteWebServerOpenPorts()
2151 StringBuilder sb =
new StringBuilder();
2153 foreach (
int Port
in webServer.
OpenPorts)
2154 sb.AppendLine(Port.ToString());
2160 catch (Exception ex)
2168 DateTime Now = DateTime.Now;
2169 string Key = e.
Trace.ToString();
2171 lock (lastUnauthorizedAccess)
2173 if (lastUnauthorizedAccess.TryGetValue(Key, out DateTime TP) && (Now - TP).TotalHours < 1)
2176 lastUnauthorizedAccess[Key] = Now;
2179 StringBuilder Markdown =
new StringBuilder();
2181 Markdown.AppendLine(
"Unauthorized access detected and prevented.");
2182 Markdown.AppendLine(
"===============================================");
2183 Markdown.AppendLine();
2184 Markdown.AppendLine(
"| Details ||");
2185 Markdown.AppendLine(
"|:---|:---|");
2186 Markdown.Append(
"| Method | `");
2187 Markdown.Append(e.
Method.Name);
2188 Markdown.AppendLine(
"` |");
2189 Markdown.Append(
"| Type | `");
2190 Markdown.Append(e.
Type.FullName);
2191 Markdown.AppendLine(
"` |");
2192 Markdown.Append(
"| Assembly | `");
2193 Markdown.Append(e.
Assembly.GetName().Name);
2194 Markdown.AppendLine(
"` |");
2195 Markdown.Append(
"| Date | ");
2197 Markdown.AppendLine(
" |");
2198 Markdown.Append(
"| Time | ");
2200 Markdown.AppendLine(
" |");
2201 Markdown.AppendLine();
2202 Markdown.AppendLine(
"Stack Trace:");
2203 Markdown.AppendLine();
2204 Markdown.AppendLine(
"```");
2206 Markdown.AppendLine(
"```");
2211 private static void CheckContentFiles(
string ManifestFileName, Dictionary<string, CopyOptions> ContentOptions)
2217 if (!(Doc.DocumentElement is
null) &&
2218 Doc.DocumentElement.LocalName ==
"Module" &&
2219 Doc.DocumentElement.NamespaceURI ==
"http://waher.se/Schema/ModuleManifest.xsd")
2221 CheckContentFiles(Doc.DocumentElement, runtimeFolder, runtimeFolder, appDataFolder, ContentOptions);
2224 catch (Exception ex)
2230 private enum CopyOptions
2237 private static void CheckContentFiles(XmlElement Element,
string RuntimeFolder,
string RuntimeSubfolder,
string AppDataSubFolder,
2238 Dictionary<string, CopyOptions> ContentOptions)
2240 bool AppDataFolderChecked =
false;
2242 foreach (XmlNode N
in Element.ChildNodes)
2244 if (N is XmlElement E)
2246 switch (E.LocalName)
2250 CheckContentFiles(E,
RuntimeFolder, Path.Combine(RuntimeSubfolder, Name), Path.Combine(AppDataSubFolder, Name),
2256 CopyOptions CopyOptions =
XML.
Attribute(E,
"copy", CopyOptions.IfNewer);
2258 string s = Path.Combine(RuntimeSubfolder, Name);
2259 if (!File.Exists(s))
2262 if (!File.Exists(s))
2266 if (!AppDataFolderChecked)
2268 AppDataFolderChecked =
true;
2270 if (!Directory.Exists(AppDataSubFolder))
2271 Directory.CreateDirectory(AppDataSubFolder);
2274 string s2 = Path.Combine(AppDataSubFolder, Name);
2276 if (CopyOptions == CopyOptions.Always || !File.Exists(s2))
2278 File.Copy(s, s2,
true);
2279 ContentOptions[s2] = CopyOptions;
2283 DateTime TP = File.GetLastWriteTimeUtc(s);
2284 DateTime TP2 = File.GetLastWriteTimeUtc(s2);
2287 (!ContentOptions.TryGetValue(s2, out CopyOptions CopyOptions2) ||
2288 CopyOptions2 != CopyOptions.Always))
2290 File.Copy(s, s2,
true);
2291 ContentOptions[s2] = CopyOptions;
2300 private static void CheckInstallUtilityFiles(
string ManifestFileName)
2306 if (!(Doc.DocumentElement is
null) &&
2307 Doc.DocumentElement.LocalName ==
"Module" &&
2308 Doc.DocumentElement.NamespaceURI ==
"http://waher.se/Schema/ModuleManifest.xsd")
2310 string InstallUtilityFolder = Path.Combine(runtimeFolder,
"InstallUtility");
2311 bool NoticeLogged =
false;
2313 if (!Directory.Exists(InstallUtilityFolder))
2314 Directory.CreateDirectory(InstallUtilityFolder);
2316 foreach (XmlNode N
in Doc.DocumentElement.ChildNodes)
2318 if (N is XmlElement E)
2320 switch (E.LocalName)
2324 CopyOptions CopyOptions =
XML.
Attribute(E,
"copy", CopyOptions.IfNewer);
2326 string s = Path.Combine(runtimeFolder, Name);
2327 if (!File.Exists(s))
2330 string s2 = Path.Combine(InstallUtilityFolder, Name);
2332 if (CopyOptions == CopyOptions.IfNewer && File.Exists(s2))
2334 DateTime TP = File.GetLastWriteTimeUtc(s);
2335 DateTime TP2 = File.GetLastWriteTimeUtc(s2);
2343 NoticeLogged =
true;
2344 Log.
Notice(
"Copying Installation Utility executable files to InstallUtility subfolder.");
2347 File.Copy(s, s2,
true);
2354 catch (Exception ex)
2360 internal static bool ConsoleOutput => consoleOutput;
2366 xmppClient.OnValidateSender += XmppClient_OnValidateSender;
2376 xmppClient.
Add(Sniffer);
2379 Sniffer =
new XmlFileSniffer(appDataFolder +
"XMPP" + Path.DirectorySeparatorChar +
2380 "XMPP Log %YEAR%-%MONTH%-%DAY%T%HOUR%.xml",
2381 appDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"SnifferXmlToHtml.xslt",
2383 xmppClient.
Add(Sniffer);
2386 if (!
string.IsNullOrEmpty(xmppCredentials.
Events))
2388 string s = xmppCredentials.
Events;
2389 int i = s.IndexOf(
'.');
2404 thingRegistryClient.Claimed += ThingRegistryClient_Claimed;
2405 thingRegistryClient.Disowned += ThingRegistryClient_Disowned;
2406 thingRegistryClient.Removed += ThingRegistryClient_Removed;
2409 if (!
string.IsNullOrEmpty(xmppCredentials.
Provisioning))
2412 provisioningClient =
null;
2414 scheduler.
Add(DateTime.Now.AddMinutes(1), CheckConnection,
null);
2416 xmppClient.OnStateChanged += XmppClient_OnStateChanged;
2418 ibbClient =
new Networking.XMPP.InBandBytestreams.
IbbClient(xmppClient, MaxChunkSize);
2435 await contractsClient.
LoadKeys(
true);
2438 contractsClient =
null;
2447 string PackagesFolder = Path.Combine(appDataFolder,
"Packages");
2448 if (!Directory.Exists(PackagesFolder))
2449 Directory.CreateDirectory(PackagesFolder);
2454 softwareUpdateClient =
null;
2462 mailClient.MailReceived += MailClient_MailReceived;
2469 domain = Configuration.
Domain;
2472 for (i = 0; i < c; i++)
2479 await Configuration.CheckDynamicIp();
2483 if (checkIp > DateTime.MinValue)
2485 scheduler.
Remove(checkIp);
2486 checkIp = DateTime.MinValue;
2489 checkIp = scheduler.
Add(DateTime.Now.AddSeconds(Configuration.
DynDnsInterval), CheckIp, Configuration);
2495 await UpdateCertificate(Configuration);
2497 if (checkCertificate > DateTime.MinValue)
2499 scheduler.
Remove(checkCertificate);
2500 checkCertificate = DateTime.MinValue;
2503 checkCertificate = scheduler.
Add(DateTime.Now.AddHours(0.5 +
NextDouble()), CheckCertificate, Configuration);
2534 if (!(Configuration.
PFX is
null))
2535 certificate =
new X509Certificate2(Configuration.
PFX, Configuration.
Password);
2538 RSACryptoServiceProvider RSA =
new RSACryptoServiceProvider();
2541 certificate =
new X509Certificate2(Configuration.
Certificate)
2554 TlsCertificateEndpoint.UpdateCertificate(
Certificate);
2559 catch (Exception ex)
2566 catch (Exception ex)
2574 private static async
void CheckCertificate(
object P)
2577 DateTime Now = DateTime.Now;
2581 if (Now.AddDays(50) >= certificate.NotAfter)
2585 if (await Configuration.CreateCertificate())
2588 if (!await UpdateCertificate(Configuration))
2589 Log.
Error(
"Unable to update gatetway with new certificate.");
2593 int DaysLeft = (int)Math.Round((certificate.NotAfter - Now.Date).TotalDays);
2596 Log.
Emergency(
"Unable to generate new certificate.", domain);
2597 else if (DaysLeft < 5)
2598 Log.
Alert(
"Unable to generate new certificate.", domain);
2599 else if (DaysLeft < 10)
2600 Log.
Critical(
"Unable to generate new certificate.", domain);
2601 else if (DaysLeft < 20)
2602 Log.
Error(
"Unable to generate new certificate.", domain);
2604 Log.
Warning(
"Unable to generate new certificate.", domain);
2608 catch (Exception ex)
2610 int DaysLeft = (int)Math.Round((certificate.NotAfter - Now.Date).TotalDays);
2614 else if (DaysLeft < 5)
2621 checkCertificate = scheduler.
Add(DateTime.Now.AddDays(0.5 +
NextDouble()), CheckCertificate, Configuration);
2630 private static async
void CheckIp(
object P)
2636 await Configuration.CheckDynamicIp();
2638 catch (Exception ex)
2644 checkIp = scheduler.
Add(DateTime.Now.AddSeconds(Configuration.
DynDnsInterval), CheckIp, Configuration);
2648 private static async
void DeleteOldDataSourceEvents(
object P)
2652 TimeSpan Limit = TimeSpan.FromDays(7);
2660 catch (Exception ex)
2666 ScheduleEvent(DeleteOldDataSourceEvents, DateTime.Today.AddDays(1).AddHours(4),
null);
2678 public static event EventHandlerAsync<GetDataSourcesEventArgs>
GetDataSources =
null;
2688 private static void Initialize()
2690 string Folder = Assembly.GetExecutingAssembly().Location;
2691 if (
string.IsNullOrEmpty(Folder))
2692 Folder = AppDomain.CurrentDomain.BaseDirectory;
2694 runtimeFolder = Path.GetDirectoryName(Folder);
2696 Directory.SetCurrentDirectory(runtimeFolder);
2700 FileName = Path.GetFileName(FileName).ToLower();
2701 if (FileName.StartsWith(
"api-ms-win-") ||
2702 FileName.StartsWith(
"system.") ||
2703 FileName.StartsWith(
"microsoft.") ||
2704 FileName.StartsWith(
"windows.") ||
2705 FileName.StartsWith(
"waher.client.") ||
2706 FileName.StartsWith(
"waher.utility.") ||
2707 FileName.StartsWith(
"mscordaccore_x86_x86_") ||
2708 FileName.StartsWith(
"sos_x86_x86_"))
2715 case "clrcompression.dll":
2716 case "clretwrc.dll":
2721 case "hostpolicy.dll":
2724 case "libglesv2.dll":
2725 case "libskiasharp.dll":
2727 case "mongocrypt.dll":
2728 case "mscordaccore.dll":
2729 case "mscordbi.dll":
2730 case "mscorlib.dll":
2731 case "mscorrc.debug.dll":
2734 case "netstandard.dll":
2735 case "snappy32.dll":
2736 case "snappy64.dll":
2737 case "snappier.dll":
2740 case "sos.netcore.dll":
2741 case "ucrtbase.dll":
2742 case "windowsbase.dll":
2743 case "waher.persistence.fileslw.dll":
2744 case "waher.persistence.serialization.dll":
2745 case "zstdsharp.dll":
2753 private static bool CopyFile(
string From,
string To, CopyOptions CopyOptions)
2758 if (!File.Exists(From))
2761 if (CopyOptions != CopyOptions.Always && File.Exists(To))
2763 if (CopyOptions == CopyOptions.IfNotExists)
2765 else if (CopyOptions == CopyOptions.IfNewer)
2767 DateTime ToTP = File.GetLastWriteTimeUtc(To);
2768 DateTime FromTP = File.GetLastWriteTimeUtc(From);
2775 File.Copy(From, To,
true);
2780 private static void CopyFolder(
string From,
string To,
string Mask, CopyOptions CopyOptions)
2782 if (Directory.Exists(From))
2784 if (!Directory.Exists(To))
2785 Directory.CreateDirectory(To);
2787 string[]
Files = Directory.GetFiles(From, Mask, SearchOption.TopDirectoryOnly);
2789 foreach (
string File
in Files)
2791 string FileName = Path.GetFileName(File);
2792 CopyFile(File, Path.Combine(To, FileName), CopyOptions);
2797 private static void CopyFolders(
string From,
string To, CopyOptions CopyOptions)
2799 if (Directory.Exists(From))
2801 CopyFolder(From, To,
"*.*", CopyOptions);
2803 string[] Folders = Directory.GetDirectories(From,
"*.*", SearchOption.TopDirectoryOnly);
2805 foreach (
string Folder
in Folders)
2807 string FolderName = Path.GetFileName(Folder);
2808 CopyFolders(Folder, Path.Combine(To, FolderName), CopyOptions);
2820 Log.
Notice(
"Request to stop Gateway, but Gateway already stopped.");
2826 bool StopInternalProvider = !(internalProvider is
null) &&
Database.
Provider != internalProvider;
2838 catch (Exception ex)
2847 catch (Exception ex)
2854 await Script.Threading.Functions.Background.TerminateTasks(10000);
2856 catch (Exception ex)
2865 catch (Exception ex)
2870 Database.CollectionRepaired -= Database_CollectionRepaired;
2872 if (StopInternalProvider)
2876 await internalProvider.
Stop();
2878 catch (Exception ex)
2884 if (!(startingServer is
null))
2888 startingServer =
null;
2891 if (!(gatewayRunning is
null))
2895 gatewayRunning =
null;
2898 if (!(configurations is
null))
2906 else if (Configuration is IDisposable D)
2909 catch (Exception ex)
2915 configurations =
null;
2928 provisioningClient =
null;
2931 thingRegistryClient =
null;
2934 concentratorServer =
null;
2937 avatarClient =
null;
2940 sensorClient =
null;
2943 controlClient =
null;
2946 concentratorClient =
null;
2949 synchronizationClient =
null;
2961 contractsClient =
null;
2964 softwareUpdateClient =
null;
2969 if (!(xmppClient is
null))
2975 catch (Exception ex)
2984 coapEndpoint =
null;
2986 InternetContent.LocalDomainCheck -= InternetContent_LocalDomainCheck;
2988 if (!(webServer is
null))
2994 catch (Exception ex)
3004 xmlFileSnifferCache =
null;
3014 if (exportExceptions)
3016 lock (exceptionFile)
3018 exportExceptions =
false;
3019 firstChanceExceptions =
null;
3021 exceptionFile.WriteLine(
new string(
'-', 80));
3022 exceptionFile.Write(
"End of export: ");
3023 exceptionFile.WriteLine(DateTime.Now.ToString());
3025 exceptionFile.Flush();
3026 exceptionFile.Close();
3029 exceptionFile =
null;
3034 Persistence.LifeCycle.DatabaseModule.Flush().Wait(60000);
3036 if (StopInternalProvider)
3037 internalProvider.
Flush().Wait(60000);
3047 if (!(Object is
null))
3053 catch (Exception ex)
3066 if (!(Object is
null))
3072 catch (Exception ex)
3092 public static bool HasDomain
3106 case "example2.com":
3107 case "example3.com":
3109 case "example2.org":
3110 case "example3.org":
3127 public static string InstanceName => instance;
3157 public static string ApplicationName
3159 get => applicationName;
3160 internal set => applicationName = value;
3171 public static bool Configuring => configuring;
3181 public static string ConfigFilePath => Path.Combine(appDataFolder, GatewayConfigLocalFileName);
3200 List<int> Result =
new List<int>();
3202 foreach (KeyValuePair<string, int> P
in ports)
3204 if (P.Key == Protocol)
3205 Result.Add(P.Value);
3208 return Result.ToArray();
3217 SortedDictionary<string, bool> Protocols =
new SortedDictionary<string, bool>();
3219 foreach (KeyValuePair<string, int> P
in ports)
3220 Protocols[P.Key] =
true;
3222 string[] Result =
new string[Protocols.Count];
3223 Protocols.Keys.CopyTo(Result, 0);
3235 EventHandlerAsync h = OnTerminate ??
throw new InvalidOperationException(
"No OnTerminate event handler set.");
3236 return h.Raise(instance, EventArgs.Empty,
false);
3253 return TryGetDefaultPage(Request.
Header.
Host?.
Value ??
string.Empty, out DefaultPage);
3264 if (defaultPageByHostName.TryGetValue(Host, out DefaultPage))
3267 if (Host.StartsWith(
"www.", StringComparison.CurrentCultureIgnoreCase) && defaultPageByHostName.TryGetValue(Host[4..], out DefaultPage))
3270 if (defaultPageByHostName.TryGetValue(
string.Empty, out DefaultPage))
3273 DefaultPage =
string.Empty;
3277 internal static void SetDefaultPages(params KeyValuePair<string, string>[] DefaultPages)
3279 Dictionary<string, string> List =
new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
3281 foreach (KeyValuePair<string, string> P
in DefaultPages)
3282 List[P.Key] = P.Value;
3284 defaultPageByHostName = List;
3296 if (
string.IsNullOrEmpty(BareJid) ||
3297 (!(xmppClient is
null) &&
3298 (BareJid == xmppClient.
Domain.ToLower() ||
3299 BareJid == xmppClient.
BareJID.ToLower())))
3303 else if (BareJid.IndexOf(
'@') > 0 &&
3304 (xmppClient is
null ||
3310 foreach (XmlNode N
in e.
Stanza.ChildNodes)
3313 return Task.CompletedTask;
3319 return Task.CompletedTask;
3322 private static async
void CheckConnection(
object State)
3328 scheduler.
Add(DateTime.Now.AddMinutes(1), CheckConnection,
null);
3331 if (State2.HasValue &&
3333 !(xmppClient is
null))
3339 catch (Exception ex)
3345 await CheckBackup();
3347 await MinuteTick.Raise(
null, EventArgs.Empty);
3350 catch (Exception ex)
3361 private static async Task XmppClient_OnStateChanged(
object _,
XmppState NewState)
3368 MarkdownToHtmlConverter.BareJID = xmppClient.
BareJID;
3370 if (!registered && !(thingRegistryClient is
null))
3372 _ = Task.Run(async () =>
3378 catch (Exception ex)
3390 immediateReconnect = connected;
3393 if (immediateReconnect &&
3394 !(xmppClient is
null) &&
3433 Log.
Debug(
"No local login: No session.");
3440 if (
string.IsNullOrEmpty(From = v.ValueObject as
string))
3447 v.ValueObject is
IUser &&
3448 !
string.IsNullOrEmpty(From) &&
3449 !From.Contains(
"Login"))
3460 LoginAuditor.
Success(
"User logged in by default, since XMPP not configued and loopback interface not available.",
3463 await
Login.DoLogin(Request, From);
3471 if (i < 0 || !
int.TryParse(
RemoteEndpoint[(i + 1)..], out
int Port))
3479 if (!IPAddress.TryParse(
RemoteEndpoint[..i], out IPAddress Address))
3487 if (!IsLocalCall(Address, Request, DoLog))
3500 await
Login.DoLogin(Request, From);
3511 switch (Environment.OSVersion.Platform)
3513 case PlatformID.Win32S:
3514 case PlatformID.Win32Windows:
3515 case PlatformID.Win32NT:
3516 case PlatformID.WinCE:
3517 FileName =
"netstat.exe";
3518 Arguments =
"-a -n -o";
3519 WaitForExit =
false;
3524 case PlatformID.Unix:
3525 case PlatformID.MacOSX:
3526 FileName =
"netstat";
3527 Arguments =
"-anv -p tcp";
3535 Log.
Debug(
"No local login: Unsupported operating system: " + Environment.OSVersion.Platform.ToString());
3540 using Process Proc =
new Process();
3541 ProcessStartInfo StartInfo =
new ProcessStartInfo()
3543 FileName = FileName,
3544 Arguments = Arguments,
3545 WindowStyle = ProcessWindowStyle.Hidden,
3546 UseShellExecute =
false,
3547 RedirectStandardInput =
true,
3548 RedirectStandardOutput =
true,
3549 RedirectStandardError =
true
3552 DateTime Start = DateTime.Now;
3554 Proc.StartInfo = StartInfo;
3559 Proc.WaitForExit(5000);
3560 if (!Proc.HasExited)
3564 string Output = Proc.StandardOutput.ReadToEnd();
3565 DateTime Return = DateTime.Now;
3567 Thread.
Interval(Start, Return,
"Shell");
3570 Log.
Debug(
"Netstat output:\r\n\r\n" + Output);
3572 if (Proc.ExitCode != 0)
3574 Thread.
Exception(
new Exception(
"Exit code: " + Proc.ExitCode.ToString()));
3577 Log.
Debug(
"Netstat exit code: " + Proc.ExitCode.ToString());
3582 string[] Rows = Output.Split(
CommonTypes.
CRLF, StringSplitOptions.RemoveEmptyEntries);
3584 foreach (
string Row
in Rows)
3586 string[] Tokens = Regex.Split(Row,
@"\s+");
3588 switch (Environment.OSVersion.Platform)
3590 case PlatformID.Win32S:
3591 case PlatformID.Win32Windows:
3592 case PlatformID.Win32NT:
3593 case PlatformID.WinCE:
3594 if (Tokens.Length < 6)
3597 if (Tokens[1] !=
"TCP")
3603 if (Tokens[4] !=
"ESTABLISHED")
3606 if (!
int.TryParse(Tokens[5], out
int PID))
3609 Process P = Process.GetProcessById(PID);
3610 int CurrentSession = WTSGetActiveConsoleSessionId();
3612 if (P.SessionId == CurrentSession)
3615 await
Login.DoLogin(Request, From);
3620 case PlatformID.Unix:
3621 case PlatformID.MacOSX:
3622 if (Tokens.Length < 9)
3625 if (Tokens[0] !=
"tcp4" && Tokens[0] !=
"tcp6")
3631 if (Tokens[5] !=
"ESTABLISHED")
3634 if (!
int.TryParse(Tokens[8], out PID))
3637 P = Process.GetProcessById(PID);
3638 CurrentSession = Process.GetCurrentProcess().SessionId;
3640 if (P.SessionId == CurrentSession)
3643 await
Login.DoLogin(Request, From);
3650 Log.
Debug(
"No local login: Unsupported operating system: " + Environment.OSVersion.Platform.ToString());
3663 ExceptionDispatchInfo.Capture(ex).Throw();
3665 catch (Exception ex)
3683 if (TotalSeconds >= 1.0)
3687 Log.
Debug(
"Long local login check.\r\n\r\n```uml\r\n" + Uml +
"\r\n```");
3692 private static bool SameEndpoint(
string EP1,
string EP2)
3694 if (
string.Compare(EP1, EP2,
true) == 0)
3697 switch (Environment.OSVersion.Platform)
3699 case PlatformID.Unix:
3700 case PlatformID.MacOSX:
3701 int i = EP1.LastIndexOf(
'.');
3705 if (!
int.TryParse(EP1[(i + 1)..], out
int Port1))
3708 if (!IPAddress.TryParse(EP1[..i], out IPAddress Addr1))
3711 i = EP2.LastIndexOf(
':');
3715 if (!
int.TryParse(EP2[(i + 1)..], out
int Port2) || Port1 != Port2)
3718 if (!IPAddress.TryParse(EP2[..i], out IPAddress Addr2))
3721 string s1 = Addr1.ToString();
3722 string s2 = Addr2.ToString();
3724 if (
string.Compare(s1, s2,
true) == 0)
3733 private static readonly IPAddress ipv6Local = IPAddress.Parse(
"[::1]");
3734 private static readonly IPAddress ipv4Local = IPAddress.Parse(
"127.0.0.1");
3736 private static bool IsLocalCall(IPAddress Address,
HttpRequest Request,
bool DoLog)
3738 if (Address.Equals(ipv4Local) || Address.Equals(ipv6Local))
3741 string s = Request.
Header.
Host?.
Value.RemovePortNumber() ??
string.Empty;
3743 if (
string.Compare(s,
"localhost",
true) != 0)
3745 if (!IPAddress.TryParse(s, out IPAddress IP) || !Address.Equals(IP))
3756 foreach (NetworkInterface Interface
in NetworkInterface.GetAllNetworkInterfaces())
3758 if (Interface.OperationalStatus != OperationalStatus.Up)
3761 IPInterfaceProperties Properties = Interface.GetIPProperties();
3763 foreach (UnicastIPAddressInformation UnicastAddress
in Properties.UnicastAddresses)
3765 if (Address.Equals(UnicastAddress.Address))
3771 Log.
Debug(
"IP Address not found among network adapters: " + Address.ToString());
3776 Log.
Debug(
"IP Address public: " + Address.ToString());
3781 if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) &&
3783 Environment.GetEnvironmentVariable(
"DOTNET_RUNNING_IN_CONTAINER") ==
"true")
3790 catch (Exception ex)
3800 [DllImport(
"kernel32.dll")]
3801 static extern int WTSGetActiveConsoleSessionId();
3883 if (Session is
null ||
3885 ((
User = v.ValueObject as
IUser) is
null) ||
3913 if (Session is
null ||
3929 private static Task SensorServer_AssignAuthority(
object Sender,
AuthorityEventArgs e)
3933 if (!
string.IsNullOrEmpty(provisioningClient?.OwnerJid) &&
3942 if (!(Item is
null) &&
3951 return Task.CompletedTask;
3956 #region Thing Registry
3958 private static Task ThingRegistryClient_Claimed(
object Sender,
ClaimedEventArgs e)
3966 return Task.CompletedTask;
3969 private static Task ThingRegistryClient_Disowned(
object Sender, Networking.XMPP.Provisioning.Events.NodeEventArgs e)
3974 ownerJid =
string.
Empty;
3978 return Task.CompletedTask;
3981 private static Task ThingRegistryClient_Removed(
object Sender, Networking.XMPP.Provisioning.Events.NodeEventArgs e)
3984 Log.
Informational(
"Gateway has been removed from the public registry.", ownerJid);
3986 return Task.CompletedTask;
3989 private static async Task Register()
3991 string Key = Guid.NewGuid().ToString().Replace(
"-",
string.Empty);
4000 new MetaDataStringTag(
"PURL",
"https://github.com/PeterWaher/IoTGateway#iotgateway"),
4004 if (!(GetMetaData is
null))
4005 MetaData = await GetMetaData(MetaData);
4007 await thingRegistryClient.
RegisterThing(MetaData, async (sender2, e2) =>
4014 ownerJid = e2.OwnerJid;
4016 ownerJid = string.Empty;
4018 RegistrationEventHandler h = RegistrationSuccessful;
4020 await h(MetaData, e2);
4144 #region Service Commands
4157 lock (serviceCommandByNr)
4159 if (!serviceCommandByNr.TryGetValue(CommandNr, out h))
4165 Log.
Warning(
"Service command lacking command handler invoked.", CommandNr.ToString());
4172 await h(
null, EventArgs.Empty);
4174 catch (Exception ex)
4192 lock (serviceCommandByNr)
4194 if (serviceCommandNrByCallback.TryGetValue(Callback, out i))
4197 i = nextServiceCommandNr++;
4199 serviceCommandNrByCallback[Callback] = i;
4200 serviceCommandByNr[i] = Callback;
4213 lock (serviceCommandByNr)
4215 if (serviceCommandNrByCallback.TryGetValue(Callback, out
int i))
4217 serviceCommandByNr.Remove(i);
4218 serviceCommandNrByCallback.Remove(Callback);
4230 public static int BeforeUninstallCommandNr => beforeUninstallCommandNr;
4237 private static Task BeforeUninstall(
object Sender, EventArgs e)
4239 return OnBeforeUninstall.Raise(Sender, e,
false);
4253 public static DateTime
ScheduleEvent(Action<object> Callback, DateTime When,
object State)
4255 return scheduler?.
Add(When, Callback, State) ?? DateTime.MinValue;
4265 public static DateTime
ScheduleEvent(Func<object, Task> Callback, DateTime When,
object State)
4267 return scheduler?.
Add(When, Callback, State) ?? DateTime.MinValue;
4277 return scheduler?.
Remove(When) ??
false;
4282 #region Random number generation
4290 byte[] b =
new byte[8];
4297 double d = BitConverter.ToUInt64(b, 0);
4298 d /= ulong.MaxValue;
4314 throw new ArgumentOutOfRangeException(
"Must be non-negative.", nameof(Max));
4323 Result = (int)(NextDouble() * Max);
4325 while (Result >= Max);
4338 throw new ArgumentException(
"Number of bytes must be non-negative.", nameof(NrBytes));
4340 byte[] Result =
new byte[NrBytes];
4344 rnd.GetBytes(Result);
4356 NextBytes(Buffer, 0, Buffer.Length);
4365 public static void NextBytes(
byte[] Buffer,
int Offset,
int Count)
4369 rnd.GetBytes(Buffer, Offset, Count);
4375 #region Momentary values
4417 #region Personal Eventing Protocol
4425 if (pepClient is
null)
4426 throw new Exception(
"No PEP client available.");
4436 public static void RegisterHandler(Type PersonalEventType, EventHandlerAsync<PersonalEventNotificationEventArgs> Handler)
4447 public static bool UnregisterHandler(Type PersonalEventType, EventHandlerAsync<PersonalEventNotificationEventArgs> Handler)
4449 if (pepClient is
null)
4459 public static event EventHandlerAsync<ItemNotificationEventArgs> PubSubItemNotification
4461 add => pepClient.NonPepItemNotification += value;
4462 remove => pepClient.NonPepItemNotification -= value;
4469 private static async Task<bool> CheckBackup()
4471 bool Result =
false;
4477 DateTime Now = DateTime.Now;
4479 DateTime EstimatedTime = Now.Date + Timepoint;
4482 if ((Timepoint.Hours == Now.Hour && Timepoint.Minutes == Now.Minute) ||
4483 (lastBackupTimeCheck.HasValue && lastBackupTimeCheck.Value < EstimatedTime && Now >= EstimatedTime) ||
4484 LastBackup.AddDays(1) < EstimatedTime)
4486 lastBackupTimeCheck = Now;
4493 catch (Exception ex)
4506 DateTime Now = DateTime.Now;
4510 StartExport.ExportInfo ExportInfo = await
StartExport.GetExporter(
"Encrypted",
false, Array.Empty<
string>());
4514 List<string> Folders =
new List<string>();
4517 Folders.AddRange(FolderCategory.Folders);
4519 await
StartExport.DoExport(ExportInfo,
true,
false,
true, Folders.ToArray());
4527 DeleteOldFiles(ExportFolder, KeepDays, KeepMonths, KeepYears, Now,
true);
4528 if (ExportFolder != KeyFolder)
4529 DeleteOldFiles(KeyFolder, KeepDays, KeepMonths, KeepYears, Now,
true);
4531 DeleteOldFiles(Path.GetTempPath(), 7, 0, 0, Now,
false);
4533 await OnAfterBackup.Raise(typeof(
Gateway), EventArgs.Empty);
4536 private static DateTime? lastBackupTimeCheck =
null;
4551 DeleteOldFiles(Path, KeepDays, 0, 0, DateTime.Now,
false);
4554 private static void DeleteOldFiles(
string Path,
long KeepDays,
long KeepMonths,
4555 long KeepYears, DateTime Now,
bool LogIndividualFileEvents)
4561 if (!Directory.Exists(Path))
4564 string[]
Files = Directory.GetFiles(Path,
"*.*", SearchOption.AllDirectories);
4565 DateTime CreationTime;
4567 foreach (
string FileName
in Files)
4571 CreationTime = File.GetCreationTime(FileName);
4573 if (KeepMonths > 0 && CreationTime.Day == 1)
4575 if (KeepYears > 0 && CreationTime.Month == 1)
4577 if (Now.Year - CreationTime.Year <= KeepYears)
4582 if ((Now.Year * 12 + Now.Month - (CreationTime.Year * 12 + Now.Month)) <= KeepMonths)
4588 if ((Now.Date - CreationTime.Date).TotalDays <= KeepDays)
4592 File.Delete(FileName);
4595 if (LogIndividualFileEvents)
4600 catch (Exception ex)
4606 catch (Exception ex)
4612 if (Count > 0 && !LogIndividualFileEvents)
4624 StringBuilder Msg =
new StringBuilder();
4626 Msg.Append(
"Collection repaired: ");
4634 Msg.Append(
"Reason: ");
4637 if (Source.
Count > 1)
4640 Msg.Append(Source.
Count.ToString());
4641 Msg.Append(
" times)");
4646 Msg.AppendLine(
"StackTrace:");
4648 Msg.AppendLine(
"```");
4650 Msg.AppendLine(
"```");
4656 return Task.CompletedTask;
4661 #region Notifications
4663 private static Task MailClient_MailReceived(
object Sender,
MailEventArgs e)
4665 return MailReceived.Raise(Sender, e);
4671 public static event EventHandlerAsync<MailEventArgs> MailReceived =
null;
4679 return SendNotification(Content.Markdown.Functions.ToMarkdown.GraphToMarkdown(
Graph));
4688 return SendNotification(Content.Markdown.Functions.ToMarkdown.PixelsToMarkdown(Pixels));
4697 return SendNotification(Markdown,
string.Empty,
false);
4707 return SendNotification(Markdown, MessageId,
false);
4717 return SendNotification(Markdown, MessageId,
true);
4726 private static async Task SendNotification(
string Markdown,
string MessageId,
bool Update)
4731 (
string Text,
string Html) = await ConvertMarkdown(Markdown);
4737 await SendNotification(AdminAddress, Markdown, Text, Html, MessageId, Update);
4739 catch (Exception ex)
4745 Addresses = GetNotificationWebHooks();
4746 if (Addresses.Length > 0)
4748 Dictionary<string, object> Data =
new Dictionary<string, object>()
4750 {
"Markdown", Markdown },
4763 catch (Exception ex)
4770 catch (Exception ex)
4776 private static Task<(string, string)> ConvertMarkdown(
string Markdown)
4778 return ConvertMarkdown(Markdown,
true,
true);
4781 private static async Task<(string, string)> ConvertMarkdown(
string Markdown,
bool TextVersion,
bool HtmlVersion)
4783 if (TextVersion || HtmlVersion)
4787 ParseMetaData =
false
4791 XmlEntitiesOnly =
true
4797 return (Text, Html);
4800 return (
null,
null);
4821 private static async Task SendNotification(
string To,
string Markdown,
string Text,
string Html,
string MessageId,
bool Update)
4829 ScheduleEvent(Resend, DateTime.Now.AddMinutes(15),
new object[] { To, Markdown, Text, Html, MessageId, Update });
4832 await SendChatMessage(
MessageType.Chat, Markdown, Text, Html, To, MessageId,
string.Empty, Update);
4835 ScheduleEvent(Resend, DateTime.Now.AddSeconds(30),
new object[] { To, Markdown, Text, Html, MessageId, Update });
4845 return SendChatMessage(Markdown, To,
string.Empty);
4856 return SendChatMessage(Markdown, To, MessageId,
string.Empty);
4866 public static async Task
SendChatMessage(
string Markdown,
string To,
string MessageId,
string ThreadId)
4868 (
string Text,
string Html) = await ConvertMarkdown(Markdown);
4869 await SendChatMessage(
MessageType.Chat, Markdown, Text, Html, To, MessageId, ThreadId,
false);
4880 return SendChatMessageUpdate(Markdown, To, MessageId,
string.Empty);
4892 (
string Text,
string Html) = await ConvertMarkdown(Markdown);
4893 await SendChatMessage(
MessageType.Chat, Markdown, Text, Html, To, MessageId, ThreadId,
true);
4903 return SendGroupChatMessage(Markdown, To,
string.Empty);
4914 return SendGroupChatMessage(Markdown, To, MessageId,
string.Empty);
4926 (
string Text,
string Html) = await ConvertMarkdown(Markdown);
4927 await SendChatMessage(
MessageType.GroupChat, Markdown, Text, Html, To, MessageId, ThreadId,
false);
4938 return SendGroupChatMessageUpdate(Markdown, To, MessageId,
string.Empty);
4950 (
string Text,
string Html) = await ConvertMarkdown(Markdown);
4951 await SendChatMessage(
MessageType.GroupChat, Markdown, Text, Html, To, MessageId, ThreadId,
true);
4961 return GetMultiFormatChatMessageXml(Markdown,
true,
true);
4973 (
string Text,
string Html) = await ConvertMarkdown(Markdown, TextVersion, HtmlVersion);
4974 return GetMultiFormatChatMessageXml(Text, Html, Markdown);
4986 StringBuilder Xml =
new StringBuilder();
4987 AppendMultiFormatChatMessageXml(Xml, Text, Html, Markdown);
4988 return Xml.ToString();
5000 if (
string.IsNullOrEmpty(Text))
5001 Xml.Append(
"<body/>");
5004 Xml.Append(
"<body>");
5006 if (Text.Contains(
"]]>"))
5010 Xml.Append(
"<![CDATA[");
5015 Xml.Append(
"</body>");
5018 if (!
string.IsNullOrEmpty(Markdown))
5020 Xml.Append(
"<content xmlns=\"urn:xmpp:content\" type=\"text/markdown\">");
5022 if (Markdown.Contains(
"]]>"))
5026 Xml.Append(
"<![CDATA[");
5027 Xml.Append(Markdown);
5031 Xml.Append(
"</content>");
5034 if (!
string.IsNullOrEmpty(Html))
5036 Xml.Append(
"<html xmlns='http://jabber.org/protocol/xhtml-im'>");
5037 Xml.Append(
"<body xmlns='http://www.w3.org/1999/xhtml'>");
5040 IEnumerable<HtmlNode> Children = (Doc.Body ?? Doc.
Root).Children;
5042 if (!(Children is
null))
5048 Xml.Append(
"</body></html>");
5052 private static async Task SendChatMessage(
MessageType Type,
string Markdown,
string Text,
string Html,
string To,
string MessageId,
string ThreadId,
bool Update)
5056 StringBuilder Xml =
new StringBuilder();
5058 AppendMultiFormatChatMessageXml(Xml, Text, Html, Markdown);
5060 if (Update && !
string.IsNullOrEmpty(MessageId))
5062 Xml.Append(
"<replace id='");
5063 Xml.Append(MessageId);
5064 Xml.Append(
"' xmlns='urn:xmpp:message-correct:0'/>");
5066 MessageId =
string.Empty;
5069 await xmppClient.
SendMessage(
QoSLevel.Unacknowledged, Type, MessageId, To, Xml.ToString(),
string.Empty,
5070 string.Empty,
string.Empty, ThreadId,
string.Empty,
null,
null);
5079 public static string GetUrl(
string LocalResource)
5092 if (LocalResource.StartsWith(
"http://") ||
5093 LocalResource.StartsWith(
"https://"))
5095 return LocalResource;
5098 StringBuilder sb =
new StringBuilder();
5104 if (certificate is
null)
5126 IPAddress IP4 =
null;
5127 IPAddress IP6 =
null;
5129 if (!(Server is
null))
5133 if (IPAddress.IsLoopback(Addr))
5136 switch (Addr.AddressFamily)
5150 sb.Append(IP4.ToString());
5151 else if (!(IP6 is
null))
5152 sb.Append(IP6.ToString());
5154 sb.Append(Dns.GetHostName());
5157 if (Array.IndexOf(Ports, DefaultPort) < 0 && Ports.Length > 0)
5163 sb.Append(LocalResource);
5165 return sb.ToString();
5174 public static bool IsDomain(
string DomainOrHost,
bool IncludeAlternativeDomains)
5178 if (DomainOrHost == domain)
5181 if (IncludeAlternativeDomains && !(alternativeDomains is
null))
5185 if (s == DomainOrHost)
5192 if (DomainOrHost ==
"localhost" ||
string.IsNullOrEmpty(DomainOrHost))
5195 if (!(webServer is
null))
5199 if (Addr.ToString() == DomainOrHost)
5204 if (DomainOrHost == Dns.GetHostName())
5216 private static async Task Resend(
object P)
5218 object[] P2 = (
object[])P;
5219 await SendNotification((
string)P2[0], (
string)P2[1], (
string)P2[2], (
string)P2[3], (
string)P2[4], (
bool)P2[5]);
5229 internal static async Task SimplifiedConfiguration()
5257 List<WebMenuItem> Result =
new List<WebMenuItem>();
5259 if (Session is
null)
5264 if (Session is
null ||
5268 Result.Add(
new WebMenuItem(
"Login",
"/Login.md"));
5272 if (!(configurations is
null))
5282 !(v.ValueObject is
bool AutoLogin) || !AutoLogin)
5288 return Result.ToArray();
5293 #region Smart Contracts
5303 if (contractsClient is
null ||
5304 contractsClient == value ||
5307 contractsClient = value;
5310 throw new InvalidOperationException(
"Not allowed to set a new Contracts Client class.");
5328 bool RoleFound =
false;
5331 throw new ArgumentException(
"Contract cannot be null.", nameof(
Contract));
5335 foreach (Networking.XMPP.Contracts.Role R in
Contract.
Roles)
5345 throw new ArgumentException(
"Invalid role.", nameof(
Role));
5347 if (
string.IsNullOrEmpty(Purpose) || Purpose.IndexOfAny(
CommonTypes.
CRLF) >= 0)
5348 throw new ArgumentException(
"Invalid purpose.", nameof(Purpose));
5352 string Module =
string.Empty;
5357 StackFrame Frame =
new StackFrame(Skip);
5358 MethodBase Method = Frame.GetMethod();
5362 Type Type = Method.DeclaringType;
5363 Assembly Assembly = Type.Assembly;
5364 Module = Assembly.GetName().Name;
5366 if (Type != typeof(
Gateway) && !Module.StartsWith(
"System."))
5381 if (Request is
null)
5385 Received = DateTime.Now,
5400 int i = Markdown.IndexOf(
"~~~~~~");
5401 int c = Markdown.Length;
5406 while (i < c && Markdown[i] ==
'~')
5409 Markdown = Markdown[i..].TrimStart();
5412 i = Markdown.IndexOf(
"~~~~~~");
5414 Markdown = Markdown[..i].TrimEnd();
5423 StringBuilder sb =
new StringBuilder(Markdown);
5426 sb.Append(
"Link: [`");
5429 sb.Append(GetUrl(
"/SignatureRequest.md?RequestId=" + Request.
ObjectId));
5432 Markdown = sb.ToString();
5436 Markdown =
"**Reminder**: Smart Contract [" + Request.ContractId +
"](" +
5437 GetUrl(
"/SignatureRequest.md?RequestId=" + Request.
ObjectId) +
") is waiting for your signature.";
5440 await SendNotification(Markdown);
5442 catch (Exception ex)
5459 EventHandlerAsync<LegalIdentityPetitionResponseEventArgs> Callback, TimeSpan Timeout,
5476 EventHandlerAsync<LegalIdentityPetitionResponseEventArgs> Callback, TimeSpan Timeout)
5491 public static Task<bool>
PetitionContract(
string ContractId,
string PetitionId,
string Purpose,
5492 EventHandlerAsync<ContractPetitionResponseEventArgs> Callback, TimeSpan Timeout,
5508 public static Task<bool>
PetitionContract(
string ContractId,
string PetitionId,
string Purpose,
string Password,
5509 EventHandlerAsync<ContractPetitionResponseEventArgs> Callback, TimeSpan Timeout)
5516 #region Finding Files
5527 public static string[]
FindFiles(Environment.SpecialFolder[] Folders,
string Pattern,
bool IncludeSubfolders,
bool BreakOnFirst)
5541 public static string[]
FindFiles(
string[] Folders,
string Pattern,
bool IncludeSubfolders,
bool BreakOnFirst)
5555 public static string[]
FindFiles(
string[] Folders,
string Pattern,
bool IncludeSubfolders,
int MaxCount)
5569 public static string[]
FindFiles(
string[] Folders,
string Pattern,
int SubfolderDepth,
int MaxCount)
5580 public static string[]
GetFolders(Environment.SpecialFolder[] Folders, params
string[] AppendWith)
5594 public static string FindLatestFile(Environment.SpecialFolder[] Folders,
string Pattern,
bool IncludeSubfolders)
5608 public static string FindLatestFile(
string[] Folders,
string Pattern,
bool IncludeSubfolders)
5622 public static string FindLatestFile(
string[] Folders,
string Pattern,
int SubfolderDepth)
5629 #region Custom Errors
5631 private static readonly Dictionary<string, KeyValuePair<DateTime, MarkdownDocument>> defaultDocuments =
new Dictionary<string, KeyValuePair<DateTime, MarkdownDocument>>();
5636 if (Accept is
null || Accept.
Value ==
"*/*")
5643 if (!
string.IsNullOrEmpty(Html))
5644 e.
SetContent(
"text/html; charset=utf-8",
System.Text.Encoding.UTF8.GetBytes(Html));
5662 if (
string.IsNullOrEmpty(ContentType))
5664 IsText = IsMarkdown =
false;
5674 if (IsEmpty || IsText || IsMarkdown)
5679 lock (defaultDocuments)
5681 if (defaultDocuments.TryGetValue(LocalFileName, out KeyValuePair<DateTime, MarkdownDocument> P))
5688 TP = DateTime.MinValue;
5693 string FullFileName = Path.Combine(appDataFolder,
"Default", LocalFileName);
5695 if (File.Exists(FullFileName))
5697 DateTime TP2 = File.GetLastWriteTimeUtc(FullFileName);
5702 bool SessionLocked =
false;
5706 if (Doc is
null || TP2 > TP)
5711 RootFolder = rootFolder,
5718 SessionLocked =
true;
5720 SessionVariables.CurrentRequest = Request;
5721 SessionVariables.CurrentResponse = Request.
Response;
5726 lock (defaultDocuments)
5728 defaultDocuments[LocalFileName] =
new KeyValuePair<DateTime, MarkdownDocument>(TP2, Doc);
5732 if (IsEmpty || Content is
null)
5737 out
System.Text.Encoding Encoding, out
_);
5739 Encoding ??=
System.Text.Encoding.UTF8;
5754 Doc.Tag = DocSynchObj;
5757 if (await DocSynchObj.TryBeginWrite(30000))
5761 Doc.Detail = Detail;
5766 await DocSynchObj.EndWrite();
5776 SessionVariables.CurrentRequest =
null;
5777 SessionVariables.CurrentResponse =
null;
5787 lock (defaultDocuments)
5789 defaultDocuments.Remove(LocalFileName);
5800 #region Sniffers & Events
5850 int i = Resource.IndexOfAny(
new char[] {
'?',
'#' });
5852 Resource = Resource[..i];
5869 public static string AddWebSniffer(
string SnifferId,
string PageResource, TimeSpan MaxLife,
5874 foreach (
ISniffer Sniffer
in ComLayer)
5886 ComLayer.Add(Sniffer);
5889 return "\r\n\r\n\r\n\r\n";
5903 AddWebEventSink(SinkId, Request, TimeSpan.FromHours(1), UserVariable,
Privileges);
5919 int i = Resource.IndexOfAny(
new char[] {
'?',
'#' });
5921 Resource = Resource[..i];
5923 AddWebEventSink(SinkId, Resource, MaxLife, UserVariable,
Privileges);
5958 #region Script Resources
5969 if (!await RemoveScriptResource(ResourceName,
true))
5988 if (!await RemoveScriptResource(ResourceName,
true))
6005 return RemoveScriptResource(ResourceName,
false);
6014 private static async Task<bool> RemoveScriptResource(
string ResourceName,
bool ConsiderNonexistantRemoved)
6019 if (!
string.IsNullOrEmpty(SubPath))
6020 return ConsiderNonexistantRemoved;
6032 private static async Task LoadScriptResources()
6036 foreach (KeyValuePair<string, object> Setting
in Settings)
6038 if (!(Setting.Value is
string Value))
6040 Log.
Error(
"Invalid Runtime setting found and ignored.",
6041 new KeyValuePair<string, object>(
"Key", Setting.Key),
6042 new KeyValuePair<string, object>(
"Value", Setting.Value));
6047 string ResourceName = Setting.Key[23..];
6048 string ReferenceFileName;
6052 i = Value.IndexOf(
" ||| ");
6054 ReferenceFileName =
string.Empty;
6057 ReferenceFileName = Value[..i];
6058 Value = Value[(i + 5)..];
6066 catch (Exception ex)
6068 Log.
Error(
"Invalid Runtime setting script. Resource could not be added.",
6069 new KeyValuePair<string, object>(
"Resource", ResourceName),
6070 new KeyValuePair<string, object>(
"Error", ex.Message),
6071 new KeyValuePair<string, object>(
"ReferenceFileName", ReferenceFileName),
6072 new KeyValuePair<string, object>(
"Script", Value));
6087 return ProcessServiceConfigurations(
true);
6090 private static async Task<int> ProcessServiceConfigurations(
bool OnlyIfChanged)
6092 string[] ConfigurationFiles = Directory.GetFiles(appDataFolder,
"*.config", SearchOption.TopDirectoryOnly);
6095 foreach (
string ConfigurationFile
in ConfigurationFiles)
6097 if (await ProcessServiceConfigurationFile(ConfigurationFile, OnlyIfChanged))
6104 private const string ServiceConfigurationRoot =
"ServiceConfiguration";
6105 private const string ServiceConfigurationNamespace =
"http://waher.se/Schema/ServiceConfiguration.xsd";
6118 ConfigurationFileName = Path.GetFullPath(ConfigurationFileName);
6120 string DirectoryName = Path.GetDirectoryName(ConfigurationFileName);
6121 if (!DirectoryName.EndsWith(
new string(Path.DirectorySeparatorChar, 1)))
6122 DirectoryName += Path.DirectorySeparatorChar;
6124 if (
string.Compare(DirectoryName, appDataFolder,
true) != 0)
6127 if (!File.Exists(ConfigurationFileName))
6132 if (Doc.DocumentElement.LocalName != ServiceConfigurationRoot || Doc.DocumentElement.NamespaceURI != ServiceConfigurationNamespace)
6135 XSL.
Validate(Path.GetFileName(ConfigurationFileName), Doc, ServiceConfigurationRoot, ServiceConfigurationNamespace,
6138 bool ExecuteInitScript = await Content.Markdown.Functions.InitScriptFile.NeedsExecution(ConfigurationFileName);
6140 if (OnlyIfChanged && !ExecuteInitScript)
6143 Log.
Notice(
"Applying Service Configurations.", ConfigurationFileName);
6147 foreach (XmlNode N
in Doc.DocumentElement.ChildNodes)
6149 if (!(N is XmlElement E))
6152 switch (E.LocalName)
6154 case "VanityResources":
6155 foreach (XmlNode N2
in E.ChildNodes)
6157 if (N2 is XmlElement E2 && E2.LocalName ==
"VanityResource")
6166 catch (Exception ex)
6168 Log.
Error(
"Unable to register vanity resource: " + ex.Message,
6169 new KeyValuePair<string, object>(
"RegEx", RegEx),
6170 new KeyValuePair<string, object>(
"Url", Url));
6176 case "StartupScript":
6182 case "InitializationScript":
6183 if (ExecuteInitScript)
6195 catch (Exception ex)
6206 private static async Task WebServer_ConnectionProfiled(
object Sender,
ProfilingEventArgs e)
6211 DateTime Now = DateTime.UtcNow;
6212 StringBuilder sb =
new StringBuilder();
6214 sb.Append(
"Profiling ");
6215 sb.Append(Now.Year.ToString(
"D4"));
6217 sb.Append(Now.Month.ToString(
"D2"));
6219 sb.Append(Now.Day.ToString(
"D2"));
6221 sb.Append(Now.Hour.ToString(
"D2"));
6223 sb.Append(Now.Minute.ToString(
"D2"));
6225 sb.Append(Now.Second.ToString(
"D2"));
6227 sb.Append(Now.Millisecond.ToString(
"D3"));
6230 string Folder = Path.Combine(appDataFolder,
"HTTP");
6232 if (!httpProfilingFolderChecked)
6234 if (!Directory.Exists(Folder))
6235 Directory.CreateDirectory(Folder);
6237 httpProfilingFolderChecked =
true;
6241 string BaseFileName = sb.ToString();
6242 string FileName = Path.Combine(Folder, BaseFileName);
6244 string Uml2 = e.
FlowControl?.ExportPlantUml(out NrNodes);
6250 FileName = Path.Combine(Folder, BaseFileName.Replace(
"Profiling ",
"States "));
6254 StringBuilder Markdown =
new StringBuilder();
6256 Markdown.AppendLine(
"```uml");
6257 Markdown.AppendLine(Uml.TrimEnd());
6258 Markdown.AppendLine(
"```");
6260 await SendNotification(Markdown.ToString());
6265 Markdown.AppendLine(
"```uml");
6266 Markdown.AppendLine(Uml.TrimEnd());
6267 Markdown.AppendLine(
"```");
6269 await SendNotification(Markdown.ToString());
6272 catch (Exception ex)
6275 httpProfilingFolderChecked =
false;
6279 private static bool httpProfilingFolderChecked =
false;
6283 #region Local, Temporary, and short URLs
6307 if (!Uri.TryCreate(Resource, UriKind.RelativeOrAbsolute, out Uri ParsedResource))
6313 if (ParsedResource.IsAbsoluteUri)
6315 if (!IsDomain(ParsedResource.Host,
true))
6321 Resource = ParsedResource.LocalPath;
6324 if (!
string.IsNullOrEmpty(Host) &&
6335 #region Nonce values
6353 return nonceValues?.
AddAsync(Nonce,
true) ?? Task.CompletedTask;
Helps with parsing of commong data types.
static readonly char[] CRLF
Contains the CR LF character sequence.
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Contains information about a response to a content request.
bool HasError
If an error occurred.
Exception Error
Error response.
Provides emojis from Emoji One (http://emojione.com/) stored as local files.
const string DefaultContentType
Default Content-Type for HTML: text/html
HtmlElement Root
Root element.
static string GetBody(string Html)
Extracts the contents of the BODY element in a HTML string.
Base class for all HTML nodes.
abstract void Export(XmlWriter Output, Dictionary< string, string > Namespaces)
Exports the HTML document to XML.
const string ContentTypeIcon
image/x-icon
Static class managing encoding and decoding of internet content.
static void SetDefaultTimeout(int Timeout, bool Lock)
Sets the default timeout of internet access methods, in milliseconds.
static Task< ContentResponse > PostAsync(Uri Uri, object Data, params KeyValuePair< string, string >[] Headers)
Posts to a resource, using a Uniform Resource Identifier (or Locator).
static bool ParseContentType(ref string ContentType, out Encoding Encoding, out KeyValuePair< string, string >[] Fields)
Parses a Content-Type, providing the base Content-Type, character encoding, if any,...
Local domain check event arguments.
bool IncludeAlternativeDomains
If alternative domains are to be checked.
string DomainOrHost
Domain or host name.
Class managing GraphViz integration into Markdown documents.
static async Task Terminate()
Terminates GraphViz processing.
static void Init(string ContentRootFolder)
Initializes the GraphViz-Markdown integration.
Class managing 2D XML Layout integration into Markdown documents.
static void Init(string ContentRootFolder)
Initializes the Layout2D-Markdown integration.
static bool IsRawEncodingAllowedLocked
If the IsRawEncodingAllowed setting is locked.
const string ContentType
Markdown content type.
static void AllowRawEncoding(bool Allow, bool Lock)
If raw encoding of web script should be allowed.
Contains a markdown document. This markdown document class supports original markdown,...
MarkdownSettings Settings
Markdown settings.
static string Encode(string s)
Encodes all special characters in a string so that it can be included in a markdown document without ...
object Tag
Property can be used to tag document with client-specific information.
static async Task< string > Preprocess(string Markdown, MarkdownSettings Settings, params Type[] TransparentExceptionTypes)
Preprocesses markdown text.
async Task< string > GeneratePlainText()
Generates Plain Text from the markdown text.
async Task< string > GenerateHTML()
Generates HTML from the markdown text.
static Task< MarkdownDocument > CreateAsync(string MarkdownText, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
Contains settings that the Markdown parser uses to customize its behavior.
static void SetDefaultEmojiSource(IEmojiSource EmojiSource, bool Lock)
Sets the default emoji source.
Class managing PlantUML integration into Markdown documents.
static void Init(string ContentRootFolder)
Initializes the PlantUML-Markdown integration.
static async Task Terminate()
Terminates PlantUML processing.
Contains settings that the HTML export uses to customize HTML output.
Web Script encoder/decoder.
static bool IsRawEncodingAllowedLocked
If the IsRawEncodingAllowed setting is locked.
static void AllowRawEncoding(bool Allow, bool Lock)
If raw encoding of web script should be allowed.
const string ContentType
Markdown content type.
Static class helping modules to find files installed on the system.
static string[] GetFolders(Environment.SpecialFolder[] Folders, params string[] AppendWith)
Gets the physical locations of special folders.
static string[] FindFiles(Environment.SpecialFolder[] Folders, string Pattern, bool IncludeSubfolders, bool BreakOnFirst)
Finds files in a set of folders, and optionally, their subfolders. This method only finds files in fo...
static string FindLatestFile(Environment.SpecialFolder[] Folders, string Pattern, bool IncludeSubfolders)
Finds the latest file matching a search pattern, by searching in a set of folders,...
Plain text encoder/decoder.
const string DefaultContentType
text/plain
Helps with common XML-related tasks.
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
static XmlDocument LoadFromFile(string FileName)
Loads an XML document from a file.
static string Encode(string s)
Encodes a string for use in XML.
static XmlException AnnotateException(XmlException ex)
Creates a new XML Exception object, with reference to the source XML file, for information.
static XmlDocument ParseXml(string Xml)
Parses an XML Document from its string representation.
Static class managing loading of XSL resources stored as embedded resources or in content files.
static XmlSchema LoadSchema(string ResourceName)
Loads an XML schema from an embedded resource.
static void Validate(string ObjectID, XmlDocument Xml, params XmlSchema[] Schemas)
Validates an XML document given a set of XML schemas.
Converts an object to a ZIP File.
static void ProtectContentType(string ContentType)
Protects a content type, so that it cannot be included in generated zip files by external parties thr...
Class representing an event.
void Avoid(IEventSink EventSink)
If the event sink EventSink should be avoided when logging the event.
string Facility
Facility can be either a facility in the network sense or in the system sense.
Outputs sniffed data to a text file.
Outputs sniffed data to an XML file.
Filters incoming events and passes remaining events to a secondary event sink.
Sends logged events to a collection of event sinks.
Static class managing the application event log. Applications and services log events on this static ...
static string CleanStackTrace(string StackTrace)
Cleans a Stack Trace string, removing entries from the asynchronous execution model,...
static IEventSink[] Sinks
Registered sinks.
static void Register(IEventSink EventSink)
Registers an event sink with the event log. Call Unregister(IEventSink) to unregister it,...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
static void Critical(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a critical event.
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
static void Emergency(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an emergency event.
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
static void Notice(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a notice event.
static void Debug(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a debug event.
static void Alert(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an alert event.
static async void Event(Event Event)
Logs an event. It will be distributed to registered event sinks.
virtual string ObjectID
Object ID, used when logging events.
Event sink sending events to a topic on an MQTT server. Events are sent as XML fragments.
Creates an even sink that stores incoming (logged) events in the local object database,...
override async Task Queue(Event Event)
Queues an event to be output.
Writes logged events to an operating system pipe, for inter-process communication.
Creates an even sink that queues incoming events in a local persisted queue, for processing by in ord...
Writes logged events to to a socket.
Event sink that sends events to a Syslog server using the Syslog protocol.
Event sink sending events to a remote service using POST.
Event sink sending events to a destination over the XMPP network.
Defines the Groups data source. This data source contains a tree structure of groups of nodes
static async Task< int > DeleteOldEvents(TimeSpan MaxAge)
Deletes old data source events.
The ClientEvents class allows applications to push information asynchronously to web clients connecte...
static Task< int > PushEvent(string[] TabIDs, string Type, object Data)
Puses an event to a set of Tabs, given their Tab IDs.
static string[] GetTabIDs()
Gets all open Tab IDs.
Web-socket binding method for the ClientEvents class. It allows clients connect to the gateway using ...
const string DefaultContentType
Default Content-Type for CSSX: text/x-cssx
Event sink that forwards events as notification messages to administrators.
Analyzes exceptions and extracts basic statistics.
static void Process(string ExceptionFileName, string OutputFileName)
Analyzes exceptions and extracts basic statistics.
Information about an exportable folder category
Static class managing data export.
static async Task< string > GetFullExportFolderAsync()
Full path to export folder.
static FolderCategory[] GetRegisteredFolders()
Gets registered exportable folders.
static async Task< string > GetFullKeyExportFolderAsync()
Full path to key folder.
static async Task SetLastBackupAsync(DateTime Value)
Set Timestamp of last backup.
static async Task< long > GetKeepMonthsAsync()
For how many months the monthly backups are kept.
static async Task< long > GetKeepYearsAsync()
For how many years the yearly backups are kept.
static async Task< DateTime > GetLastBackupAsync()
Get Timestamp of last backup.
static async Task< long > GetKeepDaysAsync()
For how many days backups are kept.
static async Task< bool > GetAutomaticBackupsAsync()
If automatic backups are activated
static async Task< TimeSpan > GetBackupTimeAsync()
Time of day to start performing backups.
Static class managing the runtime environment of the IoT Gateway.
static WebMenuItem[] GetSettingsMenu(HttpRequest Request, string UserVariable)
Gets the settings menu.
static HttpxProxy HttpxProxy
HTTPX Proxy resource
static CaseInsensitiveString Domain
Domain name.
static HttpServer HttpServer
HTTP Server
static string InstanceName
Name of the current instance. Default instance=string.Empty
static async Task CheckLocalLogin(HttpRequest Request)
Checks if a web request comes from the local host in the current session. If so, the user is automati...
static async Task< bool > ProcessServiceConfigurationFile(string ConfigurationFileName, bool OnlyIfChanged)
Processes a Service Configuration File. This method should be called for each service configuration f...
static Task Terminate()
Raises the OnTerminate event handler, letting the container executable know the application needs to ...
static Task NewMomentaryValues(IEnumerable< Field > Values)
Reports newly measured values.
static void RegisterHandler(Type PersonalEventType, EventHandlerAsync< PersonalEventNotificationEventArgs > Handler)
Registers an event handler of a specific type of personal events.
static string[] FindFiles(string[] Folders, string Pattern, bool IncludeSubfolders, int MaxCount)
Finds files in a set of folders, and optionally, their subfolders. This method only finds files in fo...
static string GetMultiFormatChatMessageXml(string Text, string Html, string Markdown)
Gets XML for a multi-formatted chat message.
static void SafeDispose(IDisposable Object)
Disposes an object, catching and logging any exceptions.
static bool IsDomain(string DomainOrHost, bool IncludeAlternativeDomains)
If a domain or host name represents the gateway.
static IUser AssertUserAuthenticated(HttpRequest Request, string Privilege)
Makes sure a request is being made from a session with a successful user login.
static RequiredPrivileges LoggedIn(string UserVariable, IAuthorization< HttpRequest > Authorization)
Authentication mechanism that makes sure the call is made from a session with a valid authenticated u...
static AvatarClient AvatarClient
XMPP Concentrator Server.
static double NextDouble()
Generates a new floating-point value between 0 and 1, using a cryptographic random number generator.
static string AddWebSniffer(string SnifferId, HttpRequest Request, ICommunicationLayer ComLayer, string UserVariable, params string[] Privileges)
Creates a web sniffer, and adds it to a sniffable object.
const string WebApplicationFirewallLocalFileName
WAF.xml
static string FindLatestFile(string[] Folders, string Pattern, int SubfolderDepth)
Finds the latest file matching a search pattern, by searching in a set of folders,...
static Task SendNotification(PixelInformation Pixels)
Sends an image as a notification message to configured notification recipients.
static X509Certificate2 Certificate
Domain certificate.
static GetDatabaseProviderEventHandler GetDatabaseProvider
Event raised when the Gateway requires its database provider from the host.
static Socks5Proxy Socks5Proxy
SOCKS5 Proxy
static void AddWebEventSink(string SinkId, string PageResource, TimeSpan MaxLife, string UserVariable, params string[] Privileges)
Creates a web event sink, and registers it with Log.
static CommunicationLayer FirstChanceExceptions
Observable layer where first chance exceptions can be monitored.
static Task SendChatMessage(string Markdown, string To, string MessageId)
Sends a chat message to a recipient.
static string FindLatestFile(string[] Folders, string Pattern, bool IncludeSubfolders)
Finds the latest file matching a search pattern, by searching in a set of folders,...
static string[] FindFiles(string[] Folders, string Pattern, int SubfolderDepth, int MaxCount)
Finds files in a set of folders, and optionally, their subfolders. This method only finds files in fo...
static Task SendNotification(string Markdown, string MessageId)
Sends a notification message to configured notification recipients.
static async Task SendChatMessageUpdate(string Markdown, string To, string MessageId, string ThreadId)
Sends a chat message update to a recipient.
static EventHandlerAsync< Events.CertificateEventArgs > OnNewCertificate
Event raised when a new server certificate has been generated.
static void DeleteOldFiles(string Path, long KeepDays)
Deletes old files in a folder.
static void AddWebEventSink(string SinkId, HttpRequest Request, TimeSpan MaxLife, string UserVariable, params string[] Privileges)
Creates a web event sink, and registers it with Log.
static Task< bool > HasNonceBeenUsed(string Nonce)
Checks if a Nonce value has been used.
static SensorClient SensorClient
XMPP Sensor Client.
static string[] FindFiles(string[] Folders, string Pattern, bool IncludeSubfolders, bool BreakOnFirst)
Finds files in a set of folders, and optionally, their subfolders. This method only finds files in fo...
static Task< bool > Start(bool ConsoleOutput, bool LoopbackIntefaceAvailable)
Starts the gateway.
static Task< bool > PetitionContract(string ContractId, string PetitionId, string Purpose, string Password, EventHandlerAsync< ContractPetitionResponseEventArgs > Callback, TimeSpan Timeout)
Petitions information about a smart contract from its owner.
static IUser AssertUserAuthenticated(HttpRequest Request, string[] Privileges)
Makes sure a request is being made from a session with a successful user login.
static async Task SendGroupChatMessageUpdate(string Markdown, string To, string MessageId, string ThreadId)
Sends a group chat message update to a recipient.
static Task< string > GetMultiFormatChatMessageXml(string Markdown)
Gets XML for a multi-formatted chat message.
static async Task DoBackup()
Performs a backup of the system.
static string RuntimeFolder
Runtime folder.
static string ConfigFilePath
Full path to Gateway.config file.
static LoginAuditor LoginAuditor
Current Login Auditor. Should be used by modules accepting user logins, to protect the system from un...
static GeoClient GeoClient
XMPP Geo-spatial Publish/Subscribe Client, if such a compoent is available on the XMPP broker.
static Task< bool > Start(bool ConsoleOutput)
Starts the gateway.
static async Task Stop()
Stops the gateway.
static async Task< string > GetMultiFormatChatMessageXml(string Markdown, bool TextVersion, bool HtmlVersion)
Gets XML for a multi-formatted chat message.
static async Task SendChatMessage(string Markdown, string To, string MessageId, string ThreadId)
Sends a chat message to a recipient.
static string AddWebSniffer(string SnifferId, HttpRequest Request, TimeSpan MaxLife, BinaryPresentationMethod BinaryPresentationMethod, ICommunicationLayer ComLayer, string UserVariable, params string[] Privileges)
Creates a web sniffer, and adds it to a sniffable object.
static bool TryGetDefaultPage(HttpRequest Request, out string DefaultPage)
Tries to get the default page of a host.
static SynchronizationClient SynchronizationClient
XMPP Synchronization Client.
static PepClient PepClient
XMPP Personal Eventing Protocol (PEP) Client.
static Task NewMomentaryValues(IThingReference Reference, IEnumerable< Field > Values)
Reports newly measured values.
static Task< int > ProcessNewServiceConfigurations()
Processes new Service Configuration Files. This method should be called after installation of new ser...
const string GatewayConfigNamespace
http://waher.se/Schema/GatewayConfiguration.xsd
static byte[] NextBytes(int NrBytes)
Generates an array of random bytes.
static string AppDataFolder
Application data folder.
static string[] GetProtocols()
Gets the protocol names defined in the configuration file.
static int[] GetConfigPorts(string Protocol)
Gets the port numbers defined for a given protocol in the configuration file.
static void AddWebEventSink(string SinkId, HttpRequest Request, string UserVariable, params string[] Privileges)
Creates a web event sink, and registers it with Log.
static async Task< bool > AddScriptResource(string ResourceName, ScriptNode Expression, string ReferenceFileName)
Adds a script resource to the web server hosted by the gateway.
static Task SendNotification(Graph Graph)
Sends a graph as a notification message to configured notification recipients.
static RequiredPrivileges LoggedIn(IAuthorization< HttpRequest > Authorization)
Authentication mechanism that makes sure the call is made from a session with a valid authenticated u...
static EventHandlerAsync< GetDataSourcesEventArgs > GetDataSources
Event raised when the Gateway requires a set of data sources to publish.
static IUser AssertUserAuthenticated(Variables Session, string Privilege)
Makes sure a request is being made from a session with a successful user login.
static string GetUrl(string LocalResource)
Gets a URL for a resource.
static async Task RequestContractSignature(Contract Contract, string Role, string Purpose)
Requests the operator to sign a smart contract.
static void NextBytes(byte[] Buffer)
Generates random bytes into an array.
static ContractsClient ContractsClient
XMPP Contracts Client, if such a compoent is available on the XMPP broker.
static async Task< string > GetCustomErrorHtml(HttpRequest Request, string LocalFileName, string ContentType, byte[] Content)
Gets a custom error HTML document.
static RequiredPrivileges LoggedIn(string[] Privileges)
Authentication mechanism that makes sure the call is made from a session with a valid authenticated u...
static DateTime ScheduleEvent(Action< object > Callback, DateTime When, object State)
Schedules a one-time event.
static async Task< bool > AddScriptResource(string ResourceName, Expression Expression, string ReferenceFileName)
Adds a script resource to the web server hosted by the gateway.
const string GatewayConfigLocalName
GatewayConfiguration
static Task SendGroupChatMessage(string Markdown, string To)
Sends a group chat message to a recipient.
static Task SendGroupChatMessage(string Markdown, string To, string MessageId)
Sends a group chat message to a recipient.
static async Task CheckWAF()
Checks the Web Application Firewall file and loads or reloads it if necessary.
static byte[] ComputeUserPasswordHash(string UserName, string Password)
Computes a hash digest based on a user name and a password, and the current domain.
static HttpxServer HttpxServer
HTTPX Server
static Task SendNotificationUpdate(string Markdown, string MessageId)
Sends a notification message to configured notification recipients.
static RequiredPrivileges LoggedIn(string UserVariable, string[] Privileges)
Authentication mechanism that makes sure the call is made from a session with a valid authenticated u...
static ThingRegistryClient ThingRegistryClient
XMPP Thing Registry Client.
static Task< bool > PetitionLegalIdentity(string LegalId, string PetitionId, string Purpose, EventHandlerAsync< LegalIdentityPetitionResponseEventArgs > Callback, TimeSpan Timeout, HttpRequest Request)
Petitions information about a legal identity from its owner.
static string FindLatestFile(Environment.SpecialFolder[] Folders, string Pattern, bool IncludeSubfolders)
Finds the latest file matching a search pattern, by searching in a set of folders,...
static Task SendChatMessage(string Markdown, string To)
Sends a chat message to a recipient.
static Task< bool > RemoveScriptResource(string ResourceName)
Removes a script resource from the web server hosted by the gateway.
static bool TryGetDefaultPage(string Host, out string DefaultPage)
Tries to get the default page of a host.
static ConcentratorClient ConcentratorClient
XMPP Concentrator Client.
static string[] FindFiles(Environment.SpecialFolder[] Folders, string Pattern, bool IncludeSubfolders, bool BreakOnFirst)
Finds files in a set of folders, and optionally, their subfolders. This method only finds files in fo...
static Task RegisterNonceValue(string Nonce)
Registers a nonce value.
static async Task SafeDispose(IDisposableAsync Object)
Disposes an object, catching and logging any exceptions.
static bool UnregisterHandler(Type PersonalEventType, EventHandlerAsync< PersonalEventNotificationEventArgs > Handler)
Unregisters an event handler of a specific type of personal events.
static int NextInteger(int Max)
Returns a non-negative random integer that is less than the specified maximum.
static Task SendChatMessageUpdate(string Markdown, string To, string MessageId)
Sends a chat message update to a recipient.
static CaseInsensitiveString[] GetNotificationWebHooks()
Returns configured notification webhooks.
static async Task< bool > Start(bool ConsoleOutput, bool LoopbackIntefaceAvailable, string InstanceName)
Starts the gateway.
static DateTime StartTime
Timepoint of starting the gateway.
static string[] GetFolders(Environment.SpecialFolder[] Folders, params string[] AppendWith)
Gets the physical locations of special folders.
static CaseInsensitiveString[] GetNotificationAddresses()
Returns configured notification addresses.
static Task NewMomentaryValues(IThingReference Reference, params Field[] Values)
Reports newly measured values.
static IUser AssertUserAuthenticated(Variables Session, string[] Privileges)
Makes sure a request is being made from a session with a successful user login.
static int RegisterServiceCommand(EventHandlerAsync Callback)
Registers an administrative service command.
static XmppClient XmppClient
XMPP Client connection of gateway.
static CoapEndpoint CoapEndpoint
CoAP Endpoint
static Task< bool > PetitionLegalIdentity(string LegalId, string PetitionId, string Purpose, string Password, EventHandlerAsync< LegalIdentityPetitionResponseEventArgs > Callback, TimeSpan Timeout)
Petitions information about a legal identity from its owner.
static void AppendMultiFormatChatMessageXml(StringBuilder Xml, string Text, string Html, string Markdown)
Appends the XML for a multi-formatted chat message to a string being built.
static void NextBytes(byte[] Buffer, int Offset, int Count)
Generates random bytes into an array.
static bool HasDomain
If a domain name is configured.
static string AddWebSniffer(string SnifferId, string PageResource, TimeSpan MaxLife, BinaryPresentationMethod BinaryPresentationMethod, ICommunicationLayer ComLayer, string UserVariable, params string[] Privileges)
Creates a web sniffer, and adds it to a sniffable object.
static bool CancelScheduledEvent(DateTime When)
Cancels a scheduled event.
static bool UnregisterServiceCommand(EventHandlerAsync Callback)
Unregisters an administrative service command.
static string GetUrl(string LocalResource, HttpServer Server)
Gets a URL for a resource.
static Task SendNotification(string Markdown)
Sends a notification message to configured notification recipients.
static Task< bool > PetitionContract(string ContractId, string PetitionId, string Purpose, EventHandlerAsync< ContractPetitionResponseEventArgs > Callback, TimeSpan Timeout, HttpRequest Request)
Petitions information about a smart contract from its owner.
static DateTime ScheduleEvent(Func< object, Task > Callback, DateTime When, object State)
Schedules a one-time event.
static Task SendGroupChatMessageUpdate(string Markdown, string To, string MessageId)
Sends a group chat message update to a recipient.
static async Task< bool > ExecuteServiceCommand(int CommandNr)
Executes a service command.
static SoftwareUpdateClient SoftwareUpdateClient
XMPP Software Updates Client, if such a compoent is available on the XMPP broker.
static ControlClient ControlClient
XMPP Control Client.
static string AddWebSniffer(string SnifferId, HttpRequest Request, BinaryPresentationMethod BinaryPresentationMethod, ICommunicationLayer ComLayer, string UserVariable, params string[] Privileges)
Creates a web sniffer, and adds it to a sniffable object.
static string GetShortUrl(string Url, bool OneTimeUse)
Shortens a URL temporarily. Shortened URLs are available at most for 24 hours (if used) and 1h if not...
static ProvisioningClient ProvisioningClient
XMPP Provisioning Client.
static MailClient MailClient
XMPP Mail Client, if support for mail-extensions is available on the XMPP broker.
static bool TryGetLocalResourceFileName(string Resource, string Host, out string FileName)
Tries to get a file name for a resource, if local.
static async Task SendGroupChatMessage(string Markdown, string To, string MessageId, string ThreadId)
Sends a group chat message to a recipient.
static Task PublishPersonalEvent(IPersonalEvent PersonalEvent)
Publishes a personal event on the XMPP network.
const string GatewayConfigLocalFileName
Gateway.config
static Task NewMomentaryValues(params Field[] Values)
Reports newly measured values.
static DomainConfiguration Instance
Current instance of configuration.
string Password
Password for PFX file, if any.
byte[] PrivateKey
Private Key
int DynDnsInterval
Interval (in seconds) for checking if the IP address has changed.
string[] AlternativeDomains
Alternative domain names
byte[] PFX
PFX container for certificate and private key, if available.
byte[] Certificate
Certificate
bool UseDomainName
If the server uses a domain name.
bool DynamicDns
If the server uses a dynamic DNS service.
bool UseEncryption
If the server uses server-side encryption.
string Domain
Principal domain name
bool HasCertificate
If the configuration has a certificate.
Contains information about a contract signature request.
string ContractId
Contract ID
void SetContract(Contract Contract)
Sets a parsed contract.
Configures legal identity for the gateway.
Task< bool > PetitionLegalIdentity(string LegalId, string PetitionId, string Purpose, EventHandlerAsync< LegalIdentityPetitionResponseEventArgs > Callback, TimeSpan Timeout, HttpRequest Request)
Petitions information about a legal identity from its owner.
Task< bool > PetitionContract(string ContractId, string PetitionId, string Purpose, EventHandlerAsync< ContractPetitionResponseEventArgs > Callback, TimeSpan Timeout, HttpRequest Request)
Petitions information about a smart contract from its owner.
static LegalIdentityConfiguration Instance
Instance of configuration object.
static string LatestApprovedLegalIdentityId
Latest approved Legal Identity ID.
Notification Configuration
CaseInsensitiveString[] Urls
Notification addresses.
static NotificationConfiguration Instance
Current instance of configuration.
CaseInsensitiveString[] Addresses
Notification addresses.
Abstract base class for system configurations.
virtual Task InitSetup(HttpServer WebServer)
Initializes the setup object.
bool Complete
If the configuration is complete.
abstract Task< string > Title(Language Language)
Gets a title for the system configuration.
virtual Task< bool > SetupConfiguration(HttpServer WebServer)
Waits for the user to provide configuration.
abstract Task ConfigureSystem()
Is called during startup to configure the system.
abstract int Priority
Priority of the setting. Configurations are sorted in ascending order.
abstract string Resource
Resource to be redirected to, to perform the configuration.
virtual Task< bool > SimplifiedConfiguration()
Simplified configuration by configuring simple default values.
abstract Task< bool > EnvironmentConfiguration()
Environment configuration by configuring values available in environment variables.
virtual Task UnregisterSetup(HttpServer WebServer)
Unregisters the setup object.
virtual Task MakeCompleted()
Sets the configuration task as completed.
virtual Task DeferredConfiguration(HttpServer WebServer)
Performs a deferred configuration. Deferred configurations are such that could not be performed durin...
abstract void SetStaticInstance(ISystemConfiguration Configuration)
Sets the static instance of the configuration.
virtual Task CleanupAfterConfiguration(HttpServer WebServer)
Cleans up after configuration has been performed.
string LegalIdentities
JID of legal identities component.
string SoftwareUpdates
JID of software updates component.
XmppCredentials GetCredentials()
Gets connection credentials.
string Geo
JID of geo-spatial publish/subscribe component.
string PubSub
JID of publish/subscribe component.
static XmppConfiguration Instance
Current instance of configuration.
string Host
Host to connect to
string MultiUserChat
JID of Multi-User Chat service.
Echoes what the client sends in.
Represents a file-based resource that can have custom values depending on what domain the resource is...
Provides a resource that allows the caller to login to the gateway through a POST method call.
const string AutoLoginVariableName
Variable to indicate if the user was automatically logged in. Not accessible via script.
Logs the user out from the gateway.
A resource that returns as a single JavaScript file, the following four files:
Proposes a new smart contract
Web Service for working with short URLs.
static string GetShortUrl(string Url, bool OneTimeUse)
Shortens a URL temporarily. Shortened URLs are available at most for 24 hours (if used) and 1h if not...
Sending events to the corresponding web page(s).
Sending sniffer events to the corresponding web page(s).
string SnifferId
Sniffer ID
Defines the Jobs data source. This data source contains a tree structure of jobs of nodes
static async Task< int > DeleteOldEvents(TimeSpan MaxAge)
Deletes old data source events.
CoAP client. CoAP is defined in RFC7252: https://tools.ietf.org/html/rfc7252
Simple base class for classes implementing communication protocols.
void Exception(Exception Exception)
Called to inform the viewer of an exception state.
ISniffer[] Sniffers
Registered sniffers.
virtual void Add(ISniffer Sniffer)
ICommunicationLayer.Add
Task RemoveRange(IEnumerable< ISniffer > Sniffers)
Removes a set of sniffers, if registered.
Represents an HTTP authentication scheme that embeds a collection of authentication schemes,...
Authentication mechanism that makes sure the user has an established session with the web server.
const string DefaultUserVariable
Default user variable: User
Event arguments for custom error content events.
void SetContent(string ContentType, byte[] Content)
Sets custom content to return.
int StatusCode
Status code of error
HttpRequest Request
Current request object.
string ContentType
Content-Type of any content.
byte[] Content
Any content.
Event arguments for customizing sniffers based on remote endpoint.
ISniffer[] Sniffers
Sniffers to use for the connection.
string RemoteEndpoint
Remote Endpoint.
The server understood the request, but is refusing to fulfill it. Authorization will not help and the...
static ForbiddenException AccessDenied(string ObjectId, string ActorId)
Returns a ForbiddenException object, and logs a entry in the event log about the event.
Base class for all HTTP authentication schemes, as defined in RFC-7235: https://datatracker....
Base class of all HTTP Exceptions.
string Value
HTTP Field Value
Publishes a folder with all its files and subfolders through HTTP GET, with optional support for PUT,...
void AllowTypeConversion(params string[] ContentTypes)
Enables content conversion on files in this folder, and its subfolders. If no content types are speci...
void AddDefaultResponseHeader(string Key, string Value)
Adds a default HTTP Response header that will be returned in responses for resources in the folder.
static void ProtectContentType(string ContentType)
Protects a content type, so that it cannot be retrieved in raw format by external parties through any...
An HTTP redirection resource. Incoming requests are redirected to another location.
Represents an HTTP request.
HttpRequestHeader Header
Request header.
string RemoteEndPoint
Remote end-point.
SessionVariables Session
Contains session states, if the resource requires sessions, or null otherwise.
HttpResponse Response
HTTP Response object, if one has been assigned to the request.
Base class for all HTTP resources.
Represets a response of an HTTP client request.
async Task SendResponse()
Sends the response back to the client. If the resource is synchronous, there's no need to call this m...
Task Write(byte[] Data)
Returns binary data in the response.
An HTTP Reverse proxy resource. Incoming requests are reverted to a another web server for processing...
Publishes a web resource whose contents is produced by script.
Implements an HTTP server.
void AddHttpsPorts(params int[] HttpsPorts)
Opens additional HTTPS ports, if not already open.
int[] OpenHttpPorts
HTTP Ports successfully opened.
void RegisterVanityResource(string RegexPattern, string MapTo)
Registers a vanity resource.
void ConfigureMutualTls(ClientCertificates ClientCertificates, bool TrustClientCertificates, bool LockSettings)
Configures Mutual-TLS capabilities of the server. Affects all connections, all resources.
void UpdateCertificate(X509Certificate ServerCertificate)
Updates the server certificate
IWebApplicationFirewall WebApplicationFirewall
Reference to Web Application Firewall (WAF) to help remove unwanted communication from the server
static SessionVariables CreateSessionVariables()
Creates a new collection of variables, that contains access to the global set of variables.
ILoginAuditor LoginAuditor
Reference to login-auditor to help remove malicious users from the server.
IPAddress[] LocalIpAddresses
IP Addresses receiving requests on.
HttpResource Register(HttpResource Resource)
Registers a resource with the server.
bool TryGetResource(HttpRequest Request, out HttpResource Resource, out string SubPath)
Tries to get a resource from the server.
const int DefaultHttpPort
Default HTTP Port (80).
bool TryGetFileName(string LocalUrl, out string FileName)
Tries to get the full path of a file-based resource.
int[] GetPorts(bool Http, bool Https)
Gets open ports
int[] OpenPorts
Ports successfully opened.
int[] OpenHttpsPorts
HTTPS Ports successfully opened.
bool Unregister(HttpResource Resource)
Unregisters a resource from the server.
const int DefaultHttpsPort
Default HTTPS port (443).
async void NetworkChanged()
Adapts the server to changes in the network. This method can be called automatically by calling the c...
void SetHttp2ConnectionSettings(int InitialStreamWindowSize, int InitialConnectionWindowSize, int MaxFrameSize, int MaxConcurrentStreams, int HeaderTableSize, bool EnablePush, bool NoRfc7540Priorities, bool Lock)
HTTP/2 connection settings (SETTINGS).
int UnregisterVanityResources(object Tag)
Unregisters vanity resources tagged with a specific object.
HttpResource RegisterDomainProxy(string LocalDomain, HttpReverseProxyResource DomainProxy)
Registers a domain proxy resource with the server.
override void Add(ISniffer Sniffer)
ICommunicationLayer.Add
void AddHttpPorts(params int[] HttpPorts)
Opens additional HTTP ports, if not already open.
An optionally-sized icon that can be displayed in a user interface.
Base interface to add icons property.
The server has not found anything matching the Request-URI. No indication is given of whether the con...
Manages the OAuth 2 environment.
OAUTH authorize resource, as defined in RFC 6749. https://datatracker.ietf.org/doc/html/rfc6749
OAUTH device authorization resource, as defined in RFC 8628. https://datatracker.ietf....
OAUTH introspection resource, as defined in RFCs 7662. https://datatracker.ietf.org/doc/html/rfc7662
OAUTH client management resource, as defined in RFCs 7591. https://datatracker.ietf....
OAUTH dynamic registration resource, as defined in RFCs 7591 and 7592. https://datatracker....
OAUTH token resource, as defined in RFC 6749. https://datatracker.ietf.org/doc/html/rfc6749
Event arguments for profiling event handlers.
IFlowControl FlowControl
Flow control mechanism used.
Profiler Profiler
Profiler for session.
The response to the request can be found under a different URI and SHOULD be retrieved using a GET me...
The server is currently unable to handle the request due to a temporary overloading or maintenance of...
Collection of session variables.
async Task LockAsync()
Locks the collection. The collection is by default thread safe. But if longer transactions require un...
bool Locked
If the session variables are currently locked.
override bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
void Release()
Releases the collection, previously locked through a call to LockAsync().
The requested resource resides temporarily under a different URI. Since the redirection MAY be altere...
Manages an MQTT connection. Implements MQTT v3.1.1, as defined in http://docs.oasis-open....
Module that controls the life cycle of communication.
static bool Stopping
If the system is stopping.
Manages registration of TCP and UDP ports in an Internet Gateway
static bool IsPublicAddress(IPAddress Address)
Checks if an IPv4 address is public.
Outputs sniffed data to the Console Output, serialized by ConsoleOut.
Outputs sniffed data to an XML file.
Maintains a set of XML-file-based sniffers. File output is organized into subfolders of a given folde...
Provides help with managing avatars.
Implements an XMPP concentrator client interface.
Implements an XMPP concentrator server interface.
IDataSource[] DataSources
All data sources.
SensorServer SensorServer
Sensor server.
static Task< ConcentratorServer > Create(XmppClient Client, params IDataSource[] DataSources)
Creates an XMPP concentrator server interface.
ControlServer ControlServer
Control server.
Contains the definition of a contract
string Provider
JID of the Trust Provider hosting the contract
Role[] Roles
Roles defined in the smart contract.
string ContractId
Contract identity
Adds support for legal identities, smart contracts and signatures to an XMPP client.
Task< bool > LoadKeys(bool CreateIfNone)
Loads keys from the underlying persistence layer.
void SetKeySettingsInstance(string InstanceName, bool Locked)
Sets the key settings instance name.
Implements an XMPP control client interface.
Event arguments for authority events, to associate a Bare JID with an authority that can authorize pr...
IRequestOrigin Authority
Authority associated with Bare JID
Event arguments for sender validation events.
string FromBareJID
Bare JID of resource sending the stanza.
void Reject()
Called from an event handler to reject the sender.
XmlElement Stanza
The stanza.
void Accept()
Called from an event handler to accept the sender.
Adds support for geo-spatial publish/subscribe communication pattern to an XMPP client.
Implements a Proxy resource that allows Web clients to fetch HTTP-based resources over HTTPX.
Class sending and receiving binary streams over XMPP using XEP-0047: In-band Bytestreams: https://xmp...
IbbClient(XmppClient Client, int MaxBlockSize)
Class sending and receiving binary streams over XMPP using XEP-0047: In-band Bytestreams: https://xmp...
Client managing communication with a Multi-User-Chat service. https://xmpp.org/extensions/xep-0045....
Client providing support for server mail-extension.
Event arguments for mail message events
Class managing a SOCKS5 proxy associated with the current XMPP server.
bool HasProxy
If a SOCKS5 proxy has been detected.
Task StartSearch(EventHandlerAsync Callback)
Starts the search of SOCKS5 proxies.
Client managing the Personal Eventing Protocol (XEP-0163). https://xmpp.org/extensions/xep-0163....
Task Publish(string Node, EventHandlerAsync< ItemResultEventArgs > Callback, object State)
Publishes an item on a node.
void RegisterHandler(Type PersonalEventType, EventHandlerAsync< PersonalEventNotificationEventArgs > Handler)
Registers an event handler of a specific type of personal events.
PubSubClient PubSubClient
PubSubClient used for the Personal Eventing Protocol. Use this client to perform administrative tasks...
bool UnregisterHandler(Type PersonalEventType, EventHandlerAsync< PersonalEventNotificationEventArgs > Handler)
Unregisters an event handler of a specific type of personal events.
Event argument base class for node information and JID events.
bool IsPublic
If the device is considered a public device, meaning it's available in searches in the thing registry...
ThingReference Node
Node reference.
Implements an XMPP provisioning client interface.
string OwnerJid
JID of owner, if known or available.
Event arguments for Registration callbacks.
Implements an XMPP thing registry client interface.
Task RegisterThing(MetaDataTag[] MetaDataTags, EventHandlerAsync< RegistrationEventArgs > Callback, object State)
Registers a thing in the Thing Registry. Only things that does not have an owner can register with th...
Client managing communication with a Publish/Subscribe component. https://xmpp.org/extensions/xep-006...
Maintains information about an item in the roster.
SubscriptionState State
roup Current subscription state.
Implements an XMPP sensor client interface.
Task NewMomentaryValues(params Field[] Values)
Reports newly measured values.
Implements an XMPP interface for remote software updates.
Implements the clock synchronization extesion as defined by the Neuro-Foundation (neuro-foundation....
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
XmppState State
Current state of connection.
Task OfflineAndDisposeAsync()
Sends an offline presence, and then disposes the object by calling DisposeAsync.
Task SendMessage(MessageType Type, string To, string CustomXml, string Body, string Subject, string Language, string ThreadId, string ParentThreadId)
Sends a simple chat message
const string NamespaceServiceDiscoveryInfo
http://jabber.org/protocol/disco#info
Task RequestPresenceSubscription(string BareJid)
Requests subscription of presence information from a contact.
async Task Reconnect()
Reconnects a client after an error or if it's offline. Reconnecting, instead of creating a completely...
Task Connect()
Connects the client.
string Domain
Current Domain.
RosterItem GetRosterItem(string BareJID)
Gets a roster item.
Class containing credentials for an XMPP client connection.
string Events
JID of entity to whom events should be sent. Leave blank if events are not to be forwarded.
bool Sniffer
If a sniffer is to be used ('true' or 'false'). If 'true', network communication will be output to th...
string ThingRegistry
JID of Thing Registry to use. Leave blank if no thing registry is to be used.
string Provisioning
JID of Provisioning Server to use. Leave blank if no thing registry is to be used.
Defines the Output data source. This data source contains a tree structure of output of nodes
static async Task< int > DeleteOldEvents(TimeSpan MaxAge)
Deletes old data source events.
Represents a case-insensitive string.
string Value
String-representation of the case-insensitive string. (Representation is case sensitive....
static readonly CaseInsensitiveString Empty
Empty case-insensitive string
string LowerCase
Lower-case representation of the case-insensitive string.
static bool IsNullOrEmpty(CaseInsensitiveString value)
Indicates whether the specified string is null or an CaseInsensitiveString.Empty string.
string Collection
Collection
Event arguments for collection repaired events.
FlagSource[] Flagged
If the collection have been flagged as corrupt, and from what stack traces. Is null,...
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static Task< IPersistentDictionary > GetDictionary(string Collection)
Gets a persistent dictionary containing objects in a collection.
static bool HasProvider
If a database provider is registered.
static void Register(IDatabaseProvider DatabaseProvider)
Registers a database provider for use from the static Database class, throughout the lifetime of the ...
static IDatabaseProvider Provider
Registered database provider.
static async Task Update(object Object)
Updates an object in the database.
static async Task Delete(object Object)
Deletes an object in the database.
static Task< IEnumerable< object > > Find(string Collection, params string[] SortOrder)
Finds objects in a given collection.
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
This filter selects objects that conform to all child-filters provided.
This filter selects objects that have a named field equal to a given value.
Source of code flagging a collection for repair.
int Count
Number of times the collection has been flagged from this source.
string StackTrace
Stack trace of source flagging the collection.
string Reason
Reason for flagging collection.
Static interface for ledger persistence. In order to work, a ledger provider has to be assigned to it...
static bool HasProvider
If a ledger provider is registered.
static ILedgerProvider Provider
Registered ledger provider.
Defines the Processors data source. This data source contains a tree structure of processor of nodes
static async Task< int > DeleteOldEvents(TimeSpan MaxAge)
Deletes old data source events.
Reports folder representing a folder on the file system containing file-based reports.
Defines the Reports data source. This data source contains a tree structure of reports published by d...
static async Task< bool > RegisterRootNode(ReportNode ReportRoot)
Registers a new report root node.
Implements an in-memory cache.
bool Ping(KeyType Key)
Pings an entry in the cache, to keep it from being removed.
void Add(KeyType Key, ValueType Value)
Adds an item to the cache.
Event arguments for cache item removal events.
ValueType Value
Value of item that was removed.
A chunked list is a linked list of chunks of objects of type T .
static async Task< string > ReadAllTextAsync(string FileName)
Reads a text file asynchronously.
static Task WriteAllTextAsync(string FileName, string Text)
Creates a text file asynchronously.
Static class managing binary representations of strings.
static string GetString(byte[] Data, int Offset, int Count, Encoding DefaultEncoding)
Gets a string from its binary representation, taking any Byte Order Mark (BOM) into account.
Orders modules in dependency order.
Static class, loading and initializing assemblies dynamically.
static void Initialize()
Initializes the inventory engine, registering types and interfaces available in Types.
Static class that dynamically manages types and interfaces available in the runtime environment.
static Task< bool > StartAllModules(int Timeout)
Starts all loaded modules.
static void SetModuleParameter(string Name, object Value)
Sets a module parameter. This parameter value will be accessible to modules when they are loaded.
static bool TryGetModuleParameter(string Name, out object Value)
Tries to get a module parameter value.
static IModule[] GetLoadedModules()
Gets an array of loaded modules.
static object Instantiate(Type Type, params object[] Arguments)
Returns an instance of the type Type . If one needs to be created, it is. If the constructor requires...
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
static Task StopAllModules()
Stops all modules.
Contains information about a language.
Language()
Contains information about a language.
Contains information about a namespace in a language.
Basic access point for runtime language localization.
const string SchemaRoot
Expected root in XML files.
static async Task ImportAsync(XmlReader Xml)
Imports language strings into the language database.
const string SchemaResource
Resource name of embedded schema file.
const string SchemaNamespace
Namespace of embedded schema file.
Class that keeps track of events and timing.
void Stop()
Stops measuring time.
ProfilerThread CreateThread(string Name, ProfilerThreadType Type)
Creates a new profiler thread.
string ExportPlantUml(TimeUnit TimeUnit)
Exports events to PlantUML.
double ElapsedSeconds
Elapsed seconds since start.
void Start()
Starts measuring time.
Class that keeps track of events and timing for one thread.
void Start()
Processing starts.
void Exception(System.Exception Exception)
Exception occurred
void Stop()
Processing starts.
void Interval(DateTime From, DateTime To, string Label)
Records an interval in the profiler thread.
void NewState(string State)
Thread changes state.
XMPP-based Service Registration Client.
static async Task< DateTime?> GetRegistrationTime()
Gets the original registration time.
Static class managing persistent settings.
static bool Set(string Key, string Value)
Sets a string-valued setting.
static Task< Dictionary< string, object > > GetWhereKeyLikeAsync(string Key, string Wildcard)
Gets available settings, matching a search filter.
static async Task< string > GetAsync(string Key, string DefaultValue)
Gets a string-valued setting.
static async Task< bool > DeleteAsync(string Key)
Deletes a runtime setting
static async Task< bool > SetAsync(string Key, string Value)
Sets a string-valued setting.
Represents an object that allows single concurrent writers but multiple concurrent readers....
Asynchronous mutex class.
async Task ReleaseMutex()
Releases the mutex earlier aquired via a call to WaitOne.
void Dispose()
IDisposable.Dispose
Task< bool > WaitOne()
Waits for the Mutex to be free, and locks it.
Class that can be used to schedule events in time. It uses a timer to execute tasks at the appointed ...
bool Remove(DateTime When)
Removes an event scheduled for a given point in time.
DateTime Add(DateTime When, Action< object > Callback, object State)
Adds an event.
Class managing a script expression.
string Script
Original script string.
async Task< object > EvaluateAsync(Variables Variables)
Evaluates the expression, using the variables provided in the Variables collection....
Base class for all nodes in a parsed script tree.
Contains information about a variable.
virtual bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
Event arguments for the Assert.UnauthorizedAccess event.
Assembly Assembly
Assembly in which the type is defined.
MethodBase Method
Method being accessed.
StackTrace Trace
StackTrace Trace
Type Type
Type on which the method is defined.
A factory that can create and validate JWT tokens.
static JwtFactory CreateHmacSha256()
Creates a JWT factory that can create and validate JWT tokens using the HMAC-SHA256 algorithm.
Class that monitors login events, and help applications determine malicious intent....
static async void Success(string Message, string UserName, string RemoteEndPoint, string Protocol, params KeyValuePair< string, object >[] Tags)
Handles a successful login attempt.
Number of failing login attempts possible during given time period.
Login state information relating to a remote endpoint
A set of intervals specific for a given endpoint.
byte[] ComputeVariable(byte[] N)
Computes the SPONGE function, as defined in section 4 of NIST FIPS 202.
Implements the SHA3-256 hash function, as defined in section 6.1 in the NIST FIPS 202: https://nvlpub...
Corresponds to a privilege in the system.
Maintains the collection of all privileges in the system.
static async Task LoadAll()
Loads all privileges
Maintains the collection of all roles in the system.
static async Task LoadAll()
Loads all roles
Corresponds to a user in the system.
bool HasPrivilege(string Privilege)
If the user has a given privilege.
Maintains the collection of all users in the system.
static bool HashMethodLocked
If the Hash Method has been registered and locked.
static void Register(HashComputationMethod HashComputationMethod, string HashMethodTypeName, LoginAuditor LoginAuditor, bool Lock)
Registers a Hash Digest Computation Method.
static IUserSource Source
User source.
Web Application Firewall for HttpServer.
static WebApplicationFirewall LoadFromFile(string FileName, ILoginAuditor LoginAuditor, string AppDataFolder)
Loads a WAF definition from file.
Origin of request has maximum authority.
Origin of request has view-only authority.
static HttpAuthenticationScheme[] GetAuthenticationSchemes()
Gets an array of authentication schemes available to authorize access to a web resource.
static async Task CheckLocalWebServerNode()
Checks if the Local Web Server Node has been created.
Event arguments for events that request an URL to a QR code.
string Text
Text to encode.
Defines the Metering Topology data source. This data source contains a tree structure of persistent r...
static async Task< int > DeleteOldEvents(TimeSpan MaxAge)
Deletes old data source events.
const string SourceID
Source ID for the metering topology data source.
Base class for all sensor data fields.
Event arguments for events collecting data sources.
IDataSource[] Sources
Added sources.
bool IsEmpty
If the reference is an empty reference.
Interface for asynchronously disposable objects.
Task DisposeAsync()
Disposes of the object, asynchronously.
Interface for all event sinks.
Interface for system configurations. The gateway will scan all module for system configuration classe...
Interface for content encodings in HTTP transfers.
void ConfigureSupport(bool Dynamic, bool Static)
Configures support for the algorithm.
Interface for observable classes implementing communication protocols.
Interface for sniffers. Sniffers can be added to ICommunicationLayer classes to eavesdrop on communic...
Interface for sets of sniffers.
Interface for personal event objects.
Interface for database providers that can be plugged into the static Database class.
Task Flush()
Persists any pending changes.
Task Start()
Called when processing starts.
Task Stop()
Called when processing ends.
Task Start()
Called when processing starts.
Persistent dictionary that can contain more entries than possible in the internal memory.
Task< bool > ContainsKeyAsync(string key)
Determines whether the System.Collections.Generic.IDictionary{string,object} contains an element with...
Task AddAsync(string key, object value)
Adds an element with the provided key and value to the System.Collections.Generic....
Interface for late-bound modules loaded at runtime.
Basic authorization interface for objects of type T .
Interface for Mutual TLS (mTLS) Clients or TLS servers.
Basic interface for a user.
Interface for datasources that are published through the concentrator interface.
Interface for thing references.
Emoji1SourceFileType
What source files to use when displaying emoji.
delegate string ToString(IElement Element)
Delegate for callback methods that convert an element value to a string.
FromEventLevel
Allows events from a certain level.
SyslogEventSeparation
How events are separated in the Syslog event stream.
delegate Task EventHandlerAsync(object Sender, EventArgs e)
Asynchronous version of EventArgs.
delegate Task< MetaDataTag[]> GetRegistryMetaDataEventHandler(MetaDataTag[] MetaData)
Delegate for events requesting meta data for registration.
delegate Task< IDatabaseProvider > GetDatabaseProviderEventHandler(XmlElement Definition)
Delegate for callback methods used for the creation of database providers.
delegate Task RegistrationEventHandler(MetaDataTag[] MetaData, RegistrationEventArgs e)
Delegate for registration callback methods.
HostDomainOptions
Options on how to handle domain names provided in the Host header.
MqttQualityOfService
MQTT Quality of Service level.
LineEnding
Type of line ending.
BinaryPresentationMethod
How binary data is to be presented.
QoSLevel
Quality of Service Level for asynchronous messages. Support for QoS Levels must be supported by the r...
SubscriptionState
State of a presence subscription.
MessageType
Type of message received.
XmppState
State of XMPP connection.
ClientCertificates
Client Certificate Options
TimeUnit
Options for presenting time in reports.
ProfilerThreadType
Type of profiler thread.
Represents a duration value, as defined by the xsd:duration data type: http://www....
static readonly Duration Zero
Zero value