← All source files

V16 / 6df58cd3ed86

Program.cs

Interfaces/Gui/LilithGui/Program.cs

Changed in this version
CS
using System.Security.Cryptography;
using System.Text.Json;
using Lilith.Gui;

string repo=Directory.GetCurrentDirectory();
bool openBrowser=args.Contains("--open-browser");args=args.Where(a=>a!="--open-browser").ToArray();
while(!File.Exists(Path.Combine(repo,"Version.props"))){repo=Directory.GetParent(repo)?.FullName??throw new DirectoryNotFoundException("Run the GUI inside the Lilith repository.");}
var builder=WebApplication.CreateBuilder(new WebApplicationOptions{Args=args,ContentRootPath=repo,WebRootPath=Path.Combine(repo,"Interfaces","Gui","LilithGui","wwwroot")});
builder.WebHost.UseUrls("http://127.0.0.1:4180");
builder.Logging.SetMinimumLevel(LogLevel.Warning);
builder.Services.Configure<Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerOptions>(o=>o.Limits.MaxRequestBodySize=64000);
var app=builder.Build();string token=Convert.ToHexString(RandomNumberGenerator.GetBytes(32));
await using var session=new GuiSession(repo);
app.Use(async(context,next)=>
{
    context.Response.Headers.CacheControl="no-store";context.Response.Headers["X-Content-Type-Options"]="nosniff";
    context.Response.Headers.ContentSecurityPolicy="default-src 'self'; img-src 'self' blob: data:; style-src 'self'; script-src 'self'; frame-ancestors 'none'; base-uri 'none'";
    string origin="http://127.0.0.1:4180";
    if(context.Request.Host.Value!="127.0.0.1:4180"||context.Request.Headers.Origin is {Count:>0} sent&&sent.ToString()!=origin){context.Response.StatusCode=403;return;}
    if(context.Request.Path.StartsWithSegments("/api")&&context.Request.Headers["X-Lilith-Gui"]!=token){context.Response.StatusCode=401;return;}
    try{await next();}catch(Exception ex){if(!context.Response.HasStarted){context.Response.StatusCode=409;await context.Response.WriteAsJsonAsync(new{error=ex.Message});}}
});
app.UseDefaultFiles();app.UseStaticFiles();
app.MapGet("/api/versions",()=>new VersionCatalog(repo).ListAsync());
app.MapGet("/api/session",()=>session.Summary());
app.MapGet("/api/events",(long? after)=>session.Events(after??0));
app.MapGet("/api/image/{hash}",(string hash)=>Results.File(session.ReadImage(hash),"image/png"));
app.MapPost("/api/boot",async(JsonElement body)=>await session.BootAsync(body.GetProperty("major").GetInt32(),body));
app.MapPost("/api/action",async(JsonElement body)=>
{
    string action=body.GetProperty("action").GetString()??"";
    if(action is not ("chat" or "command" or "panel" or "scenario" or "history" or "cancel" or "approvals" or "approval_decide"))throw new ArgumentException("Unknown GUI action.");
    return await session.SendAsync(action,body);
});
await app.StartAsync();
string url="http://127.0.0.1:4180/#"+token;Console.WriteLine("Lilith GUI: "+url);
GuiTray? tray=null;
if(OperatingSystem.IsWindows())
{
    try{tray=new GuiTray(url);}
    catch(Exception ex){Console.WriteLine("Windows tray unavailable in this desktop session: "+ex.Message+" Use the printed GUI URL.");}
}
using var ownedTray=tray;
if(openBrowser)
{
    try{System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(url){UseShellExecute=true});}
    catch(Exception ex){Console.WriteLine("Open the printed local address in your browser. "+ex.Message);}
}
await app.WaitForShutdownAsync();