Browse Source

Merge branch 'master' of github.com:Squidex/squidex

pull/216/head
Sebastian Stehle 8 years ago
parent
commit
58b5fe801d
  1. 4
      src/Squidex.Domain.Apps.Entities/Rules/RuleDequeuer.cs
  2. 4
      src/Squidex.Infrastructure.Azure/Assets/AzureBlobAssetStore.cs
  3. 0
      src/Squidex.Infrastructure.GetEventStore/EventSourcing/Formatter.cs
  4. 29
      src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStore.cs
  5. 73
      src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStoreSubscription.cs
  6. 88
      src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionHelper.cs
  7. 4
      src/Squidex.Infrastructure.GoogleCloud/Assets/GoogleCloudAssetStore.cs
  8. 4
      src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs
  9. 2
      src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs
  10. 4
      src/Squidex.Infrastructure.RabbitMq/CQRS/Events/RabbitMqEventConsumer.cs
  11. 4
      src/Squidex.Infrastructure.Redis/RedisPubSub.cs
  12. 4
      src/Squidex.Infrastructure/Assets/FolderAssetStore.cs
  13. 4
      src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerGrainManager.cs
  14. 15
      src/Squidex.Infrastructure/IInitializable.cs
  15. 6
      src/Squidex.Infrastructure/IRunnable.cs
  16. 4
      src/Squidex.Infrastructure/Log/FileChannel.cs
  17. 4
      src/Squidex.Infrastructure/States/StateFactory.cs
  18. 6
      src/Squidex/Config/Domain/AssetServices.cs
  19. 2
      src/Squidex/Config/Domain/EventPublishersServices.cs
  20. 4
      src/Squidex/Config/Domain/EventStoreServices.cs
  21. 2
      src/Squidex/Config/Domain/InfrastructureServices.cs
  22. 2
      src/Squidex/Config/Domain/PubSubServices.cs
  23. 6
      src/Squidex/Config/Domain/ReadServices.cs
  24. 30
      src/Squidex/Config/Domain/StoreServices.cs
  25. 16
      src/Squidex/Config/Domain/SystemExtensions.cs
  26. 3
      src/Squidex/WebStartup.cs
  27. 10
      tests/Squidex.Infrastructure.Tests/Assets/AssetStoreTests.cs
  28. 2
      tests/Squidex.Infrastructure.Tests/Assets/AzureBlobAssetStoreTests.cs
  29. 6
      tests/Squidex.Infrastructure.Tests/Assets/FolderAssetStoreTests.cs
  30. 2
      tests/Squidex.Infrastructure.Tests/Assets/GoogleCloudAssetStoreTests.cs
  31. 10
      tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerManagerTests.cs
  32. 2
      tests/Squidex.Infrastructure.Tests/States/StateEventSourcingTests.cs
  33. 2
      tests/Squidex.Infrastructure.Tests/States/StateSnapshotTests.cs

4
src/Squidex.Domain.Apps.Entities/Rules/RuleDequeuer.cs

@ -21,7 +21,7 @@ using Squidex.Infrastructure.Timers;
namespace Squidex.Domain.Apps.Entities.Rules
{
public class RuleDequeuer : DisposableObjectBase, IExternalSystem
public class RuleDequeuer : DisposableObjectBase, IRunnable
{
private readonly ActionBlock<IRuleEventEntity> requestBlock;
private readonly IRuleEventRepository ruleEventRepository;
@ -63,7 +63,7 @@ namespace Squidex.Domain.Apps.Entities.Rules
}
}
public void Connect()
public void Run()
{
}

4
src/Squidex.Infrastructure.Azure/Assets/AzureBlobAssetStore.cs

@ -14,7 +14,7 @@ using Microsoft.WindowsAzure.Storage.Blob;
namespace Squidex.Infrastructure.Assets
{
public class AzureBlobAssetStore : IAssetStore, IExternalSystem
public class AzureBlobAssetStore : IAssetStore, IInitializable
{
private const string AssetVersion = "AssetVersion";
private const string AssetId = "AssetId";
@ -31,7 +31,7 @@ namespace Squidex.Infrastructure.Assets
this.containerName = containerName;
}
public void Connect()
public void Initialize()
{
try
{

0
src/Squidex.Infrastructure.GetEventStore/EventSourcing/Events/Formatter.cs → src/Squidex.Infrastructure.GetEventStore/EventSourcing/Formatter.cs

29
src/Squidex.Infrastructure.GetEventStore/EventSourcing/Events/GetEventStore.cs → src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStore.cs

@ -15,7 +15,7 @@ using EventStore.ClientAPI;
namespace Squidex.Infrastructure.EventSourcing
{
public sealed class GetEventStore : IEventStore, IExternalSystem
public sealed class GetEventStore : IEventStore, IInitializable
{
private const int WritePageSize = 500;
private const int ReadPageSize = 500;
@ -37,7 +37,7 @@ namespace Squidex.Infrastructure.EventSourcing
{
}
public void Connect()
public void Initialize()
{
try
{
@ -54,9 +54,30 @@ namespace Squidex.Infrastructure.EventSourcing
return new GetEventStoreSubscription(connection, subscriber, projectionHost, prefix, position, streamFilter);
}
public Task GetEventsAsync(Func<StoredEvent, Task> callback, CancellationToken cancellationToken, string streamFilter = null, string position = null)
public async Task GetEventsAsync(Func<StoredEvent, Task> callback, CancellationToken cancellationToken, string streamFilter = null, string position = null)
{
throw new NotSupportedException();
var streamName = await connection.CreateProjectionAsync(projectionHost, prefix, streamFilter);
var sliceStart = ProjectionHelper.ParsePosition(position);
StreamEventsSlice currentSlice;
do
{
currentSlice = await connection.ReadStreamEventsForwardAsync(GetStreamName(streamName), sliceStart, ReadPageSize, false);
if (currentSlice.Status == SliceReadStatus.Success)
{
sliceStart = currentSlice.NextEventNumber;
foreach (var resolved in currentSlice.Events)
{
var storedEvent = Formatter.Read(resolved);
await callback(storedEvent);
}
}
}
while (!currentSlice.IsEndOfStream && !cancellationToken.IsCancellationRequested);
}
public async Task<IReadOnlyList<StoredEvent>> GetEventsAsync(string streamName, long streamPosition = 0)

73
src/Squidex.Infrastructure.GetEventStore/EventSourcing/GetEventStoreSubscription.cs

@ -0,0 +1,73 @@
// ==========================================================================
// GetEventStoreSubscription.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
using System.Threading.Tasks;
using EventStore.ClientAPI;
using EventStore.ClientAPI.Exceptions;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Infrastructure.EventSourcing
{
internal sealed class GetEventStoreSubscription : IEventSubscription
{
private readonly IEventStoreConnection eventStoreConnection;
private readonly IEventSubscriber eventSubscriber;
private readonly EventStoreCatchUpSubscription subscription;
private readonly long? position;
public GetEventStoreSubscription(
IEventStoreConnection eventStoreConnection,
IEventSubscriber eventSubscriber,
string projectionHost,
string prefix,
string position,
string streamFilter)
{
Guard.NotNull(eventSubscriber, nameof(eventSubscriber));
Guard.NotNullOrEmpty(streamFilter, nameof(streamFilter));
this.eventStoreConnection = eventStoreConnection;
this.eventSubscriber = eventSubscriber;
this.position = ProjectionHelper.ParsePositionOrNull(position);
var streamName = eventStoreConnection.CreateProjectionAsync(projectionHost, prefix, streamFilter).Result;
subscription = SubscribeToStream(streamName);
}
public Task StopAsync()
{
subscription.Stop();
return TaskHelper.Done;
}
private EventStoreCatchUpSubscription SubscribeToStream(string streamName)
{
var settings = CatchUpSubscriptionSettings.Default;
return eventStoreConnection.SubscribeToStreamFrom(streamName, position, settings,
(s, e) =>
{
var storedEvent = Formatter.Read(e);
eventSubscriber.OnEventAsync(this, storedEvent).Wait();
}, null,
(s, reason, ex) =>
{
if (reason != SubscriptionDropReason.ConnectionClosed &&
reason != SubscriptionDropReason.UserInitiated)
{
ex = ex ?? new ConnectionClosedException($"Subscription closed with reason {reason}.");
eventSubscriber.OnErrorAsync(this, ex);
}
});
}
}
}

88
src/Squidex.Infrastructure.GetEventStore/EventSourcing/Events/GetEventStoreSubscription.cs → src/Squidex.Infrastructure.GetEventStore/EventSourcing/ProjectionHelper.cs

@ -1,5 +1,5 @@
// ==========================================================================
// GetEventStoreSubscription.cs
// ProjectionHelper.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -16,82 +16,26 @@ using System.Threading.Tasks;
using EventStore.ClientAPI;
using EventStore.ClientAPI.Exceptions;
using EventStore.ClientAPI.Projections;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Infrastructure.EventSourcing
{
internal sealed class GetEventStoreSubscription : IEventSubscription
public static class ProjectionHelper
{
private const string ProjectionName = "by-{0}-{1}";
private static readonly ConcurrentDictionary<string, bool> SubscriptionsCreated = new ConcurrentDictionary<string, bool>();
private readonly IEventStoreConnection eventStoreConnection;
private readonly IEventSubscriber eventSubscriber;
private readonly string prefix;
private readonly string streamFilter;
private readonly string projectionHost;
private readonly EventStoreCatchUpSubscription subscription;
private readonly long? position;
public GetEventStoreSubscription(
IEventStoreConnection eventStoreConnection,
IEventSubscriber eventSubscriber,
string projectionHost,
string prefix,
string position,
string streamFilter)
{
Guard.NotNull(eventSubscriber, nameof(eventSubscriber));
Guard.NotNullOrEmpty(streamFilter, nameof(streamFilter));
this.eventStoreConnection = eventStoreConnection;
this.eventSubscriber = eventSubscriber;
this.position = ParsePosition(position);
this.prefix = prefix;
this.projectionHost = projectionHost;
this.streamFilter = streamFilter;
var streamName = ParseFilter(prefix, streamFilter);
InitializeAsync(streamName).Wait();
subscription = SubscribeToStream(streamName);
}
public Task StopAsync()
private static string ParseFilter(string prefix, string filter)
{
subscription.Stop();
return TaskHelper.Done;
return string.Format(CultureInfo.InvariantCulture, ProjectionName, prefix.Simplify(), filter.Simplify());
}
private EventStoreCatchUpSubscription SubscribeToStream(string streamName)
public static async Task<string> CreateProjectionAsync(this IEventStoreConnection connection, string projectionHost, string prefix, string streamFilter = null)
{
var settings = CatchUpSubscriptionSettings.Default;
return eventStoreConnection.SubscribeToStreamFrom(streamName, position, settings,
(s, e) =>
{
var storedEvent = Formatter.Read(e);
eventSubscriber.OnEventAsync(this, storedEvent).Wait();
}, null,
(s, reason, ex) =>
{
if (reason != SubscriptionDropReason.ConnectionClosed &&
reason != SubscriptionDropReason.UserInitiated)
{
ex = ex ?? new ConnectionClosedException($"Subscription closed with reason {reason}.");
eventSubscriber.OnErrorAsync(this, ex);
}
});
}
var streamName = ParseFilter(prefix, streamFilter);
private async Task InitializeAsync(string streamName)
{
if (SubscriptionsCreated.TryAdd(streamName, true))
{
var projectsManager = await ConnectToProjections();
var projectsManager = await ConnectToProjections(connection, projectionHost);
var projectionConfig =
$@"fromAll()
@ -105,7 +49,7 @@ namespace Squidex.Infrastructure.EventSourcing
try
{
var credentials = eventStoreConnection.Settings.DefaultUserCredentials;
var credentials = connection.Settings.DefaultUserCredentials;
await projectsManager.CreateContinuousAsync($"${streamName}", projectionConfig, credentials);
}
@ -117,9 +61,11 @@ namespace Squidex.Infrastructure.EventSourcing
}
}
}
return streamName;
}
private async Task<ProjectionsManager> ConnectToProjections()
private static async Task<ProjectionsManager> ConnectToProjections(IEventStoreConnection connection, string projectionHost)
{
var addressParts = projectionHost.Split(':');
@ -133,20 +79,20 @@ namespace Squidex.Infrastructure.EventSourcing
var projectionsManager =
new ProjectionsManager(
eventStoreConnection.Settings.Log, endpoint,
eventStoreConnection.Settings.OperationTimeout);
connection.Settings.Log, endpoint,
connection.Settings.OperationTimeout);
return projectionsManager;
}
private static string ParseFilter(string prefix, string filter)
public static long? ParsePositionOrNull(string position)
{
return string.Format(CultureInfo.InvariantCulture, ProjectionName, prefix.Simplify(), filter.Simplify());
return long.TryParse(position, out var parsedPosition) ? (long?)parsedPosition : null;
}
private static long? ParsePosition(string position)
public static long ParsePosition(string position)
{
return long.TryParse(position, out var parsedPosition) ? (long?)parsedPosition : null;
return long.TryParse(position, out var parsedPosition) ? parsedPosition : 0;
}
}
}

4
src/Squidex.Infrastructure.GoogleCloud/Assets/GoogleCloudAssetStore.cs

@ -16,7 +16,7 @@ using Google.Cloud.Storage.V1;
namespace Squidex.Infrastructure.Assets
{
public sealed class GoogleCloudAssetStore : IAssetStore, IExternalSystem
public sealed class GoogleCloudAssetStore : IAssetStore, IInitializable
{
private readonly string bucketName;
private StorageClient storageClient;
@ -28,7 +28,7 @@ namespace Squidex.Infrastructure.Assets
this.bucketName = bucketName;
}
public void Connect()
public void Initialize()
{
try
{

4
src/Squidex.Infrastructure.MongoDb/MongoDb/MongoRepositoryBase.cs

@ -17,7 +17,7 @@ using Squidex.Infrastructure.Tasks;
namespace Squidex.Infrastructure.MongoDb
{
public abstract class MongoRepositoryBase<TEntity> : IExternalSystem
public abstract class MongoRepositoryBase<TEntity> : IInitializable
{
private const string CollectionFormat = "{0}Set";
@ -106,7 +106,7 @@ namespace Squidex.Infrastructure.MongoDb
}
}
public void Connect()
public void Initialize()
{
try
{

2
src/Squidex.Infrastructure.MongoDb/States/MongoSnapshotStore.cs

@ -13,7 +13,7 @@ using Squidex.Infrastructure.MongoDb;
namespace Squidex.Infrastructure.States
{
public class MongoSnapshotStore<T, TKey> : MongoRepositoryBase<MongoState<T, TKey>>, ISnapshotStore<T, TKey>, IExternalSystem
public class MongoSnapshotStore<T, TKey> : MongoRepositoryBase<MongoState<T, TKey>>, ISnapshotStore<T, TKey>, IInitializable
{
private readonly JsonSerializer serializer;

4
src/Squidex.Infrastructure.RabbitMq/CQRS/Events/RabbitMqEventConsumer.cs

@ -15,7 +15,7 @@ using Squidex.Infrastructure.Tasks;
namespace Squidex.Infrastructure.EventSourcing
{
public sealed class RabbitMqEventConsumer : DisposableObjectBase, IExternalSystem, IEventConsumer
public sealed class RabbitMqEventConsumer : DisposableObjectBase, IInitializable, IEventConsumer
{
private readonly JsonSerializerSettings serializerSettings;
private readonly string eventPublisherName;
@ -61,7 +61,7 @@ namespace Squidex.Infrastructure.EventSourcing
}
}
public void Connect()
public void Initialize()
{
try
{

4
src/Squidex.Infrastructure.Redis/RedisPubSub.cs

@ -13,7 +13,7 @@ using StackExchange.Redis;
namespace Squidex.Infrastructure
{
public sealed class RedisPubSub : IPubSub, IExternalSystem
public sealed class RedisPubSub : IPubSub, IInitializable
{
private readonly ConcurrentDictionary<string, object> subscriptions = new ConcurrentDictionary<string, object>();
private readonly Lazy<IConnectionMultiplexer> redisClient;
@ -31,7 +31,7 @@ namespace Squidex.Infrastructure
redisSubscriber = new Lazy<ISubscriber>(() => redis.Value.GetSubscriber());
}
public void Connect()
public void Initialize()
{
try
{

4
src/Squidex.Infrastructure/Assets/FolderAssetStore.cs

@ -14,7 +14,7 @@ using Squidex.Infrastructure.Tasks;
namespace Squidex.Infrastructure.Assets
{
public sealed class FolderAssetStore : IAssetStore, IExternalSystem
public sealed class FolderAssetStore : IAssetStore, IInitializable
{
private readonly ISemanticLog log;
private readonly DirectoryInfo directory;
@ -29,7 +29,7 @@ namespace Squidex.Infrastructure.Assets
directory = new DirectoryInfo(path);
}
public void Connect()
public void Initialize()
{
try
{

4
src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerGrainManager.cs

@ -15,7 +15,7 @@ using Squidex.Infrastructure.States;
namespace Squidex.Infrastructure.EventSourcing.Grains
{
public sealed class EventConsumerGrainManager : DisposableObjectBase, IExternalSystem
public sealed class EventConsumerGrainManager : DisposableObjectBase, IRunnable
{
private readonly IStateFactory factory;
private readonly IPubSub pubSub;
@ -33,7 +33,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
this.consumers = consumers.ToList();
}
public void Connect()
public void Run()
{
var actors = new Dictionary<string, EventConsumerGrain>();

15
src/Squidex.Infrastructure/IInitializable.cs

@ -0,0 +1,15 @@
// ==========================================================================
// IInitializable.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
// All rights reserved.
// ==========================================================================
namespace Squidex.Infrastructure
{
public interface IInitializable
{
void Initialize();
}
}

6
src/Squidex.Infrastructure/IExternalSystem.cs → src/Squidex.Infrastructure/IRunnable.cs

@ -1,5 +1,5 @@
// ==========================================================================
// IExternalSystem.cs
// IRunnable.cs
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex Group
@ -8,8 +8,8 @@
namespace Squidex.Infrastructure
{
public interface IExternalSystem
public interface IRunnable
{
void Connect();
void Run();
}
}

4
src/Squidex.Infrastructure/Log/FileChannel.cs

@ -10,7 +10,7 @@ using Squidex.Infrastructure.Log.Internal;
namespace Squidex.Infrastructure.Log
{
public sealed class FileChannel : DisposableObjectBase, ILogChannel, IExternalSystem
public sealed class FileChannel : DisposableObjectBase, ILogChannel, IInitializable
{
private readonly FileLogProcessor processor;
@ -34,7 +34,7 @@ namespace Squidex.Infrastructure.Log
processor.EnqueueMessage(new LogMessageEntry { Message = message });
}
public void Connect()
public void Initialize()
{
processor.Connect();
}

4
src/Squidex.Infrastructure/States/StateFactory.cs

@ -15,7 +15,7 @@ using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Infrastructure.States
{
public sealed class StateFactory : DisposableObjectBase, IExternalSystem, IStateFactory
public sealed class StateFactory : DisposableObjectBase, IInitializable, IStateFactory
{
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(10);
private readonly IPubSub pubSub;
@ -70,7 +70,7 @@ namespace Squidex.Infrastructure.States
this.streamNameResolver = streamNameResolver;
}
public void Connect()
public void Initialize()
{
pubSubSubscription = pubSub.Subscribe<InvalidateMessage>(m =>
{

6
src/Squidex/Config/Domain/AssetServices.cs

@ -26,7 +26,7 @@ namespace Squidex.Config.Domain
services.AddSingletonAs(c => new FolderAssetStore(path, c.GetRequiredService<ISemanticLog>()))
.As<IAssetStore>()
.As<IExternalSystem>();
.As<IInitializable>();
},
["GoogleCloud"] = () =>
{
@ -34,7 +34,7 @@ namespace Squidex.Config.Domain
services.AddSingletonAs(c => new GoogleCloudAssetStore(bucketName))
.As<IAssetStore>()
.As<IExternalSystem>();
.As<IInitializable>();
},
["AzureBlob"] = () =>
{
@ -43,7 +43,7 @@ namespace Squidex.Config.Domain
services.AddSingletonAs(c => new AzureBlobAssetStore(connectionString, containerName))
.As<IAssetStore>()
.As<IExternalSystem>();
.As<IInitializable>();
}
});
}

2
src/Squidex/Config/Domain/EventPublishersServices.cs

@ -56,7 +56,7 @@ namespace Squidex.Config.Domain
{
services.AddSingletonAs(c => new RabbitMqEventConsumer(c.GetRequiredService<JsonSerializerSettings>(), name, publisherConfig, exchange, eventsFilter))
.As<IEventConsumer>()
.As<IExternalSystem>();
.As<IInitializable>();
}
}
else

4
src/Squidex/Config/Domain/EventStoreServices.cs

@ -33,7 +33,7 @@ namespace Squidex.Config.Domain
return new MongoEventStore(mongDatabase, c.GetRequiredService<IEventNotifier>());
})
.As<IExternalSystem>()
.As<IInitializable>()
.As<IEventStore>();
},
["GetEventStore"] = () =>
@ -45,7 +45,7 @@ namespace Squidex.Config.Domain
var connection = EventStoreConnection.Create(eventStoreConfiguration);
services.AddSingletonAs(c => new GetEventStore(connection, eventStorePrefix, eventStoreProjectionHost))
.As<IExternalSystem>()
.As<IInitializable>()
.As<IEventStore>();
}
});

2
src/Squidex/Config/Domain/InfrastructureServices.cs

@ -45,7 +45,7 @@ namespace Squidex.Config.Domain
{
services.AddSingletonAs(new FileChannel(loggingFile))
.As<ILogChannel>()
.As<IExternalSystem>();
.As<IInitializable>();
}
services.AddSingletonAs(c => new ApplicationInfoLogAppender(typeof(Program).Assembly, Guid.NewGuid()))

2
src/Squidex/Config/Domain/PubSubServices.cs

@ -33,7 +33,7 @@ namespace Squidex.Config.Domain
services.AddSingletonAs(c => new RedisPubSub(redis, c.GetRequiredService<ISemanticLog>()))
.As<IPubSub>()
.As<IExternalSystem>();
.As<IInitializable>();
}
});
}

6
src/Squidex/Config/Domain/ReadServices.cs

@ -44,9 +44,9 @@ namespace Squidex.Config.Domain
services.AddTransient<EventConsumerGrain>();
services.AddSingletonAs<EventConsumerGrainManager>()
.As<IExternalSystem>();
.As<IRunnable>();
services.AddSingletonAs<RuleDequeuer>()
.As<IExternalSystem>();
.As<IRunnable>();
}
var exposeSourceUrl = config.GetOptionalValue("assetStore:exposeSourceUrl", true);
@ -58,7 +58,7 @@ namespace Squidex.Config.Domain
.As<IGraphQLUrlGenerator>();
services.AddSingletonAs<StateFactory>()
.As<IExternalSystem>()
.As<IInitializable>()
.As<IStateFactory>();
services.AddSingletonAs(c => c.GetService<IOptions<MyUsageOptions>>()?.Value?.Plans.OrEmpty());

30
src/Squidex/Config/Domain/StoreServices.cs

@ -64,74 +64,74 @@ namespace Squidex.Config.Domain
services.AddSingletonAs(c => new MongoXmlRepository(mongoDatabase))
.As<IXmlRepository>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoMigrationStatus(mongoDatabase))
.As<IMigrationStatus>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoSnapshotStore<EventConsumerState, string>(mongoDatabase, c.GetRequiredService<JsonSerializer>()))
.As<ISnapshotStore<EventConsumerState, string>>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoUserStore(mongoDatabase))
.As<IUserStore<IUser>>()
.As<IUserFactory>()
.As<IUserResolver>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoRoleStore(mongoDatabase))
.As<IRoleStore<IRole>>()
.As<IRoleFactory>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoPersistedGrantStore(mongoDatabase))
.As<IPersistedGrantStore>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoUsageStore(mongoDatabase))
.As<IUsageStore>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoRuleEventRepository(mongoDatabase))
.As<IRuleEventRepository>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoAppRepository(mongoDatabase))
.As<IAppRepository>()
.As<ISnapshotStore<AppState, Guid>>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoAssetRepository(mongoDatabase))
.As<IAssetRepository>()
.As<ISnapshotStore<AssetState, Guid>>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoRuleRepository(mongoDatabase))
.As<IRuleRepository>()
.As<ISnapshotStore<RuleState, Guid>>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoSchemaRepository(mongoDatabase))
.As<ISchemaRepository>()
.As<ISnapshotStore<SchemaState, Guid>>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoContentRepository(mongoContentDatabase, c.GetService<IAppProvider>()))
.As<IContentRepository>()
.As<ISnapshotStore<ContentState, Guid>>()
.As<IEventConsumer>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoHistoryEventRepository(mongoDatabase, c.GetServices<IHistoryEventsCreator>()))
.As<IHistoryEventRepository>()
.As<IEventConsumer>()
.As<IExternalSystem>();
.As<IInitializable>();
services.AddSingletonAs(c => new MongoAssetStatsRepository(mongoDatabase))
.As<IAssetStatsRepository>()
.As<IEventConsumer>()
.As<IExternalSystem>();
.As<IInitializable>();
}
});
}

16
src/Squidex/Config/Domain/SystemExtensions.cs

@ -16,13 +16,23 @@ namespace Squidex.Config.Domain
{
public static class SystemExtensions
{
public static void TestExternalSystems(this IServiceProvider services)
public static void InitializeAll(this IServiceProvider services)
{
var systems = services.GetRequiredService<IEnumerable<IExternalSystem>>();
var systems = services.GetRequiredService<IEnumerable<IInitializable>>();
foreach (var system in systems)
{
system.Connect();
system.Initialize();
}
}
public static void RunAll(this IServiceProvider services)
{
var systems = services.GetRequiredService<IEnumerable<IRunnable>>();
foreach (var system in systems)
{
system.Run();
}
}

3
src/Squidex/WebStartup.cs

@ -39,8 +39,9 @@ namespace Squidex
public void Configure(IApplicationBuilder app)
{
app.ApplicationServices.LogConfiguration();
app.ApplicationServices.InitializeAll();
app.ApplicationServices.Migrate();
app.ApplicationServices.TestExternalSystems();
app.ApplicationServices.RunAll();
app.UseMyCors();
app.UseMyForwardingRules();

10
tests/Squidex.Infrastructure.Tests/Assets/AssetStoreTests.cs

@ -34,7 +34,7 @@ namespace Squidex.Infrastructure.Assets
[Fact]
public Task Should_throw_exception_if_asset_to_download_is_not_found()
{
((IExternalSystem)Sut).Connect();
((IInitializable)Sut).Initialize();
return Assert.ThrowsAsync<AssetNotFoundException>(() => Sut.DownloadAsync(Id(), 1, "suffix", new MemoryStream()));
}
@ -42,7 +42,7 @@ namespace Squidex.Infrastructure.Assets
[Fact]
public Task Should_throw_exception_if_asset_to_copy_is_not_found()
{
((IExternalSystem)Sut).Connect();
((IInitializable)Sut).Initialize();
return Assert.ThrowsAsync<AssetNotFoundException>(() => Sut.CopyTemporaryAsync(Id(), Id(), 1, null));
}
@ -50,7 +50,7 @@ namespace Squidex.Infrastructure.Assets
[Fact]
public async Task Should_read_and_write_file()
{
((IExternalSystem)Sut).Connect();
((IInitializable)Sut).Initialize();
var assetId = Id();
var assetData = new MemoryStream(new byte[] { 0x1, 0x2, 0x3, 0x4 });
@ -67,7 +67,7 @@ namespace Squidex.Infrastructure.Assets
[Fact]
public async Task Should_commit_temporary_file()
{
((IExternalSystem)Sut).Connect();
((IInitializable)Sut).Initialize();
var tempId = Id();
@ -87,7 +87,7 @@ namespace Squidex.Infrastructure.Assets
[Fact]
public async Task Should_ignore_when_deleting_twice()
{
((IExternalSystem)Sut).Connect();
((IInitializable)Sut).Initialize();
var tempId = Id();

2
tests/Squidex.Infrastructure.Tests/Assets/AzureBlobAssetStoreTests.cs

@ -25,7 +25,7 @@ namespace Squidex.Infrastructure.Assets
// [Fact]
public void Should_calculate_source_url()
{
Sut.Connect();
Sut.Initialize();
var id = Guid.NewGuid().ToString();

6
tests/Squidex.Infrastructure.Tests/Assets/FolderAssetStoreTests.cs

@ -34,13 +34,13 @@ namespace Squidex.Infrastructure.Assets
[Fact]
public void Should_throw_when_creating_directory_failed()
{
Assert.Throws<ConfigurationException>(() => new FolderAssetStore(CreateInvalidPath(), A.Dummy<ISemanticLog>()).Connect());
Assert.Throws<ConfigurationException>(() => new FolderAssetStore(CreateInvalidPath(), A.Dummy<ISemanticLog>()).Initialize());
}
[Fact]
public void Should_create_directory_when_connecting()
{
Sut.Connect();
Sut.Initialize();
Assert.True(Directory.Exists(testFolder));
}
@ -48,7 +48,7 @@ namespace Squidex.Infrastructure.Assets
[Fact]
public void Should_calculate_source_url()
{
Sut.Connect();
Sut.Initialize();
var id = Guid.NewGuid().ToString();

2
tests/Squidex.Infrastructure.Tests/Assets/GoogleCloudAssetStoreTests.cs

@ -25,7 +25,7 @@ namespace Squidex.Infrastructure.Assets
// [Fact]
public void Should_calculate_source_url()
{
Sut.Connect();
Sut.Initialize();
var id = Guid.NewGuid().ToString();

10
tests/Squidex.Infrastructure.Tests/EventSourcing/Grains/EventConsumerManagerTests.cs

@ -42,7 +42,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
[Fact]
public void Should_activate_all_actors()
{
sut.Connect();
sut.Run();
A.CallTo(() => actor1.Activate(consumer1))
.MustHaveHappened();
@ -54,7 +54,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
[Fact]
public void Should_start_correct_actor()
{
sut.Connect();
sut.Run();
pubSub.Publish(new StartConsumerMessage { ConsumerName = consumerName1 }, true);
@ -68,7 +68,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
[Fact]
public void Should_stop_correct_actor()
{
sut.Connect();
sut.Run();
pubSub.Publish(new StopConsumerMessage { ConsumerName = consumerName1 }, true);
@ -82,7 +82,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
[Fact]
public void Should_reset_correct_actor()
{
sut.Connect();
sut.Run();
pubSub.Publish(new ResetConsumerMessage { ConsumerName = consumerName2 }, true);
@ -96,7 +96,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
[Fact]
public async Task Should_get_state_from_all_actors()
{
sut.Connect();
sut.Run();
A.CallTo(() => actor1.GetState())
.Returns(new EventConsumerInfo { Name = consumerName1, Position = "123 " });

2
tests/Squidex.Infrastructure.Tests/States/StateEventSourcingTests.cs

@ -88,7 +88,7 @@ namespace Squidex.Infrastructure.States
.Returns(key);
sut = new StateFactory(pubSub, cache, eventStore, eventDataFormatter, services, streamNameResolver);
sut.Connect();
sut.Initialize();
}
[Fact]

2
tests/Squidex.Infrastructure.Tests/States/StateSnapshotTests.cs

@ -75,7 +75,7 @@ namespace Squidex.Infrastructure.States
.Returns(snapshotStore);
sut = new StateFactory(pubSub, cache, eventStore, eventDataFormatter, services, streamNameResolver);
sut.Connect();
sut.Initialize();
}
public void Dispose()

Loading…
Cancel
Save