Listener.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. using GenHTTP.Api.Content;
  2. using GenHTTP.Api.Infrastructure;
  3. using GenHTTP.Api.Protocol;
  4. using GenHTTP.Engine;
  5. using GenHTTP.Modules.Practices;
  6. using InABox.API;
  7. using InABox.Core;
  8. using NPOI.SS.Formula.Functions;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.Diagnostics.CodeAnalysis;
  12. using System.IO;
  13. using System.Linq;
  14. using System.Net;
  15. using System.Security.Cryptography.X509Certificates;
  16. using System.Text;
  17. using System.Threading.Tasks;
  18. using System.Timers;
  19. using Timer = System.Timers.Timer;
  20. namespace PRSServices;
  21. public abstract class Handler<TProperties> : IHandler
  22. {
  23. public IHandler Parent { get; set; }
  24. public abstract void Init(TProperties properties);
  25. public abstract ValueTask<IResponse?> HandleAsync(IRequest request);
  26. public ValueTask PrepareAsync()
  27. {
  28. return new ValueTask();
  29. }
  30. public IEnumerable<ContentElement> GetContent(IRequest request)
  31. {
  32. return Enumerable.Empty<ContentElement>();
  33. }
  34. }
  35. public class HandlerBuilder<THandler, TProperties> : IHandlerBuilder<HandlerBuilder<THandler, TProperties>>
  36. where THandler : Handler<TProperties>, new()
  37. {
  38. private readonly List<IConcernBuilder> _Concerns = new();
  39. public HandlerBuilder(TProperties properties)
  40. {
  41. Properties = properties;
  42. }
  43. private TProperties Properties;
  44. public HandlerBuilder<THandler, TProperties> Add(IConcernBuilder concern)
  45. {
  46. _Concerns.Add(concern);
  47. return this;
  48. }
  49. public IHandler Build(IHandler parent)
  50. {
  51. return Concerns.Chain(parent, _Concerns, p => {
  52. var handler = new THandler { Parent = p };
  53. handler.Init(Properties);
  54. return handler;
  55. });
  56. }
  57. }
  58. public class Listener<THandler, TProperties>
  59. where THandler : Handler<TProperties>, new()
  60. where TProperties : notnull
  61. {
  62. private CertificateManager CertificateManager;
  63. private ushort Port;
  64. private IServerHost host;
  65. private TProperties Properties;
  66. public Listener(TProperties properties)
  67. {
  68. CertificateManager = new CertificateManager();
  69. CertificateManager.UpdateCertificate += CertificateManager_UpdateCertificate;
  70. CertificateManager.CertificateExpiring += CertificateManager_CertificateExpiring;
  71. CertificateManager.CertificateExpired += CertificateManager_CertificateExpired;
  72. Init(properties);
  73. }
  74. private void CertificateManager_CertificateExpired()
  75. {
  76. Logger.Send(LogType.Information, "", "Expiry of certificate reached; restarting HTTPS listener...");
  77. Restart();
  78. }
  79. private void CertificateManager_CertificateExpiring(DateTime expiry)
  80. {
  81. string message;
  82. if (expiry.Date == DateTime.Now.Date)
  83. {
  84. message = $"HTTPS Certificate will expire today at {expiry.TimeOfDay:hh\\:mm}";
  85. }
  86. else
  87. {
  88. message = $"HTTPS Certificate will expire in {(expiry - DateTime.Now).Days} at {expiry:dd/MM/yyyy hh:mm}";
  89. }
  90. Logger.Send(LogType.Information, "", message);
  91. }
  92. private void CertificateManager_UpdateCertificate(X509Certificate2 certificate)
  93. {
  94. Logger.Send(LogType.Information, "", "HTTPS Certificate with greater expiry date found; restarting HTTPS listener...");
  95. Restart();
  96. }
  97. [MemberNotNull("host", "Properties")]
  98. public void Init(TProperties properties)
  99. {
  100. Properties = properties;
  101. host = Host.Create()
  102. .Console()
  103. .Handler(new HandlerBuilder<THandler, TProperties>(properties))
  104. .Defaults();
  105. }
  106. private void InitCertificate(ushort port, X509Certificate2 certificate)
  107. {
  108. host.Bind(IPAddress.Any, port, certificate);
  109. }
  110. public void InitPort(ushort port)
  111. {
  112. Port = port;
  113. host.Bind(IPAddress.Any, port);
  114. }
  115. public void InitHTTPS(ushort port, string certificateFile)
  116. {
  117. Port = port;
  118. CertificateManager.SetFile(certificateFile);
  119. var status = CertificateManager.GetCertificate(out var certificate);
  120. switch (status)
  121. {
  122. case CertificateStatus.Valid:
  123. var names = certificate!.GetNameInfo(X509NameType.DnsName, false);
  124. Logger.Send(LogType.Information, "", $"Certificate valid for {names}");
  125. InitCertificate(port, certificate);
  126. break;
  127. case CertificateStatus.Expired:
  128. Logger.Send(LogType.Error, "", "HTTPS Certificate has expired, using HTTP instead");
  129. InitPort(port);
  130. break;
  131. case CertificateStatus.NotFound:
  132. InitPort(port);
  133. break;
  134. case CertificateStatus.Error:
  135. Logger.Send(LogType.Error, "", "Error validating HTTPS Certificate, using HTTP instead");
  136. InitPort(port);
  137. break;
  138. }
  139. }
  140. public void Start()
  141. {
  142. host.Start();
  143. }
  144. public void Stop()
  145. {
  146. host.Stop();
  147. CertificateManager.Stop();
  148. }
  149. private void Restart()
  150. {
  151. Clear();
  152. Init(Properties);
  153. if(CertificateManager.CertificateFile != null)
  154. {
  155. InitHTTPS(Port, CertificateManager.CertificateFile);
  156. }
  157. else
  158. {
  159. InitPort(Port);
  160. }
  161. Start();
  162. }
  163. /// <summary>
  164. /// Clears certificate and host information, and stops the listener.
  165. /// </summary>
  166. private void Clear()
  167. {
  168. host?.Stop();
  169. CertificateManager.Clear();
  170. }
  171. }