1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00
Artemis/src/Artemis.Core/Services/DataModelService.cs
Robert a06ad8f011 Marked all service implementations as internal
Core - Enabled XML docs
Modules - Added DI to module VMs
2020-08-19 19:45:22 +02:00

261 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Artemis.Core.Events;
using Artemis.Core.Exceptions;
using Artemis.Core.Extensions;
using Artemis.Core.Models.Profile.Conditions;
using Artemis.Core.Models.Profile.Conditions.Operators;
using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Plugins.Abstract.DataModels;
using Artemis.Core.Plugins.Exceptions;
using Artemis.Core.Plugins.Models;
using Artemis.Core.Services.Interfaces;
using Newtonsoft.Json;
using Serilog;
namespace Artemis.Core.Services
{
/// <summary>
/// Provides access to the main data model
/// </summary>
internal class DataModelService : IDataModelService
{
private readonly List<DataModel> _dataModelExpansions;
private readonly IPluginService _pluginService;
private readonly ILogger _logger;
private readonly List<DisplayConditionOperator> _registeredConditionOperators;
public DataModelService(IPluginService pluginService, ILogger logger)
{
_pluginService = pluginService;
_logger = logger;
_dataModelExpansions = new List<DataModel>();
_registeredConditionOperators = new List<DisplayConditionOperator>();
_pluginService.PluginEnabled += PluginServiceOnPluginEnabled;
_pluginService.PluginDisabled += PluginServiceOnPluginDisabled;
RegisterBuiltInConditionOperators();
foreach (var module in _pluginService.GetPluginsOfType<Module>().Where(m => m.InternalExpandsMainDataModel))
AddModuleDataModel(module);
foreach (var dataModelExpansion in _pluginService.GetPluginsOfType<BaseDataModelExpansion>())
AddDataModelExpansionDataModel(dataModelExpansion);
}
public IReadOnlyCollection<DisplayConditionOperator> RegisteredConditionOperators
{
get
{
lock (_registeredConditionOperators)
{
return _registeredConditionOperators.AsReadOnly();
}
}
}
public IReadOnlyCollection<DataModel> DataModelExpansions
{
get
{
lock (_dataModelExpansions)
{
return new List<DataModel>(_dataModelExpansions).AsReadOnly();
}
}
}
public void AddExpansion(DataModel dataModelExpansion)
{
lock (_dataModelExpansions)
{
_dataModelExpansions.Add(dataModelExpansion);
// TODO SpoinkyNL 3-3-2018: Initialize the expansion and fire an event
}
}
public void RemoveExpansion(DataModel dataModelExpansion)
{
lock (_dataModelExpansions)
{
if (!_dataModelExpansions.Contains(dataModelExpansion))
throw new ArtemisCoreException("Cannot remove a data model expansion that wasn't previously added.");
// TODO SpoinkyNL 3-3-2018: Dispose the expansion and fire an event
_dataModelExpansions.Remove(dataModelExpansion);
}
}
public DataModel GetPluginDataModel(Plugin plugin)
{
if (plugin is Module module)
return module.InternalDataModel;
if (plugin is BaseDataModelExpansion dataModelExpansion)
return dataModelExpansion.InternalDataModel;
return null;
}
public DataModel GetPluginDataModelByGuid(Guid pluginGuid)
{
var pluginInfo = _pluginService.GetAllPluginInfo().FirstOrDefault(i => i.Guid == pluginGuid);
if (pluginInfo == null || !pluginInfo.Enabled)
return null;
return GetPluginDataModel(pluginInfo.Instance);
}
public bool GetPluginExtendsDataModel(Plugin plugin)
{
if (plugin is Module module)
return module.InternalExpandsMainDataModel;
if (plugin is BaseDataModelExpansion)
return true;
return false;
}
public void RegisterConditionOperator(PluginInfo pluginInfo, DisplayConditionOperator displayConditionOperator)
{
if (pluginInfo == null)
throw new ArgumentNullException(nameof(pluginInfo));
if (displayConditionOperator == null)
throw new ArgumentNullException(nameof(displayConditionOperator));
lock (_registeredConditionOperators)
{
if (_registeredConditionOperators.Contains(displayConditionOperator))
return;
displayConditionOperator.Register(pluginInfo, this);
_registeredConditionOperators.Add(displayConditionOperator);
}
}
public void RemoveConditionOperator(DisplayConditionOperator displayConditionOperator)
{
if (displayConditionOperator == null)
throw new ArgumentNullException(nameof(displayConditionOperator));
lock (_registeredConditionOperators)
{
if (!_registeredConditionOperators.Contains(displayConditionOperator))
return;
displayConditionOperator.Unsubscribe();
_registeredConditionOperators.Remove(displayConditionOperator);
}
}
public List<DisplayConditionOperator> GetCompatibleConditionOperators(Type type)
{
lock (_registeredConditionOperators)
{
if (type == null)
return new List<DisplayConditionOperator>(_registeredConditionOperators);
var candidates = _registeredConditionOperators.Where(c => c.CompatibleTypes.Any(t => t.IsCastableFrom(type))).ToList();
// If there are multiple operators with the same description, use the closest match
foreach (var displayConditionOperators in candidates.GroupBy(c => c.Description).Where(g => g.Count() > 1).ToList())
{
var bestCandidate = displayConditionOperators.OrderByDescending(c => c.CompatibleTypes.Contains(type)).FirstOrDefault();
foreach (var displayConditionOperator in displayConditionOperators)
{
if (displayConditionOperator != bestCandidate)
candidates.Remove(displayConditionOperator);
}
}
return candidates;
}
}
public DisplayConditionOperator GetConditionOperator(Guid operatorPluginGuid, string operatorType)
{
return RegisteredConditionOperators.FirstOrDefault(o => o.PluginInfo.Guid == operatorPluginGuid && o.GetType().Name == operatorType);
}
public void LogPredicateDeserializationFailure(DisplayConditionPredicate displayConditionPredicate, JsonException exception)
{
_logger.Warning(
exception,
"Failed to deserialize display condition predicate {left} {operator} {right}",
displayConditionPredicate.Entity.LeftPropertyPath,
displayConditionPredicate.Entity.OperatorType,
displayConditionPredicate.Entity.RightPropertyPath
);
}
public void LogListPredicateDeserializationFailure(DisplayConditionListPredicate displayConditionPredicate, JsonException exception)
{
_logger.Warning(
exception,
"Failed to deserialize display condition list predicate {list} => {left} {operator} {right}",
displayConditionPredicate.Entity.ListPropertyPath,
displayConditionPredicate.Entity.LeftPropertyPath,
displayConditionPredicate.Entity.OperatorType,
displayConditionPredicate.Entity.RightPropertyPath
);
}
private void RegisterBuiltInConditionOperators()
{
// General usage for any type
RegisterConditionOperator(Constants.CorePluginInfo, new EqualsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new NotEqualConditionOperator());
// Numeric operators
RegisterConditionOperator(Constants.CorePluginInfo, new LessThanConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new LessThanOrEqualConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanOrEqualConditionOperator());
// String operators
RegisterConditionOperator(Constants.CorePluginInfo, new StringEqualsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringNotEqualConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringContainsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringNotContainsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringStartsWithConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringEndsWithConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringNullConditionOperator());
}
private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e)
{
if (e.PluginInfo.Instance is Module module && module.InternalExpandsMainDataModel)
AddModuleDataModel(module);
else if (e.PluginInfo.Instance is BaseDataModelExpansion dataModelExpansion)
AddDataModelExpansionDataModel(dataModelExpansion);
}
private void AddDataModelExpansionDataModel(BaseDataModelExpansion dataModelExpansion)
{
if (dataModelExpansion.InternalDataModel.DataModelDescription == null)
throw new ArtemisPluginException(dataModelExpansion.PluginInfo, "Data model expansion overrides GetDataModelDescription but returned null");
AddExpansion(dataModelExpansion.InternalDataModel);
}
private void AddModuleDataModel(Module module)
{
if (module.InternalDataModel.DataModelDescription == null)
throw new ArtemisPluginException(module.PluginInfo, "Module overrides GetDataModelDescription but returned null");
AddExpansion(module.InternalDataModel);
}
private void PluginServiceOnPluginDisabled(object sender, PluginEventArgs e)
{
// Remove all data models related to the plugin
lock (_dataModelExpansions)
{
var toRemove = _dataModelExpansions.Where(d => d.PluginInfo == e.PluginInfo).ToList();
foreach (var dataModel in toRemove)
_dataModelExpansions.Remove(dataModel);
}
}
}
}