2using System.Collections.Generic;
3using System.Diagnostics;
6using System.Net.NetworkInformation;
7using System.Reflection;
8using System.Runtime.ExceptionServices;
9using System.Runtime.InteropServices;
10using System.Security.Cryptography;
11using System.Security.Cryptography.X509Certificates;
13using System.Text.RegularExpressions;
14using System.Threading;
15using System.Threading.Tasks;
17using System.Xml.Schema;
142 private const int MaxChunkSize = 4096;
144 private static readonly LinkedList<KeyValuePair<string, int>> ports =
new LinkedList<KeyValuePair<string, int>>();
145 private static readonly Dictionary<int, EventHandlerAsync> serviceCommandByNr =
new Dictionary<int, EventHandlerAsync>();
146 private static readonly Dictionary<EventHandlerAsync, int> serviceCommandNrByCallback =
new Dictionary<EventHandlerAsync, int>();
147 private static readonly Dictionary<string, DateTime> lastUnauthorizedAccess =
new Dictionary<string, DateTime>();
148 private static readonly DateTime startTime = DateTime.Now;
162 private static PepClient pepClient =
null;
167 private static X509Certificate2 certificate =
null;
168 private static DateTime checkCertificate = DateTime.MinValue;
169 private static DateTime checkIp = DateTime.MinValue;
177 private static Scheduler scheduler =
null;
178 private readonly
static RandomNumberGenerator rnd = RandomNumberGenerator.Create();
179 private static AsyncMutex gatewayRunning =
null;
180 private static AsyncMutex startingServer =
null;
182 private static StreamWriter exceptionFile =
null;
186 private static Dictionary<string, string> defaultPageByHostName =
null;
187 private static string instance;
188 private static string appDataFolder;
189 private static string runtimeFolder;
190 private static string rootFolder;
191 private static string applicationName;
192 private static string exceptionFolder =
null;
193 private static string exceptionFileName =
null;
194 private static int nextServiceCommandNr = 128;
195 private static int beforeUninstallCommandNr = 0;
196 private static bool firstStart =
true;
197 private static bool registered =
false;
198 private static bool connected =
false;
199 private static bool immediateReconnect;
200 private static bool consoleOutput;
201 private static bool loopbackIntefaceAvailable;
202 private static bool configuring =
false;
203 private static bool exportExceptions =
false;
204 private static bool stopped =
false;
218 public static Task<bool>
Start(
bool ConsoleOutput)
220 return Start(ConsoleOutput,
true,
string.Empty);
229 public static Task<bool>
Start(
bool ConsoleOutput,
bool LoopbackIntefaceAvailable)
231 return Start(ConsoleOutput, LoopbackIntefaceAvailable,
string.Empty);
241 public static async Task<bool>
Start(
bool ConsoleOutput,
bool LoopbackIntefaceAvailable,
string InstanceName)
243 bool FirstStart = firstStart;
249 gatewayRunning =
new AsyncMutex(
false,
"Waher.IoTGateway.Running" + Suffix);
250 if (!await gatewayRunning.
WaitOne(1000))
253 startingServer =
new AsyncMutex(
false,
"Waher.IoTGateway.Starting" + Suffix);
254 if (!await startingServer.
WaitOne(1000))
258 gatewayRunning =
null;
261 startingServer =
null;
268 consoleOutput = ConsoleOutput;
269 loopbackIntefaceAvailable = LoopbackIntefaceAvailable;
271 appDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
273 if (!appDataFolder.EndsWith(
new string(Path.DirectorySeparatorChar, 1)))
274 appDataFolder += Path.DirectorySeparatorChar;
276 appDataFolder +=
"IoT Gateway";
281 if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && !Directory.Exists(appDataFolder))
282 appDataFolder = appDataFolder.Replace(
"/usr/share",
"/usr/local/share");
284 appDataFolder += Path.DirectorySeparatorChar;
285 rootFolder = appDataFolder +
"Root" + Path.DirectorySeparatorChar;
291 appDataFolder +
"Events" + Path.DirectorySeparatorChar +
"Event Log %YEAR%-%MONTH%-%DAY%T%HOUR%.xml",
292 appDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"EventXmlToHtml.xslt", 7));
295 Assert.UnauthorizedAccess += Assert_UnauthorizedAccess;
305 if (!Directory.Exists(rootFolder))
307 string s = Path.Combine(runtimeFolder,
"Root");
308 if (Directory.Exists(s))
310 CopyFolder(runtimeFolder, appDataFolder,
"*.config",
true);
311 CopyFolders(s, rootFolder,
true);
312 CopyFolders(Path.Combine(runtimeFolder,
"Graphics"), Path.Combine(appDataFolder,
"Graphics"),
true);
313 CopyFolders(Path.Combine(runtimeFolder,
"Transforms"), Path.Combine(appDataFolder,
"Transforms"),
true);
317 string[] ManifestFiles = Directory.GetFiles(runtimeFolder,
"*.manifest", SearchOption.TopDirectoryOnly);
318 Dictionary<string, CopyOptions> ContentOptions =
new Dictionary<string, CopyOptions>();
321 for (i = 0; i < 2; i++)
323 foreach (
string ManifestFile
in ManifestFiles)
325 string FileName = Path.GetFileName(ManifestFile);
326 bool GatewayFile = FileName.StartsWith(
"Waher.IoTGateway", StringComparison.CurrentCultureIgnoreCase);
328 if ((i == 0 && GatewayFile) || (i == 1 && !GatewayFile))
330 CheckContentFiles(ManifestFile, ContentOptions);
332 if (ManifestFile.EndsWith(
"Waher.Utility.Install.manifest"))
333 CheckInstallUtilityFiles(ManifestFile);
347 Task T = Task.Run(() =>
355 XmlDocument Config =
new XmlDocument()
357 PreserveWhitespace =
true
361 if (!File.Exists(GatewayConfigFileName))
364 Config.Load(GatewayConfigFileName);
370 bool TrustClientCertificates =
false;
371 Dictionary<int, KeyValuePair<ClientCertificates, bool>> PortSpecificMTlsSettings =
null;
373 foreach (XmlNode N
in Config.DocumentElement.ChildNodes)
375 if (N is XmlElement E)
379 case "ApplicationName":
380 applicationName = E.InnerText;
384 if (defaultPageByHostName is
null)
385 defaultPageByHostName =
new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
387 defaultPageByHostName[
XML.
Attribute(E,
"host")] = E.InnerText;
392 TrustClientCertificates =
XML.
Attribute(E,
"trustCertificates",
false);
394 foreach (XmlNode N2
in E.ChildNodes)
396 if (N2.LocalName ==
"Port" &&
int.TryParse(N2.InnerText, out
int PortNumber))
398 XmlElement E2 = (XmlElement)N2;
400 bool TrustClientCertificatesPort =
XML.
Attribute(E2,
"trustCertificates", TrustClientCertificates);
402 if (PortSpecificMTlsSettings is
null)
403 PortSpecificMTlsSettings =
new Dictionary<int, KeyValuePair<ClientCertificates, bool>>();
405 PortSpecificMTlsSettings[PortNumber] =
new KeyValuePair<ClientCertificates, bool>(ClientCertificatesPort, TrustClientCertificatesPort);
410 case "ContentEncodings":
411 foreach (XmlNode N2
in E.ChildNodes)
413 if (N2.LocalName ==
"ContentEncoding")
415 XmlElement E2 = (XmlElement)N2;
422 if (Encoding is
null)
432 case "ExportExceptions":
433 exceptionFolder = Path.Combine(appDataFolder,
XML.
Attribute(E,
"folder",
"Exceptions"));
435 if (!Directory.Exists(exceptionFolder))
436 Directory.CreateDirectory(exceptionFolder);
438 DateTime Now = DateTime.Now;
439 string[] ExceptionFiles = Directory.GetFiles(exceptionFolder,
"*.txt", SearchOption.TopDirectoryOnly);
440 foreach (
string ExceptionFile
in ExceptionFiles)
444 DateTime TP = File.GetLastWriteTime(ExceptionFile);
445 if ((Now - TP).TotalDays > 90)
446 File.Delete(ExceptionFile);
449 string XmlFile = Path.ChangeExtension(ExceptionFile,
"xml");
450 if (!File.Exists(XmlFile))
469 exceptionFileName = Path.Combine(exceptionFolder, Now.Year.ToString(
"D4") +
"-" + Now.Month.ToString(
"D2") +
"-" + Now.Day.ToString(
"D2") +
470 " " + Now.Hour.ToString(
"D2") +
"." + Now.Minute.ToString(
"D2") +
"." + Now.Second.ToString(
"D2") +
".txt");
474 exceptionFile = File.CreateText(exceptionFileName);
478 exceptionFile =
null;
482 while (exceptionFile is
null && --MaxTries > 0);
484 exportExceptions = !(exceptionFile is
null);
486 if (exportExceptions)
488 exceptionFile.Write(
"Start of export: ");
489 exceptionFile.WriteLine(DateTime.Now.ToString());
491 AppDomain.CurrentDomain.FirstChanceException += (Sender, e) =>
493 if (!(exceptionFile is
null))
497 if (!exportExceptions || e.Exception.StackTrace.Contains(
"FirstChanceExceptionEventArgs"))
500 exceptionFile.WriteLine(
new string(
'-', 80));
501 exceptionFile.Write(
"Type: ");
503 if (!(e.Exception is
null))
504 exceptionFile.WriteLine(e.Exception.GetType().FullName);
506 exceptionFile.WriteLine(
"null");
508 exceptionFile.Write(
"Time: ");
509 exceptionFile.WriteLine(DateTime.Now.ToString());
511 if (!(e.Exception is
null))
513 LinkedList<Exception> Exceptions =
new LinkedList<Exception>();
514 Exceptions.AddLast(e.Exception);
516 while (!(Exceptions.First is
null))
518 Exception ex = Exceptions.First.Value;
519 Exceptions.RemoveFirst();
521 exceptionFile.WriteLine();
523 exceptionFile.WriteLine(ex.Message);
524 exceptionFile.WriteLine();
526 exceptionFile.WriteLine();
528 if (ex is AggregateException ex2)
530 foreach (Exception ex3
in ex2.InnerExceptions)
531 Exceptions.AddLast(ex3);
533 else if (!(ex.InnerException is
null))
534 Exceptions.AddLast(ex.InnerException);
538 exceptionFile.Flush();
549 if (!(DatabaseProvider is
null))
550 throw new Exception(
"Database provider already initiated.");
555 DatabaseProvider =
null;
557 if (DatabaseProvider is
null)
558 throw new Exception(
"Database provider not defined. Make sure the GetDatabaseProvider event has an appropriate event handler.");
560 internalProvider = DatabaseProvider;
566 await DatabaseProvider.
Start();
574 foreach (XmlNode N2
in E.ChildNodes)
576 if (N2.LocalName ==
"Port")
578 XmlElement E2 = (XmlElement)N2;
580 if (!
string.IsNullOrEmpty(Protocol) &&
int.TryParse(E2.InnerText, out
int Port2))
581 ports.AddLast(
new KeyValuePair<string, int>(Protocol, Port2));
587 List<LoginInterval> LoginIntervals =
new List<LoginInterval>();
589 bool LastMaxInterval =
false;
591 foreach (XmlNode N2
in E.ChildNodes)
593 if (N2.LocalName ==
"Interval")
597 Log.
Error(
"Only the last login auditor interval can be the empty 'eternal' interval.",
602 XmlElement E2 = (XmlElement)N2;
606 Log.
Error(
"Number of attempts must be positive when defining an interval for the LoginAuditor",
611 if (!E2.HasAttribute(
"interval"))
613 LoginIntervals.Add(
new LoginInterval(NrAttempts, TimeSpan.MaxValue));
614 LastMaxInterval =
true;
625 if (Interval <= LastInterval)
627 Log.
Error(
"Login Auditor intervals must be specified in an increasing order.",
633 LastInterval = Interval;
638 if (LoginIntervals.Count == 0)
641 loginAuditor =
new LoginAuditor(
"Login Auditor", LoginIntervals.ToArray());
647 if (DatabaseProvider is
null)
650 Database.CollectionRepaired += Database_CollectionRepaired;
652 await RepairIfInproperShutdown();
670 if (loginAuditor is
null)
691 LinkedList<SystemConfiguration> NewConfigurations =
null;
692 Dictionary<string, Type> SystemConfigurationTypes =
new Dictionary<string, Type>();
693 Dictionary<string, SystemConfiguration> SystemConfigurations =
new Dictionary<string, SystemConfiguration>();
694 bool Configured =
true;
699 if (SystemConfigurationType.IsAbstract || SystemConfigurationType.IsInterface || SystemConfigurationType.IsGenericTypeDefinition)
702 SystemConfigurationTypes[SystemConfigurationType.FullName] = SystemConfigurationType;
709 if (SystemConfigurations.ContainsKey(s))
714 SystemConfigurationTypes.Remove(s);
723 if (NewConfigurations is
null)
724 NewConfigurations =
new LinkedList<SystemConfiguration>();
735 if (NewConfigurations is
null)
736 NewConfigurations =
new LinkedList<SystemConfiguration>();
747 foreach (KeyValuePair<string, Type> P
in SystemConfigurationTypes)
752 SystemConfiguration.Complete =
false;
753 SystemConfiguration.Created = DateTime.Now;
764 if (NewConfigurations is
null)
765 NewConfigurations =
new LinkedList<SystemConfiguration>();
776 if (NewConfigurations is
null)
777 NewConfigurations =
new LinkedList<SystemConfiguration>();
793 SystemConfigurations.Values.CopyTo(configurations, 0);
794 Array.Sort(configurations, (c1, c2) => c1.
Priority - c2.Priority);
797 LinkedList<HttpResource> SetupResources =
null;
803 if (loopbackIntefaceAvailable)
804 Log.
Notice(
"System needs to be configured. This is done by navigating to the loopback interface using a browser on this machine.");
806 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.");
810 ResourceOverride =
"/Starting.md",
811 ResourceOverrideFilter =
"(?<!Login)[.]md(\\?[.]*)?$",
815 webServer.
Register(
"/Starting.md", StartingMd);
816 webServer.CustomError += WebServer_CustomError;
818 SetupResources =
new LinkedList<HttpResource>();
824 SetupResources.AddLast(webServer.
Register(
"/", GoToDefaultPage));
831 Path.Combine(runtimeFolder,
"Graphics",
"Emoji1.zip"), Path.Combine(appDataFolder,
"Graphics"));
835 MarkdownToHtmlConverter.EmojiSource = emoji1_24x24;
836 MarkdownToHtmlConverter.RootFolder = rootFolder;
843 if (!(webServer is
null))
844 await Configuration.
InitSetup(webServer);
847 bool ReloadConfigurations;
851 ReloadConfigurations =
false;
855 bool NeedsCleanup =
false;
859 CurrentConfiguration = Configuration;
861 if (!(webServer is
null))
862 webServer.ResourceOverride = Configuration.
Resource;
866 if (!(startingServer is
null))
870 startingServer =
null;
876 ReloadConfigurations =
true;
881 DateTime StartConfig = DateTime.Now;
889 await RepairIfInproperShutdown();
901 if (NeedsCleanup && !(webServer is
null))
904 if (ReloadConfigurations)
912 if (!(webServer is
null) && SystemConfigurations.TryGetValue(s, out
SystemConfiguration OldConfiguration))
918 if (!(webServer is
null))
932 SystemConfigurations.Values.CopyTo(configurations, 0);
933 Array.Sort(configurations, (c1, c2) => c1.Priority - c2.Priority);
938 if (DateTime.Now.Subtract(StartConfig).TotalSeconds > 2)
942 while (ReloadConfigurations);
947 if (!(webServer is
null))
949 webServer.ResourceOverride =
"/Starting.md";
952 if (!(SetupResources is
null))
963 if (!(certificate is
null))
971 if (!(certificate is
null))
979 webServer.
Register(
"/Starting.md", StartingMd);
980 webServer.ResourceOverride =
"/Starting.md";
981 webServer.LoginAuditor = loginAuditor;
983 webServer.CustomError += WebServer_CustomError;
989 await Configuration.
InitSetup(webServer);
993 await RepairIfInproperShutdown();
997 await Configuration.
InitSetup(webServer);
1011 await WriteWebServerOpenPorts();
1012 webServer.OnNetworkChanged += async (Sender, e) =>
1016 await WriteWebServerOpenPorts();
1018 catch (Exception ex)
1028 webServer.
Register(httpxProxy =
new HttpxProxy(
"/HttpxProxy", xmppClient, MaxChunkSize));
1029 webServer.
Register(
"/", GoToDefaultPage);
1038 if (emoji1_24x24 is
null)
1041 Path.Combine(runtimeFolder,
"Graphics",
"Emoji1.zip"), Path.Combine(appDataFolder,
"Graphics"));
1043 MarkdownToHtmlConverter.EmojiSource = emoji1_24x24;
1044 MarkdownToHtmlConverter.RootFolder = rootFolder;
1049 XmlElement DefaultHttpResponseHeaders = Config.DocumentElement[
"DefaultHttpResponseHeaders"];
1050 if (!(DefaultHttpResponseHeaders is
null))
1052 foreach (XmlNode N
in DefaultHttpResponseHeaders.ChildNodes)
1054 if (N is XmlElement E && E.LocalName ==
"DefaultHttpResponseHeader")
1064 XmlElement FileFolders = Config.DocumentElement[
"FileFolders"];
1065 if (!(FileFolders is
null))
1067 foreach (XmlNode N
in FileFolders.ChildNodes)
1069 if (N is XmlElement E && E.LocalName ==
"FileFolder")
1077 foreach (XmlNode N2
in E.ChildNodes)
1079 if (N2 is XmlElement E2 && E2.LocalName ==
"DefaultHttpResponseHeader")
1084 FileFolder.AddDefaultResponseHeader(HeaderKey, HeaderValue);
1091 XmlElement VanityResources = Config.DocumentElement[
"VanityResources"];
1092 if (!(VanityResources is
null))
1094 foreach (XmlNode N
in VanityResources.ChildNodes)
1096 if (N is XmlElement E && E.LocalName ==
"VanityResource")
1105 catch (Exception ex)
1107 Log.
Error(
"Unable to register vanity resource: " + ex.Message,
1108 new KeyValuePair<string, object>(
"RegEx", RegEx),
1109 new KeyValuePair<string, object>(
"Url", Url));
1115 XmlElement Redirections = Config.DocumentElement[
"Redirections"];
1116 if (!(Redirections is
null))
1118 foreach (XmlNode N
in Redirections.ChildNodes)
1120 if (N is XmlElement E && E.LocalName ==
"Redirection")
1124 bool IncludeSubPaths =
XML.
Attribute(E,
"includeSubPaths",
false);
1131 catch (Exception ex)
1133 Log.
Error(
"Unable to register redirection: " + ex.Message,
1134 new KeyValuePair<string, object>(
"Resource", Resource),
1135 new KeyValuePair<string, object>(
"Location", Location),
1136 new KeyValuePair<string, object>(
"IncludeSubPaths", IncludeSubPaths),
1137 new KeyValuePair<string, object>(
"Permanent", Permanent));
1143 XmlElement ReverseProxy = Config.DocumentElement[
"ReverseProxy"];
1144 if (!(ReverseProxy is
null))
1146 foreach (XmlNode N
in ReverseProxy.ChildNodes)
1148 if (N is XmlElement E && E.LocalName ==
"ProxyResource")
1150 string LocalResource =
XML.
Attribute(E,
"localResource");
1151 string RemoteDomain =
XML.
Attribute(E,
"remoteDomain");
1152 string RemoteFolder =
XML.
Attribute(E,
"remoteFolder");
1155 bool UseSession =
XML.
Attribute(E,
"useSession",
false);
1161 TimeSpan.FromMilliseconds(TimeoutMs), UseSession));
1163 catch (Exception ex)
1165 Log.
Error(
"Unable to register reverse proxy: " + ex.Message,
1166 new KeyValuePair<string, object>(
"LocalResource", LocalResource),
1167 new KeyValuePair<string, object>(
"RemoteDomain", RemoteDomain),
1168 new KeyValuePair<string, object>(
"Encrypted", Encrypted),
1169 new KeyValuePair<string, object>(
"RemotePort", RemotePort),
1170 new KeyValuePair<string, object>(
"RemoteFolder", RemoteFolder),
1171 new KeyValuePair<string, object>(
"UseSession", UseSession),
1172 new KeyValuePair<string, object>(
"TimeoutMs", TimeoutMs));
1178 await LoadScriptResources();
1180 httpxServer =
new HttpxServer(xmppClient, webServer, MaxChunkSize);
1184 httpxProxy.IbbClient = ibbClient;
1185 httpxServer.IbbClient = ibbClient;
1187 httpxProxy.Socks5Proxy = socksProxy;
1188 httpxServer.Socks5Proxy = socksProxy;
1194 Sniffer =
new XmlFileSniffer(appDataFolder +
"HTTP" + Path.DirectorySeparatorChar +
1195 "HTTP Log %YEAR%-%MONTH%-%DAY%T%HOUR%.xml",
1196 appDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"SnifferXmlToHtml.xslt",
1198 webServer.
Add(Sniffer);
1208 catch (Exception ex)
1221 await RepairIfInproperShutdown();
1227 catch (Exception ex)
1240 concentratorServer = await
ConcentratorServer.
Create(xmppClient, thingRegistryClient, provisioningClient, Sources);
1241 avatarClient =
new Networking.XMPP.Avatar.
AvatarClient(xmppClient, pepClient);
1256 ProvisionedMeteringNode.QrCodeUrlRequested += ProvisionedMeteringNode_QrCodeUrlRequested;
1259 DeleteOldDataSourceEvents(
null);
1263 string BinaryFolder = AppDomain.CurrentDomain.BaseDirectory;
1264 string[] LanguageFiles = Directory.GetFiles(BinaryFolder,
"*.lng", SearchOption.AllDirectories);
1267 if (LanguageFiles.Length > 0)
1271 foreach (
string LanguageFile
in LanguageFiles)
1277 FileName = LanguageFile;
1278 if (FileName.StartsWith(BinaryFolder))
1279 FileName = FileName.Substring(BinaryFolder.Length);
1281 DateTime LastWriteTime = File.GetLastWriteTime(LanguageFile);
1284 if (LastWriteTime > LastImportedTime)
1289 XmlDocument Doc =
new XmlDocument()
1291 PreserveWhitespace =
true
1297 using (XmlReader r =
new XmlNodeReader(Doc))
1305 catch (XmlException ex)
1310 catch (Exception ex)
1317 foreach (
string UnhandledException
in Directory.GetFiles(appDataFolder,
"UnhandledException*.txt", SearchOption.TopDirectoryOnly))
1322 File.Delete(UnhandledException);
1324 StringBuilder sb =
new StringBuilder();
1326 sb.AppendLine(
"Unhandled Exception");
1327 sb.AppendLine(
"=======================");
1329 sb.AppendLine(
"```");
1331 sb.AppendLine(
"```");
1335 catch (Exception ex)
1344 await ProcessServiceConfigurations(
false);
1349 if (!(NewConfigurations is
null))
1353 StringBuilder sb =
new StringBuilder();
1355 sb.AppendLine(
"New System Configuration");
1356 sb.AppendLine(
"=============================");
1358 sb.AppendLine(
"A new system configuration is available.");
1359 sb.AppendLine(
"It has been set to simplified configuration, to not stop processing.");
1360 sb.AppendLine(
"You should review the configuration however, as soon as possible.");
1362 sb.Append(
"[Click here to review the new system configuration](http");
1370 sb.AppendLine(
").");
1376 catch (Exception ex)
1382 if (!(webServer is
null))
1384 webServer.ResourceOverride =
null;
1385 webServer.ResourceOverrideFilter =
null;
1388 if (!(startingServer is
null))
1392 startingServer =
null;
1399 catch (Exception ex)
1403 if (!(startingServer is
null))
1407 startingServer =
null;
1410 if (!(gatewayRunning is
null))
1414 gatewayRunning =
null;
1417 ExceptionDispatchInfo.Capture(ex).Throw();
1423 private static Task ProvisionedMeteringNode_QrCodeUrlRequested(
object Sender,
GetQrCodeUrlEventArgs e)
1425 StringBuilder Link =
new StringBuilder();
1426 Link.Append(
"https://");
1428 if (
string.IsNullOrEmpty(
Domain))
1433 Link.Append(
"/QR/");
1434 Link.Append(WebUtility.UrlEncode(e.
Text));
1436 e.Url = Link.ToString();
1438 return Task.CompletedTask;
1443 if (
string.IsNullOrEmpty(webServer?.ResourceOverride))
1454 StringBuilder sb =
new StringBuilder();
1456 sb.AppendLine(
"Title: Starting");
1457 sb.AppendLine(
"Description: The starting page will be displayed while the service is being started.");
1458 sb.AppendLine(
"Cache-Control: max-age=0, no-cache, no-store");
1459 sb.AppendLine(
"Refresh: 2");
1461 sb.AppendLine(
"============================================================================================================================================");
1463 sb.AppendLine(
"Starting Service");
1464 sb.AppendLine(
"====================");
1466 sb.AppendLine(
"Please wait while the service is being started. This page will update automatically.");
1468 Markdown = sb.ToString();
1476 Response.ContentType =
"text/html; charset=utf-8";
1477 await Response.
Write(System.Text.Encoding.UTF8.GetBytes(Html));
1489 private class ModuleStartOrder : IComparer<IModule>
1495 int c1 = this.ModuleCategory(x);
1496 int c2 = this.ModuleCategory(y);
1502 return this.dependencyOrder.Compare(x, y);
1505 private int ModuleCategory(
IModule x)
1507 if (x is Persistence.LifeCycle.DatabaseModule)
1509 else if (x is Runtime.Transactions.TransactionModule)
1512 return int.MaxValue;
1518 private static async Task RepairIfInproperShutdown()
1521 Type ProviderType = DatabaseProvider.GetType();
1522 PropertyInfo AutoRepairReportFolder = ProviderType.GetProperty(
"AutoRepairReportFolder");
1523 AutoRepairReportFolder?.SetValue(DatabaseProvider, Path.Combine(
AppDataFolder,
"Backup"));
1525 MethodInfo MI = ProviderType.GetMethod(
"RepairIfInproperShutdown",
new Type[] { typeof(
string) });
1529 Task T = MI.Invoke(DatabaseProvider,
new object[] {
AppDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"DbStatXmlToHtml.xslt" }) as Task;
1531 if (T is Task<
string[]> StringArrayTask)
1532 DatabaseConfiguration.RepairedCollections = await StringArrayTask;
1533 else if (!(T is
null))
1538 private static async Task WriteWebServerOpenPorts()
1540 StringBuilder sb =
new StringBuilder();
1542 foreach (
int Port
in webServer.
OpenPorts)
1543 sb.AppendLine(Port.ToString());
1549 catch (Exception ex)
1557 DateTime Now = DateTime.Now;
1558 string Key = e.
Trace.ToString();
1560 lock (lastUnauthorizedAccess)
1562 if (lastUnauthorizedAccess.TryGetValue(Key, out DateTime TP) && (Now - TP).TotalHours < 1)
1565 lastUnauthorizedAccess[Key] = Now;
1568 StringBuilder Markdown =
new StringBuilder();
1570 Markdown.AppendLine(
"Unauthorized access detected and prevented.");
1571 Markdown.AppendLine(
"===============================================");
1572 Markdown.AppendLine();
1573 Markdown.AppendLine(
"| Details ||");
1574 Markdown.AppendLine(
"|:---|:---|");
1575 Markdown.Append(
"| Method | `");
1576 Markdown.Append(e.
Method.Name);
1577 Markdown.AppendLine(
"` |");
1578 Markdown.Append(
"| Type | `");
1579 Markdown.Append(e.
Type.FullName);
1580 Markdown.AppendLine(
"` |");
1581 Markdown.Append(
"| Assembly | `");
1582 Markdown.Append(e.
Assembly.GetName().Name);
1583 Markdown.AppendLine(
"` |");
1584 Markdown.Append(
"| Date | ");
1586 Markdown.AppendLine(
" |");
1587 Markdown.Append(
"| Time | ");
1589 Markdown.AppendLine(
" |");
1590 Markdown.AppendLine();
1591 Markdown.AppendLine(
"Stack Trace:");
1592 Markdown.AppendLine();
1593 Markdown.AppendLine(
"```");
1595 Markdown.AppendLine(
"```");
1600 private static void CheckContentFiles(
string ManifestFileName, Dictionary<string, CopyOptions> ContentOptions)
1604 XmlDocument Doc =
new XmlDocument()
1606 PreserveWhitespace =
true
1608 Doc.Load(ManifestFileName);
1610 if (!(Doc.DocumentElement is
null) &&
1611 Doc.DocumentElement.LocalName ==
"Module" &&
1612 Doc.DocumentElement.NamespaceURI ==
"http://waher.se/Schema/ModuleManifest.xsd")
1614 CheckContentFiles(Doc.DocumentElement, runtimeFolder, runtimeFolder, appDataFolder, ContentOptions);
1617 catch (Exception ex)
1623 private enum CopyOptions
1629 private static void CheckContentFiles(XmlElement Element,
string RuntimeFolder,
string RuntimeSubfolder,
string AppDataSubFolder,
1630 Dictionary<string, CopyOptions> ContentOptions)
1632 bool AppDataFolderChecked =
false;
1634 foreach (XmlNode N
in Element.ChildNodes)
1636 if (N is XmlElement E)
1638 switch (E.LocalName)
1642 CheckContentFiles(E,
RuntimeFolder, Path.Combine(RuntimeSubfolder, Name), Path.Combine(AppDataSubFolder, Name),
1648 CopyOptions CopyOptions =
XML.
Attribute(E,
"copy", CopyOptions.IfNewer);
1650 string s = Path.Combine(RuntimeSubfolder, Name);
1651 if (!File.Exists(s))
1654 if (!File.Exists(s))
1658 if (!AppDataFolderChecked)
1660 AppDataFolderChecked =
true;
1662 if (!Directory.Exists(AppDataSubFolder))
1663 Directory.CreateDirectory(AppDataSubFolder);
1666 string s2 = Path.Combine(AppDataSubFolder, Name);
1668 if (CopyOptions == CopyOptions.Always || !File.Exists(s2))
1670 File.Copy(s, s2,
true);
1671 ContentOptions[s2] = CopyOptions;
1675 DateTime TP = File.GetLastWriteTime(s);
1676 DateTime TP2 = File.GetLastWriteTime(s2);
1679 (!ContentOptions.TryGetValue(s2, out CopyOptions CopyOptions2) ||
1680 CopyOptions2 != CopyOptions.Always))
1682 File.Copy(s, s2,
true);
1683 ContentOptions[s2] = CopyOptions;
1692 private static void CheckInstallUtilityFiles(
string ManifestFileName)
1696 XmlDocument Doc =
new XmlDocument()
1698 PreserveWhitespace =
true
1700 Doc.Load(ManifestFileName);
1702 if (!(Doc.DocumentElement is
null) &&
1703 Doc.DocumentElement.LocalName ==
"Module" &&
1704 Doc.DocumentElement.NamespaceURI ==
"http://waher.se/Schema/ModuleManifest.xsd")
1706 string InstallUtilityFolder = Path.Combine(runtimeFolder,
"InstallUtility");
1707 bool NoticeLogged =
false;
1709 if (!Directory.Exists(InstallUtilityFolder))
1710 Directory.CreateDirectory(InstallUtilityFolder);
1712 foreach (XmlNode N
in Doc.DocumentElement.ChildNodes)
1714 if (N is XmlElement E)
1716 switch (E.LocalName)
1720 CopyOptions CopyOptions =
XML.
Attribute(E,
"copy", CopyOptions.IfNewer);
1722 string s = Path.Combine(runtimeFolder, Name);
1723 if (!File.Exists(s))
1726 string s2 = Path.Combine(InstallUtilityFolder, Name);
1728 if (CopyOptions == CopyOptions.IfNewer && File.Exists(s2))
1730 DateTime TP = File.GetLastWriteTime(s);
1731 DateTime TP2 = File.GetLastWriteTime(s2);
1739 NoticeLogged =
true;
1740 Log.
Notice(
"Copying Installation Utility executable files to InstallUtility subfolder.");
1743 File.Copy(s, s2,
true);
1750 catch (Exception ex)
1756 internal static bool ConsoleOutput => consoleOutput;
1762 xmppClient.OnValidateSender += XmppClient_OnValidateSender;
1772 xmppClient.
Add(Sniffer);
1775 Sniffer =
new XmlFileSniffer(appDataFolder +
"XMPP" + Path.DirectorySeparatorChar +
1776 "XMPP Log %YEAR%-%MONTH%-%DAY%T%HOUR%.xml",
1777 appDataFolder +
"Transforms" + Path.DirectorySeparatorChar +
"SnifferXmlToHtml.xslt",
1779 xmppClient.
Add(Sniffer);
1782 if (!
string.IsNullOrEmpty(xmppCredentials.
Events))
1784 string s = xmppCredentials.
Events;
1785 int i = s.IndexOf(
'.');
1787 s = s.Substring(i + 1);
1800 thingRegistryClient.Claimed += ThingRegistryClient_Claimed;
1801 thingRegistryClient.Disowned += ThingRegistryClient_Disowned;
1802 thingRegistryClient.Removed += ThingRegistryClient_Removed;
1805 if (!
string.IsNullOrEmpty(xmppCredentials.
Provisioning))
1808 provisioningClient =
null;
1810 scheduler.
Add(DateTime.Now.AddMinutes(1), CheckConnection,
null);
1812 xmppClient.OnStateChanged += XmppClient_OnStateChanged;
1814 ibbClient =
new Networking.XMPP.InBandBytestreams.
IbbClient(xmppClient, MaxChunkSize);
1831 await contractsClient.
LoadKeys(
true);
1834 contractsClient =
null;
1843 string PackagesFolder = Path.Combine(appDataFolder,
"Packages");
1844 if (!Directory.Exists(PackagesFolder))
1845 Directory.CreateDirectory(PackagesFolder);
1850 softwareUpdateClient =
null;
1853 mailClient.MailReceived += MailClient_MailReceived;
1860 domain = Configuration.
Domain;
1863 for (i = 0; i < c; i++)
1870 await Configuration.CheckDynamicIp();
1874 if (checkIp > DateTime.MinValue)
1876 scheduler.
Remove(checkIp);
1877 checkIp = DateTime.MinValue;
1880 checkIp = scheduler.
Add(DateTime.Now.AddSeconds(Configuration.
DynDnsInterval), CheckIp, Configuration);
1888 await UpdateCertificate(Configuration);
1890 if (checkCertificate > DateTime.MinValue)
1892 scheduler.
Remove(checkCertificate);
1893 checkCertificate = DateTime.MinValue;
1896 checkCertificate = scheduler.
Add(DateTime.Now.AddHours(0.5 +
NextDouble()), CheckCertificate, Configuration);
1920 return H.
ComputeVariable(System.Text.Encoding.UTF8.GetBytes(UserName +
":" + domain +
":" + Password));
1927 if (!(Configuration.
PFX is
null))
1928 certificate =
new X509Certificate2(Configuration.
PFX, Configuration.
Password);
1931 RSACryptoServiceProvider RSA =
new RSACryptoServiceProvider();
1934 certificate =
new X509Certificate2(Configuration.
Certificate)
1946 catch (Exception ex)
1953 catch (Exception ex)
1961 private static async
void CheckCertificate(
object P)
1964 DateTime Now = DateTime.Now;
1968 if (Now.AddDays(50) >= certificate.NotAfter)
1972 if (await Configuration.CreateCertificate())
1975 if (!await UpdateCertificate(Configuration))
1976 Log.
Error(
"Unable to update gatetway with new certificate.");
1980 int DaysLeft = (int)Math.Round((certificate.NotAfter - Now.Date).TotalDays);
1983 Log.
Emergency(
"Unable to generate new certificate.", domain);
1984 else if (DaysLeft < 5)
1985 Log.
Alert(
"Unable to generate new certificate.", domain);
1986 else if (DaysLeft < 10)
1987 Log.
Critical(
"Unable to generate new certificate.", domain);
1988 else if (DaysLeft < 20)
1989 Log.
Error(
"Unable to generate new certificate.", domain);
1991 Log.
Warning(
"Unable to generate new certificate.", domain);
1995 catch (Exception ex)
1997 int DaysLeft = (int)Math.Round((certificate.NotAfter - Now.Date).TotalDays);
2001 else if (DaysLeft < 5)
2008 checkCertificate = scheduler.
Add(DateTime.Now.AddDays(0.5 +
NextDouble()), CheckCertificate, Configuration);
2017 private static async
void CheckIp(
object P)
2023 await Configuration.CheckDynamicIp();
2025 catch (Exception ex)
2031 checkIp = scheduler.
Add(DateTime.Now.AddSeconds(Configuration.
DynDnsInterval), CheckIp, Configuration);
2035 private static async
void DeleteOldDataSourceEvents(
object P)
2041 catch (Exception ex)
2047 ScheduleEvent(DeleteOldDataSourceEvents, DateTime.Today.AddDays(1).AddHours(4),
null);
2064 private static void Initialize()
2066 string Folder = Assembly.GetExecutingAssembly().Location;
2067 if (
string.IsNullOrEmpty(Folder))
2068 Folder = AppDomain.CurrentDomain.BaseDirectory;
2070 runtimeFolder = Path.GetDirectoryName(Folder);
2072 Directory.SetCurrentDirectory(runtimeFolder);
2076 FileName = Path.GetFileName(FileName).ToLower();
2077 if (FileName.StartsWith(
"api-ms-win-") ||
2078 FileName.StartsWith(
"system.") ||
2079 FileName.StartsWith(
"microsoft.") ||
2080 FileName.StartsWith(
"windows.") ||
2081 FileName.StartsWith(
"waher.client.") ||
2082 FileName.StartsWith(
"waher.utility.") ||
2083 FileName.StartsWith(
"mscordaccore_x86_x86_") ||
2084 FileName.StartsWith(
"sos_x86_x86_"))
2091 case "clrcompression.dll":
2092 case "clretwrc.dll":
2097 case "hostpolicy.dll":
2100 case "libglesv2.dll":
2101 case "libskiasharp.dll":
2103 case "mongocrypt.dll":
2104 case "mscordaccore.dll":
2105 case "mscordbi.dll":
2106 case "mscorlib.dll":
2107 case "mscorrc.debug.dll":
2110 case "netstandard.dll":
2111 case "snappy32.dll":
2112 case "snappy64.dll":
2113 case "snappier.dll":
2116 case "sos.netcore.dll":
2117 case "ucrtbase.dll":
2118 case "windowsbase.dll":
2119 case "waher.persistence.fileslw.dll":
2120 case "waher.persistence.serialization.dll":
2121 case "zstdsharp.dll":
2129 private static bool CopyFile(
string From,
string To,
bool OnlyIfNewer)
2134 if (!File.Exists(From))
2137 if (OnlyIfNewer && File.Exists(To))
2139 DateTime ToTP = File.GetLastWriteTimeUtc(To);
2140 DateTime FromTP = File.GetLastWriteTimeUtc(From);
2146 File.Copy(From, To,
true);
2151 private static void CopyFolder(
string From,
string To,
string Mask,
bool OnlyIfNewer)
2153 if (Directory.Exists(From))
2155 if (!Directory.Exists(To))
2156 Directory.CreateDirectory(To);
2158 string[] Files = Directory.GetFiles(From, Mask, SearchOption.TopDirectoryOnly);
2160 foreach (
string File
in Files)
2162 string FileName = Path.GetFileName(File);
2163 CopyFile(File, Path.Combine(To, FileName), OnlyIfNewer);
2168 private static void CopyFolders(
string From,
string To,
bool OnlyIfNewer)
2170 if (Directory.Exists(From))
2172 CopyFolder(From, To,
"*.*", OnlyIfNewer);
2174 string[] Folders = Directory.GetDirectories(From,
"*.*", SearchOption.TopDirectoryOnly);
2176 foreach (
string Folder
in Folders)
2178 string FolderName = Path.GetFileName(Folder);
2179 CopyFolders(Folder, Path.Combine(To, FolderName), OnlyIfNewer);
2191 Log.
Notice(
"Request to stop Gateway, but Gateway already stopped.");
2197 bool StopInternalProvider = !(internalProvider is
null) &&
Database.
Provider != internalProvider;
2205 await Script.Threading.Functions.Background.TerminateTasks(10000);
2208 Database.CollectionRepaired -= Database_CollectionRepaired;
2210 if (StopInternalProvider)
2211 await internalProvider.
Stop();
2213 if (!(startingServer is
null))
2217 startingServer =
null;
2220 if (!(gatewayRunning is
null))
2224 gatewayRunning =
null;
2227 if (!(configurations is
null))
2231 if (Configuration is IDisposable D)
2237 catch (Exception ex)
2244 configurations =
null;
2256 provisioningClient?.
Dispose();
2257 provisioningClient =
null;
2259 thingRegistryClient?.
Dispose();
2260 thingRegistryClient =
null;
2262 concentratorServer?.
Dispose();
2263 concentratorServer =
null;
2266 avatarClient =
null;
2269 sensorClient =
null;
2272 controlClient =
null;
2274 concentratorClient?.
Dispose();
2275 concentratorClient =
null;
2277 synchronizationClient?.
Dispose();
2278 synchronizationClient =
null;
2290 contractsClient =
null;
2292 softwareUpdateClient?.
Dispose();
2293 softwareUpdateClient =
null;
2295 if (!(xmppClient is
null))
2302 coapEndpoint =
null;
2304 if (!(webServer is
null))
2308 webServer.Remove(Sniffer);
2310 if (Sniffer is IDisposable Disposable)
2311 Disposable.Dispose();
2320 if (exportExceptions)
2322 lock (exceptionFile)
2324 exportExceptions =
false;
2326 exceptionFile.WriteLine(
new string(
'-', 80));
2327 exceptionFile.Write(
"End of export: ");
2328 exceptionFile.WriteLine(DateTime.Now.ToString());
2330 exceptionFile.Flush();
2331 exceptionFile.Close();
2334 exceptionFile =
null;
2339 Persistence.LifeCycle.DatabaseModule.Flush().Wait(60000);
2341 if (StopInternalProvider)
2342 internalProvider.
Flush().Wait(60000);
2349 public static X509Certificate2 Certificate => certificate;
2364 public static string InstanceName => instance;
2369 public static string AppDataFolder => appDataFolder;
2374 public static string RuntimeFolder => runtimeFolder;
2379 public static string RootFolder => rootFolder;
2389 public static string ApplicationName
2391 get => applicationName;
2392 internal set => applicationName = value;
2403 public static bool Configuring => configuring;
2413 public static string ConfigFilePath => Path.Combine(appDataFolder, GatewayConfigLocalFileName);
2422 List<int> Result =
new List<int>();
2424 foreach (KeyValuePair<string, int> P
in ports)
2426 if (P.Key == Protocol)
2427 Result.Add(P.Value);
2430 return Result.ToArray();
2439 SortedDictionary<string, bool> Protocols =
new SortedDictionary<string, bool>();
2441 foreach (KeyValuePair<string, int> P
in ports)
2442 Protocols[P.Key] =
true;
2444 string[] Result =
new string[Protocols.Count];
2445 Protocols.Keys.CopyTo(Result, 0);
2457 EventHandlerAsync h = OnTerminate ??
throw new InvalidOperationException(
"No OnTerminate event handler set.");
2458 return h.Raise(instance, EventArgs.Empty,
false);
2475 return TryGetDefaultPage(Request.
Header.
Host?.
Value ??
string.Empty, out DefaultPage);
2486 if (defaultPageByHostName.TryGetValue(Host, out DefaultPage))
2489 if (Host.StartsWith(
"www.", StringComparison.CurrentCultureIgnoreCase) && defaultPageByHostName.TryGetValue(Host.Substring(4), out DefaultPage))
2492 if (defaultPageByHostName.TryGetValue(
string.Empty, out DefaultPage))
2495 DefaultPage =
string.Empty;
2499 internal static void SetDefaultPages(params KeyValuePair<string, string>[] DefaultPages)
2501 Dictionary<string, string> List =
new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase);
2503 foreach (KeyValuePair<string, string> P
in DefaultPages)
2504 List[P.Key] = P.Value;
2506 defaultPageByHostName = List;
2518 if (
string.IsNullOrEmpty(BareJid) ||
2519 (!(xmppClient is
null) &&
2520 (BareJid == xmppClient.
Domain.ToLower() ||
2521 BareJid == xmppClient.
BareJID.ToLower())))
2525 else if (BareJid.IndexOf(
'@') > 0 &&
2526 (xmppClient is
null ||
2532 foreach (XmlNode N
in e.
Stanza.ChildNodes)
2535 return Task.CompletedTask;
2541 return Task.CompletedTask;
2544 private static async
void CheckConnection(
object State)
2550 scheduler.
Add(DateTime.Now.AddMinutes(1), CheckConnection,
null);
2553 if (State2.HasValue &&
2555 !(xmppClient is
null))
2561 catch (Exception ex)
2567 await CheckBackup();
2569 await MinuteTick.Raise(
null, EventArgs.Empty);
2572 catch (Exception ex)
2583 private static async Task XmppClient_OnStateChanged(
object _,
XmppState NewState)
2590 MarkdownToHtmlConverter.BareJID = xmppClient.
BareJID;
2592 if (!registered && !(thingRegistryClient is
null))
2594 _ = Task.Run(async () =>
2600 catch (Exception ex)
2612 immediateReconnect = connected;
2615 if (immediateReconnect &&
2616 !(xmppClient is
null) &&
2652 Log.
Debug(
"No local login: No session.");
2662 LoginAuditor.
Success(
"User logged in by default, since XMPP not configued and loopback interface not available.",
2665 Login.DoLogin(Request, From);
2673 if (i < 0 || !
int.TryParse(
RemoteEndpoint.Substring(i + 1), out
int Port))
2681 if (!IPAddress.TryParse(
RemoteEndpoint.Substring(0, i), out IPAddress Address))
2689 if (!IsLocalCall(Address, Request, DoLog))
2702 Login.DoLogin(Request, From);
2713 switch (Environment.OSVersion.Platform)
2715 case PlatformID.Win32S:
2716 case PlatformID.Win32Windows:
2717 case PlatformID.Win32NT:
2718 case PlatformID.WinCE:
2719 FileName =
"netstat.exe";
2720 Arguments =
"-a -n -o";
2721 WaitForExit =
false;
2726 case PlatformID.Unix:
2727 case PlatformID.MacOSX:
2728 FileName =
"netstat";
2729 Arguments =
"-anv -p tcp";
2737 Log.
Debug(
"No local login: Unsupported operating system: " + Environment.OSVersion.Platform.ToString());
2742 using (Process Proc =
new Process())
2744 ProcessStartInfo StartInfo =
new ProcessStartInfo()
2746 FileName = FileName,
2747 Arguments = Arguments,
2748 WindowStyle = ProcessWindowStyle.Hidden,
2749 UseShellExecute =
false,
2750 RedirectStandardInput =
true,
2751 RedirectStandardOutput =
true,
2752 RedirectStandardError =
true
2755 DateTime Start = DateTime.Now;
2757 Proc.StartInfo = StartInfo;
2762 Proc.WaitForExit(5000);
2763 if (!Proc.HasExited)
2767 string Output = Proc.StandardOutput.ReadToEnd();
2768 DateTime Return = DateTime.Now;
2770 Thread.
Interval(Start, Return,
"Shell");
2773 Log.
Debug(
"Netstat output:\r\n\r\n" + Output);
2775 if (Proc.ExitCode != 0)
2777 Thread.
Exception(
new Exception(
"Exit code: " + Proc.ExitCode.ToString()));
2780 Log.
Debug(
"Netstat exit code: " + Proc.ExitCode.ToString());
2785 string[] Rows = Output.Split(
CommonTypes.
CRLF, StringSplitOptions.RemoveEmptyEntries);
2787 foreach (
string Row
in Rows)
2789 string[] Tokens = Regex.Split(Row,
@"\s+");
2791 switch (Environment.OSVersion.Platform)
2793 case PlatformID.Win32S:
2794 case PlatformID.Win32Windows:
2795 case PlatformID.Win32NT:
2796 case PlatformID.WinCE:
2797 if (Tokens.Length < 6)
2800 if (Tokens[1] !=
"TCP")
2806 if (Tokens[4] !=
"ESTABLISHED")
2809 if (!
int.TryParse(Tokens[5], out
int PID))
2812 Process P = Process.GetProcessById(PID);
2813 int CurrentSession = WTSGetActiveConsoleSessionId();
2815 if (P.SessionId == CurrentSession)
2818 Login.DoLogin(Request, From);
2823 case PlatformID.Unix:
2824 case PlatformID.MacOSX:
2825 if (Tokens.Length < 9)
2828 if (Tokens[0] !=
"tcp4" && Tokens[0] !=
"tcp6")
2834 if (Tokens[5] !=
"ESTABLISHED")
2837 if (!
int.TryParse(Tokens[8], out PID))
2840 P = Process.GetProcessById(PID);
2841 CurrentSession = Process.GetCurrentProcess().SessionId;
2843 if (P.SessionId == CurrentSession)
2846 Login.DoLogin(Request, From);
2853 Log.
Debug(
"No local login: Unsupported operating system: " + Environment.OSVersion.Platform.ToString());
2867 ExceptionDispatchInfo.Capture(ex).Throw();
2869 catch (Exception ex)
2887 if (TotalSeconds >= 1.0)
2891 Log.
Debug(
"Long local login check.\r\n\r\n```uml\r\n" + Uml +
"\r\n```");
2896 private static bool SameEndpoint(
string EP1,
string EP2)
2898 if (
string.Compare(EP1, EP2,
true) == 0)
2901 switch (Environment.OSVersion.Platform)
2903 case PlatformID.Unix:
2904 case PlatformID.MacOSX:
2905 int i = EP1.LastIndexOf(
'.');
2909 if (!
int.TryParse(EP1.Substring(i + 1), out
int Port1))
2912 if (!IPAddress.TryParse(EP1.Substring(0, i), out IPAddress Addr1))
2915 i = EP2.LastIndexOf(
':');
2919 if (!
int.TryParse(EP2.Substring(i + 1), out
int Port2) || Port1 != Port2)
2922 if (!IPAddress.TryParse(EP2.Substring(0, i), out IPAddress Addr2))
2925 string s1 = Addr1.ToString();
2926 string s2 = Addr2.ToString();
2928 if (
string.Compare(s1, s2,
true) == 0)
2937 private static readonly IPAddress ipv6Local = IPAddress.Parse(
"[::1]");
2938 private static readonly IPAddress ipv4Local = IPAddress.Parse(
"127.0.0.1");
2940 private static bool IsLocalCall(IPAddress Address,
HttpRequest Request,
bool DoLog)
2942 if (Address.Equals(ipv4Local) || Address.Equals(ipv6Local))
2946 int i = s.IndexOf(
':');
2948 s = s.Substring(0, i);
2950 if (
string.Compare(s,
"localhost",
true) != 0)
2952 if (!IPAddress.TryParse(s, out IPAddress IP) || !Address.Equals(IP))
2963 foreach (NetworkInterface Interface
in NetworkInterface.GetAllNetworkInterfaces())
2965 if (Interface.OperationalStatus != OperationalStatus.Up)
2968 IPInterfaceProperties Properties = Interface.GetIPProperties();
2970 foreach (UnicastIPAddressInformation UnicastAddress
in Properties.UnicastAddresses)
2972 if (Address.Equals(UnicastAddress.Address))
2978 Log.
Debug(
"IP Address not found among network adapters: " + Address.ToString());
2982 catch (Exception ex)
2992 [DllImport(
"kernel32.dll")]
2993 static extern int WTSGetActiveConsoleSessionId();
3056 if (Session is
null ||
3058 ((
User = v.ValueObject as
IUser) is
null) ||
3086 if (Session is
null ||
3104 #region Thing Registry
3106 private static Task ThingRegistryClient_Claimed(
object Sender,
ClaimedEventArgs e)
3114 return Task.CompletedTask;
3117 private static Task ThingRegistryClient_Disowned(
object Sender, Networking.XMPP.Provisioning.Events.NodeEventArgs e)
3122 ownerJid =
string.
Empty;
3126 return Task.CompletedTask;
3129 private static Task ThingRegistryClient_Removed(
object Sender, Networking.XMPP.Provisioning.Events.NodeEventArgs e)
3132 Log.
Informational(
"Gateway has been removed from the public registry.", ownerJid);
3134 return Task.CompletedTask;
3137 private static async Task Register()
3139 string Key = Guid.NewGuid().ToString().Replace(
"-",
string.Empty);
3148 new MetaDataStringTag(
"PURL",
"https://github.com/PeterWaher/IoTGateway#iotgateway"),
3152 if (!(GetMetaData is
null))
3153 MetaData = await GetMetaData(MetaData);
3155 await thingRegistryClient.
RegisterThing(MetaData, async (sender2, e2) =>
3162 ownerJid = e2.OwnerJid;
3164 ownerJid = string.Empty;
3166 RegistrationEventHandler h = RegistrationSuccessful;
3168 await h(MetaData, e2);
3188 get {
return xmppClient; }
3196 get {
return thingRegistryClient; }
3204 get {
return provisioningClient; }
3212 get {
return concentratorServer; }
3220 get {
return avatarClient; }
3228 get {
return sensorClient; }
3236 get {
return controlClient; }
3244 get {
return concentratorClient; }
3252 get {
return synchronizationClient; }
3260 get {
return pepClient; }
3268 get {
return mucClient; }
3284 get {
return softwareUpdateClient; }
3292 get {
return mailClient; }
3300 get {
return webServer; }
3308 get {
return httpxServer; }
3316 get {
return httpxProxy; }
3324 get {
return socksProxy; }
3332 get {
return coapEndpoint; }
3340 #region Service Commands
3353 lock (serviceCommandByNr)
3355 if (!serviceCommandByNr.TryGetValue(CommandNr, out h))
3361 Log.
Warning(
"Service command lacking command handler invoked.", CommandNr.ToString());
3368 await h(
null, EventArgs.Empty);
3370 catch (Exception ex)
3388 lock (serviceCommandByNr)
3390 if (serviceCommandNrByCallback.TryGetValue(Callback, out i))
3393 i = nextServiceCommandNr++;
3395 serviceCommandNrByCallback[Callback] = i;
3396 serviceCommandByNr[i] = Callback;
3409 lock (serviceCommandByNr)
3411 if (serviceCommandNrByCallback.TryGetValue(Callback, out
int i))
3413 serviceCommandByNr.Remove(i);
3414 serviceCommandNrByCallback.Remove(Callback);
3426 public static int BeforeUninstallCommandNr
3428 get {
return beforeUninstallCommandNr; }
3436 private static Task BeforeUninstall(
object Sender, EventArgs e)
3438 return OnBeforeUninstall.Raise(Sender, e,
false);
3454 return scheduler?.
Add(When, Callback, State) ?? DateTime.MinValue;
3466 return scheduler?.
Add(When, Callback, State) ?? DateTime.MinValue;
3476 return scheduler?.
Remove(When) ??
false;
3481 #region Random number generation
3489 byte[] b =
new byte[8];
3496 double d = BitConverter.ToUInt64(b, 0);
3497 d /= ulong.MaxValue;
3513 throw new ArgumentOutOfRangeException(
"Must be non-negative.", nameof(Max));
3522 Result = (int)(NextDouble() * Max);
3524 while (Result >= Max);
3537 throw new ArgumentException(
"Number of bytes must be non-negative.", nameof(NrBytes));
3539 byte[] Result =
new byte[NrBytes];
3543 rnd.GetBytes(Result);
3551 #region Momentary values
3560 return Task.CompletedTask;
3571 return Task.CompletedTask;
3581 return Task.CompletedTask;
3592 return Task.CompletedTask;
3597 #region Personal Eventing Protocol
3605 if (pepClient is
null)
3606 throw new Exception(
"No PEP client available.");
3616 public static void RegisterHandler(Type PersonalEventType, EventHandlerAsync<PersonalEventNotificationEventArgs> Handler)
3627 public static bool UnregisterHandler(Type PersonalEventType, EventHandlerAsync<PersonalEventNotificationEventArgs> Handler)
3629 if (pepClient is
null)
3639 public static event EventHandlerAsync<ItemNotificationEventArgs> PubSubItemNotification
3641 add => pepClient.NonPepItemNotification += value;
3642 remove => pepClient.NonPepItemNotification -= value;
3649 private static async Task<bool> CheckBackup()
3651 bool Result =
false;
3657 DateTime Now = DateTime.Now;
3659 DateTime EstimatedTime = Now.Date + Timepoint;
3662 if ((Timepoint.Hours == Now.Hour && Timepoint.Minutes == Now.Minute) ||
3663 (lastBackupTimeCheck.HasValue && lastBackupTimeCheck.Value < EstimatedTime && Now >= EstimatedTime) ||
3664 LastBackup.AddDays(1) < EstimatedTime)
3666 lastBackupTimeCheck = Now;
3673 catch (Exception ex)
3686 DateTime Now = DateTime.Now;
3690 StartExport.ExportInfo ExportInfo = await
StartExport.GetExporter(
"Encrypted",
false,
new string[0]);
3694 List<string> Folders =
new List<string>();
3697 Folders.AddRange(FolderCategory.Folders);
3699 await
StartExport.DoExport(ExportInfo,
true,
false,
true, Folders.ToArray());
3707 DeleteOldFiles(ExportFolder, KeepDays, KeepMonths, KeepYears, Now);
3708 if (ExportFolder != KeyFolder)
3709 DeleteOldFiles(KeyFolder, KeepDays, KeepMonths, KeepYears, Now);
3711 await OnAfterBackup.Raise(typeof(
Gateway), EventArgs.Empty);
3714 private static DateTime? lastBackupTimeCheck =
null;
3722 private static void DeleteOldFiles(
string Path,
long KeepDays,
long KeepMonths,
long KeepYears, DateTime Now)
3726 string[] Files = Directory.GetFiles(Path,
"*.*", SearchOption.AllDirectories);
3727 DateTime CreationTime;
3729 foreach (
string FileName
in Files)
3733 CreationTime = File.GetCreationTime(FileName);
3735 if (CreationTime.Day == 1)
3737 if (CreationTime.Month == 1)
3739 if (Now.Year - CreationTime.Year <= KeepYears)
3744 if (((Now.Year * 12 + Now.Month) - (CreationTime.Year * 12 + Now.Month)) <= KeepMonths)
3750 if ((Now.Date - CreationTime.Date).TotalDays <= KeepDays)
3754 File.Delete(FileName);
3759 catch (Exception ex)
3765 catch (Exception ex)
3773 StringBuilder Msg =
new StringBuilder();
3775 Msg.Append(
"Collection repaired: ");
3783 Msg.Append(
"Reason: ");
3786 if (Source.
Count > 1)
3789 Msg.Append(Source.
Count.ToString());
3790 Msg.Append(
" times)");
3795 Msg.AppendLine(
"StackTrace:");
3797 Msg.AppendLine(
"```");
3799 Msg.AppendLine(
"```");
3805 return Task.CompletedTask;
3810 #region Notifications
3812 private static Task MailClient_MailReceived(
object Sender,
MailEventArgs e)
3814 return MailReceived.Raise(Sender, e);
3820 public static event EventHandlerAsync<MailEventArgs> MailReceived =
null;
3828 return SendNotification(Content.Markdown.Functions.ToMarkdown.GraphToMarkdown(
Graph));
3837 return SendNotification(Content.Markdown.Functions.ToMarkdown.PixelsToMarkdown(Pixels));
3846 return SendNotification(Markdown,
string.Empty,
false);
3856 return SendNotification(Markdown, MessageId,
false);
3866 return SendNotification(Markdown, MessageId,
true);
3875 private static async Task SendNotification(
string Markdown,
string MessageId,
bool Update)
3880 (
string Text,
string Html) = await ConvertMarkdown(Markdown);
3883 await SendNotification(Admin, Markdown, Text, Html, MessageId, Update);
3885 catch (Exception ex)
3891 private static Task<(string, string)> ConvertMarkdown(
string Markdown)
3893 return ConvertMarkdown(Markdown,
true,
true);
3896 private static async Task<(string, string)> ConvertMarkdown(
string Markdown,
bool TextVersion,
bool HtmlVersion)
3898 if (TextVersion || HtmlVersion)
3902 ParseMetaData =
false
3906 XmlEntitiesOnly =
true
3912 return (Text, Html);
3915 return (
null,
null);
3927 private static async Task SendNotification(
string To,
string Markdown,
string Text,
string Html,
string MessageId,
bool Update)
3935 ScheduleEvent(Resend, DateTime.Now.AddMinutes(15),
new object[] { To, Markdown, Text, Html, MessageId, Update });
3938 await SendChatMessage(
MessageType.Chat, Markdown, Text, Html, To, MessageId,
string.Empty, Update);
3941 ScheduleEvent(Resend, DateTime.Now.AddSeconds(30),
new object[] { To, Markdown, Text, Html, MessageId, Update });
3951 return SendChatMessage(Markdown, To,
string.Empty);
3962 return SendChatMessage(Markdown, To, MessageId,
string.Empty);
3972 public static async Task
SendChatMessage(
string Markdown,
string To,
string MessageId,
string ThreadId)
3974 (
string Text,
string Html) = await ConvertMarkdown(Markdown);
3975 await SendChatMessage(
MessageType.Chat, Markdown, Text, Html, To, MessageId, ThreadId,
false);
3986 return SendChatMessageUpdate(Markdown, To, MessageId,
string.Empty);
3998 (
string Text,
string Html) = await ConvertMarkdown(Markdown);
3999 await SendChatMessage(
MessageType.Chat, Markdown, Text, Html, To, MessageId, ThreadId,
true);
4009 return SendGroupChatMessage(Markdown, To,
string.Empty);
4020 return SendGroupChatMessage(Markdown, To, MessageId,
string.Empty);
4032 (
string Text,
string Html) = await ConvertMarkdown(Markdown);
4033 await SendChatMessage(
MessageType.GroupChat, Markdown, Text, Html, To, MessageId, ThreadId,
false);
4044 return SendGroupChatMessageUpdate(Markdown, To, MessageId,
string.Empty);
4056 (
string Text,
string Html) = await ConvertMarkdown(Markdown);
4057 await SendChatMessage(
MessageType.GroupChat, Markdown, Text, Html, To, MessageId, ThreadId,
true);
4067 return GetMultiFormatChatMessageXml(Markdown,
true,
true);
4079 (
string Text,
string Html) = await ConvertMarkdown(Markdown, TextVersion, HtmlVersion);
4080 return GetMultiFormatChatMessageXml(Text, Html, Markdown);
4092 StringBuilder Xml =
new StringBuilder();
4093 AppendMultiFormatChatMessageXml(Xml, Text, Html, Markdown);
4094 return Xml.ToString();
4106 if (
string.IsNullOrEmpty(Text))
4107 Xml.Append(
"<body/>");
4110 Xml.Append(
"<body><![CDATA[");
4111 Xml.Append(Text.Replace(
"]]>",
"]] >"));
4112 Xml.Append(
"]]></body>");
4115 if (!
string.IsNullOrEmpty(Markdown))
4117 Xml.Append(
"<content xmlns=\"urn:xmpp:content\" type=\"text/markdown\"><![CDATA[");
4118 Xml.Append(Markdown.Replace(
"]]>",
"]] >"));
4119 Xml.Append(
"]]></content>");
4122 if (!
string.IsNullOrEmpty(Html))
4124 Xml.Append(
"<html xmlns='http://jabber.org/protocol/xhtml-im'>");
4125 Xml.Append(
"<body xmlns='http://www.w3.org/1999/xhtml'>");
4128 IEnumerable<HtmlNode> Children = (Doc.Body ?? Doc.
Root).Children;
4130 if (!(Children is
null))
4136 Xml.Append(
"</body></html>");
4140 private static async Task SendChatMessage(
MessageType Type,
string Markdown,
string Text,
string Html,
string To,
string MessageId,
string ThreadId,
bool Update)
4144 StringBuilder Xml =
new StringBuilder();
4146 AppendMultiFormatChatMessageXml(Xml, Text, Html, Markdown);
4148 if (Update && !
string.IsNullOrEmpty(MessageId))
4150 Xml.Append(
"<replace id='");
4151 Xml.Append(MessageId);
4152 Xml.Append(
"' xmlns='urn:xmpp:message-correct:0'/>");
4154 MessageId =
string.Empty;
4157 await xmppClient.
SendMessage(
QoSLevel.Unacknowledged, Type, MessageId, To, Xml.ToString(),
string.Empty,
4158 string.Empty,
string.Empty, ThreadId,
string.Empty,
null,
null);
4167 public static string GetUrl(
string LocalResource)
4169 return GetUrl(LocalResource, webServer);
4180 StringBuilder sb =
new StringBuilder();
4186 if (certificate is
null)
4208 IPAddress IP4 =
null;
4209 IPAddress IP6 =
null;
4211 if (!(Server is
null))
4215 if (IPAddress.IsLoopback(Addr))
4218 switch (Addr.AddressFamily)
4220 case System.Net.Sockets.AddressFamily.InterNetwork:
4225 case System.Net.Sockets.AddressFamily.InterNetworkV6:
4234 sb.Append(IP4.ToString());
4235 else if (!(IP6 is
null))
4236 sb.Append(IP6.ToString());
4238 sb.Append(Dns.GetHostName());
4241 if (Array.IndexOf(Ports, DefaultPort) < 0 && Ports.Length > 0)
4247 sb.Append(LocalResource);
4249 return sb.ToString();
4258 public static bool IsDomain(
string DomainOrHost,
bool IncludeAlternativeDomains)
4262 if (DomainOrHost == domain)
4265 if (IncludeAlternativeDomains && !(alternativeDomains is
null))
4269 if (s == DomainOrHost)
4276 if (DomainOrHost ==
"localhost" ||
string.IsNullOrEmpty(DomainOrHost))
4279 if (!(webServer is
null))
4283 if (Addr.ToString() == DomainOrHost)
4288 if (DomainOrHost == Dns.GetHostName())
4295 private static async Task Resend(
object P)
4297 object[] P2 = (
object[])P;
4298 await SendNotification((
string)P2[0], (
string)P2[1], (
string)P2[2], (
string)P2[3], (
string)P2[4], (
bool)P2[5]);
4308 internal static async Task SimplifiedConfiguration()
4336 List<WebMenuItem> Result =
new List<WebMenuItem>();
4338 if (Session is
null)
4343 if (Session is
null ||
4347 Result.Add(
new WebMenuItem(
"Login",
"/Login.md"));
4351 if (!(configurations is
null))
4360 if (!Session.
TryGetVariable(
" AutoLogin ", out v) || !(v.ValueObject is
bool AutoLogin) || !AutoLogin)
4364 return Result.ToArray();
4369 #region Smart Contracts
4376 get {
return contractsClient; }
4379 if (contractsClient is
null ||
4380 contractsClient == value ||
4383 contractsClient = value;
4386 throw new InvalidOperationException(
"Not allowed to set a new Contracts Client class.");
4393 public static string LatestApprovedLegalIdentityId
4407 bool RoleFound =
false;
4410 throw new ArgumentException(
"Contract cannot be null.", nameof(
Contract));
4414 foreach (Networking.XMPP.Contracts.Role R in
Contract.
Roles)
4424 throw new ArgumentException(
"Invalid role.", nameof(
Role));
4426 if (
string.IsNullOrEmpty(Purpose) || Purpose.IndexOfAny(
CommonTypes.
CRLF) >= 0)
4427 throw new ArgumentException(
"Invalid purpose.", nameof(Purpose));
4431 string Module =
string.Empty;
4436 StackFrame Frame =
new StackFrame(Skip);
4437 MethodBase Method = Frame.GetMethod();
4441 Type Type = Method.DeclaringType;
4442 Assembly Assembly = Type.Assembly;
4443 Module = Assembly.GetName().Name;
4445 if (Type != typeof(
Gateway) && !Module.StartsWith(
"System."))
4460 if (Request is
null)
4464 Received = DateTime.Now,
4479 int i = Markdown.IndexOf(
"~~~~~~");
4480 int c = Markdown.Length;
4485 while (i < c && Markdown[i] ==
'~')
4488 Markdown = Markdown.Substring(i).TrimStart();
4491 i = Markdown.IndexOf(
"~~~~~~");
4493 Markdown = Markdown.Substring(0, i).TrimEnd();
4502 StringBuilder sb =
new StringBuilder(Markdown);
4505 sb.Append(
"Link: [`");
4508 sb.Append(GetUrl(
"/SignatureRequest.md?RequestId=" + Request.
ObjectId));
4511 Markdown = sb.ToString();
4515 Markdown =
"**Reminder**: Smart Contract [" + Request.ContractId +
"](" +
4516 GetUrl(
"/SignatureRequest.md?RequestId=" + Request.
ObjectId) +
") is waiting for your signature.";
4519 await SendNotification(Markdown);
4521 catch (Exception ex)
4537 EventHandlerAsync<LegalIdentityPetitionResponseEventArgs> Callback, TimeSpan Timeout)
4553 EventHandlerAsync<LegalIdentityPetitionResponseEventArgs> Callback, TimeSpan Timeout)
4567 public static Task<bool>
PetitionContract(
string ContractId,
string PetitionId,
string Purpose,
4568 EventHandlerAsync<ContractPetitionResponseEventArgs> Callback, TimeSpan Timeout)
4583 public static Task<bool>
PetitionContract(
string ContractId,
string PetitionId,
string Purpose,
string Password,
4584 EventHandlerAsync<ContractPetitionResponseEventArgs> Callback, TimeSpan Timeout)
4591 #region Finding Files
4602 public static string[]
FindFiles(Environment.SpecialFolder[] Folders,
string Pattern,
bool IncludeSubfolders,
bool BreakOnFirst)
4616 public static string[]
FindFiles(
string[] Folders,
string Pattern,
bool IncludeSubfolders,
bool BreakOnFirst)
4630 public static string[]
FindFiles(
string[] Folders,
string Pattern,
bool IncludeSubfolders,
int MaxCount)
4644 public static string[]
FindFiles(
string[] Folders,
string Pattern,
int SubfolderDepth,
int MaxCount)
4655 public static string[]
GetFolders(Environment.SpecialFolder[] Folders, params
string[] AppendWith)
4669 public static string FindLatestFile(Environment.SpecialFolder[] Folders,
string Pattern,
bool IncludeSubfolders)
4683 public static string FindLatestFile(
string[] Folders,
string Pattern,
bool IncludeSubfolders)
4697 public static string FindLatestFile(
string[] Folders,
string Pattern,
int SubfolderDepth)
4704 #region Custom Errors
4706 private static readonly Dictionary<string, KeyValuePair<DateTime, MarkdownDocument>> defaultDocuments =
new Dictionary<string, KeyValuePair<DateTime, MarkdownDocument>>();
4711 if (Accept is
null || Accept.
Value ==
"*/*")
4718 if (!
string.IsNullOrEmpty(Html))
4719 e.
SetContent(
"text/html; charset=utf-8", System.Text.Encoding.UTF8.GetBytes(Html));
4737 if (
string.IsNullOrEmpty(ContentType))
4739 IsText = IsMarkdown =
false;
4749 if (IsEmpty || IsText || IsMarkdown)
4754 lock (defaultDocuments)
4756 if (defaultDocuments.TryGetValue(LocalFileName, out KeyValuePair<DateTime, MarkdownDocument> P))
4763 TP = DateTime.MinValue;
4768 string FullFileName = Path.Combine(appDataFolder,
"Default", LocalFileName);
4770 if (File.Exists(FullFileName))
4772 DateTime TP2 = File.GetLastWriteTime(FullFileName);
4777 if (Doc is
null || TP2 > TP)
4782 RootFolder = rootFolder,
4787 Settings.
Variables[
"Request"] = Request;
4791 lock (defaultDocuments)
4793 defaultDocuments[LocalFileName] =
new KeyValuePair<DateTime, MarkdownDocument>(TP2, Doc);
4797 if (IsEmpty || Content is
null)
4801 System.Text.Encoding Encoding =
null;
4802 int i = ContentType.IndexOf(
';');
4808 foreach (KeyValuePair<string, string>
Field in Fields)
4810 if (
string.Compare(
Field.Key,
"CHARSET",
true) == 0)
4815 if (Encoding is
null)
4816 Encoding = System.Text.Encoding.UTF8;
4831 Doc.Tag = DocSynchObj;
4834 if (await DocSynchObj.TryBeginWrite(30000))
4838 Doc.Detail = Detail;
4843 await DocSynchObj.EndWrite();
4853 lock (defaultDocuments)
4855 defaultDocuments.Remove(LocalFileName);
4866 #region Sniffers & Events
4916 int i = Resource.IndexOfAny(
new char[] {
'?',
'#' });
4918 Resource = Resource.Substring(0, i);
4935 public static string AddWebSniffer(
string SnifferId,
string PageResource, TimeSpan MaxLife,
4940 foreach (
ISniffer Sniffer
in ComLayer)
4952 ComLayer.Add(Sniffer);
4955 return "\r\n\r\n\r\n\r\n";
4969 AddWebEventSink(SinkId, Request, TimeSpan.FromHours(1), UserVariable,
Privileges);
4985 int i = Resource.IndexOfAny(
new char[] {
'?',
'#' });
4987 Resource = Resource.Substring(0, i);
4989 AddWebEventSink(SinkId, Resource, MaxLife, UserVariable,
Privileges);
5024 #region Script Resources
5035 if (!await RemoveScriptResource(ResourceName,
true))
5054 if (!await RemoveScriptResource(ResourceName,
true))
5071 return RemoveScriptResource(ResourceName,
false);
5080 private static async Task<bool> RemoveScriptResource(
string ResourceName,
bool ConsiderNonexistantRemoved)
5085 if (!
string.IsNullOrEmpty(SubPath))
5086 return ConsiderNonexistantRemoved;
5098 private static async Task LoadScriptResources()
5102 foreach (KeyValuePair<string, object> Setting
in Settings)
5104 if (!(Setting.Value is
string Value))
5106 Log.
Error(
"Invalid Runtime setting found and ignored.",
5107 new KeyValuePair<string, object>(
"Key", Setting.Key),
5108 new KeyValuePair<string, object>(
"Value", Setting.Value));
5113 string ResourceName = Setting.Key.Substring(23);
5114 string ReferenceFileName;
5118 i = Value.IndexOf(
" ||| ");
5120 ReferenceFileName =
string.Empty;
5123 ReferenceFileName = Value.Substring(0, i);
5124 Value = Value.Substring(i + 5);
5132 catch (Exception ex)
5134 Log.
Error(
"Invalid Runtime setting script. Resource could not be added.",
5135 new KeyValuePair<string, object>(
"Resource", ResourceName),
5136 new KeyValuePair<string, object>(
"Error", ex.Message),
5137 new KeyValuePair<string, object>(
"ReferenceFileName", ReferenceFileName),
5138 new KeyValuePair<string, object>(
"Script", Value));
5153 return ProcessServiceConfigurations(
true);
5156 private static async Task<int> ProcessServiceConfigurations(
bool OnlyIfChanged)
5158 string[] ConfigurationFiles = Directory.GetFiles(appDataFolder,
"*.config", SearchOption.TopDirectoryOnly);
5161 foreach (
string ConfigurationFile
in ConfigurationFiles)
5163 if (await ProcessServiceConfigurationFile(ConfigurationFile, OnlyIfChanged))
5170 private const string ServiceConfigurationRoot =
"ServiceConfiguration";
5171 private const string ServiceConfigurationNamespace =
"http://waher.se/Schema/ServiceConfiguration.xsd";
5184 ConfigurationFileName = Path.GetFullPath(ConfigurationFileName);
5186 string DirectoryName = Path.GetDirectoryName(ConfigurationFileName);
5187 if (!DirectoryName.EndsWith(
new string(Path.DirectorySeparatorChar, 1)))
5188 DirectoryName += Path.DirectorySeparatorChar;
5190 if (
string.Compare(DirectoryName, appDataFolder,
true) != 0)
5193 if (!File.Exists(ConfigurationFileName))
5196 XmlDocument Doc =
new XmlDocument();
5197 Doc.Load(ConfigurationFileName);
5199 if (Doc.DocumentElement.LocalName != ServiceConfigurationRoot || Doc.DocumentElement.NamespaceURI != ServiceConfigurationNamespace)
5202 XSL.
Validate(Path.GetFileName(ConfigurationFileName), Doc, ServiceConfigurationRoot, ServiceConfigurationNamespace,
5205 bool ExecuteInitScript = await Content.Markdown.Functions.InitScriptFile.NeedsExecution(ConfigurationFileName);
5207 if (OnlyIfChanged && !ExecuteInitScript)
5210 Log.
Notice(
"Applying Service Configurations.", ConfigurationFileName);
5214 foreach (XmlNode N
in Doc.DocumentElement.ChildNodes)
5216 if (!(N is XmlElement E))
5219 switch (E.LocalName)
5221 case "VanityResources":
5222 foreach (XmlNode N2
in E.ChildNodes)
5224 if (N2 is XmlElement E2 && E2.LocalName ==
"VanityResource")
5233 catch (Exception ex)
5235 Log.
Error(
"Unable to register vanity resource: " + ex.Message,
5236 new KeyValuePair<string, object>(
"RegEx", RegEx),
5237 new KeyValuePair<string, object>(
"Url", Url));
5243 case "StartupScript":
5249 case "InitializationScript":
5250 if (ExecuteInitScript)
5262 catch (Exception ex)
Helps with parsing of commong data types.
static readonly char[] CRLF
Contains the CR LF character sequence.
static KeyValuePair< string, string >[] ParseFieldValues(string Value)
Parses a set of comma or semicolon-separated field values, optionaly delimited by ' or " characters.
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
static string GetString(byte[] Data, Encoding DefaultEncoding)
Gets a string from its binary representation, taking any Byte Order Mark (BOM) into account.
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)
Exports the HTML document to XML.
const string ContentTypeIcon
image/x-icon
Static class managing encoding and decoding of internet content.
static Encoding GetEncoding(string CharacterSet)
Gets a character encoding from its name.
Class managing GraphViz integration into Markdown documents.
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.
Variables Variables
Collection of variables. Providing such a collection enables script execution inside markdown documen...
Class managing PlantUML integration into Markdown documents.
static void Init(string ContentRootFolder)
Initializes the PlantUML-Markdown integration.
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 managing loading of resources stored as embedded resources or in content files.
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 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 XmlException AnnotateException(XmlException ex)
Creates a new XML Exception object, with reference to the source XML file, for information.
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.
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 an XML file.
Filters incoming events and passes remaining events to a secondary event sink.
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.
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.
Event sink sending events to a destination over the XMPP network.
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 ...
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< 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 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 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.
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 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 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 > PetitionLegalIdentity(string LegalId, string PetitionId, string Purpose, EventHandlerAsync< LegalIdentityPetitionResponseEventArgs > Callback, TimeSpan Timeout)
Petitions information about a legal identity from its owner.
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 RequiredUserPrivileges LoggedIn(string[] Privileges)
Authentication mechanism that makes sure the call is made from a session with a valid authenticated u...
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 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 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 Task< bool > PetitionContract(string ContractId, string PetitionId, string Purpose, EventHandlerAsync< ContractPetitionResponseEventArgs > Callback, TimeSpan Timeout)
Petitions information about a smart contract from its owner.
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 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 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 GetDataSources GetDataSources
Event raised when the Gateway requires a set of data sources to publish.
static ThingRegistryClient ThingRegistryClient
XMPP Thing Registry Client.
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 DateTime ScheduleEvent(ScheduledEventCallback Callback, DateTime When, object State)
Schedules a one-time event.
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 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 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 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 RequiredUserPrivileges LoggedIn(string UserVariable, string LoginPage, string[] Privileges)
Authentication mechanism that makes sure the call is made from a session with a valid authenticated u...
static DateTime ScheduleEvent(ScheduledEventCallbackAsync 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 RequiredUserPrivileges LoggedIn(string UserVariable, string[] Privileges)
Authentication mechanism that makes sure the call is made from a session with a valid authenticated u...
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 ProvisioningClient ProvisioningClient
XMPP Provisioning Client.
static MailClient MailClient
XMPP Mail Client, if support for mail-extensions is available on the XMPP broker.
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 void CheckLocalLogin(HttpRequest Request)
Checks if a web request comes from the local host in the current session. If so, the user is automati...
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
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)
Petitions information about a legal identity from its owner.
static LegalIdentityConfiguration Instance
Instance of configuration object.
Task< bool > PetitionContract(string ContractId, string PetitionId, string Purpose, EventHandlerAsync< ContractPetitionResponseEventArgs > Callback, TimeSpan Timeout)
Petitions information about a smart contract from its owner.
static string LatestApprovedLegalIdentityId
Latest approved Legal Identity ID.
Notification Configuration
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.
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 PubSub
JID of publish/subscribe component.
static XmppConfiguration Instance
Current instance of configuration.
string MultiUserChat
JID of Multi-User Chat service.
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.
Logs the user out from the gateway.
Proposes a new smart contract
Authentication mechanism that makes sure the user has an established session with the IoT Gateway,...
Sending events to the corresponding web page(s).
Sending sniffer events to the corresponding web page(s).
string SnifferId
Sniffer ID
CoAP client. CoAP is defined in RFC7252: https://tools.ietf.org/html/rfc7252
void Dispose()
IDisposable.Dispose
ISniffer[] Sniffers
Registered sniffers.
virtual void Add(ISniffer Sniffer)
ICommunicationLayer.Add
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.
The server understood the request, but is refusing to fulfill it. Authorization will not help and the...
static ForbiddenException AccessDenied(string ObjectId, string ActorId, string MissingPrivilege)
Returns a ForbiddenException object, and logs a entry in the event log about the event.
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.
Variables Session
Contains session states, if the resource requires sessions, or null otherwise.
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...
async 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.
static Variables CreateVariables()
Creates a new collection of variables, that contains access to the global set of variables.
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
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.
const int DefaultHttpPort
Default HTTP Port (80).
bool TryGetResource(string ResourceName, out HttpResource Resource, out string SubPath)
Tries to get a resource from the server.
void Dispose()
IDisposable.Dispose
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...
int UnregisterVanityResources(object Tag)
Unregisters vanity resources tagged with a specific object.
override void Add(ISniffer Sniffer)
ICommunicationLayer.Add
void AddHttpPorts(params int[] HttpPorts)
Opens additional HTTP ports, if not already open.
The server has not found anything matching the Request-URI. No indication is given of whether the con...
The server is currently unable to handle the request due to a temporary overloading or maintenance of...
The requested resource resides temporarily under a different URI. Since the redirection MAY be altere...
Module that controls the life cycle of communication.
static bool Stopping
If the system is stopping.
Outputs sniffed data to the Console Output, serialized by ConsoleOut.
Outputs sniffed data to an XML file.
Provides help with managing avatars.
override void Dispose()
Disposes of the extension.
AvatarClient(XmppClient Client)
Provides help with managing avatars.
Implements an XMPP concentrator client interface.
override void Dispose()
Disposes of the extension.
Implements an XMPP concentrator server interface.
override void Dispose()
Disposes of the extension.
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.
override void Dispose()
Disposes of the extension.
void SetKeySettingsInstance(string InstanceName, bool Locked)
Sets the key settings instance name.
Implements an XMPP control client interface.
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.
Implements a Proxy resource that allows Web clients to fetch HTTP-based resources over HTTPX.
void Dispose()
IDisposable.Dispose
override void Dispose()
IDisposable.Dispose
Class sending and receiving binary streams over XMPP using XEP-0047: In-band Bytestreams: https://xmp...
override void Dispose()
Disposes of the extension.
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....
override void Dispose()
Disposes of the extension.
Client providing support for server mail-extension.
override void Dispose()
Disposes of the 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.
override void Dispose()
Disposes of the extension.
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.
override void Dispose()
Disposes of the extension.
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...
override void Dispose()
Disposes of the extension.
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.
override void Dispose()
Disposes of the extension.
Task NewMomentaryValues(params Field[] Values)
Reports newly measured values.
Implements an XMPP interface for remote software updates.
override void Dispose()
Disposes of the extension.
Implements the clock synchronization extesion as defined by the Neuro-Foundation (neuro-foundation....
void Dispose()
IDisposable.Dispose()
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.
virtual void Dispose()
Disposes of the extension.
Represents a case-insensitive string.
static readonly CaseInsensitiveString Empty
Empty case-insensitive 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 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.
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 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.
void Dispose()
IDisposable.Dispose
DateTime Add(DateTime When, ScheduledEventCallback 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 ContainsVariable(string Name)
If the collection contains a variable with a given name.
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.
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
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.
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.
bool IsEmpty
If the reference is an empty reference.
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 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.
Interface for late-bound modules loaded at runtime.
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.
delegate bool CustomEventFilterDelegate(Event Event)
Delegate for custom event filters.
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< IDataSource[]> GetDataSources(params IDataSource[] DataSources)
Delegate for events requesting an array of data sources.
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.
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.
delegate void ScheduledEventCallback(object State)
Callback method for scheduled events.
delegate Task ScheduledEventCallbackAsync(object State)
Callback method for asynchronous scheduled events.
Represents a duration value, as defined by the xsd:duration data type: http://www....
static readonly Duration Zero
Zero value