mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-17 11:57:59 +00:00
Improve ipc (#102)
This commit is contained in:
1 parent
47f5756e5a
commit
fc64c0b505
81 files changed
+2408
-799
No files matched your search
@@ -1,7 +1,6 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings.DataModel;
|
||||
|
||||
// ReSharper disable NotAccessedPositionalProperty.Local
|
||||
@@ -11,7 +10,7 @@ namespace AIStudio.Settings;
|
||||
/// <summary>
|
||||
/// The settings manager.
|
||||
/// </summary>
|
||||
public sealed class SettingsManager
|
||||
public sealed class SettingsManager(ILogger<SettingsManager> logger)
|
||||
{
|
||||
private const string SETTINGS_FILENAME = "settings.json";
|
||||
|
||||
@@ -20,6 +19,8 @@ public sealed class SettingsManager
|
||||
WriteIndented = true,
|
||||
Converters = { new JsonStringEnumConverter() },
|
||||
};
|
||||
|
||||
private ILogger<SettingsManager> logger = logger;
|
||||
|
||||
/// <summary>
|
||||
/// The directory where the configuration files are stored.
|
||||
@@ -37,64 +38,6 @@ public sealed class SettingsManager
|
||||
public Data ConfigurationData { get; private set; } = new();
|
||||
|
||||
private bool IsSetUp => !string.IsNullOrWhiteSpace(ConfigDirectory) && !string.IsNullOrWhiteSpace(DataDirectory);
|
||||
|
||||
#region API Key Handling
|
||||
|
||||
private readonly record struct GetSecretRequest(string Destination, string UserName);
|
||||
|
||||
/// <summary>
|
||||
/// Data structure for any requested secret.
|
||||
/// </summary>
|
||||
/// <param name="Success">True, when the secret was successfully retrieved.</param>
|
||||
/// <param name="Secret">The secret, e.g., API key.</param>
|
||||
/// <param name="Issue">The issue, when the secret could not be retrieved.</param>
|
||||
public readonly record struct RequestedSecret(bool Success, string Secret, string Issue);
|
||||
|
||||
/// <summary>
|
||||
/// Try to get the API key for the given provider.
|
||||
/// </summary>
|
||||
/// <param name="jsRuntime">The JS runtime to access the Rust code.</param>
|
||||
/// <param name="provider">The provider to get the API key for.</param>
|
||||
/// <returns>The requested secret.</returns>
|
||||
public async Task<RequestedSecret> GetAPIKey(IJSRuntime jsRuntime, IProvider provider) => await jsRuntime.InvokeAsync<RequestedSecret>("window.__TAURI__.invoke", "get_secret", new GetSecretRequest($"provider::{provider.Id}::{provider.InstanceName}::api_key", Environment.UserName));
|
||||
|
||||
private readonly record struct StoreSecretRequest(string Destination, string UserName, string Secret);
|
||||
|
||||
/// <summary>
|
||||
/// Data structure for storing a secret response.
|
||||
/// </summary>
|
||||
/// <param name="Success">True, when the secret was successfully stored.</param>
|
||||
/// <param name="Issue">The issue, when the secret could not be stored.</param>
|
||||
public readonly record struct StoreSecretResponse(bool Success, string Issue);
|
||||
|
||||
/// <summary>
|
||||
/// Try to store the API key for the given provider.
|
||||
/// </summary>
|
||||
/// <param name="jsRuntime">The JS runtime to access the Rust code.</param>
|
||||
/// <param name="provider">The provider to store the API key for.</param>
|
||||
/// <param name="key">The API key to store.</param>
|
||||
/// <returns>The store secret response.</returns>
|
||||
public async Task<StoreSecretResponse> SetAPIKey(IJSRuntime jsRuntime, IProvider provider, string key) => await jsRuntime.InvokeAsync<StoreSecretResponse>("window.__TAURI__.invoke", "store_secret", new StoreSecretRequest($"provider::{provider.Id}::{provider.InstanceName}::api_key", Environment.UserName, key));
|
||||
|
||||
private readonly record struct DeleteSecretRequest(string Destination, string UserName);
|
||||
|
||||
/// <summary>
|
||||
/// Data structure for deleting a secret response.
|
||||
/// </summary>
|
||||
/// <param name="Success">True, when the secret was successfully deleted or not found.</param>
|
||||
/// <param name="Issue">The issue, when the secret could not be deleted.</param>
|
||||
/// <param name="WasEntryFound">True, when the entry was found and deleted.</param>
|
||||
public readonly record struct DeleteSecretResponse(bool Success, string Issue, bool WasEntryFound);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to delete the API key for the given provider.
|
||||
/// </summary>
|
||||
/// <param name="jsRuntime">The JS runtime to access the Rust code.</param>
|
||||
/// <param name="provider">The provider to delete the API key for.</param>
|
||||
/// <returns>The delete secret response.</returns>
|
||||
public async Task<DeleteSecretResponse> DeleteAPIKey(IJSRuntime jsRuntime, IProvider provider) => await jsRuntime.InvokeAsync<DeleteSecretResponse>("window.__TAURI__.invoke", "delete_secret", new DeleteSecretRequest($"provider::{provider.Id}::{provider.InstanceName}::api_key", Environment.UserName));
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Loads the settings from the file system.
|
||||
@@ -102,12 +45,18 @@ public sealed class SettingsManager
|
||||
public async Task LoadSettings()
|
||||
{
|
||||
if(!this.IsSetUp)
|
||||
{
|
||||
this.logger.LogWarning("Cannot load settings, because the configuration is not set up yet.");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
var settingsPath = Path.Combine(ConfigDirectory!, SETTINGS_FILENAME);
|
||||
if(!File.Exists(settingsPath))
|
||||
{
|
||||
this.logger.LogWarning("Cannot load settings, because the settings file does not exist.");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// We read the `"Version": "V3"` line to determine the version of the settings file:
|
||||
await foreach (var line in File.ReadLinesAsync(settingsPath))
|
||||
{
|
||||
@@ -123,16 +72,16 @@ public sealed class SettingsManager
|
||||
Enum.TryParse(settingsVersionText, out Version settingsVersion);
|
||||
if(settingsVersion is Version.UNKNOWN)
|
||||
{
|
||||
Console.WriteLine("Error: Unknown version of the settings file.");
|
||||
this.logger.LogError("Unknown version of the settings file found.");
|
||||
this.ConfigurationData = new();
|
||||
return;
|
||||
}
|
||||
|
||||
this.ConfigurationData = SettingsMigrations.Migrate(settingsVersion, await File.ReadAllTextAsync(settingsPath), JSON_OPTIONS);
|
||||
this.ConfigurationData = SettingsMigrations.Migrate(this.logger, settingsVersion, await File.ReadAllTextAsync(settingsPath), JSON_OPTIONS);
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Error: Failed to read the version of the settings file.");
|
||||
this.logger.LogError("Failed to read the version of the settings file.");
|
||||
this.ConfigurationData = new();
|
||||
}
|
||||
|
||||
@@ -142,14 +91,22 @@ public sealed class SettingsManager
|
||||
public async Task StoreSettings()
|
||||
{
|
||||
if(!this.IsSetUp)
|
||||
{
|
||||
this.logger.LogWarning("Cannot store settings, because the configuration is not set up yet.");
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
var settingsPath = Path.Combine(ConfigDirectory!, SETTINGS_FILENAME);
|
||||
if(!Directory.Exists(ConfigDirectory))
|
||||
{
|
||||
this.logger.LogInformation("Creating the configuration directory.");
|
||||
Directory.CreateDirectory(ConfigDirectory!);
|
||||
|
||||
}
|
||||
|
||||
var settingsJson = JsonSerializer.Serialize(this.ConfigurationData, JSON_OPTIONS);
|
||||
await File.WriteAllTextAsync(settingsPath, settingsJson);
|
||||
|
||||
this.logger.LogInformation("Stored the settings to the file system.");
|
||||
}
|
||||
|
||||
public void InjectSpellchecking(Dictionary<string, object?> attributes) => attributes["spellcheck"] = this.ConfigurationData.App.EnableSpellchecking ? "true" : "false";
|
||||
|
||||
Reference in new issue
Block a user