mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-04-19 23:46:49 +00:00
feat: implement login functionality with LoginRequestHandler and integrate asset loading
This commit is contained in:
parent
6e9480f503
commit
9ea5ec5d1a
7 changed files with 406 additions and 140 deletions
|
|
@ -19,4 +19,5 @@ jobs:
|
||||||
version: ${{ needs.getVersion.outputs.version }}
|
version: ${{ needs.getVersion.outputs.version }}
|
||||||
tag: ${{ needs.getVersion.outputs.tag }}
|
tag: ${{ needs.getVersion.outputs.tag }}
|
||||||
channel: ${{ needs.getVersion.outputs.channel }}
|
channel: ${{ needs.getVersion.outputs.channel }}
|
||||||
bypassPackageCheck: true
|
bypassPackageCheck: true
|
||||||
|
devToolsVersion: ${{ vars.ESSENTIALSDEVTOOLSVERSION }}
|
||||||
|
|
@ -99,6 +99,8 @@ namespace PepperDash.Core.Web
|
||||||
|
|
||||||
if (_server == null) _server = new HttpCwsServer(BasePath);
|
if (_server == null) _server = new HttpCwsServer(BasePath);
|
||||||
|
|
||||||
|
_server.AuthenticateAllRoutes = false;
|
||||||
|
|
||||||
_server.setProcessName(Key);
|
_server.setProcessName(Key);
|
||||||
_server.HttpRequestHandler = new DefaultRequestHandler();
|
_server.HttpRequestHandler = new DefaultRequestHandler();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,11 @@ namespace PepperDash.Essentials.Core.Web
|
||||||
{
|
{
|
||||||
var routes = new List<HttpCwsRoute>
|
var routes = new List<HttpCwsRoute>
|
||||||
{
|
{
|
||||||
|
new HttpCwsRoute("login")
|
||||||
|
{
|
||||||
|
Name = "Root",
|
||||||
|
RouteHandler = new LoginRequestHandler()
|
||||||
|
},
|
||||||
new HttpCwsRoute("versions")
|
new HttpCwsRoute("versions")
|
||||||
{
|
{
|
||||||
Name = "ReportVersions",
|
Name = "ReportVersions",
|
||||||
|
|
|
||||||
|
|
@ -36,17 +36,25 @@ namespace PepperDash.Essentials.Core.Web
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// MapToDeviceListObject method
|
/// MapToDeviceListObject method
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static object MapToDeviceListObject(IKeyed device)
|
public static object MapToDeviceListObject(IKeyed device)
|
||||||
{
|
{
|
||||||
|
var interfaces = device.GetType()
|
||||||
|
.GetInterfaces()
|
||||||
|
.Select(i => i.Name)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
return new
|
return new
|
||||||
{
|
{
|
||||||
device.Key,
|
device.Key,
|
||||||
Name = (device is IKeyName)
|
Name = (device is IKeyName)
|
||||||
? (device as IKeyName).Name
|
? (device as IKeyName).Name
|
||||||
: "---"
|
: "---",
|
||||||
|
Interfaces = interfaces
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,5 +118,10 @@ namespace PepperDash.Essentials.Core.Web
|
||||||
CType = device.Value.Type == null ? "---": device.Value.Type.ToString()
|
CType = device.Value.Type == null ? "---": device.Value.Type.ToString()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
internal static bool IsAuthenticated(HttpCwsContext context)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using Crestron.SimplSharp.CrestronAuthentication;
|
||||||
|
using Crestron.SimplSharp.WebScripting;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using PepperDash.Core.Web.RequestHandlers;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a LoginRequestHandler
|
||||||
|
/// </summary>
|
||||||
|
public class LoginRequestHandler : WebApiBaseRequestHandler
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// base(true) enables CORS support by default
|
||||||
|
/// </remarks>
|
||||||
|
public LoginRequestHandler()
|
||||||
|
: base(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles POST method requests for user login and token generation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The HTTP context for the request.</param>
|
||||||
|
protected override void HandlePost(HttpCwsContext context)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (context.Request.ContentLength < 0)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 400;
|
||||||
|
context.Response.StatusDescription = "Bad Request";
|
||||||
|
context.Response.End();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = context.Request.GetRequestBody();
|
||||||
|
if (string.IsNullOrEmpty(data))
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 400;
|
||||||
|
context.Response.StatusDescription = "Bad Request";
|
||||||
|
context.Response.End();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var loginRequest = JsonConvert.DeserializeObject<LoginRequest>(data);
|
||||||
|
|
||||||
|
if (loginRequest == null || string.IsNullOrEmpty(loginRequest.Username) || string.IsNullOrEmpty(loginRequest.Password))
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 400;
|
||||||
|
context.Response.StatusDescription = "Bad Request";
|
||||||
|
context.Response.End();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Authentication.UserToken token;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
token = Authentication.GetAuthenticationToken(loginRequest.Username, loginRequest.Password);
|
||||||
|
}
|
||||||
|
catch (ArgumentException)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 401;
|
||||||
|
context.Response.StatusDescription = "Bad Request";
|
||||||
|
context.Response.End();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!token.Valid)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 401;
|
||||||
|
context.Response.StatusDescription = "Unauthorized";
|
||||||
|
context.Response.End();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Response.StatusCode = 200;
|
||||||
|
context.Response.StatusDescription = "OK";
|
||||||
|
context.Response.ContentType = "application/json";
|
||||||
|
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
|
||||||
|
context.Response.Write(JsonConvert.SerializeObject(new { Token = token }, Formatting.Indented), false);
|
||||||
|
context.Response.End();
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 500;
|
||||||
|
context.Response.StatusDescription = "Internal Server Error";
|
||||||
|
context.Response.ContentType = "application/json";
|
||||||
|
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
|
||||||
|
context.Response.Write(JsonConvert.SerializeObject(new { Error = ex.Message }, Formatting.Indented), false);
|
||||||
|
context.Response.End();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a LoginRequest
|
||||||
|
/// </summary>
|
||||||
|
public class LoginRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the username.
|
||||||
|
/// </summary>
|
||||||
|
public string Username { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the password.
|
||||||
|
/// </summary>
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
257
src/PepperDash.Essentials/AssetLoader.cs
Normal file
257
src/PepperDash.Essentials/AssetLoader.cs
Normal file
|
|
@ -0,0 +1,257 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Linq;
|
||||||
|
using PepperDash.Core;
|
||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles extracting embedded asset bundles and moving configuration files from the
|
||||||
|
/// application directory to the program file-path prefix at startup.
|
||||||
|
/// Implemented using <c>System.IO</c> types so it can run (and be tested) outside
|
||||||
|
/// of a Crestron runtime environment.
|
||||||
|
/// </summary>
|
||||||
|
internal static class AssetLoader
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Scans <paramref name="applicationDirectoryPath"/> for well-known zip bundles and
|
||||||
|
/// JSON configuration files and deploys them to <paramref name="filePathPrefix"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="applicationDirectoryPath">
|
||||||
|
/// The directory to scan (typically the Crestron application root).
|
||||||
|
/// </param>
|
||||||
|
/// <param name="filePathPrefix">
|
||||||
|
/// The program's runtime working directory (e.g. <c>/nvram/program1/</c>).
|
||||||
|
/// </param>
|
||||||
|
internal static void Load(string applicationDirectoryPath, string filePathPrefix)
|
||||||
|
{
|
||||||
|
var applicationDirectory = new DirectoryInfo(applicationDirectoryPath);
|
||||||
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
|
"Searching: {applicationDirectory:l} for embedded assets - {Destination}",
|
||||||
|
applicationDirectory.FullName, filePathPrefix);
|
||||||
|
|
||||||
|
ExtractAssetsZip(applicationDirectory, filePathPrefix);
|
||||||
|
ExtractHtmlAssetsZip(applicationDirectory, filePathPrefix);
|
||||||
|
ExtractDevToolsZip(applicationDirectory, filePathPrefix);
|
||||||
|
MoveConfigurationFile(applicationDirectory, filePathPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Private helpers
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private static void ExtractAssetsZip(DirectoryInfo applicationDirectory, string filePathPrefix)
|
||||||
|
{
|
||||||
|
var zipFiles = applicationDirectory.GetFiles("assets*.zip");
|
||||||
|
|
||||||
|
if (zipFiles.Length > 1)
|
||||||
|
throw new Exception("Multiple assets zip files found. Cannot continue.");
|
||||||
|
|
||||||
|
if (zipFiles.Length == 1)
|
||||||
|
{
|
||||||
|
var zipFile = zipFiles[0];
|
||||||
|
var assetsRoot = Path.GetFullPath(filePathPrefix);
|
||||||
|
if (!assetsRoot.EndsWith(Path.DirectorySeparatorChar.ToString()) &&
|
||||||
|
!assetsRoot.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
|
||||||
|
{
|
||||||
|
assetsRoot += Path.DirectorySeparatorChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
|
"Found assets zip file: {zipFile:l}... Unzipping...", zipFile.FullName);
|
||||||
|
|
||||||
|
using (var archive = ZipFile.OpenRead(zipFile.FullName))
|
||||||
|
{
|
||||||
|
foreach (var entry in archive.Entries)
|
||||||
|
{
|
||||||
|
var destinationPath = Path.Combine(filePathPrefix, entry.FullName);
|
||||||
|
var fullDest = Path.GetFullPath(destinationPath);
|
||||||
|
if (!fullDest.StartsWith(assetsRoot, StringComparison.OrdinalIgnoreCase))
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Entry '{entry.FullName}' is trying to extract outside of the target directory.");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(entry.Name))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(destinationPath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Directory.Exists(destinationPath))
|
||||||
|
Directory.Delete(destinationPath, recursive: true);
|
||||||
|
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
|
||||||
|
entry.ExtractToFile(destinationPath, overwrite: true);
|
||||||
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
|
"Extracted: {entry:l} to {Destination}", entry.FullName, destinationPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var file in zipFiles)
|
||||||
|
File.Delete(file.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ExtractHtmlAssetsZip(DirectoryInfo applicationDirectory, string filePathPrefix)
|
||||||
|
{
|
||||||
|
var htmlZipFiles = applicationDirectory.GetFiles("htmlassets*.zip");
|
||||||
|
|
||||||
|
if (htmlZipFiles.Length > 1)
|
||||||
|
throw new Exception(
|
||||||
|
"Multiple htmlassets zip files found in application directory. " +
|
||||||
|
"Please ensure only one htmlassets*.zip file is present and retry.");
|
||||||
|
|
||||||
|
if (htmlZipFiles.Length == 1)
|
||||||
|
{
|
||||||
|
var htmlZipFile = htmlZipFiles[0];
|
||||||
|
var programDir = new DirectoryInfo(
|
||||||
|
filePathPrefix.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
|
||||||
|
var userOrNvramDir = programDir.Parent;
|
||||||
|
var rootDir = userOrNvramDir?.Parent;
|
||||||
|
if (rootDir == null)
|
||||||
|
throw new Exception(
|
||||||
|
$"Unable to determine root directory for html extraction. Current path: {filePathPrefix}");
|
||||||
|
|
||||||
|
var htmlDir = Path.Combine(rootDir.FullName, "html");
|
||||||
|
var htmlRoot = Path.GetFullPath(htmlDir);
|
||||||
|
if (!htmlRoot.EndsWith(Path.DirectorySeparatorChar.ToString()) &&
|
||||||
|
!htmlRoot.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
|
||||||
|
{
|
||||||
|
htmlRoot += Path.DirectorySeparatorChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
|
"Found htmlassets zip file: {zipFile:l}... Unzipping...", htmlZipFile.FullName);
|
||||||
|
|
||||||
|
using (var archive = ZipFile.OpenRead(htmlZipFile.FullName))
|
||||||
|
{
|
||||||
|
foreach (var entry in archive.Entries)
|
||||||
|
{
|
||||||
|
var destinationPath = Path.Combine(htmlDir, entry.FullName);
|
||||||
|
var fullDest = Path.GetFullPath(destinationPath);
|
||||||
|
if (!fullDest.StartsWith(htmlRoot, StringComparison.OrdinalIgnoreCase))
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Entry '{entry.FullName}' is trying to extract outside of the target directory.");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(entry.Name))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(destinationPath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(destinationPath))
|
||||||
|
File.Delete(destinationPath);
|
||||||
|
|
||||||
|
var parentDir = Path.GetDirectoryName(destinationPath);
|
||||||
|
if (!string.IsNullOrEmpty(parentDir))
|
||||||
|
Directory.CreateDirectory(parentDir);
|
||||||
|
|
||||||
|
entry.ExtractToFile(destinationPath, overwrite: true);
|
||||||
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
|
"Extracted: {entry:l} to {Destination}", entry.FullName, destinationPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var file in htmlZipFiles)
|
||||||
|
File.Delete(file.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ExtractDevToolsZip(DirectoryInfo applicationDirectory, string filePathPrefix)
|
||||||
|
{
|
||||||
|
var devToolsZipFiles = applicationDirectory.GetFiles("essentials-devtools*.zip");
|
||||||
|
|
||||||
|
if (devToolsZipFiles.Length > 1)
|
||||||
|
throw new Exception(
|
||||||
|
"Multiple essentials-devtools zip files found in application directory. " +
|
||||||
|
"Please ensure only one essentials-devtools*.zip file is present and retry.");
|
||||||
|
|
||||||
|
if (devToolsZipFiles.Length == 1)
|
||||||
|
{
|
||||||
|
var devToolsZipFile = devToolsZipFiles[0];
|
||||||
|
var programDir = new DirectoryInfo(
|
||||||
|
filePathPrefix.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
|
||||||
|
var userOrNvramDir = programDir.Parent;
|
||||||
|
var rootDir = userOrNvramDir?.Parent;
|
||||||
|
if (rootDir == null)
|
||||||
|
throw new Exception(
|
||||||
|
$"Unable to determine root directory for debug html extraction. Current path: {filePathPrefix}");
|
||||||
|
|
||||||
|
var debugDir = Path.Combine(rootDir.FullName, "html", "debug");
|
||||||
|
var debugRoot = Path.GetFullPath(debugDir);
|
||||||
|
if (!debugRoot.EndsWith(Path.DirectorySeparatorChar.ToString()) &&
|
||||||
|
!debugRoot.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
|
||||||
|
{
|
||||||
|
debugRoot += Path.DirectorySeparatorChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
|
"Found essentials-devtools zip file: {zipFile:l}... Unzipping to {Destination}...",
|
||||||
|
devToolsZipFile.FullName, debugDir);
|
||||||
|
|
||||||
|
using (var archive = ZipFile.OpenRead(devToolsZipFile.FullName))
|
||||||
|
{
|
||||||
|
foreach (var entry in archive.Entries)
|
||||||
|
{
|
||||||
|
var destinationPath = Path.Combine(debugDir, entry.FullName);
|
||||||
|
var fullDest = Path.GetFullPath(destinationPath);
|
||||||
|
if (!fullDest.StartsWith(debugRoot, StringComparison.OrdinalIgnoreCase))
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Entry '{entry.FullName}' is trying to extract outside of the target directory.");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(entry.Name))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(destinationPath);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (File.Exists(destinationPath))
|
||||||
|
File.Delete(destinationPath);
|
||||||
|
|
||||||
|
var parentDir = Path.GetDirectoryName(destinationPath);
|
||||||
|
if (!string.IsNullOrEmpty(parentDir))
|
||||||
|
Directory.CreateDirectory(parentDir);
|
||||||
|
|
||||||
|
entry.ExtractToFile(destinationPath, overwrite: true);
|
||||||
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
|
"Extracted: {entry:l} to {Destination}", entry.FullName, destinationPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var file in devToolsZipFiles)
|
||||||
|
File.Delete(file.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MoveConfigurationFile(DirectoryInfo applicationDirectory, string filePathPrefix)
|
||||||
|
{
|
||||||
|
var jsonFiles = applicationDirectory.GetFiles("*configurationFile*.json");
|
||||||
|
|
||||||
|
if (jsonFiles.Length > 1)
|
||||||
|
{
|
||||||
|
Debug.LogError("Multiple configuration files found in application directory: {@jsonFiles}",
|
||||||
|
jsonFiles.Select(f => f.FullName).ToArray());
|
||||||
|
throw new Exception("Multiple configuration files found. Cannot continue.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonFiles.Length == 1)
|
||||||
|
{
|
||||||
|
var jsonFile = jsonFiles[0];
|
||||||
|
var finalPath = Path.Combine(filePathPrefix, jsonFile.Name);
|
||||||
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
|
"Found configuration file: {jsonFile:l}... Moving to: {Destination}",
|
||||||
|
jsonFile.FullName, finalPath);
|
||||||
|
|
||||||
|
if (File.Exists(finalPath))
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Information,
|
||||||
|
"Removing existing configuration file: {Destination}", finalPath);
|
||||||
|
File.Delete(finalPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonFile.MoveTo(finalPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -245,7 +245,7 @@ namespace PepperDash.Essentials
|
||||||
// _ = new ProcessorExtensionDeviceFactory();
|
// _ = new ProcessorExtensionDeviceFactory();
|
||||||
// _ = new MobileControlFactory();
|
// _ = new MobileControlFactory();
|
||||||
|
|
||||||
LoadAssets();
|
LoadAssets(Global.ApplicationDirectoryPathPrefix, Global.FilePathPrefix);
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Starting Essentials load from configuration");
|
Debug.LogMessage(LogEventLevel.Information, "Starting Essentials load from configuration");
|
||||||
|
|
||||||
|
|
@ -825,142 +825,8 @@ namespace PepperDash.Essentials
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void LoadAssets()
|
internal static void LoadAssets(string applicationDirectoryPath, string filePathPrefix) =>
|
||||||
{
|
AssetLoader.Load(applicationDirectoryPath, filePathPrefix);
|
||||||
var applicationDirectory = new DirectoryInfo(Global.ApplicationDirectoryPathPrefix);
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Searching: {applicationDirectory:l} for embedded assets - {Destination}", applicationDirectory.FullName, Global.FilePathPrefix);
|
|
||||||
|
|
||||||
var zipFiles = applicationDirectory.GetFiles("assets*.zip");
|
|
||||||
|
|
||||||
if (zipFiles.Length > 1)
|
|
||||||
{
|
|
||||||
throw new Exception("Multiple assets zip files found. Cannot continue.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zipFiles.Length == 1)
|
|
||||||
{
|
|
||||||
var zipFile = zipFiles[0];
|
|
||||||
var assetsRoot = System.IO.Path.GetFullPath(Global.FilePathPrefix);
|
|
||||||
if (!assetsRoot.EndsWith(Path.DirectorySeparatorChar.ToString()) && !assetsRoot.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
|
|
||||||
{
|
|
||||||
assetsRoot += Path.DirectorySeparatorChar;
|
|
||||||
}
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Found assets zip file: {zipFile:l}... Unzipping...", zipFile.FullName);
|
|
||||||
using (var archive = ZipFile.OpenRead(zipFile.FullName))
|
|
||||||
{
|
|
||||||
foreach (var entry in archive.Entries)
|
|
||||||
{
|
|
||||||
var destinationPath = Path.Combine(Global.FilePathPrefix, entry.FullName);
|
|
||||||
var fullDest = System.IO.Path.GetFullPath(destinationPath);
|
|
||||||
if (!fullDest.StartsWith(assetsRoot, StringComparison.OrdinalIgnoreCase))
|
|
||||||
throw new InvalidOperationException($"Entry '{entry.FullName}' is trying to extract outside of the target directory.");
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(entry.Name))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(destinationPath);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a directory exists where a file should go, delete it
|
|
||||||
if (Directory.Exists(destinationPath))
|
|
||||||
Directory.Delete(destinationPath, true);
|
|
||||||
|
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
|
|
||||||
entry.ExtractToFile(destinationPath, true);
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Extracted: {entry:l} to {Destination}", entry.FullName, destinationPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleaning up zip files
|
|
||||||
foreach (var file in zipFiles)
|
|
||||||
{
|
|
||||||
File.Delete(file.FullName);
|
|
||||||
}
|
|
||||||
|
|
||||||
var htmlZipFiles = applicationDirectory.GetFiles("htmlassets*.zip");
|
|
||||||
|
|
||||||
if (htmlZipFiles.Length > 1)
|
|
||||||
{
|
|
||||||
throw new Exception("Multiple htmlassets zip files found in application directory. Please ensure only one htmlassets*.zip file is present and retry.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (htmlZipFiles.Length == 1)
|
|
||||||
{
|
|
||||||
var htmlZipFile = htmlZipFiles[0];
|
|
||||||
var programDir = new DirectoryInfo(Global.FilePathPrefix.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar));
|
|
||||||
var userOrNvramDir = programDir.Parent;
|
|
||||||
var rootDir = userOrNvramDir?.Parent;
|
|
||||||
if (rootDir == null)
|
|
||||||
{
|
|
||||||
throw new Exception($"Unable to determine root directory for html extraction. Current path: {Global.FilePathPrefix}");
|
|
||||||
}
|
|
||||||
var htmlDir = Path.Combine(rootDir.FullName, "html");
|
|
||||||
var htmlRoot = System.IO.Path.GetFullPath(htmlDir);
|
|
||||||
if (!htmlRoot.EndsWith(Path.DirectorySeparatorChar.ToString()) &&
|
|
||||||
!htmlRoot.EndsWith(Path.AltDirectorySeparatorChar.ToString()))
|
|
||||||
{
|
|
||||||
htmlRoot += Path.DirectorySeparatorChar;
|
|
||||||
}
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Found htmlassets zip file: {zipFile:l}... Unzipping...", htmlZipFile.FullName);
|
|
||||||
using (var archive = ZipFile.OpenRead(htmlZipFile.FullName))
|
|
||||||
{
|
|
||||||
foreach (var entry in archive.Entries)
|
|
||||||
{
|
|
||||||
var destinationPath = Path.Combine(htmlDir, entry.FullName);
|
|
||||||
var fullDest = System.IO.Path.GetFullPath(destinationPath);
|
|
||||||
if (!fullDest.StartsWith(htmlRoot, StringComparison.OrdinalIgnoreCase))
|
|
||||||
throw new InvalidOperationException($"Entry '{entry.FullName}' is trying to extract outside of the target directory.");
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(entry.Name))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(destinationPath);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only delete the file if it exists and is a file, not a directory
|
|
||||||
if (File.Exists(destinationPath))
|
|
||||||
File.Delete(destinationPath);
|
|
||||||
|
|
||||||
var parentDir = Path.GetDirectoryName(destinationPath);
|
|
||||||
if (!string.IsNullOrEmpty(parentDir))
|
|
||||||
Directory.CreateDirectory(parentDir);
|
|
||||||
|
|
||||||
entry.ExtractToFile(destinationPath, true);
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Extracted: {entry:l} to {Destination}", entry.FullName, destinationPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleaning up html zip files
|
|
||||||
foreach (var file in htmlZipFiles)
|
|
||||||
{
|
|
||||||
File.Delete(file.FullName);
|
|
||||||
}
|
|
||||||
|
|
||||||
var jsonFiles = applicationDirectory.GetFiles("*configurationFile*.json");
|
|
||||||
|
|
||||||
if (jsonFiles.Length > 1)
|
|
||||||
{
|
|
||||||
Debug.LogError("Multiple configuration files found in application directory: {@jsonFiles}", jsonFiles.Select(f => f.FullName).ToArray());
|
|
||||||
throw new Exception("Multiple configuration files found. Cannot continue.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonFiles.Length == 1)
|
|
||||||
{
|
|
||||||
var jsonFile = jsonFiles[0];
|
|
||||||
var finalPath = Path.Combine(Global.FilePathPrefix, jsonFile.Name);
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Found configuration file: {jsonFile:l}... Moving to: {Destination}", jsonFile.FullName, finalPath);
|
|
||||||
|
|
||||||
if (File.Exists(finalPath))
|
|
||||||
{
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Removing existing configuration file: {Destination}", finalPath);
|
|
||||||
File.Delete(finalPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonFile.MoveTo(finalPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue