XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text;

namespace XFESystem.Browser;

/// <summary>Explicit packaged application resources. This interface never reads host paths on behalf of a URL.</summary>
public interface IBrowserResourceSource
{
    bool TryGet(Uri address, out WebResponse response);
}

public sealed class PackagedBrowserResources : IBrowserResourceSource
{
    public const string Origin = "http://xfesystem.local";
    public const string MonacoCoreRoot = Origin + "/Browser/Monaco/0.52.2/Core/";
    public const string MonacoPageAddress = Origin + "/Browser/Monaco/Index.html";
    public const string WebsiteCodeRoot = Origin + "/Browser/WebsiteCode/";
    private sealed record CachedResource(string ContentType, string Body);
    // Only this finite assembly manifest is cached. The completed dictionary
    // is never mutated, and script execution still uses a fresh page/runtime.
    private static readonly IReadOnlyDictionary<string, CachedResource> resources = LoadEmbeddedResources();

    /// <summary>Reserve large immutable script strings while the early boot
    /// heap still has contiguous space, before browsers allocate transient DOM/JS state.</summary>
    public static int PrewarmTextResources() => resources.Count;

    private static IReadOnlyDictionary<string, CachedResource> LoadEmbeddedResources()
    {
        var loaded = new Dictionary<string, CachedResource>(StringComparer.Ordinal);
        foreach (string name in typeof(PackagedBrowserResources).Assembly.GetManifestResourceNames())
        {
            var normalized = name.Replace('\\', '/');
            string? path = normalized.StartsWith("MonacoCore/", StringComparison.Ordinal) ? "/Browser/Monaco/0.52.2/Core/" + normalized[11..] :
                normalized.StartsWith("WebsiteCode/", StringComparison.Ordinal) ? "/Browser/WebsiteCode/" + normalized[12..] : null;
            if (path is null) continue;
            string extension = Path.GetExtension(path).ToLowerInvariant();
            if (extension is not (".js" or ".css" or ".json")) continue;
            using var stream = typeof(PackagedBrowserResources).Assembly.GetManifestResourceStream(name)!;
            using var reader = new StreamReader(stream, Encoding.UTF8, true);
            loaded.Add(path, new(extension == ".css" ? "text/css" : extension == ".json" ? "application/json" : "application/javascript", reader.ReadToEnd()));
        }
        return new System.Collections.ObjectModel.ReadOnlyDictionary<string, CachedResource>(loaded);
    }

    public bool TryGet(Uri address, out WebResponse response)
    {
        response = null!;
        if (address.GetLeftPart(UriPartial.Authority) != Origin) return false;
        if (address.AbsolutePath == "/Browser/Monaco/Index.html")
        { response = new(address, 200, "text/html", MonacoPage); return true; }
        if (XFESystem.Documents.WebsiteAssets.TryReadWebText(address.AbsolutePath, out var website, out var mime))
        {
            response = new(address, 200, mime, website); return true;
        }
        if (!resources.TryGetValue(address.AbsolutePath, out var cached)) return false;
        response = new(address, 200, cached.ContentType, cached.Body);
        return true;
    }

    public const string MonacoPage = """
        <!doctype html><html><head><meta charset="utf-8"><title>XFESystem Monaco</title>
        <style>html,body{margin:0;padding:0;width:100%;height:100%;background:#09121b;color:#e7f3fc;font-family:monospace}
        #Status{height:28px;line-height:28px;padding-left:12px;color:#75c9f5}#Editor{position:absolute;left:0;right:0;top:28px;bottom:0}
        #Languages{position:absolute;right:4px;top:2px;display:flex;gap:4px}#Languages button{height:24px;padding:2px 10px;border:1px solid #75c9f5;border-radius:4px;background:#182e40;color:#e7f3fc;cursor:pointer}#Languages button:hover{background:#315069}</style>
        <link rel="stylesheet" href="0.52.2/Core/EditorCore.css">
        </head><body><div id="Status">Loading official Monaco Editor 0.52.2...</div><div id="Languages"><button id="JavaScriptLanguage">JavaScript</button><button id="CSharpLanguage">C#</button></div><div id="Editor"></div>
        <script src="../WebsiteCode/Highlight.js"></script><script src="../WebsiteCode/CSharp.js"></script>
        <script src="0.52.2/Core/EditorCore.js"></script><script src="../WebsiteCode/CodePalette.js"></script><script src="../WebsiteCode/WebsiteMonaco.js"></script><script>
          try {
          // Keep upstream Monarch syntax coloring; worker-backed TypeScript
          // language services are unavailable in this browser profile.
          if(monaco.languages.typescript) monaco.languages.typescript.javascriptDefaults.setModeConfiguration({completionItems:false,hovers:false,documentSymbols:false,
            definitions:false,references:false,documentHighlights:false,rename:false,diagnostics:false,
            documentRangeFormattingEdits:false,documentFormattingEdits:false,codeActions:false,inlayHints:false});
          const defaultJavaScript='// XFESystem | XFEstudio\nconst answer = 6 * 7;\nconsole.log(answer);';
          const defaultCSharp='using System;\nnamespace XFEstudio;\npublic sealed class Preview\n{\n    public string Message { get; set; } = "Hello XFESystem";\n    public static int Run(int value)\n    {\n        if (value > 0) return Math.Max(value, 42);\n        Console.WriteLine("Ready");\n        return 0;\n    }\n}';
          const initialLanguage=typeof __xfeMonacoInitialLanguage==='string'?__xfeMonacoInitialLanguage:location.search.indexOf('language=csharp')>=0?'csharp':'javascript';
          const initialSource=typeof __xfeMonacoInitialSource==='string'?__xfeMonacoInitialSource:initialLanguage==='csharp'?defaultCSharp:defaultJavaScript;
          delete globalThis.__xfeMonacoInitialSource;delete globalThis.__xfeMonacoInitialLanguage;
          let initialModel=null;
          xfeWebsiteHighlight.install(function(){return globalThis.xfeMonacoEditor?xfeMonacoEditor.getModel():initialModel;});
          const initialTheme=initialLanguage==='csharp'?'xfe-website':'vs-dark';
          monaco.editor.setTheme(initialTheme);
          initialModel=monaco.editor.createModel(initialSource,initialLanguage);
          globalThis.xfeMonacoEditor=monaco.editor.create(document.getElementById('Editor'),{
            model:initialModel,theme:initialTheme,
            fontSize:13,lineHeight:20,fontFamily:'Consolas',minimap:{enabled:false},automaticLayout:true,
            accessibilitySupport:'off',renderWhitespace:'none',scrollBeyondLastLine:false,overviewRulerLanes:0,overviewRulerBorder:false,
            wordBasedSuggestions:'off',links:false,colorDecorators:false,codeLens:false,quickSuggestions:false,suggestOnTriggerCharacters:false,
            renderValidationDecorations:'off',folding:false,unicodeHighlight:{ambiguousCharacters:false,invisibleCharacters:false,nonBasicASCII:false},
            occurrencesHighlight:'off',selectionHighlight:false,bracketPairColorization:{enabled:false},stickyScroll:{enabled:false},
            guides:{indentation:false,highlightActiveIndentation:false,bracketPairs:false},renderLineHighlight:'none'
          });
          xfeMonacoEditor.getModel().updateOptions({bracketColorizationOptions:{enabled:false,independentColorPoolPerBracketType:false}});
          const status=function(language){document.getElementById('Status').textContent=language==='csharp'?'Monaco C# - website grammar and palette':language==='plaintext'?'Monaco plain text - ready':'Official Monaco 0.52.2 - ready';};
          status(initialLanguage);
          globalThis.xfeMonacoSetLanguage=function(language,source){
            if(language!=='csharp' && language!=='javascript' && language!=='plaintext')throw new Error('Unsupported editor language');
            monaco.editor.setModelLanguage(xfeMonacoEditor.getModel(),language);
            monaco.editor.setTheme(language==='csharp'?'xfe-website':'vs-dark');
            if(typeof source==='string')xfeMonacoEditor.setValue(source);
            else if(!globalThis.xfeMonacoFileMode)xfeMonacoEditor.setValue(language==='csharp'?defaultCSharp:defaultJavaScript);
            status(language);
          };
          document.getElementById('JavaScriptLanguage').addEventListener('click',function(){xfeMonacoSetLanguage('javascript');});
          document.getElementById('CSharpLanguage').addEventListener('click',function(){xfeMonacoSetLanguage('csharp');});
          xfeMonacoEditor.onDidChangeModelContent(function(){document.getElementById('Status').textContent='Monaco - edited '+xfeMonacoEditor.getValue().length+' characters';});
          } catch(error) {document.getElementById('Status').textContent='Monaco failed: '+String(error);console.error(String(error),error.stack);}
        </script></body></html>
        """;
}