Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
GatewayConfigSource.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Reflection;
5using System.Text;
6using System.Threading.Tasks;
7using System.Xml;
8using Waher.Content;
11using Waher.Events;
19using Waher.Things;
21
23{
27 public class GatewayConfigSource : IDataSource, IDisposable
28 {
29 private readonly static Dictionary<string, INode> nodesById = new Dictionary<string, INode>();
30 private static IEnumerable<INode> nodes = null;
31 private static GeneralInformation generalInformation = null;
32 private static WebServer webServer = null;
33 private static DatabaseDefinition databaseDefinition = null;
34 private static Ports ports = null;
35 private static LoginAuditorNode loginAuditor = null;
36 private static DateTime writeTime = DateTime.MinValue;
37 private static GatewayConfigSource instance = null;
38 internal static DateTime nodesTimestamp = DateTime.MinValue;
39
43 public const string GatewayConfigSourceID = "GatewayConfig";
44
49 {
50 instance = this;
51 this.LoadConfiguration();
52 }
53
57 public void Dispose()
58 {
59 }
60
61 private void CheckLoadConfiguration()
62 {
63 if (nodes is null || nodesTimestamp < this.LastChanged)
64 this.LoadConfiguration();
65 }
66
67 private void LoadConfiguration()
68 {
69 try
70 {
71 string GatewayConfigFileName = Gateway.ConfigFilePath;
72 if (!File.Exists(GatewayConfigFileName))
73 {
74 GatewayConfigFileName = Gateway.GatewayConfigLocalFileName;
75 if (!File.Exists(GatewayConfigFileName))
76 throw new Exception("Gateway.config not found.");
77 }
78
79 XmlDocument Config = new XmlDocument();
80 Config.Load(GatewayConfigFileName);
81
83 XSL.LoadSchema(typeof(Gateway).Namespace + ".Schema.GatewayConfiguration.xsd", typeof(Gateway).Assembly));
84
85 generalInformation = new GeneralInformation(this);
86 webServer = new WebServer(this);
87 databaseDefinition = new DatabaseDefinition(this);
88 ports = new Ports(this);
89 loginAuditor = null;
90
91 List<INode> Nodes = new List<INode>()
92 {
93 generalInformation,
94 webServer,
95 databaseDefinition,
96 ports
97 };
98
99 Dictionary<string, bool> ContentEncodingsFound = new Dictionary<string, bool>();
100
101 foreach (XmlNode N in Config.DocumentElement.ChildNodes)
102 {
103 if (N is XmlElement E)
104 {
105 switch (E.LocalName)
106 {
107 case "ApplicationName":
108 generalInformation.ApplicationName = E.InnerText;
109 break;
110
111 case "DefaultPage":
112 DefaultPage DefaultPage = new DefaultPage(this, webServer, XML.Attribute(E, "host"), E.InnerText);
113 webServer.AddInternal(DefaultPage);
114 break;
115
116 case "MutualTls":
117 webServer.ClientCertificates = XML.Attribute(E, "clientCertificates", ClientCertificates.NotUsed);
118 webServer.TrustClientCertificates = XML.Attribute(E, "trustCertificates", false);
119
120 foreach (XmlNode N2 in E.ChildNodes)
121 {
122 if (N2.LocalName == "Port" && int.TryParse(N2.InnerText, out int PortNumber))
123 {
124 XmlElement E2 = (XmlElement)N2;
125 ClientCertificates ClientCertificatesPort = XML.Attribute(E2, "clientCertificates", webServer.ClientCertificates);
126 bool TrustClientCertificatesPort = XML.Attribute(E2, "trustCertificates", webServer.TrustClientCertificates);
127
128 webServer.AddInternal(new MTlsPort(this, webServer, PortNumber, ClientCertificatesPort, TrustClientCertificatesPort));
129 }
130 }
131 break;
132
133 case "ContentEncodings":
134 foreach (XmlNode N2 in E.ChildNodes)
135 {
136 if (N2.LocalName == "ContentEncoding")
137 {
138 XmlElement E2 = (XmlElement)N2;
139 string Method = XML.Attribute(E2, "method");
140 bool Dynamic = XML.Attribute(E2, "dynamic", true);
141 bool Static = XML.Attribute(E2, "static", true);
142
143 IContentEncoding Encoding = Types.FindBest<IContentEncoding, string>(Method);
144
145 Encoding?.ConfigureSupport(Dynamic, Static);
146 ContentEncodingsFound[Method] = true;
147
148 webServer.AddInternal(new ContentEncoding(this, webServer, Method, Dynamic, Static));
149 }
150 }
151
153 break;
154
155 case "ExportExceptions":
156 generalInformation.ExceptionFolder = XML.Attribute(E, "folder", "Exceptions");
157 break;
158
159 case "Database":
160 databaseDefinition.Folder = XML.Attribute(E, "folder");
161 databaseDefinition.DefaultCollectionName = XML.Attribute(E, "defaultCollectionName", string.Empty);
162 databaseDefinition.BlockSize = XML.Attribute(E, "blockSize", 0);
163 databaseDefinition.BlocksInCache = XML.Attribute(E, "blocksInCache", 0);
164 databaseDefinition.BlobBlockSize = XML.Attribute(E, "blobBlockSize", 0);
165 databaseDefinition.TimeoutMs = XML.Attribute(E, "timeoutMs", 0);
166 databaseDefinition.Encrypted = XML.Attribute(E, "encrypted", false);
167 databaseDefinition.Compiled = XML.Attribute(E, "compiled", false);
168 break;
169
170 case "Ports":
171 foreach (XmlNode N2 in E.ChildNodes)
172 {
173 if (N2.LocalName == "Port")
174 {
175 XmlElement E2 = (XmlElement)N2;
176 string Protocol = XML.Attribute(E2, "protocol");
177 if (!string.IsNullOrEmpty(Protocol) && int.TryParse(E2.InnerText, out int PortNumber))
178 ports.AddInternal(new Port(this, ports, Protocol, PortNumber));
179 }
180 }
181 break;
182
183 case "DefaultHttpResponseHeaders":
184 foreach (XmlNode N2 in E.ChildNodes)
185 {
186 if (N2.LocalName == "DefaultHttpResponseHeader")
187 {
188 XmlElement E2 = (XmlElement)N2;
189 string Name = XML.Attribute(E2, "key");
190 string Value = XML.Attribute(E2, "value");
191 webServer.AddInternal(new DefaultHttpResponseHeader(this, webServer, Name, Value));
192 }
193 }
194 break;
195
196 case "FileFolders":
197 foreach (XmlNode N2 in E.ChildNodes)
198 {
199 if (N2.LocalName == "FileFolder")
200 {
201 XmlElement E2 = (XmlElement)N2;
202 string WebFolder = XML.Attribute(E2, "webFolder");
203 string FolderPath = XML.Attribute(E2, "folderPath");
204 FileFolder Folder = new FileFolder(this, webServer, WebFolder, FolderPath);
205 webServer.AddInternal(Folder);
206
207 foreach (XmlNode N3 in E2.ChildNodes)
208 {
209 if (N3.LocalName == "DefaultHttpResponseHeader")
210 {
211 XmlElement E3 = (XmlElement)N3;
212 string Name = XML.Attribute(E3, "key");
213 string Value = XML.Attribute(E3, "value");
214 Folder.AddInternal(new DefaultHttpResponseHeader(this, Folder, Name, Value));
215 }
216 }
217 }
218 }
219 break;
220
221 case "VanityResources":
222 foreach (XmlNode N2 in E.ChildNodes)
223 {
224 if (N2.LocalName == "VanityResource")
225 {
226 XmlElement E2 = (XmlElement)N2;
227 string Regex = XML.Attribute(E2, "regex");
228 string Url = XML.Attribute(E2, "url");
229 webServer.AddInternal(new VanityResource(this, webServer, Regex, Url));
230 }
231 }
232 break;
233
234 case "Redirections":
235 foreach (XmlNode N2 in E.ChildNodes)
236 {
237 if (N2.LocalName == "Redirection")
238 {
239 XmlElement E2 = (XmlElement)N2;
240 string Resource = XML.Attribute(E2, "resource");
241 string Location = XML.Attribute(E2, "location");
242 bool IncludeSubPaths = XML.Attribute(E2, "includeSubPaths", false);
243 bool Permanent = XML.Attribute(E2, "permanent", false);
244 webServer.AddInternal(new Redirection(this, webServer, Resource, Location, IncludeSubPaths, Permanent));
245 }
246 }
247 break;
248
249 case "ReverseProxy":
250 foreach (XmlNode N2 in E.ChildNodes)
251 {
252 if (N2.LocalName == "ProxyResource")
253 {
254 XmlElement E2 = (XmlElement)N2;
255 string LocalResource = XML.Attribute(E2, "localResource");
256 string RemoteDomain = XML.Attribute(E2, "remoteDomain");
257 string RemoteFolder = XML.Attribute(E2, "remoteFolder");
258 bool Encrypted = XML.Attribute(E2, "encrypted", false);
259 int RemotePort = XML.Attribute(E2, "remotePort", Encrypted ? HttpServer.DefaultHttpsPort : HttpServer.DefaultHttpPort);
260 bool UseSession = XML.Attribute(E2, "useSession", false);
261 int TimeoutMs = XML.Attribute(E2, "timeoutMs", 10000);
262 webServer.AddInternal(new ProxyResource(this, webServer, LocalResource, RemoteDomain, RemoteFolder,
263 RemotePort, Encrypted, UseSession, TimeoutMs));
264 }
265 }
266 break;
267
268 case "LoginAuditor":
269 if (loginAuditor is null)
270 {
271 loginAuditor = new LoginAuditorNode(this);
272 Nodes.Add(loginAuditor);
273
274 foreach (XmlNode N2 in E.ChildNodes)
275 {
276 if (N2.LocalName == "Interval")
277 {
278 XmlElement E2 = (XmlElement)N2;
279 int NrAttempts = XML.Attribute(E2, "nrAttempts", 0);
280 Duration? Interval = XML.Attribute(E2, "interval", Duration.Zero);
281 if (Interval.Value <= Duration.Zero)
282 Interval = null;
283
284 loginAuditor.AddInternal(new IntervalNode(this, NrAttempts, Interval));
285 }
286 }
287 }
288 else
289 Log.Error("Only one LoginAuditor element permitted.", GatewayConfigFileName);
290 break;
291 }
292 }
293 }
294
295 if (loginAuditor is null)
296 {
297 loginAuditor = new LoginAuditorNode(this);
298 Nodes.Add(loginAuditor);
299 }
300
301 foreach (Type T in Types.GetTypesImplementingInterface(typeof(IContentEncoding)))
302 {
303 IContentEncoding Encoding;
304
305 try
306 {
307 ConstructorInfo CI = Types.GetDefaultConstructor(T);
308 if (CI is null)
309 continue;
310
311 Encoding = (IContentEncoding)CI.Invoke(Types.NoParameters);
312 }
313 catch (Exception)
314 {
315 continue; // Ignore
316 }
317
318 if (ContentEncodingsFound.ContainsKey(Encoding.Label))
319 continue;
320
321 ContentEncodingsFound[Encoding.Label] = true;
322
323 webServer.AddInternal(new ContentEncoding(this, webServer, Encoding.Label, Encoding.SupportsDynamicEncoding,
324 Encoding.SupportsStaticEncoding));
325 }
326
327 lock (nodesById)
328 {
329 nodes = Nodes.ToArray();
330 nodesTimestamp = this.LastChanged;
331
332 nodesById.Clear();
333
334 foreach (INode Node in nodes)
335 {
336 nodesById[Node.NodeId] = Node;
337
338 if (Node is ConfigurationNode ConfigurationNode && ConfigurationNode.HasChildren)
339 {
340 foreach (INode Child in ConfigurationNode.Children)
341 nodesById[Child.NodeId] = Child;
342 }
343 }
344 }
345 }
346 catch (Exception ex)
347 {
348 Log.Exception(ex);
349 }
350 }
351
356
360 public bool HasChildren => false;
361
365 public DateTime LastChanged => File.GetLastWriteTimeUtc(Gateway.ConfigFilePath);
366
370 public IEnumerable<IDataSource> ChildSources => null;
371
375 public IEnumerable<INode> RootNodes
376 {
377 get
378 {
379 this.CheckLoadConfiguration();
380 return nodes;
381 }
382 }
383
387 public event EventHandlerAsync<SourceEvent> OnEvent;
388
394 public Task<bool> CanViewAsync(RequestOrigin Caller)
395 {
396 return XmppServerModule.IsAdmin(Caller.From);
397 }
398
404 public Task<string> GetNameAsync(Language Language)
405 {
406 return Language.GetStringAsync(typeof(GatewayConfigSource), 1, "Gateway configuration");
407 }
408
414 public Task<INode> GetNodeAsync(IThingReference NodeRef)
415 {
416 if (NodeRef.SourceId != this.SourceID || !string.IsNullOrEmpty(NodeRef.Partition))
417 return Task.FromResult<INode>(null);
418
419 lock (nodesById)
420 {
421 if (nodesById.TryGetValue(NodeRef.NodeId, out INode Node))
422 return Task.FromResult(Node);
423 else
424 return Task.FromResult<INode>(null);
425 }
426 }
427
428 private Task RaiseSourceEvent(SourceEvent Event)
429 {
430 return this.OnEvent.Raise(this, Event);
431 }
432
433 internal async Task NodeAdded(INode Node, bool External)
434 {
435 if (!External)
436 ScheduleSave();
437
438 await this.RaiseSourceEvent(await Things.SourceEvents.NodeAdded.FromNode(Node, await Translator.GetDefaultLanguageAsync(),
439 RequestOrigin.Empty, false));
440
441 lock (nodesById)
442 {
443 nodesById[Node.NodeId] = Node;
444 }
445 }
446
447 internal async Task NodeUpdated(INode Node, bool External)
448 {
449 if (!External)
450 ScheduleSave();
451
452 await this.RaiseSourceEvent(await Things.SourceEvents.NodeUpdated.FromNode(Node, await Translator.GetDefaultLanguageAsync(),
454
455 lock (nodesById)
456 {
457 if (nodesById.TryGetValue(Node.NodeId, out INode Node2) && Node == Node2)
458 return;
459
460 foreach (KeyValuePair<string, INode> P in nodesById)
461 {
462 if (P.Value == Node)
463 {
464 nodesById.Remove(P.Key);
465 break;
466 }
467 }
468
469 nodesById[Node.NodeId] = Node;
470 }
471 }
472
473 internal async Task NodeDeleted(INode Node, bool External)
474 {
475 if (!External)
476 ScheduleSave();
477
478 await this.RaiseSourceEvent(NodeRemoved.FromNode(Node));
479
480 lock (nodesById)
481 {
482 if (nodesById.TryGetValue(Node.NodeId, out INode Node2) && Node == Node2)
483 nodesById.Remove(Node.NodeId);
484 }
485 }
486
487 private static void ScheduleSave()
488 {
489 if (writeTime > DateTime.MinValue)
490 {
491 Gateway.CancelScheduledEvent(writeTime);
492 writeTime = DateTime.MinValue;
493 }
494
495 writeTime = Gateway.ScheduleEvent(SaveFile, DateTime.Now.AddSeconds(5), null);
496 }
497
498 private static async Task SaveFile(object _)
499 {
500 try
501 {
502 string ConfigFileName = Path.Combine(Gateway.AppDataFolder, Gateway.GatewayConfigLocalFileName);
503 string BakFileName = Path.Combine(Gateway.AppDataFolder, Gateway.GatewayConfigLocalFileName + ".bak");
504
505 if (File.Exists(BakFileName))
506 File.Delete(BakFileName);
507
508 if (File.Exists(ConfigFileName))
509 {
510 string OldConfig = await Resources.ReadAllTextAsync(ConfigFileName);
511
512 Log.Notice("Gateway.config file updated.\r\n\r\nOld Config file:\r\n\r\n```\r\n" + OldConfig + "\r\n```",
513 ConfigFileName, string.Empty, "GatewayConfigUpdated");
514
515 File.Move(ConfigFileName, BakFileName);
516 }
517
518 using (FileStream fs = File.Create(ConfigFileName))
519 {
520 using (XmlWriter Xml = XmlWriter.Create(fs, XML.WriterSettings(true, false, Encoding.UTF8)))
521 {
522 Xml.WriteStartDocument();
524
525 Xml.WriteComment("The configuration file in the program data folder, will have precedence over the configuration file in the installation folder.");
526 Xml.WriteComment("When upgrading, the configuration file in the installation folder will be updated, but the configuration file in the program data");
527 Xml.WriteComment("folder will be maintained. If you make changes to the configuration file, make a copy and place it in the program data folder, and");
528 Xml.WriteComment("edit it there. This will make sure you don't lose any changes when you update the software.");
529
530 Xml.WriteElementString("ApplicationName", generalInformation.ApplicationName);
531
532 if (webServer.HasChildren)
533 {
534 foreach (INode Node in await webServer.ChildNodes)
535 {
536 if (Node is DefaultPage DefaultPage)
537 {
538 Xml.WriteStartElement("DefaultPage");
539
540 if (!string.IsNullOrEmpty(DefaultPage.Host))
541 Xml.WriteAttributeString("host", DefaultPage.Host);
542
543 Xml.WriteValue(DefaultPage.Page);
544 Xml.WriteEndElement();
545 }
546 }
547 }
548
549 Xml.WriteStartElement("MutualTls");
550 Xml.WriteAttributeString("clientCertificates", webServer.ClientCertificates.ToString());
551 Xml.WriteAttributeString("trustCertificates", CommonTypes.Encode(webServer.TrustClientCertificates));
552
553 foreach (INode Node in await webServer.ChildNodes)
554 {
555 if (Node is MTlsPort MTlsPort)
556 {
557 Xml.WriteStartElement("Port");
558 Xml.WriteAttributeString("clientCertificates", MTlsPort.ClientCertificates.ToString());
559 Xml.WriteAttributeString("trustCertificates", CommonTypes.Encode(MTlsPort.TrustClientCertificates));
560 Xml.WriteValue(MTlsPort.PortNumber.ToString());
561 Xml.WriteEndElement();
562 }
563 }
564
565 Xml.WriteEndElement();
566
567 if (webServer.HasChildren)
568 {
569 Dictionary<string, bool> Found = new Dictionary<string, bool>();
570
571 Xml.WriteStartElement("ContentEncodings");
572
573 foreach (INode Node in await webServer.ChildNodes)
574 {
575 if (Node is ContentEncoding ContentEncoding)
576 {
577 Xml.WriteStartElement("ContentEncoding");
578 Xml.WriteAttributeString("method", ContentEncoding.Method);
579 Xml.WriteAttributeString("dynamic", CommonTypes.Encode(ContentEncoding.Dynamic));
580 Xml.WriteAttributeString("static", CommonTypes.Encode(ContentEncoding.Static));
581 Xml.WriteEndElement();
582
583 Found[ContentEncoding.Method] = true;
584 }
585 }
586
587 foreach (Type T in Types.GetTypesImplementingInterface(typeof(IContentEncoding)))
588 {
589 IContentEncoding Encoding;
590
591 try
592 {
593 ConstructorInfo CI = Types.GetDefaultConstructor(T);
594 if (CI is null)
595 continue;
596
597 Encoding = (IContentEncoding)CI.Invoke(Types.NoParameters);
598 }
599 catch (Exception)
600 {
601 continue; // Ignore
602 }
603
604 if (Found.ContainsKey(Encoding.Label))
605 continue;
606
607 Found[Encoding.Label] = true;
608
609 Xml.WriteStartElement("ContentEncoding");
610 Xml.WriteAttributeString("method", Encoding.Label);
611 Xml.WriteAttributeString("dynamic", CommonTypes.Encode(Encoding.SupportsDynamicEncoding));
612 Xml.WriteAttributeString("static", CommonTypes.Encode(Encoding.SupportsStaticEncoding));
613 Xml.WriteEndElement();
614 }
615
616 Xml.WriteEndElement();
617 }
618
619 Xml.WriteStartElement("Database");
620 Xml.WriteAttributeString("folder", databaseDefinition.Folder);
621 Xml.WriteAttributeString("defaultCollectionName", databaseDefinition.DefaultCollectionName);
622 Xml.WriteAttributeString("blockSize", databaseDefinition.BlockSize.ToString());
623 Xml.WriteAttributeString("blocksInCache", databaseDefinition.BlocksInCache.ToString());
624 Xml.WriteAttributeString("blobBlockSize", databaseDefinition.BlobBlockSize.ToString());
625 Xml.WriteAttributeString("timeoutMs", databaseDefinition.TimeoutMs.ToString());
626 Xml.WriteAttributeString("encrypted", CommonTypes.Encode(databaseDefinition.Encrypted));
627 Xml.WriteAttributeString("compiled", CommonTypes.Encode(databaseDefinition.Compiled));
628 Xml.WriteEndElement();
629
630 Xml.WriteStartElement("Ports");
631
632 if (ports.HasChildren)
633 {
634 foreach (INode Node in await ports.ChildNodes)
635 {
636 if (Node is Port Port)
637 {
638 Xml.WriteStartElement("Port");
639 Xml.WriteAttributeString("protocol", Port.Protocol);
640 Xml.WriteValue(Port.PortNumber.ToString());
641 Xml.WriteEndElement();
642 }
643 }
644 }
645
646 Xml.WriteEndElement();
647
648 if (webServer.HasChildren)
649 {
650 Xml.WriteStartElement("DefaultHttpResponseHeaders");
651
652 foreach (INode Node in await webServer.ChildNodes)
653 {
654 if (Node is DefaultHttpResponseHeader DefaultHttpResponseHeader)
655 {
656 Xml.WriteStartElement("DefaultHttpResponseHeader");
657 Xml.WriteAttributeString("key", DefaultHttpResponseHeader.Name);
658 Xml.WriteAttributeString("value", DefaultHttpResponseHeader.Value);
659 Xml.WriteEndElement();
660 }
661 }
662
663 Xml.WriteEndElement();
664 Xml.WriteStartElement("FileFolders");
665
666 Xml.WriteComment("Add a sequence of FileFolder elements. Each FileFolder element creates a web folder defined by the webFolder attribute. These folder resources are absolute");
667 Xml.WriteComment("resources. Each web folder will be mapped to a corresponding folder on the local machine or in the network, defined by the folderPath attribute. ");
668 Xml.WriteComment("");
669 Xml.WriteComment("Example:");
670 Xml.WriteComment("");
671 Xml.WriteComment("<FileFolder webFolder=\"/Folder\" folderPath=\"\\\\Server\\Path\"/>");
672
673 foreach (INode Node in await webServer.ChildNodes)
674 {
675 if (Node is FileFolder FileFolder)
676 {
677 Xml.WriteStartElement("FileFolder");
678 Xml.WriteAttributeString("webFolder", FileFolder.WebFolder);
679 Xml.WriteAttributeString("folderPath", FileFolder.FolderPath);
680 Xml.WriteEndElement();
681 }
682 }
683
684 Xml.WriteEndElement();
685 }
686
687 if (webServer.HasChildren)
688 {
689 Xml.WriteStartElement("VanityResources");
690
691 foreach (INode Node in await webServer.ChildNodes)
692 {
693 if (Node is VanityResource VanityResource)
694 {
695 Xml.WriteStartElement("VanityResource");
696 Xml.WriteAttributeString("regex", VanityResource.Regex);
697 Xml.WriteAttributeString("url", VanityResource.Url);
698 Xml.WriteEndElement();
699 }
700 }
701
702 Xml.WriteEndElement();
703
704 Xml.WriteStartElement("Redirections");
705
706 foreach (INode Node in await webServer.ChildNodes)
707 {
708 if (Node is Redirection Redirection)
709 {
710 Xml.WriteStartElement("Redirection");
711 Xml.WriteAttributeString("resource", Redirection.Resource);
712 Xml.WriteAttributeString("location", Redirection.Location);
713 Xml.WriteAttributeString("includeSubPaths", CommonTypes.Encode(Redirection.IncludeSubPaths));
714 Xml.WriteAttributeString("permanent", CommonTypes.Encode(Redirection.Permanent));
715 Xml.WriteEndElement();
716 }
717 }
718
719 Xml.WriteEndElement();
720
721 Xml.WriteStartElement("ReverseProxy");
722
723 foreach (INode Node in await webServer.ChildNodes)
724 {
725 if (Node is ProxyResource ProxyResource)
726 {
727 Xml.WriteStartElement("ProxyResource");
728 Xml.WriteAttributeString("localResource", ProxyResource.LocalResource);
729 Xml.WriteAttributeString("remoteDomain", ProxyResource.RemoteDomain);
730 Xml.WriteAttributeString("remoteFolder", ProxyResource.RemoteFolder);
731 Xml.WriteAttributeString("remotePort", ProxyResource.RemotePort.ToString());
732 Xml.WriteAttributeString("encrypted", CommonTypes.Encode(ProxyResource.Encrypted));
733 Xml.WriteAttributeString("useSession", CommonTypes.Encode(ProxyResource.UseSession));
734 Xml.WriteAttributeString("timeoutMs", ProxyResource.TimeoutMs.ToString());
735 Xml.WriteEndElement();
736 }
737 }
738
739 Xml.WriteEndElement();
740 }
741
742 if (!string.IsNullOrEmpty(generalInformation.ExceptionFolder))
743 {
744 Xml.WriteStartElement("ExportExceptions");
745 Xml.WriteAttributeString("folder", generalInformation.ExceptionFolder);
746 Xml.WriteEndElement();
747 }
748
749 if (!(loginAuditor is null))
750 {
751 IEnumerable<INode> Intervals = await loginAuditor.ChildNodes;
752 bool Empty = true;
753
754 foreach (INode _2 in Intervals)
755 {
756 Empty = false;
757 break;
758 }
759
760 if (!Empty)
761 {
762 Xml.WriteStartElement("LoginAuditor");
763
764 foreach (INode Node in Intervals)
765 {
766 if (Node is IntervalNode Interval)
767 {
768 Xml.WriteStartElement("Interval");
769 Xml.WriteAttributeString("nrAttempts", Interval.NrAttempts.ToString());
770
771 if (Interval.Interval.HasValue)
772 Xml.WriteAttributeString("interval", Interval.Interval.Value.ToString());
773
774 Xml.WriteEndElement();
775 }
776 }
777
778 Xml.WriteEndElement();
779 }
780 }
781
782 Xml.WriteEndElement();
783 Xml.WriteEndDocument();
784
785 Xml.Flush();
786 }
787 }
788
789 await Task.Delay(5000);
790 }
791 catch (Exception ex)
792 {
793 Log.Exception(ex);
794 }
795 finally
796 {
797 writeTime = DateTime.MinValue;
798 }
799 }
800
805 internal static async Task FileUpdated()
806 {
807 try
808 {
809 if (writeTime > DateTime.MinValue)
810 return;
811
812 Log.Notice("Gateway.config changed outside of the system. Loading configuration.");
813
814 Dictionary<string, INode> OldNodes = new Dictionary<string, INode>();
815 List<INode> Updated = new List<INode>();
816 List<INode> Added = new List<INode>();
817
818 lock (nodesById)
819 {
820 foreach (KeyValuePair<string, INode> P in nodesById)
821 OldNodes[P.Key] = P.Value;
822 }
823
824 instance.LoadConfiguration();
825
826 lock (nodesById)
827 {
828 foreach (KeyValuePair<string, INode> P in nodesById)
829 {
830 if (OldNodes.Remove(P.Key))
831 Updated.Add(P.Value);
832 else
833 Added.Add(P.Value);
834 }
835 }
836
837 foreach (INode Node in OldNodes.Values)
838 await instance.NodeDeleted(Node, true);
839
840 foreach (INode Node in Added)
841 await instance.NodeAdded(Node, true);
842
843 foreach (INode Node in Updated)
844 await instance.NodeUpdated(Node, true);
845 }
846 catch (Exception ex)
847 {
848 Log.Exception(ex);
849 }
850 }
851 }
852}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
Definition: CommonTypes.cs:594
Static class managing loading of resources stored as embedded resources or in content files.
Definition: Resources.cs:15
static async Task< string > ReadAllTextAsync(string FileName)
Reads a text file asynchronously.
Definition: Resources.cs:205
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
static XmlWriterSettings WriterSettings(bool Indent, bool OmitXmlDeclaration)
Gets an XML writer settings object.
Definition: XML.cs:1177
Static class managing loading of XSL resources stored as embedded resources or in content files.
Definition: XSL.cs:15
static XmlSchema LoadSchema(string ResourceName)
Loads an XML schema from an embedded resource.
Definition: XSL.cs:23
static void Validate(string ObjectID, XmlDocument Xml, params XmlSchema[] Schemas)
Validates an XML document given a set of XML schemas.
Definition: XSL.cs:118
Class representing an event.
Definition: Event.cs:10
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
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.
Definition: Log.cs:1647
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.
Definition: Log.cs:682
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.
Definition: Log.cs:450
Static class managing the runtime environment of the IoT Gateway.
Definition: Gateway.cs:126
static string ConfigFilePath
Full path to Gateway.config file.
Definition: Gateway.cs:2413
const string GatewayConfigNamespace
http://waher.se/Schema/GatewayConfiguration.xsd
Definition: Gateway.cs:140
static string AppDataFolder
Application data folder.
Definition: Gateway.cs:2369
const string GatewayConfigLocalName
GatewayConfiguration
Definition: Gateway.cs:135
static DateTime ScheduleEvent(ScheduledEventCallback Callback, DateTime When, object State)
Schedules a one-time event.
Definition: Gateway.cs:3452
static bool CancelScheduledEvent(DateTime When)
Cancels a scheduled event.
Definition: Gateway.cs:3474
const string GatewayConfigLocalFileName
Gateway.config
Definition: Gateway.cs:130
Accept-Encoding HTTP Field header. (RFC 2616, §14.3)
static void ContentEncodingsReconfigured()
If Content-Encodings have been reconfigured.
Implements an HTTP server.
Definition: HttpServer.cs:36
const int DefaultHttpPort
Default HTTP Port (80).
Definition: HttpServer.cs:40
const int DefaultHttpsPort
Default HTTPS port (443).
Definition: HttpServer.cs:45
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:14
static object[] NoParameters
Contains an empty array of parameter values.
Definition: Types.cs:548
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
Definition: Types.cs:84
static ConstructorInfo GetDefaultConstructor(Type Type)
Gets the default constructor of a type, if one exists.
Definition: Types.cs:1630
Contains information about a language.
Definition: Language.cs:17
Task< string > GetStringAsync(Type Type, int Id, string Default)
Gets the string value of a string ID. If no such string exists, a string is created with the default ...
Definition: Language.cs:209
Contains information about a namespace in a language.
Definition: Namespace.cs:17
Basic access point for runtime language localization.
Definition: Translator.cs:16
static async Task< Language > GetDefaultLanguageAsync()
Gets the default language.
Definition: Translator.cs:223
virtual Task< IEnumerable< INode > > ChildNodes
Child nodes. If no child nodes are available, null is returned.
virtual bool HasChildren
If the source has any child sources.
int TimeoutMs
Timeout of database operations, in milliseconds.
int BlockSize
Number of bytes of each B-Tree block in the database.
int BlocksInCache
Number of blocks to maintain in internal memory.
string Folder
Folder, relative to the application data folder, where object database files will be stored.
bool Compiled
If object serializers should be compiled or not.
int BlobBlockSize
Number of bytes of each BLOB block in the database.
string DefaultCollectionName
Name of the collection to use, if the class definition lacks a collection definition.
IEnumerable< IDataSource > ChildSources
Child sources. If no child sources are available, null is returned.
Task< string > GetNameAsync(Language Language)
Gets the name of data source.
const string GatewayConfigSourceID
Data source mirroring the Gateway.config file.
Task< bool > CanViewAsync(RequestOrigin Caller)
If the data source is visible to the caller.
GatewayConfigSource()
Data source mirroring the Gateway.config file.
Task< INode > GetNodeAsync(IThingReference NodeRef)
Gets the node, given a reference to it.
EventHandlerAsync< SourceEvent > OnEvent
Event raised when a data source event has been raised.
IEnumerable< INode > RootNodes
Root node references. If no root nodes are available, null is returned.
Contains configuration of the Login Auditor.
Root node of port numbers to use.
Definition: Ports.cs:11
ClientCertificates ClientCertificates
mTLS-configuration
Definition: WebServer.cs:37
bool TrustClientCertificates
If certificates are to be trusted, or if they are required to be valid.
Definition: WebServer.cs:45
Service Module hosting the XMPP broker and its components.
Tokens available in request.
Definition: RequestOrigin.cs:9
static readonly RequestOrigin Empty
Empty request origin.
string From
Address of caller.
static NodeRemoved FromNode(INode Node)
Creates an event object from a node object.
Definition: NodeRemoved.cs:30
Abstract base class for all data source events.
Definition: SourceEvent.cs:13
Interface for content encodings in HTTP transfers.
bool SupportsStaticEncoding
If encoding can be used for static encoding.
void ConfigureSupport(bool Dynamic, bool Static)
Configures support for the algorithm.
bool SupportsDynamicEncoding
If encoding can be used for dynamic encoding.
string Label
Label identifying the Content-Encoding
Interface for datasources that are published through the concentrator interface.
Definition: IDataSource.cs:14
Interface for nodes that are published through the concentrator interface.
Definition: INode.cs:49
Interface for thing references.
string Partition
Optional partition in which the Node ID is unique.
string SourceId
Optional ID of source containing node.
ClientCertificates
Client Certificate Options
Represents a duration value, as defined by the xsd:duration data type: http://www....
Definition: Duration.cs:13
static readonly Duration Zero
Zero value
Definition: Duration.cs:532