📄 ui/src/Services/ScanSession.cs
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Cfa.Ui.Services;

public interface IScanSession : IDisposable
{
    void LoadConfig(FileInfo config);
    Task<CallGraphAnalysis> AnalyzeAsync(FileInfo file, int line, CancellationToken token);
}

public interface IScanSessionFactory
{
    Task<IScanSession> OpenAsync(FileInfo solution, CancellationToken token);
}

public sealed class ScanSessionFactory : IScanSessionFactory
{
    public async Task<IScanSession> OpenAsync(FileInfo solution, CancellationToken token)
    {
        var localPath = Path.Combine(solution.DirectoryName!, ".cfa.json");
        var options = new ScannerOptions { Messages = MessageOptions.LoadJson(localPath: localPath) };
        var scanner = await Scanner.Create(solution, options, token);
        return new ScanSession(scanner, localPath);
    }

    private sealed class ScanSession(Scanner scanner, string localPath) : IScanSession
    {
        public void LoadConfig(FileInfo config) =>
            scanner.ConfigureMessages(MessageOptions.LoadJson(config.FullName, localPath: localPath));

        public async Task<CallGraphAnalysis> AnalyzeAsync(FileInfo file, int line, CancellationToken token) =>
            Analyzer.Analyze(await scanner.BuildCallGraph(file, line, token));

        public void Dispose() => scanner.Dispose();
    }
}