using System; using System.Collections.Generic; using System.Linq; using System.Threading; using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; using PepperDash.Core.Web.RequestHandlers; using PepperDash.Core.Logging; namespace PepperDash.Core.Web; /// /// Web API server /// public class WebApiServer : IKeyName { private const string SplusKey = "Uninitialized Web API Server"; private const string DefaultName = "Web API Server"; private const string DefaultBasePath = "/api"; private readonly object _serverLock = new(); private HttpCwsServer _server; /// /// Gets or sets the Key /// public string Key { get; private set; } /// /// Gets or sets the Name /// public string Name { get; private set; } /// /// Gets or sets the BasePath /// public string BasePath { get; private set; } /// /// Gets or sets the IsRegistered /// public bool IsRegistered { get; private set; } /// /// Constructor for S+. Make sure to set necessary properties using init method /// public WebApiServer() : this(SplusKey, DefaultName, null) { } /// /// Constructor /// /// /// public WebApiServer(string key, string basePath) : this(key, DefaultName, basePath) { } /// /// Constructor /// /// /// /// public WebApiServer(string key, string name, string basePath) { Key = key; Name = string.IsNullOrEmpty(name) ? DefaultName : name; BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; this.LogInformation("Creating Web API Server with Key: {Key}, Name: {Name}, BasePath: {BasePath}", Key, Name, BasePath); if (_server == null) _server = new HttpCwsServer(BasePath); _server.AuthenticateAllRoutes = false; _server.setProcessName(Key); _server.HttpRequestHandler = new DefaultRequestHandler(); _server.ReceivedRequestEvent += ReceivedRequestEventHandler; CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; } /// /// Program status event handler /// /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { if (programEventType != eProgramStatusEventType.Stopping) return; this.LogInformation("Program stopping. stopping server"); Stop(); } /// /// Ethernet event handler /// /// void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) { if (ethernetEventArgs.EthernetEventType != eEthernetEventType.LinkUp) { return; } if (IsRegistered) { this.LogInformation("Ethernet link up. Server is already registered."); return; } this.LogInformation("Ethernet link up. Starting server"); Start(); } // /// // /// Initialize method // /// // public void Initialize(string key, string basePath) // { // Key = key; // BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; // } /// /// Adds a route to CWS /// public void AddRoute(HttpCwsRoute route) { if (route == null) { this.LogWarning("Failed to add route, route parameter is null"); return; } _server.Routes.Add(route); } /// /// Removes a route from CWS /// /// /// /// RemoveRoute method /// public void RemoveRoute(HttpCwsRoute route) { if (route == null) { this.LogWarning("Failed to remove route, route parameter is null"); return; } _server.Routes.Remove(route); } /// /// Sets the fallback request handler that is invoked when no registered route /// matches an incoming request. Must be called before . /// /// The handler to use as the server-level fallback. public void SetFallbackHandler(IHttpCwsHandler handler) { if (handler == null) { this.LogWarning("SetFallbackHandler: handler parameter is null, ignoring"); return; } _server.HttpRequestHandler = handler; } /// /// GetRouteCollection method /// public HttpCwsRouteCollection GetRouteCollection() { return _server.Routes; } /// /// Starts CWS instance /// public void Start() { lock (_serverLock) { try { if (_server == null) { this.LogDebug("Server is null, unable to start"); return; } if (IsRegistered) { this.LogDebug("Server has already been started"); return; } IsRegistered = _server.Register(); this.LogDebug("Starting server, registration {0}", IsRegistered ? "was successful" : "failed"); } catch (Exception ex) { this.LogException(ex, "Start Exception Message: {0}", ex.Message); this.LogVerbose("Start Exception StackTrace: {0}", ex.StackTrace); } } // end lock } /// /// Stop method /// public void Stop() { lock (_serverLock) { try { if (_server == null) { this.LogDebug("Server is null or has already been stopped"); return; } var unregistered = _server.Unregister(); IsRegistered = !unregistered; this.LogDebug("Stopping server, unregistration {0}", unregistered ? "was successful" : "failed"); } catch (Exception ex) { this.LogException(ex, "Server Stop Exception Message: {0}", ex.Message); } } // end lock } /// /// Received request handler /// /// /// This is here for development and testing /// /// /// public void ReceivedRequestEventHandler(object sender, HttpCwsRequestEventArgs args) { try { var req = args.Context?.Request; this.LogVerbose("ReceivedRequestEventHandler: {Method} {Path}", req?.HttpMethod, req?.Path); } catch (Exception ex) { this.LogException(ex, "ReceivedRequestEventHandler Exception Message: {0}", ex.Message); } } }