← All source files

V18 / 8d896b8a86e5

DesktopResearchBridge.cs

Interfaces/Gui/LilithGui.Worker/DesktopResearchBridge.cs

Unchanged from the preceding version
CS
using System.Collections.Concurrent;
using System.Reflection;
using System.Text.Json;

namespace Lilith.Gui.Worker;

// Implements the selected release's interface without loading a newer Core.
public class DesktopResearchBridge : DispatchProxy, IDisposable
{
    private static readonly ConcurrentDictionary<string,TaskCompletionSource<JsonElement>> Pending = new();
    internal Action<string,object?>? Emit;
    internal object? Options;
    private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive=true };
    internal static bool Complete(JsonElement payload)
    {
        if(!Pending.TryRemove(payload.GetProperty("requestId").GetString()!,out var completion))return false;
        if(payload.TryGetProperty("error",out var error))completion.TrySetException(new IOException(error.GetString()));
        else completion.TrySetResult(payload.GetProperty("result").Clone());
        return true;
    }
    protected override object? Invoke(MethodInfo? method,object?[]? args)
    {
        if(method is null)throw new MissingMethodException();
        if(method.Name=="Dispose"){Dispose();return null;}
        var returnType=method.ReturnType.GetGenericArguments().Single();
        return typeof(DesktopResearchBridge).GetMethod(nameof(Request),BindingFlags.Instance|BindingFlags.NonPublic)!
            .MakeGenericMethod(returnType).Invoke(this,[method.Name,args!]);
    }
    private async Task<T> Request<T>(string operation,object?[] args)
    {
        var ct=args.OfType<CancellationToken>().FirstOrDefault();
        string id=Guid.NewGuid().ToString("N");var completion=new TaskCompletionSource<JsonElement>(TaskCreationOptions.RunContinuationsAsynchronously);
        Pending[id]=completion;
        try
        {
            Emit!("browser_request",new{requestId=id,operation,value=args[0],limit=operation=="SearchAsync"?args[1]:null,options=Options});
            var result=await completion.Task.WaitAsync(TimeSpan.FromMinutes(4),ct);
            return result.Deserialize<T>(JsonOptions)!;
        }
        finally{Pending.TryRemove(id,out _);}
    }
    public void Dispose()=>Emit?.Invoke("browser_close",new{});
}