Plugins - Ported prerequisites UI

Scripting - Ported scripting UI
This commit is contained in:
Robert committed 2022-07-10 23:25:34 +02:00
1 parent 0256a0d625
commit 3b4194cb9d
56 files changed
+1301 -274

No files matched your search

@@ -8,33 +8,40 @@ namespace Artemis.Core.Services
/// </summary>
public interface IScriptingService : IArtemisService
{
/// <summary>
/// Gets a list of all available scripting providers
/// </summary>
ReadOnlyCollection<ScriptingProvider> ScriptingProviders { get; }
/// <summary>
/// Gets a list of all currently active global scripts
/// </summary>
ReadOnlyCollection<GlobalScript> GlobalScripts { get; }
/// <summary>
/// Creates a <see cref="GlobalScript" /> instance for the given <paramref name="scriptConfiguration" />
/// Adds a script by the provided script configuration to the provided profile and instantiates it.
/// </summary>
/// <param name="scriptConfiguration">The script configuration of the script</param>
/// <returns>
/// If the <see cref="ScriptingProvider" /> was found an instance of the script; otherwise <see langword="null" />.
/// </returns>
GlobalScript? CreateScriptInstance(ScriptConfiguration scriptConfiguration);
/// <param name="scriptConfiguration">The script configuration whose script to add.</param>
/// <param name="profile">The profile to add the script to.</param>
ProfileScript AddScript(ScriptConfiguration scriptConfiguration, Profile profile);
/// <summary>
/// Creates a <see cref="ProfileScript" /> instance for the given <paramref name="scriptConfiguration" />
/// Removes a script by the provided script configuration from the provided profile and disposes it.
/// </summary>
/// <param name="profile">The profile the script configuration is configured for</param>
/// <param name="scriptConfiguration">The script configuration of the script</param>
/// <returns>
/// If the <see cref="ScriptingProvider" /> was found an instance of the script; otherwise <see langword="null" />.
/// </returns>
ProfileScript? CreateScriptInstance(Profile profile, ScriptConfiguration scriptConfiguration);
/// <param name="scriptConfiguration">The script configuration whose script to remove.</param>
/// <param name="profile">The profile to remove the script from.</param>
void RemoveScript(ScriptConfiguration scriptConfiguration, Profile profile);
/// <summary>
/// Deletes the provided global script by it's configuration
/// Adds a script by the provided script configuration to the global collection and instantiates it.
/// </summary>
void DeleteScript(ScriptConfiguration scriptConfiguration);
/// <param name="scriptConfiguration">The script configuration whose script to add.</param>
GlobalScript AddScript(ScriptConfiguration scriptConfiguration);
/// <summary>
/// Removes a script by the provided script configuration from the global collection and disposes it.
/// </summary>
/// <param name="scriptConfiguration">The script configuration whose script to remove.</param>
void RemoveScript(ScriptConfiguration scriptConfiguration);
}
}
+123 -92
View File
@@ -6,29 +6,28 @@ using System.Reflection;
using Artemis.Core.ScriptingProviders;
using Ninject;
using Ninject.Parameters;
using Serilog;
namespace Artemis.Core.Services
{
internal class ScriptingService : IScriptingService
{
private readonly ILogger _logger;
private readonly IPluginManagementService _pluginManagementService;
private readonly IProfileService _profileService;
private List<ScriptingProvider> _scriptingProviders;
private readonly List<GlobalScript> _globalScripts;
private readonly List<ScriptingProvider> _scriptingProviders;
public ScriptingService(ILogger logger, IPluginManagementService pluginManagementService, IProfileService profileService)
public ScriptingService(IPluginManagementService pluginManagementService, IProfileService profileService)
{
_logger = logger;
_pluginManagementService = pluginManagementService;
_profileService = profileService;
InternalGlobalScripts = new List<GlobalScript>();
GlobalScripts = new ReadOnlyCollection<GlobalScript>(InternalGlobalScripts);
_pluginManagementService.PluginFeatureEnabled += PluginManagementServiceOnPluginFeatureToggled;
_pluginManagementService.PluginFeatureDisabled += PluginManagementServiceOnPluginFeatureToggled;
_scriptingProviders = _pluginManagementService.GetFeaturesOfType<ScriptingProvider>();
_globalScripts = new List<GlobalScript>();
ScriptingProviders = new ReadOnlyCollection<ScriptingProvider>(_scriptingProviders);
GlobalScripts = new ReadOnlyCollection<GlobalScript>(_globalScripts);
// No need to sub to Deactivated, scripts will deactivate themselves
profileService.ProfileActivated += ProfileServiceOnProfileActivated;
@@ -39,9 +38,112 @@ namespace Artemis.Core.Services
InitializeProfileScripts(profileConfiguration.Profile);
}
}
/// <inheritdoc />
public ReadOnlyCollection<ScriptingProvider> ScriptingProviders { get; }
internal List<GlobalScript> InternalGlobalScripts { get; }
/// <inheritdoc />
public ReadOnlyCollection<GlobalScript> GlobalScripts { get; }
/// <inheritdoc />
public ProfileScript AddScript(ScriptConfiguration scriptConfiguration, Profile profile)
{
profile.AddScriptConfiguration(scriptConfiguration);
return CreateScriptInstance(scriptConfiguration, profile);
}
/// <inheritdoc />
public void RemoveScript(ScriptConfiguration scriptConfiguration, Profile profile)
{
profile.RemoveScriptConfiguration(scriptConfiguration);
}
/// <inheritdoc />
public GlobalScript AddScript(ScriptConfiguration scriptConfiguration)
{
throw new NotImplementedException("Global scripts are not yet implemented.");
}
/// <inheritdoc />
public void RemoveScript(ScriptConfiguration scriptConfiguration)
{
throw new NotImplementedException("Global scripts are not yet implemented.");
}
private GlobalScript CreateScriptInstance(ScriptConfiguration scriptConfiguration)
{
GlobalScript? script = null;
try
{
if (scriptConfiguration.Script != null)
throw new ArtemisCoreException("The provided script configuration already has an active script");
ScriptingProvider? provider = _scriptingProviders.FirstOrDefault(p => p.Id == scriptConfiguration.ScriptingProviderId);
if (provider == null)
throw new ArtemisCoreException($"Can't create script instance as there is no matching scripting provider found for the script ({scriptConfiguration.ScriptingProviderId}).");
script = (GlobalScript) provider.Plugin.Kernel!.Get(
provider.GlobalScriptType,
CreateScriptConstructorArgument(provider.GlobalScriptType, scriptConfiguration)
);
script.ScriptingProvider = provider;
script.ScriptingService = this;
scriptConfiguration.Script = script;
provider.InternalScripts.Add(script);
return script;
}
catch (Exception e)
{
script?.Dispose();
throw new ArtemisCoreException("Failed to initialize global script", e);
}
}
private ProfileScript CreateScriptInstance(ScriptConfiguration scriptConfiguration, Profile profile)
{
ProfileScript? script = null;
try
{
if (scriptConfiguration.Script != null)
throw new ArtemisCoreException("The provided script configuration already has an active script");
ScriptingProvider? provider = _scriptingProviders.FirstOrDefault(p => p.Id == scriptConfiguration.ScriptingProviderId);
if (provider == null)
throw new ArtemisCoreException($"Can't create script instance as there is no matching scripting provider found for the script ({scriptConfiguration.ScriptingProviderId}).");
script = (ProfileScript) provider.Plugin.Kernel!.Get(
provider.ProfileScriptType,
CreateScriptConstructorArgument(provider.ProfileScriptType, profile),
CreateScriptConstructorArgument(provider.ProfileScriptType, scriptConfiguration)
);
script.ScriptingProvider = provider;
scriptConfiguration.Script = script;
provider.InternalScripts.Add(script);
lock (profile)
{
profile.AddScript(script);
}
return script;
}
catch (Exception e)
{
// If something went wrong but the script was created, clean up as best we can
if (script != null)
{
if (profile.Scripts.Contains(script))
profile.RemoveScript(script);
else
script.Dispose();
}
throw new ArtemisCoreException("Failed to initialize profile script", e);
}
}
private ConstructorArgument CreateScriptConstructorArgument(Type scriptType, object value)
{
// Limit to one constructor, there's no need to have more and it complicates things anyway
@@ -57,9 +159,19 @@ namespace Artemis.Core.Services
return new ConstructorArgument(configurationParameter.Name, value);
}
private void InitializeProfileScripts(Profile profile)
{
// Initialize the scripts on the profile
foreach (ScriptConfiguration scriptConfiguration in profile.ScriptConfigurations.Where(c => c.Script == null && _scriptingProviders.Any(p => p.Id == c.ScriptingProviderId)))
CreateScriptInstance(scriptConfiguration, profile);
}
#region Event handlers
private void PluginManagementServiceOnPluginFeatureToggled(object? sender, PluginFeatureEventArgs e)
{
_scriptingProviders = _pluginManagementService.GetFeaturesOfType<ScriptingProvider>();
_scriptingProviders.Clear();
_scriptingProviders.AddRange(_pluginManagementService.GetFeaturesOfType<ScriptingProvider>());
foreach (ProfileConfiguration profileConfiguration in _profileService.ProfileConfigurations)
{
@@ -74,87 +186,6 @@ namespace Artemis.Core.Services
InitializeProfileScripts(e.ProfileConfiguration.Profile);
}
private void InitializeProfileScripts(Profile profile)
{
// Initialize the scripts on the profile
foreach (ScriptConfiguration scriptConfiguration in profile.ScriptConfigurations.Where(c => c.Script == null))
CreateScriptInstance(profile, scriptConfiguration);
}
public ReadOnlyCollection<GlobalScript> GlobalScripts { get; }
public GlobalScript? CreateScriptInstance(ScriptConfiguration scriptConfiguration)
{
GlobalScript? script = null;
try
{
if (scriptConfiguration.Script != null)
throw new ArtemisCoreException("The provided script configuration already has an active script");
ScriptingProvider? provider = _scriptingProviders.FirstOrDefault(p => p.Id == scriptConfiguration.ScriptingProviderId);
if (provider == null)
return null;
script = (GlobalScript) provider.Plugin.Kernel!.Get(
provider.GlobalScriptType,
CreateScriptConstructorArgument(provider.GlobalScriptType, scriptConfiguration)
);
script.ScriptingProvider = provider;
script.ScriptingService = this;
provider.InternalScripts.Add(script);
InternalGlobalScripts.Add(script);
scriptConfiguration.Script = script;
return script;
}
catch (Exception e)
{
_logger.Warning(e, "Failed to initialize global script");
script?.Dispose();
return null;
}
}
public ProfileScript? CreateScriptInstance(Profile profile, ScriptConfiguration scriptConfiguration)
{
ProfileScript? script = null;
try
{
if (scriptConfiguration.Script != null)
throw new ArtemisCoreException("The provided script configuration already has an active script");
ScriptingProvider? provider = _scriptingProviders.FirstOrDefault(p => p.Id == scriptConfiguration.ScriptingProviderId);
if (provider == null)
return null;
script = (ProfileScript) provider.Plugin.Kernel!.Get(
provider.ProfileScriptType,
CreateScriptConstructorArgument(provider.ProfileScriptType, profile),
CreateScriptConstructorArgument(provider.ProfileScriptType, scriptConfiguration)
);
script.ScriptingProvider = provider;
provider.InternalScripts.Add(script);
lock (profile)
{
scriptConfiguration.Script = script;
profile.Scripts.Add(script);
}
return script;
}
catch (Exception e)
{
_logger.Warning(e, "Failed to initialize profile script");
script?.Dispose();
return null;
}
}
/// <inheritdoc />
public void DeleteScript(ScriptConfiguration scriptConfiguration)
{
}
#endregion
}
}
@@ -102,6 +102,16 @@ namespace Artemis.Core.Services
/// </summary>
/// <typeparam name="T">The type of Web API controller to remove</typeparam>
void RemoveController<T>() where T : WebApiController;
/// <summary>
/// Adds a new EmbedIO module and restarts the web server
/// </summary>
void AddModule(PluginFeature feature, Func<IWebModule> create);
/// <summary>
/// Removes a EmbedIO module and restarts the web server
/// </summary>
void RemoveModule(Func<IWebModule> create);
/// <summary>
/// Adds a new EmbedIO module and restarts the web server
@@ -7,14 +7,28 @@ namespace Artemis.Core.Services
internal class WebModuleRegistration
{
public PluginFeature Feature { get; }
public Type WebModuleType { get; }
public Type? WebModuleType { get; }
public Func<IWebModule>? Create { get; }
public WebModuleRegistration(PluginFeature feature, Type webModuleType)
{
Feature = feature;
WebModuleType = webModuleType;
Feature = feature ?? throw new ArgumentNullException(nameof(feature));
WebModuleType = webModuleType ?? throw new ArgumentNullException(nameof(webModuleType));
}
public IWebModule CreateInstance() => (IWebModule) Feature.Plugin.Kernel!.Get(WebModuleType);
public WebModuleRegistration(PluginFeature feature, Func<IWebModule> create)
{
Feature = feature ?? throw new ArgumentNullException(nameof(feature));
Create = create ?? throw new ArgumentNullException(nameof(create));
}
public IWebModule CreateInstance()
{
if (Create != null)
return Create();
if (WebModuleType != null)
return (IWebModule) Feature.Plugin.Kernel!.Get(WebModuleType);
throw new ArtemisCoreException("WebModuleRegistration doesn't have a create function nor a web module type :(");
}
}
}
@@ -170,6 +170,20 @@ namespace Artemis.Core.Services
#region Module management
public void AddModule(PluginFeature feature, Func<IWebModule> create)
{
if (feature == null) throw new ArgumentNullException(nameof(feature));
_modules.Add(new WebModuleRegistration(feature, create));
StartWebServer();
}
public void RemoveModule(Func<IWebModule> create)
{
_modules.RemoveAll(r => r.Create == create);
StartWebServer();
}
public void AddModule<T>(PluginFeature feature) where T : IWebModule
{
if (feature == null) throw new ArgumentNullException(nameof(feature));