mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 11:26:27 +00:00
Plugins - Ported prerequisites UI
Scripting - Ported scripting UI
This commit is contained in:
1 parent
0256a0d625
commit
3b4194cb9d
56 files changed
+1301
-274
No files matched your search
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core.ScriptingProviders;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
@@ -15,19 +16,24 @@ namespace Artemis.Core
|
||||
private readonly object _lock = new();
|
||||
private bool _isFreshImport;
|
||||
private ProfileElement? _lastSelectedProfileElement;
|
||||
private readonly ObservableCollection<ProfileScript> _scripts;
|
||||
private readonly ObservableCollection<ScriptConfiguration> _scriptConfigurations;
|
||||
|
||||
internal Profile(ProfileConfiguration configuration, ProfileEntity profileEntity) : base(null!)
|
||||
{
|
||||
_scripts = new ObservableCollection<ProfileScript>();
|
||||
_scriptConfigurations = new ObservableCollection<ScriptConfiguration>();
|
||||
|
||||
Configuration = configuration;
|
||||
Profile = this;
|
||||
ProfileEntity = profileEntity;
|
||||
EntityId = profileEntity.Id;
|
||||
Scripts = new List<ProfileScript>();
|
||||
ScriptConfigurations = new List<ScriptConfiguration>();
|
||||
|
||||
UndoStack = new MaxStack<string>(20);
|
||||
RedoStack = new MaxStack<string>(20);
|
||||
Exceptions = new List<Exception>();
|
||||
Scripts = new ReadOnlyObservableCollection<ProfileScript>(_scripts);
|
||||
ScriptConfigurations = new ReadOnlyObservableCollection<ScriptConfiguration>(_scriptConfigurations);
|
||||
|
||||
Load();
|
||||
}
|
||||
@@ -40,12 +46,12 @@ namespace Artemis.Core
|
||||
/// <summary>
|
||||
/// Gets a collection of all active scripts assigned to this profile
|
||||
/// </summary>
|
||||
public List<ProfileScript> Scripts { get; }
|
||||
public ReadOnlyObservableCollection<ProfileScript> Scripts { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of all script configurations assigned to this profile
|
||||
/// </summary>
|
||||
public List<ScriptConfiguration> ScriptConfigurations { get; }
|
||||
public ReadOnlyObservableCollection<ScriptConfiguration> ScriptConfigurations { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether this profile is freshly imported i.e. no changes have been made to it
|
||||
@@ -169,8 +175,8 @@ namespace Artemis.Core
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
while (Scripts.Count > 1)
|
||||
Scripts[0].Dispose();
|
||||
while (Scripts.Count > 0)
|
||||
RemoveScript(Scripts[0]);
|
||||
|
||||
foreach (ProfileElement profileElement in Children)
|
||||
profileElement.Dispose();
|
||||
@@ -208,16 +214,62 @@ namespace Artemis.Core
|
||||
else
|
||||
LastSelectedProfileElement = null;
|
||||
|
||||
foreach (ScriptConfiguration scriptConfiguration in ScriptConfigurations)
|
||||
scriptConfiguration.Script?.Dispose();
|
||||
ScriptConfigurations.Clear();
|
||||
ScriptConfigurations.AddRange(ProfileEntity.ScriptConfigurations.Select(e => new ScriptConfiguration(e)));
|
||||
while (_scriptConfigurations.Any())
|
||||
RemoveScriptConfiguration(_scriptConfigurations[0]);
|
||||
foreach (ScriptConfiguration scriptConfiguration in ProfileEntity.ScriptConfigurations.Select(e => new ScriptConfiguration(e)))
|
||||
AddScriptConfiguration(scriptConfiguration);
|
||||
|
||||
// Load node scripts last since they may rely on the profile structure being in place
|
||||
foreach (RenderProfileElement renderProfileElement in renderElements)
|
||||
foreach (RenderProfileElement renderProfileElement in renderElements)
|
||||
renderProfileElement.LoadNodeScript();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a script configuration from the profile, if the configuration has an active script it is also removed.
|
||||
/// </summary>
|
||||
internal void RemoveScriptConfiguration(ScriptConfiguration scriptConfiguration)
|
||||
{
|
||||
if (!_scriptConfigurations.Contains(scriptConfiguration))
|
||||
return;
|
||||
|
||||
Script? script = scriptConfiguration.Script;
|
||||
if (script != null)
|
||||
RemoveScript((ProfileScript) script);
|
||||
|
||||
_scriptConfigurations.Remove(scriptConfiguration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a script configuration to the profile but does not instantiate it's script.
|
||||
/// </summary>
|
||||
internal void AddScriptConfiguration(ScriptConfiguration scriptConfiguration)
|
||||
{
|
||||
if (!_scriptConfigurations.Contains(scriptConfiguration))
|
||||
_scriptConfigurations.Add(scriptConfiguration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a script that has a script configuration belonging to this profile.
|
||||
/// </summary>
|
||||
internal void AddScript(ProfileScript script)
|
||||
{
|
||||
if (!_scriptConfigurations.Contains(script.ScriptConfiguration))
|
||||
throw new ArtemisCoreException("Cannot add a script to a profile whose script configuration doesn't belong to the same profile.");
|
||||
|
||||
if (!_scripts.Contains(script))
|
||||
_scripts.Add(script);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a script from the profile and disposes it.
|
||||
/// </summary>
|
||||
internal void RemoveScript(ProfileScript script)
|
||||
{
|
||||
_scripts.Remove(script);
|
||||
script.Dispose();
|
||||
|
||||
}
|
||||
|
||||
internal override void Save()
|
||||
{
|
||||
if (Disposed)
|
||||
|
||||
@@ -166,10 +166,13 @@ namespace Artemis.Core
|
||||
/// <inheritdoc />
|
||||
public List<PluginPrerequisite> Prerequisites { get; } = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<PluginPrerequisite> PlatformPrerequisites => Prerequisites.Where(p => p.AppliesToPlatform());
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ArePrerequisitesMet()
|
||||
{
|
||||
return Prerequisites.All(p => p.IsMet());
|
||||
return PlatformPrerequisites.All(p => p.IsMet());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,11 +175,14 @@ namespace Artemis.Core
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<PluginPrerequisite> Prerequisites { get; } = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<PluginPrerequisite> PlatformPrerequisites => Prerequisites.Where(p => p.AppliesToPlatform());
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ArePrerequisitesMet()
|
||||
{
|
||||
return Prerequisites.All(p => p.IsMet());
|
||||
return PlatformPrerequisites.All(p => p.IsMet());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies OS platforms a plugin may support.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum PluginPlatform
|
||||
{
|
||||
/// <summary>The Windows platform.</summary>
|
||||
Windows = 0,
|
||||
|
||||
/// <summary>The Linux platform.</summary>
|
||||
Linux = 1,
|
||||
|
||||
/// <summary>The OSX platform.</summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
OSX = 2
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
@@ -12,6 +11,11 @@ namespace Artemis.Core
|
||||
/// Gets a list of prerequisites for this plugin
|
||||
/// </summary>
|
||||
List<PluginPrerequisite> Prerequisites { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of prerequisites of the current platform for this plugin
|
||||
/// </summary>
|
||||
IEnumerable<PluginPrerequisite> PlatformPrerequisites { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the prerequisites of this plugin are met
|
||||
|
||||
@@ -22,6 +22,11 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public abstract string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the platform(s) this prerequisite applies to.
|
||||
/// </summary>
|
||||
public PluginPlatform? Platform { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of actions to execute when <see cref="Install" /> is called
|
||||
/// </summary>
|
||||
@@ -91,6 +96,23 @@ namespace Artemis.Core
|
||||
/// <returns><see langword="true" /> if the prerequisite is met; otherwise <see langword="false" /></returns>
|
||||
public abstract bool IsMet();
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this prerequisite applies to the current operating system.
|
||||
/// </summary>
|
||||
public bool AppliesToPlatform()
|
||||
{
|
||||
if (Platform == null)
|
||||
return true;
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
return Platform.Value.HasFlag(PluginPlatform.Windows);
|
||||
if (OperatingSystem.IsLinux())
|
||||
return Platform.Value.HasFlag(PluginPlatform.Linux);
|
||||
if (OperatingSystem.IsMacOS())
|
||||
return Platform.Value.HasFlag(PluginPlatform.OSX);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before installation starts
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -36,6 +38,11 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public string Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an optional list of files to extract, if <see langword="null"/> all files will be extracted.
|
||||
/// </summary>
|
||||
public List<string>? FilesToExtract { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task Execute(CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -50,10 +57,15 @@ namespace Artemis.Core
|
||||
{
|
||||
ZipArchive archive = new(fileStream);
|
||||
long count = 0;
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
|
||||
List<ZipArchiveEntry> entries = new(archive.Entries);
|
||||
if (FilesToExtract != null)
|
||||
entries = entries.Where(e => FilesToExtract.Contains(e.FullName)).ToList();
|
||||
|
||||
foreach (ZipArchiveEntry entry in entries)
|
||||
{
|
||||
await using Stream unzippedEntryStream = entry.Open();
|
||||
Progress.Report((count, archive.Entries.Count));
|
||||
Progress.Report((count, entries.Count));
|
||||
if (entry.Length > 0)
|
||||
{
|
||||
string path = Path.Combine(Target, entry.FullName);
|
||||
|
||||
@@ -18,11 +18,13 @@ namespace Artemis.Core.ScriptingProviders
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="ScriptConfiguration" /> class
|
||||
/// </summary>
|
||||
public ScriptConfiguration(ScriptingProvider provider, string name)
|
||||
public ScriptConfiguration(ScriptingProvider provider, string name, ScriptType scriptType)
|
||||
{
|
||||
_scriptingProviderId = provider.Id;
|
||||
_name = name;
|
||||
Entity = new ScriptConfigurationEntity();
|
||||
PendingScriptContent = provider.GetDefaultScriptContent(scriptType);
|
||||
ScriptContent = PendingScriptContent;
|
||||
}
|
||||
|
||||
internal ScriptConfiguration(ScriptConfigurationEntity entity)
|
||||
|
||||
@@ -71,5 +71,11 @@ namespace Artemis.Core.ScriptingProviders
|
||||
/// </summary>
|
||||
/// <param name="scriptType">The type of script the editor will host</param>
|
||||
public abstract IScriptEditorViewModel CreateScriptEditor(ScriptType scriptType);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a script for a certain type needs default content.
|
||||
/// </summary>
|
||||
/// <param name="scriptType">The type of script the default content is for.</param>
|
||||
public abstract string GetDefaultScriptContent(ScriptType scriptType);
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ namespace Artemis.Core.ScriptingProviders
|
||||
/// <inheritdoc />
|
||||
internal override void InternalCleanup()
|
||||
{
|
||||
ScriptingService?.InternalGlobalScripts.Remove(this);
|
||||
ScriptingService?.RemoveScript(ScriptConfiguration);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -60,10 +60,7 @@ namespace Artemis.Core.ScriptingProviders
|
||||
/// <inheritdoc />
|
||||
internal override void InternalCleanup()
|
||||
{
|
||||
lock (Profile.Scripts)
|
||||
{
|
||||
Profile.Scripts.Remove(this);
|
||||
}
|
||||
Profile.RemoveScript(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Artemis.Core.ScriptingProviders
|
||||
public abstract class Script : CorePropertyChanged, IDisposable
|
||||
{
|
||||
private ScriptingProvider _scriptingProvider = null!;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// The base constructor of any script
|
||||
@@ -71,6 +72,10 @@ namespace Artemis.Core.ScriptingProviders
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
_disposed = true;
|
||||
ScriptConfiguration.PropertyChanged -= ScriptConfigurationOnPropertyChanged;
|
||||
ScriptConfiguration.Script = null;
|
||||
ScriptingProvider.InternalScripts.Remove(this);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
Reference in new issue
Block a user