mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2025-08-21 04:12:56 +00:00
Add EnterpriseEnvironmentService and plugin management
This commit is contained in:
parent
944f4a836e
commit
72ea91d5aa
@ -133,6 +133,7 @@ internal sealed class Program
|
|||||||
builder.Services.AddTransient<AgentTextContentCleaner>();
|
builder.Services.AddTransient<AgentTextContentCleaner>();
|
||||||
builder.Services.AddHostedService<UpdateService>();
|
builder.Services.AddHostedService<UpdateService>();
|
||||||
builder.Services.AddHostedService<TemporaryChatService>();
|
builder.Services.AddHostedService<TemporaryChatService>();
|
||||||
|
builder.Services.AddHostedService<EnterpriseEnvironmentService>();
|
||||||
builder.Services.AddRazorComponents()
|
builder.Services.AddRazorComponents()
|
||||||
.AddInteractiveServerComponents()
|
.AddInteractiveServerComponents()
|
||||||
.AddHubOptions(options =>
|
.AddHubOptions(options =>
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
|
namespace AIStudio.Tools.PluginSystem;
|
||||||
|
|
||||||
|
public static partial class PluginFactory
|
||||||
|
{
|
||||||
|
public static async Task<bool> TryDownloadingConfigPluginAsync(Guid configPlugId, string configServerUrl, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
if (!IS_INITIALIZED)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LOG.LogInformation($"Downloading configuration plugin with ID: {configPlugId} from server: {configServerUrl}");
|
||||||
|
var tempDownloadFile = Path.GetTempFileName();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var httpClient = new HttpClient();
|
||||||
|
var response = await httpClient.GetAsync($"{configServerUrl}/{configPlugId}.zip", cancellationToken);
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
await using var tempFileStream = File.Create(tempDownloadFile);
|
||||||
|
await response.Content.CopyToAsync(tempFileStream, cancellationToken);
|
||||||
|
|
||||||
|
var pluginDirectory = Path.Join(CONFIGURATION_PLUGINS_ROOT, configPlugId.ToString());
|
||||||
|
if(Directory.Exists(pluginDirectory))
|
||||||
|
Directory.Delete(pluginDirectory, true);
|
||||||
|
|
||||||
|
Directory.CreateDirectory(pluginDirectory);
|
||||||
|
ZipFile.ExtractToDirectory(tempDownloadFile, pluginDirectory);
|
||||||
|
|
||||||
|
LOG.LogInformation($"Configuration plugin with ID='{configPlugId}' downloaded and extracted successfully to '{pluginDirectory}'.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG.LogError($"Failed to download the enterprise configuration plugin. HTTP Status: {response.StatusCode}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.LogError(e, "An error occurred while downloading or extracting the enterprise configuration plugin.");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (File.Exists(tempDownloadFile))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(tempDownloadFile);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOG.LogError(e, "Failed to delete the temporary download file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
namespace AIStudio.Tools.PluginSystem;
|
||||||
|
|
||||||
|
public static partial class PluginFactory
|
||||||
|
{
|
||||||
|
public static void RemovePluginAsync(Guid pluginId)
|
||||||
|
{
|
||||||
|
if (!IS_INITIALIZED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOG.LogWarning($"Try to remove plugin with ID: {pluginId}");
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remove the plugin from the available plugins list:
|
||||||
|
//
|
||||||
|
var availablePluginToRemove = AVAILABLE_PLUGINS.FirstOrDefault(p => p.Id == pluginId);
|
||||||
|
if (availablePluginToRemove == null)
|
||||||
|
{
|
||||||
|
LOG.LogWarning($"No plugin found with ID: {pluginId}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVAILABLE_PLUGINS.Remove(availablePluginToRemove);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remove the plugin from the running plugins list:
|
||||||
|
//
|
||||||
|
var runningPluginToRemove = RUNNING_PLUGINS.FirstOrDefault(p => p.Id == pluginId);
|
||||||
|
if (runningPluginToRemove == null)
|
||||||
|
LOG.LogWarning($"No running plugin found with ID: {pluginId}");
|
||||||
|
else
|
||||||
|
RUNNING_PLUGINS.Remove(runningPluginToRemove);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Delete the plugin directory:
|
||||||
|
//
|
||||||
|
var pluginDirectory = Path.Join(CONFIGURATION_PLUGINS_ROOT, availablePluginToRemove.Id.ToString());
|
||||||
|
if (Directory.Exists(pluginDirectory))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.Delete(pluginDirectory, true);
|
||||||
|
LOG.LogInformation($"Plugin directory '{pluginDirectory}' deleted successfully.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LOG.LogError(ex, $"Failed to delete plugin directory '{pluginDirectory}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG.LogWarning($"Plugin directory '{pluginDirectory}' does not exist.");
|
||||||
|
|
||||||
|
LOG.LogInformation($"Plugin with ID: {pluginId} removed successfully.");
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ public static partial class PluginFactory
|
|||||||
private static string DATA_DIR = string.Empty;
|
private static string DATA_DIR = string.Empty;
|
||||||
private static string PLUGINS_ROOT = string.Empty;
|
private static string PLUGINS_ROOT = string.Empty;
|
||||||
private static string INTERNAL_PLUGINS_ROOT = string.Empty;
|
private static string INTERNAL_PLUGINS_ROOT = string.Empty;
|
||||||
|
private static string CONFIGURATION_PLUGINS_ROOT = string.Empty;
|
||||||
private static FileSystemWatcher HOT_RELOAD_WATCHER = null!;
|
private static FileSystemWatcher HOT_RELOAD_WATCHER = null!;
|
||||||
private static ILanguagePlugin BASE_LANGUAGE_PLUGIN = NoPluginLanguage.INSTANCE;
|
private static ILanguagePlugin BASE_LANGUAGE_PLUGIN = NoPluginLanguage.INSTANCE;
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ public static partial class PluginFactory
|
|||||||
DATA_DIR = SettingsManager.DataDirectory!;
|
DATA_DIR = SettingsManager.DataDirectory!;
|
||||||
PLUGINS_ROOT = Path.Join(DATA_DIR, "plugins");
|
PLUGINS_ROOT = Path.Join(DATA_DIR, "plugins");
|
||||||
INTERNAL_PLUGINS_ROOT = Path.Join(PLUGINS_ROOT, ".internal");
|
INTERNAL_PLUGINS_ROOT = Path.Join(PLUGINS_ROOT, ".internal");
|
||||||
|
CONFIGURATION_PLUGINS_ROOT = Path.Join(PLUGINS_ROOT, ".config");
|
||||||
|
|
||||||
if (!Directory.Exists(PLUGINS_ROOT))
|
if (!Directory.Exists(PLUGINS_ROOT))
|
||||||
Directory.CreateDirectory(PLUGINS_ROOT);
|
Directory.CreateDirectory(PLUGINS_ROOT);
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
using AIStudio.Tools.PluginSystem;
|
||||||
|
|
||||||
|
namespace AIStudio.Tools.Services;
|
||||||
|
|
||||||
|
public sealed class EnterpriseEnvironmentService(ILogger<TemporaryChatService> logger, RustService rustService) : BackgroundService
|
||||||
|
{
|
||||||
|
public static EnterpriseEnvironment CURRENT_ENVIRONMENT;
|
||||||
|
|
||||||
|
private static readonly TimeSpan CHECK_INTERVAL = TimeSpan.FromMinutes(16);
|
||||||
|
|
||||||
|
#region Overrides of BackgroundService
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||||
|
{
|
||||||
|
logger.LogInformation("The enterprise environment service was initialized.");
|
||||||
|
|
||||||
|
await this.StartUpdating();
|
||||||
|
while (!stoppingToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
await Task.Delay(CHECK_INTERVAL, stoppingToken);
|
||||||
|
await this.StartUpdating();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private async Task StartUpdating()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
logger.LogInformation("Starting update of the enterprise environment.");
|
||||||
|
|
||||||
|
var enterpriseRemoveConfigId = await rustService.EnterpriseEnvRemoveConfigId();
|
||||||
|
var isPlugin2RemoveInUse = PluginFactory.AvailablePlugins.Any(plugin => plugin.Id == enterpriseRemoveConfigId);
|
||||||
|
if (enterpriseRemoveConfigId != Guid.Empty && isPlugin2RemoveInUse)
|
||||||
|
{
|
||||||
|
logger.LogWarning($"The enterprise environment configuration ID '{enterpriseRemoveConfigId}' must be removed.");
|
||||||
|
PluginFactory.RemovePluginAsync(enterpriseRemoveConfigId);
|
||||||
|
}
|
||||||
|
|
||||||
|
var enterpriseConfigServerUrl = await rustService.EnterpriseEnvConfigServerUrl();
|
||||||
|
var enterpriseConfigId = await rustService.EnterpriseEnvConfigId();
|
||||||
|
var nextEnterpriseEnvironment = new EnterpriseEnvironment(enterpriseConfigServerUrl, enterpriseConfigId);
|
||||||
|
if (CURRENT_ENVIRONMENT != nextEnterpriseEnvironment)
|
||||||
|
{
|
||||||
|
logger.LogInformation("The enterprise environment has changed. Updating the current environment.");
|
||||||
|
CURRENT_ENVIRONMENT = nextEnterpriseEnvironment;
|
||||||
|
|
||||||
|
switch (enterpriseConfigServerUrl)
|
||||||
|
{
|
||||||
|
case null when enterpriseConfigId == Guid.Empty:
|
||||||
|
logger.LogInformation("AI Studio runs without an enterprise configuration.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case null:
|
||||||
|
logger.LogWarning($"AI Studio runs with an enterprise configuration id ('{enterpriseConfigId}'), but the configuration server URL is not set.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case not null when enterpriseConfigId == Guid.Empty:
|
||||||
|
logger.LogWarning($"AI Studio runs with an enterprise configuration server URL ('{enterpriseConfigServerUrl}'), but the configuration ID is not set.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger.LogInformation($"AI Studio runs with an enterprise configuration id ('{enterpriseConfigId}') and configuration server URL ('{enterpriseConfigServerUrl}').");
|
||||||
|
await PluginFactory.TryDownloadingConfigPluginAsync(enterpriseConfigId, enterpriseConfigServerUrl);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
logger.LogError(e, "An error occurred while updating the enterprise environment.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user