Files
lserp_cs_6.0/插件库/Lskj.AgentPet.Host/EmbeddedPetResources.cs
2026-08-14 14:28:28 +08:00

100 lines
3.5 KiB
C#

using System.IO;
using System.Reflection;
using Lskj.AgentPet.Host.Core;
namespace Lskj.AgentPet.Host;
internal sealed class EmbeddedPetResource
{
public EmbeddedPetResource(byte[] bytes, string contentType, bool document)
{
Bytes = bytes ?? throw new ArgumentNullException(nameof(bytes));
ContentType = contentType ?? throw new ArgumentNullException(nameof(contentType));
IsDocument = document;
}
public byte[] Bytes { get; }
public string ContentType { get; }
public bool IsDocument { get; }
}
internal static class EmbeddedPetResources
{
public const string PageUrl = "https://lserp-pet.local/index.html";
private const int MaximumResourceBytes = 2 * 1024 * 1024;
private const int MaximumTotalBytes = 4 * 1024 * 1024;
private static readonly ResourceSpec[] Specs =
{
new(PageUrl, "Lskj.AgentPet.Web.index.html", "text/html; charset=utf-8", true),
new("https://lserp-pet.local/pet.css", "Lskj.AgentPet.Web.pet.css", "text/css; charset=utf-8", false),
new("https://lserp-pet.local/pet-runtime.js", "Lskj.AgentPet.Web.pet-runtime.js", "text/javascript; charset=utf-8", false),
new("https://lserp-pet.local/bridge-client.js", "Lskj.AgentPet.Web.bridge-client.js", "text/javascript; charset=utf-8", false),
new("https://lserp-pet.local/pet-shell.js", "Lskj.AgentPet.Web.pet-shell.js", "text/javascript; charset=utf-8", false)
};
public static IReadOnlyDictionary<string, EmbeddedPetResource> Load()
{
Assembly assembly = typeof(EmbeddedPetResources).Assembly;
Dictionary<string, EmbeddedPetResource> result =
new(StringComparer.Ordinal);
int totalBytes = 0;
foreach (ResourceSpec spec in Specs)
{
using Stream? stream = assembly.GetManifestResourceStream(spec.Name);
if (stream is null
|| !stream.CanRead
|| stream.Length <= 0
|| stream.Length > MaximumResourceBytes)
{
throw new HostError(
"pet_web_resource_invalid",
"签名桌宠程序集缺少有效的嵌入式页面资源。");
}
totalBytes = checked(totalBytes + (int)stream.Length);
if (totalBytes > MaximumTotalBytes)
{
throw new HostError(
"pet_web_resource_invalid",
"签名桌宠页面资源超过安全上限。");
}
byte[] bytes = new byte[(int)stream.Length];
int offset = 0;
while (offset < bytes.Length)
{
int read = stream.Read(bytes, offset, bytes.Length - offset);
if (read <= 0)
throw new HostError(
"pet_web_resource_invalid",
"无法完整读取签名桌宠页面资源。");
offset += read;
}
result.Add(
spec.Url,
new EmbeddedPetResource(bytes, spec.ContentType, spec.Document));
}
return result;
}
private sealed class ResourceSpec
{
public ResourceSpec(
string url,
string name,
string contentType,
bool document)
{
Url = url;
Name = name;
ContentType = contentType;
Document = document;
}
public string Url { get; }
public string Name { get; }
public string ContentType { get; }
public bool Document { get; }
}
}