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);
}
}
}