You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Framework/Connected.Instance/EntitySynchronizer.cs

120 lines
3.6 KiB

using System.Reflection;
using Connected.Configuration.Environment;
using Connected.Data.Schema;
using Connected.Entities;
using Connected.ServiceModel;
using Connected.ServiceModel.Transactions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace Connected.Instance;
internal static class EntitySynchronizer
{
public static async Task Synchronize(IServiceProvider services, string value)
{
var logger = services.GetService<ILogger<ServerStartup>>();
if (logger is null)
throw new NullReferenceException(nameof(ILogger<ServerStartup>));
logger.LogTrace("Starting entities synchronization.");
if (services.GetService<IContextProvider>() is not IContextProvider provider)
throw new NullReferenceException(nameof(IContextProvider));
using var ctx = provider.Create();
if (ctx.GetService<IEnvironmentService>() is not IEnvironmentService environmentService)
throw new NullReferenceException(nameof(IEnvironmentService));
if (ctx.GetService<ISchemaService>() is not ISchemaService schemaService)
{
logger.LogWarning("ISchemaService is not registered. Entity synchronization skipped.");
return;
}
/*
* entitySynchronization = rebuild
*/
if (string.Equals(value, "rebuild", StringComparison.OrdinalIgnoreCase))
{
logger.LogTrace("Rebuilding entities.");
foreach (var assembly in environmentService.MicroServices)
await Synchronize(schemaService, assembly, logger);
}
else
{
/*
* entitySynchronization = token1; token2,...
*/
var tokens = value.Split(',');
/*
* token1: assembly : assemblyName
* token2: type : typeName
*/
foreach (var token in tokens)
{
var subTokens = token.Split(':');
if (subTokens.Length != 2)
throw new ArgumentException("Invalid entitySyncronization token '{token}'. Expected assembly:[assembly] or type:[type].", token);
if (string.Equals(subTokens[0], "assembly", StringComparison.OrdinalIgnoreCase))
{
logger.LogTrace("Loading assembly '{assembly}'", subTokens[1]);
await Synchronize(schemaService, Assembly.Load(AssemblyName.GetAssemblyName(subTokens[1])), logger);
}
else if (string.Equals(subTokens[0], "type", StringComparison.OrdinalIgnoreCase))
{
var typeTokens = subTokens[1].Split("/");
if (typeTokens.Length != 2)
throw new ArgumentException("Invalid entitySyncronization token '{token}'. Expected type:[assembly]/[type].", subTokens[1]);
var qualifier = $"{typeTokens[1]}, {typeTokens[0]}";
logger.LogTrace("Loading type '{type}'", qualifier);
if (Type.GetType(qualifier) is not Type type)
{
logger.LogWarning("Entity type '{type}' could not be loaded. Synchronization on the specified type could not be performed.", qualifier);
continue;
}
await Synchronize(schemaService, new List<Type> { type });
}
}
}
logger.LogTrace("Commiting snchronization.");
if (ctx.GetService<ITransactionContext>() is ITransactionContext transaction)
await transaction.Commit();
logger.LogTrace("Snchronization completed.");
}
private static async Task Synchronize(ISchemaService schemaService, Assembly assembly, ILogger<ServerStartup> logger)
{
var entities = new List<Type>();
foreach (var type in assembly.GetTypes())
{
if (type.IsAbstract || !type.IsAssignableTo(typeof(IEntity)))
continue;
entities.Add(type);
}
if (entities.Any())
await Synchronize(schemaService, entities);
}
private static async Task Synchronize(ISchemaService schemaService, List<Type> entities)
{
await schemaService.Synchronize(entities);
}
}