feat: move MC into Essentials

In order to solve some dependency issues that keep cropping up, MC
should be moved back into the Essentials repo and loaded automatically
on startup. This will allow for all plugins that use the MC Messengers
library to use the same version without fear of overwriting a dll due to
loading of plugin libraries.
This commit is contained in:
Andrew Welker
2025-03-24 22:28:27 -05:00
parent 3d91723ab0
commit f6fdc14059
89 changed files with 15625 additions and 7 deletions

View File

@@ -0,0 +1,52 @@
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core.Web.RequestHandlers;
using PepperDash.Essentials.AppServer.Messengers;
using System.Collections.Generic;
using System.Linq;
namespace PepperDash.Essentials.WebApiHandlers
{
public class ActionPathsHandler : WebApiBaseRequestHandler
{
private readonly MobileControlSystemController mcController;
public ActionPathsHandler(MobileControlSystemController controller) : base(true)
{
mcController = controller;
}
protected override void HandleGet(HttpCwsContext context)
{
var response = JsonConvert.SerializeObject(new ActionPathsResponse(mcController));
context.Response.StatusCode = 200;
context.Response.ContentType = "application/json";
context.Response.Headers.Add("Content-Type", "application/json");
context.Response.Write(response, false);
context.Response.End();
}
}
public class ActionPathsResponse
{
[JsonIgnore]
private readonly MobileControlSystemController mcController;
[JsonProperty("actionPaths")]
public List<ActionPath> ActionPaths => mcController.GetActionDictionaryPaths().Select((path) => new ActionPath { MessengerKey = path.Item1, Path = path.Item2}).ToList();
public ActionPathsResponse(MobileControlSystemController mcController)
{
this.mcController = mcController;
}
}
public class ActionPath
{
[JsonProperty("messengerKey")]
public string MessengerKey { get; set; }
[JsonProperty("path")]
public string Path { get; set; }
}
}

View File

@@ -0,0 +1,59 @@
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Web.RequestHandlers;
using PepperDash.Essentials.Core.Web;
using System;
using System.Threading.Tasks;
namespace PepperDash.Essentials.WebApiHandlers
{
public class MobileAuthRequestHandler : WebApiBaseRequestAsyncHandler
{
private readonly MobileControlSystemController mcController;
public MobileAuthRequestHandler(MobileControlSystemController controller) : base(true)
{
mcController = controller;
}
protected override async Task HandlePost(HttpCwsContext context)
{
try
{
var requestBody = EssentialsWebApiHelpers.GetRequestBody(context.Request);
var grantCode = JsonConvert.DeserializeObject<AuthorizationRequest>(requestBody);
if (string.IsNullOrEmpty(grantCode?.GrantCode))
{
Debug.LogMessage(Serilog.Events.LogEventLevel.Error, "Missing grant code");
context.Response.StatusCode = 400;
context.Response.StatusDescription = "Missing grant code";
context.Response.End();
return;
}
var response = await mcController.ApiService.SendAuthorizationRequest(mcController.Host, grantCode.GrantCode, mcController.SystemUuid);
Debug.LogMessage(Serilog.Events.LogEventLevel.Debug, $"response received");
if (response.Authorized)
{
mcController.RegisterSystemToServer();
}
context.Response.StatusCode = 200;
var responseBody = JsonConvert.SerializeObject(response, Formatting.None);
context.Response.ContentType = "application/json";
context.Response.Headers.Add("Content-Type", "application/json");
context.Response.Write(responseBody, false);
context.Response.End();
}
catch (Exception ex)
{
Debug.LogMessage(ex, "Exception recieved authorizing system");
}
}
}
}

View File

@@ -0,0 +1,159 @@
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Web.RequestHandlers;
using PepperDash.Essentials.Core.Config;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PepperDash.Essentials.WebApiHandlers
{
public class MobileInfoHandler : WebApiBaseRequestHandler
{
private readonly MobileControlSystemController mcController;
public MobileInfoHandler(MobileControlSystemController controller) : base(true)
{
mcController = controller;
}
protected override void HandleGet(HttpCwsContext context)
{
try
{
var response = new InformationResponse(mcController);
context.Response.StatusCode = 200;
context.Response.ContentType = "application/json";
context.Response.Write(JsonConvert.SerializeObject(response), false);
context.Response.End();
}
catch (Exception ex)
{
Debug.Console(1, $"exception showing mobile info: {ex.Message}");
Debug.Console(2, $"stack trace: {ex.StackTrace}");
context.Response.StatusCode = 500;
context.Response.End();
}
}
}
public class InformationResponse
{
[JsonIgnore]
private readonly MobileControlSystemController mcController;
[JsonProperty("edgeServer", NullValueHandling = NullValueHandling.Ignore)]
public MobileControlEdgeServer EdgeServer => mcController.Config.EnableApiServer ? new MobileControlEdgeServer(mcController) : null;
[JsonProperty("directServer", NullValueHandling = NullValueHandling.Ignore)]
public MobileControlDirectServer DirectServer => mcController.Config.DirectServer.EnableDirectServer ? new MobileControlDirectServer(mcController.DirectServer) : null;
public InformationResponse(MobileControlSystemController controller)
{
mcController = controller;
}
}
public class MobileControlEdgeServer
{
[JsonIgnore]
private readonly MobileControlSystemController mcController;
[JsonProperty("serverAddress")]
public string ServerAddress => mcController.Config == null ? "No Config" : mcController.Host;
[JsonProperty("systemName")]
public string SystemName => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].RoomName : "No Config";
[JsonProperty("systemUrl")]
public string SystemUrl => ConfigReader.ConfigObject.SystemUrl;
[JsonProperty("userCode")]
public string UserCode => mcController.RoomBridges.Count > 0 ? mcController.RoomBridges[0].UserCode : "Not available";
[JsonProperty("connected")]
public bool Connected => mcController.Connected;
[JsonProperty("secondsSinceLastAck")]
public int SecondsSinceLastAck => (DateTime.Now - mcController.LastAckMessage).Seconds;
public MobileControlEdgeServer(MobileControlSystemController controller)
{
mcController = controller;
}
}
public class MobileControlDirectServer
{
[JsonIgnore]
private readonly MobileControlWebsocketServer directServer;
[JsonProperty("userAppUrl")]
public string UserAppUrl => $"{directServer.UserAppUrlPrefix}/[insert_client_token]";
[JsonProperty("serverPort")]
public int ServerPort => directServer.Port;
[JsonProperty("tokensDefined")]
public int TokensDefined => directServer.UiClients.Count;
[JsonProperty("clientsConnected")]
public int ClientsConnected => directServer.ConnectedUiClientsCount;
[JsonProperty("clients")]
public List<MobileControlDirectClient> Clients => directServer.UiClients.Select((c, i) => { return new MobileControlDirectClient(c, i, directServer.UserAppUrlPrefix); }).ToList();
public MobileControlDirectServer(MobileControlWebsocketServer server)
{
directServer = server;
}
}
public class MobileControlDirectClient
{
[JsonIgnore]
private readonly UiClientContext context;
[JsonIgnore]
private readonly string Key;
[JsonIgnore]
private readonly int clientNumber;
[JsonIgnore]
private readonly string urlPrefix;
[JsonProperty("clientNumber")]
public string ClientNumber => $"{clientNumber}";
[JsonProperty("roomKey")]
public string RoomKey => context.Token.RoomKey;
[JsonProperty("touchpanelKey")]
public string TouchpanelKey => context.Token.TouchpanelKey;
[JsonProperty("url")]
public string Url => $"{urlPrefix}{Key}";
[JsonProperty("token")]
public string Token => Key;
[JsonProperty("connected")]
public bool Connected => context.Client == null ? false : context.Client.Context.WebSocket.IsAlive;
[JsonProperty("duration")]
public double Duration => context.Client == null ? 0 : context.Client.ConnectedDuration.TotalSeconds;
public MobileControlDirectClient(KeyValuePair<string, UiClientContext> clientContext, int index, string urlPrefix)
{
context = clientContext.Value;
Key = clientContext.Key;
clientNumber = index;
this.urlPrefix = urlPrefix;
}
}
}

View File

@@ -0,0 +1,164 @@
using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json;
using PepperDash.Core;
using PepperDash.Core.Web.RequestHandlers;
using PepperDash.Essentials.Core.Web;
namespace PepperDash.Essentials.WebApiHandlers
{
public class UiClientHandler : WebApiBaseRequestHandler
{
private readonly MobileControlWebsocketServer server;
public UiClientHandler(MobileControlWebsocketServer directServer) : base(true)
{
server = directServer;
}
protected override void HandlePost(HttpCwsContext context)
{
var req = context.Request;
var res = context.Response;
var body = EssentialsWebApiHelpers.GetRequestBody(req);
var request = JsonConvert.DeserializeObject<ClientRequest>(body);
var response = new ClientResponse();
if (string.IsNullOrEmpty(request?.RoomKey))
{
response.Error = "roomKey is required";
res.StatusCode = 400;
res.ContentType = "application/json";
res.Headers.Add("Content-Type", "application/json");
res.Write(JsonConvert.SerializeObject(response), false);
res.End();
return;
}
if (string.IsNullOrEmpty(request.GrantCode))
{
response.Error = "grantCode is required";
res.StatusCode = 400;
res.ContentType = "application/json";
res.Headers.Add("Content-Type", "application/json");
res.Write(JsonConvert.SerializeObject(response), false);
res.End();
return;
}
var (token, path) = server.ValidateGrantCode(request.GrantCode, request.RoomKey);
response.Token = token;
response.Path = path;
res.StatusCode = 200;
res.ContentType = "application/json";
res.Headers.Add("Content-Type", "application/json");
res.Write(JsonConvert.SerializeObject(response), false);
res.End();
}
protected override void HandleDelete(HttpCwsContext context)
{
var req = context.Request;
var res = context.Response;
var body = EssentialsWebApiHelpers.GetRequestBody(req);
var request = JsonConvert.DeserializeObject<ClientRequest>(body);
if (string.IsNullOrEmpty(request?.Token))
{
var response = new ClientResponse
{
Error = "token is required"
};
res.StatusCode = 400;
res.ContentType = "application/json";
res.Headers.Add("Content-Type", "application/json");
res.Write(JsonConvert.SerializeObject(response), false);
res.End();
return;
}
if (!server.UiClients.TryGetValue(request.Token, out UiClientContext clientContext))
{
var response = new ClientResponse
{
Error = $"Unable to find client with token: {request.Token}"
};
res.StatusCode = 200;
res.ContentType = "application/json";
res.Headers.Add("Content-Type", "application/json");
res.Write(JsonConvert.SerializeObject(response), false);
res.End();
return;
}
if (clientContext.Client != null && clientContext.Client.Context.WebSocket.IsAlive)
{
clientContext.Client.Context.WebSocket.Close(WebSocketSharp.CloseStatusCode.Normal, "Token removed from server");
}
var path = server.WsPath + request.Token;
if (!server.Server.RemoveWebSocketService(path))
{
Debug.Console(0, $"Unable to remove client with token {request.Token}");
var response = new ClientResponse
{
Error = $"Unable to remove client with token {request.Token}"
};
res.StatusCode = 500;
res.ContentType = "application/json";
res.Headers.Add("Content-Type", "application/json");
res.Write(JsonConvert.SerializeObject(response), false);
res.End();
return;
}
server.UiClients.Remove(request.Token);
server.UpdateSecret();
res.StatusCode = 200;
res.End();
}
}
public class ClientRequest
{
[JsonProperty("roomKey", NullValueHandling = NullValueHandling.Ignore)]
public string RoomKey { get; set; }
[JsonProperty("grantCode", NullValueHandling = NullValueHandling.Ignore)]
public string GrantCode { get; set; }
[JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)]
public string Token { get; set; }
}
public class ClientResponse
{
[JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)]
public string Error { get; set; }
[JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)]
public string Token { get; set; }
[JsonProperty("path", NullValueHandling = NullValueHandling.Ignore)]
public string Path { get; set; }
}
}