2026-02-19 19:43:47 +00:00
using System.Text.RegularExpressions ;
2025-06-01 19:14:21 +00:00
namespace AIStudio.Tools.PluginSystem ;
public static partial class PluginFactory
{
2026-02-19 19:43:47 +00:00
private const string REASON_NO_LONGER_REFERENCED = "no longer referenced by active enterprise environments" ;
public static void RemoveUnreferencedManagedConfigurationPlugins ( ISet < Guid > activeConfigurationIds )
2025-06-01 19:14:21 +00:00
{
2026-02-19 19:43:47 +00:00
if ( ! IsInitialized )
2025-06-01 19:14:21 +00:00
return ;
2026-02-19 19:43:47 +00:00
var pluginIdsToRemove = new HashSet < Guid > ( ) ;
// Case 1: Plugins are already loaded and metadata is available.
foreach ( var plugin in AVAILABLE_PLUGINS . Where ( plugin = >
plugin . Type is PluginType . CONFIGURATION & &
plugin . IsManagedByConfigServer & &
! activeConfigurationIds . Contains ( plugin . Id ) ) )
pluginIdsToRemove . Add ( plugin . Id ) ;
// Case 2: Startup cleanup before the initial plugin load.
// In this case, we inspect the .config directories directly.
if ( Directory . Exists ( CONFIGURATION_PLUGINS_ROOT ) )
{
foreach ( var pluginDirectory in Directory . EnumerateDirectories ( CONFIGURATION_PLUGINS_ROOT ) )
{
var directoryName = Path . GetFileName ( pluginDirectory ) ;
if ( ! Guid . TryParse ( directoryName , out var pluginId ) )
continue ;
if ( activeConfigurationIds . Contains ( pluginId ) )
continue ;
var deployFlag = ReadDeployFlagFromPluginFile ( pluginDirectory ) ;
var isManagedByConfigServer = deployFlag ? ? true ;
if ( ! deployFlag . HasValue )
LOG . LogWarning ( $"Configuration plugin '{pluginId}' does not define 'DEPLOYED_USING_CONFIG_SERVER'. Falling back to the plugin path and treating it as managed because it is stored under '{CONFIGURATION_PLUGINS_ROOT}'." ) ;
if ( isManagedByConfigServer )
pluginIdsToRemove . Add ( pluginId ) ;
}
}
foreach ( var pluginId in pluginIdsToRemove )
RemovePluginAsync ( pluginId , REASON_NO_LONGER_REFERENCED ) ;
}
private static void RemovePluginAsync ( Guid pluginId , string reason )
{
if ( ! IsInitialized )
return ;
LOG . LogWarning ( "Removing plugin with ID '{PluginId}'. Reason: {Reason}." , pluginId , reason ) ;
2025-06-01 19:14:21 +00:00
//
// Remove the plugin from the available plugins list:
//
var availablePluginToRemove = AVAILABLE_PLUGINS . FirstOrDefault ( p = > p . Id = = pluginId ) ;
2026-02-19 19:43:47 +00:00
if ( availablePluginToRemove ! = null )
AVAILABLE_PLUGINS . Remove ( availablePluginToRemove ) ;
else
LOG . LogWarning ( "No available plugin found with ID '{PluginId}' while removing plugin. Reason: {Reason}." , pluginId , reason ) ;
2025-06-01 19:14:21 +00:00
//
// Remove the plugin from the running plugins list:
//
var runningPluginToRemove = RUNNING_PLUGINS . FirstOrDefault ( p = > p . Id = = pluginId ) ;
if ( runningPluginToRemove = = null )
2026-02-19 19:43:47 +00:00
LOG . LogWarning ( "No running plugin found with ID '{PluginId}' while removing plugin. Reason: {Reason}." , pluginId , reason ) ;
2025-06-01 19:14:21 +00:00
else
RUNNING_PLUGINS . Remove ( runningPluginToRemove ) ;
//
// Delete the plugin directory:
//
2026-02-19 19:43:47 +00:00
DeleteConfigurationPluginDirectory ( pluginId ) ;
LOG . LogInformation ( "Plugin with ID '{PluginId}' removed successfully. Reason: {Reason}." , pluginId , reason ) ;
}
private static bool? ReadDeployFlagFromPluginFile ( string pluginDirectory )
{
try
2025-06-01 19:14:21 +00:00
{
2026-02-19 19:43:47 +00:00
var pluginFile = Path . Join ( pluginDirectory , "plugin.lua" ) ;
if ( ! File . Exists ( pluginFile ) )
return null ;
var pluginCode = File . ReadAllText ( pluginFile ) ;
var match = DeployedByConfigServerRegex ( ) . Match ( pluginCode ) ;
if ( ! match . Success )
return null ;
return bool . TryParse ( match . Groups [ 1 ] . Value , out var deployFlag )
? deployFlag
: null ;
2025-06-01 19:14:21 +00:00
}
2026-02-19 19:43:47 +00:00
catch ( Exception ex )
{
LOG . LogWarning ( ex , $"Failed to parse deployment flag from plugin directory '{pluginDirectory}'." ) ;
return null ;
}
}
private static void DeleteConfigurationPluginDirectory ( Guid pluginId )
{
var pluginDirectory = Path . Join ( CONFIGURATION_PLUGINS_ROOT , pluginId . ToString ( ) ) ;
if ( ! Directory . Exists ( pluginDirectory ) )
{
2025-06-01 19:14:21 +00:00
LOG . LogWarning ( $"Plugin directory '{pluginDirectory}' does not exist." ) ;
2026-02-19 19:43:47 +00:00
return ;
}
2025-06-01 19:14:21 +00:00
2026-02-19 19:43:47 +00:00
try
{
Directory . Delete ( pluginDirectory , true ) ;
LOG . LogInformation ( $"Plugin directory '{pluginDirectory}' deleted successfully." ) ;
}
catch ( Exception ex )
{
LOG . LogError ( ex , $"Failed to delete plugin directory '{pluginDirectory}'." ) ;
}
2025-06-01 19:14:21 +00:00
}
2026-02-19 19:43:47 +00:00
[GeneratedRegex(@"^\s*DEPLOYED_USING_CONFIG_SERVER\s*=\s*(true|false)\s*(?:--.*)?$", RegexOptions.IgnoreCase | RegexOptions.Multiline)]
private static partial Regex DeployedByConfigServerRegex ( ) ;
2025-06-01 19:14:21 +00:00
}