Browse Source

Continued with basic setup.

pull/249/head
Sebastian Stehle 9 years ago
parent
commit
80dc7c12a6
  1. 5
      src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEvent.cs
  2. 2
      src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs
  3. 12
      src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonConvention.cs
  4. 2
      src/Squidex.Infrastructure/Commands/DomainObjectBase.cs
  5. 12
      src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerBootstrap.cs
  6. 7
      src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerGrain.cs
  7. 4
      src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerManagerGrain.cs
  8. 12
      src/Squidex.Infrastructure/EventSourcing/Grains/OrleansEventNotifier.cs
  9. 6
      src/Squidex.Infrastructure/States/IStore.cs
  10. 6
      src/Squidex.Infrastructure/States/Persistence.cs
  11. 16
      src/Squidex.Infrastructure/States/Persistence{TSnapshot,TKey}.cs
  12. 4
      src/Squidex.Infrastructure/States/StateFactory.cs
  13. 18
      src/Squidex.Infrastructure/States/Store.cs
  14. 43
      src/Squidex.Infrastructure/States/StoreExtensions.cs
  15. 26
      src/Squidex/AppConfiguration.cs
  16. 3
      src/Squidex/Areas/IdentityServer/Config/LazyClientStore.cs
  17. 43
      src/Squidex/Areas/OrleansDashboard/Middlewares/OrleansDashboardAuthenticationMiddleware.cs
  18. 27
      src/Squidex/Areas/OrleansDashboard/Startup.cs
  19. 2
      src/Squidex/Config/Constants.cs
  20. 2
      src/Squidex/Config/Domain/InfrastructureServices.cs
  21. 8
      src/Squidex/Config/Domain/ReadServices.cs
  22. 41
      src/Squidex/Config/Orleans/ClientServices.cs
  23. 50
      src/Squidex/Config/Orleans/ClientWrapper.cs
  24. 40
      src/Squidex/Config/Orleans/OrleansServices.cs
  25. 32
      src/Squidex/Config/Orleans/SiloServices.cs
  26. 90
      src/Squidex/Config/Orleans/SiloWrapper.cs
  27. 59
      src/Squidex/Program.cs
  28. 1
      src/Squidex/Squidex.csproj
  29. 5
      src/Squidex/WebStartup.cs
  30. 10
      src/Squidex/appsettings.json

5
src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEvent.cs

@ -7,6 +7,7 @@
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using Squidex.Infrastructure.MongoDb;
namespace Squidex.Infrastructure.EventSourcing namespace Squidex.Infrastructure.EventSourcing
{ {
@ -16,7 +17,7 @@ namespace Squidex.Infrastructure.EventSourcing
[BsonRequired] [BsonRequired]
public string Payload { get; set; } public string Payload { get; set; }
[BsonElement] [BsonJson]
[BsonRequired] [BsonRequired]
public JToken Metadata { get; set; } public JToken Metadata { get; set; }
@ -26,7 +27,7 @@ namespace Squidex.Infrastructure.EventSourcing
public static MongoEvent FromEventData(EventData data) public static MongoEvent FromEventData(EventData data)
{ {
return new MongoEvent { Type = data.Type, Metadata = data.Metadata, Payload = data.ToString() }; return new MongoEvent { Type = data.Type, Metadata = data.Metadata, Payload = data.Payload.ToString() };
} }
public EventData ToEventData() public EventData ToEventData()

2
src/Squidex.Infrastructure.MongoDb/EventSourcing/MongoEventStore_Reader.cs

@ -27,7 +27,7 @@ namespace Squidex.Infrastructure.EventSourcing
Guard.NotNull(subscriber, nameof(subscriber)); Guard.NotNull(subscriber, nameof(subscriber));
Guard.NotNullOrEmpty(streamFilter, nameof(streamFilter)); Guard.NotNullOrEmpty(streamFilter, nameof(streamFilter));
return new PollingSubscription(this, notifier, subscriber, streamFilter, position); return new PollingSubscription(this, subscriber, streamFilter, position);
} }
public async Task<IReadOnlyList<StoredEvent>> QueryAsync(string streamName, long streamPosition = 0) public async Task<IReadOnlyList<StoredEvent>> QueryAsync(string streamName, long streamPosition = 0)

12
src/Squidex.Infrastructure.MongoDb/MongoDb/BsonJsonConvention.cs

@ -32,18 +32,6 @@ namespace Squidex.Infrastructure.MongoDb
memberMap.SetSerializer((IBsonSerializer)bsonSerializer); memberMap.SetSerializer((IBsonSerializer)bsonSerializer);
} }
else if (memberMap.MemberType == typeof(JToken))
{
memberMap.SetSerializer(JTokenSerializer<JToken>.Instance);
}
else if (memberMap.MemberType == typeof(JObject))
{
memberMap.SetSerializer(JTokenSerializer<JObject>.Instance);
}
else if (memberMap.MemberType == typeof(JValue))
{
memberMap.SetSerializer(JTokenSerializer<JValue>.Instance);
}
}); });
ConventionRegistry.Register("json", pack, t => true); ConventionRegistry.Register("json", pack, t => true);

2
src/Squidex.Infrastructure/Commands/DomainObjectBase.cs

@ -34,7 +34,7 @@ namespace Squidex.Infrastructure.Commands
{ {
id = key; id = key;
persistence = store.WithSnapshotsAndEventSourcing<T, Guid>(key, ApplySnapshot, ApplyEvent); persistence = store.WithSnapshotsAndEventSourcing<T, Guid>(GetType(), key, ApplySnapshot, ApplyEvent);
return persistence.ReadAsync(); return persistence.ReadAsync();
} }

12
src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerBootstrap.cs

@ -7,10 +7,11 @@
using Orleans; using Orleans;
using Orleans.Runtime; using Orleans.Runtime;
using Squidex.Infrastructure.Tasks;
namespace Squidex.Infrastructure.EventSourcing.Grains namespace Squidex.Infrastructure.EventSourcing.Grains
{ {
public sealed class EventConsumerBootstrap : ILifecycleParticipant<ISiloLifecycle> public sealed class EventConsumerBootstrap : IRunnable
{ {
private readonly IGrainFactory grainFactory; private readonly IGrainFactory grainFactory;
@ -21,14 +22,11 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
this.grainFactory = grainFactory; this.grainFactory = grainFactory;
} }
public void Participate(ISiloLifecycle lifecycle) public void Run()
{ {
lifecycle.Subscribe(SiloLifecycleStage.SiloActive, ct => var grain = grainFactory.GetGrain<IEventConsumerManagerGrain>("Default");
{
var grain = grainFactory.GetGrain<IEventConsumerManagerGrain>("Default");
return grain.ActivateAsync(); grain.ActivateAsync().Forget();
});
} }
} }
} }

7
src/Squidex.Infrastructure/EventSourcing/Grains/EventConsumerGrain.cs

@ -21,11 +21,12 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
public class EventConsumerGrain : Grain, IEventConsumerGrain public class EventConsumerGrain : Grain, IEventConsumerGrain
{ {
private readonly EventConsumerFactory eventConsumerFactory; private readonly EventConsumerFactory eventConsumerFactory;
private readonly IStore<string> store;
private readonly IEventDataFormatter eventDataFormatter; private readonly IEventDataFormatter eventDataFormatter;
private readonly IEventStore eventStore; private readonly IEventStore eventStore;
private readonly ISemanticLog log; private readonly ISemanticLog log;
private readonly IPersistence<EventConsumerState> persistence;
private TaskScheduler scheduler; private TaskScheduler scheduler;
private IPersistence<EventConsumerState> persistence;
private IEventSubscription currentSubscription; private IEventSubscription currentSubscription;
private IEventConsumer eventConsumer; private IEventConsumer eventConsumer;
private EventConsumerState state = new EventConsumerState(); private EventConsumerState state = new EventConsumerState();
@ -61,7 +62,7 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
this.eventDataFormatter = eventDataFormatter; this.eventDataFormatter = eventDataFormatter;
this.eventConsumerFactory = eventConsumerFactory; this.eventConsumerFactory = eventConsumerFactory;
persistence = store.WithSnapshots<EventConsumerState, string>(this.GetPrimaryKeyString(), s => state = s); this.store = store;
} }
public override Task OnActivateAsync() public override Task OnActivateAsync()
@ -70,6 +71,8 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
eventConsumer = eventConsumerFactory(this.GetPrimaryKeyString()); eventConsumer = eventConsumerFactory(this.GetPrimaryKeyString());
persistence = store.WithSnapshots<EventConsumerGrain, EventConsumerState, string>(this.GetPrimaryKeyString(), s => state = s);
return persistence.ReadAsync(); return persistence.ReadAsync();
} }

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

@ -46,8 +46,8 @@ namespace Squidex.Infrastructure.EventSourcing.Grains
{ {
DelayDeactivation(TimeSpan.FromDays(1)); DelayDeactivation(TimeSpan.FromDays(1));
RegisterOrUpdateReminder("Default", TimeSpan.Zero, TimeSpan.FromMinutes(10)); // RegisterOrUpdateReminder("Default", TimeSpan.Zero, TimeSpan.FromMinutes(10));
RegisterTimer(x => ActivateAsync(), null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); // RegisterTimer(x => ActivateAsync(), null, TimeSpan.Zero, TimeSpan.FromSeconds(10));
return Task.FromResult(true); return Task.FromResult(true);
} }

12
src/Squidex.Infrastructure/EventSourcing/Grains/OrleansEventNotifier.cs

@ -10,20 +10,26 @@ using Orleans;
namespace Squidex.Infrastructure.EventSourcing.Grains namespace Squidex.Infrastructure.EventSourcing.Grains
{ {
public sealed class OrleansEventNotifier : IEventNotifier public sealed class OrleansEventNotifier : IEventNotifier, IInitializable
{ {
private readonly IEventConsumerManagerGrain eventConsumerManagerGrain; private readonly IGrainFactory factory;
private IEventConsumerManagerGrain eventConsumerManagerGrain;
public OrleansEventNotifier(IGrainFactory factory) public OrleansEventNotifier(IGrainFactory factory)
{ {
Guard.NotNull(factory, nameof(factory)); Guard.NotNull(factory, nameof(factory));
this.factory = factory;
}
public void Initialize()
{
eventConsumerManagerGrain = factory.GetGrain<IEventConsumerManagerGrain>("Default"); eventConsumerManagerGrain = factory.GetGrain<IEventConsumerManagerGrain>("Default");
} }
public void NotifyEventsStored(string streamName) public void NotifyEventsStored(string streamName)
{ {
eventConsumerManagerGrain.WakeUpAsync(streamName); eventConsumerManagerGrain?.WakeUpAsync(streamName);
} }
public IDisposable Subscribe(Action<string> handler) public IDisposable Subscribe(Action<string> handler)

6
src/Squidex.Infrastructure/States/IStore.cs

@ -13,10 +13,10 @@ namespace Squidex.Infrastructure.States
{ {
public interface IStore<TKey> public interface IStore<TKey>
{ {
IPersistence WithEventSourcing(TKey key, Func<Envelope<IEvent>, Task> applyEvent); IPersistence WithEventSourcing(Type owner, TKey key, Func<Envelope<IEvent>, Task> applyEvent);
IPersistence<T> WithSnapshots<T>(TKey key, Func<T, Task> applySnapshot); IPersistence<TState> WithSnapshots<TState>(Type owner, TKey key, Func<TState, Task> applySnapshot);
IPersistence<T> WithSnapshotsAndEventSourcing<T>(TKey key, Func<T, Task> applySnapshot, Func<Envelope<IEvent>, Task> applyEvent); IPersistence<TState> WithSnapshotsAndEventSourcing<TState>(Type owner, TKey key, Func<TState, Task> applySnapshot, Func<Envelope<IEvent>, Task> applyEvent);
} }
} }

6
src/Squidex.Infrastructure/States/Persistence.cs

@ -11,15 +11,15 @@ using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Infrastructure.States namespace Squidex.Infrastructure.States
{ {
internal sealed class Persistence<TOwner, TKey> : Persistence<TOwner, object, TKey>, IPersistence internal sealed class Persistence<TKey> : Persistence<object, TKey>, IPersistence
{ {
public Persistence(TKey ownerKey, public Persistence(TKey ownerKey, Type ownerType,
IEventStore eventStore, IEventStore eventStore,
IEventDataFormatter eventDataFormatter, IEventDataFormatter eventDataFormatter,
ISnapshotStore<object, TKey> snapshotStore, ISnapshotStore<object, TKey> snapshotStore,
IStreamNameResolver streamNameResolver, IStreamNameResolver streamNameResolver,
Func<Envelope<IEvent>, Task> applyEvent) Func<Envelope<IEvent>, Task> applyEvent)
: base(ownerKey, eventStore, eventDataFormatter, snapshotStore, streamNameResolver, PersistenceMode.EventSourcing, null, applyEvent) : base(ownerKey, ownerType, eventStore, eventDataFormatter, snapshotStore, streamNameResolver, PersistenceMode.EventSourcing, null, applyEvent)
{ {
} }
} }

16
src/Squidex.Infrastructure/States/Persistence{TOwner,TSnapshot,TKey}.cs → src/Squidex.Infrastructure/States/Persistence{TSnapshot,TKey}.cs

@ -15,9 +15,10 @@ using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Infrastructure.States namespace Squidex.Infrastructure.States
{ {
internal class Persistence<TOwner, TSnapshot, TKey> : IPersistence<TSnapshot> internal class Persistence<TSnapshot, TKey> : IPersistence<TSnapshot>
{ {
private readonly TKey ownerKey; private readonly TKey ownerKey;
private readonly Type ownerType;
private readonly ISnapshotStore<TSnapshot, TKey> snapshotStore; private readonly ISnapshotStore<TSnapshot, TKey> snapshotStore;
private readonly IStreamNameResolver streamNameResolver; private readonly IStreamNameResolver streamNameResolver;
private readonly IEventStore eventStore; private readonly IEventStore eventStore;
@ -34,7 +35,7 @@ namespace Squidex.Infrastructure.States
get { return version; } get { return version; }
} }
public Persistence(TKey ownerKey, public Persistence(TKey ownerKey, Type ownerType,
IEventStore eventStore, IEventStore eventStore,
IEventDataFormatter eventDataFormatter, IEventDataFormatter eventDataFormatter,
ISnapshotStore<TSnapshot, TKey> snapshotStore, ISnapshotStore<TSnapshot, TKey> snapshotStore,
@ -44,6 +45,7 @@ namespace Squidex.Infrastructure.States
Func<Envelope<IEvent>, Task> applyEvent) Func<Envelope<IEvent>, Task> applyEvent)
{ {
this.ownerKey = ownerKey; this.ownerKey = ownerKey;
this.ownerType = ownerType;
this.applyState = applyState; this.applyState = applyState;
this.applyEvent = applyEvent; this.applyEvent = applyEvent;
this.eventStore = eventStore; this.eventStore = eventStore;
@ -67,11 +69,11 @@ namespace Squidex.Infrastructure.States
{ {
if (version == EtagVersion.Empty) if (version == EtagVersion.Empty)
{ {
throw new DomainObjectNotFoundException(ownerKey.ToString(), typeof(TOwner)); throw new DomainObjectNotFoundException(ownerKey.ToString(), ownerType);
} }
else else
{ {
throw new DomainObjectVersionException(ownerKey.ToString(), typeof(TOwner), version, expectedVersion); throw new DomainObjectVersionException(ownerKey.ToString(), ownerType, version, expectedVersion);
} }
} }
} }
@ -134,7 +136,7 @@ namespace Squidex.Infrastructure.States
} }
catch (InconsistentStateException ex) catch (InconsistentStateException ex)
{ {
throw new DomainObjectVersionException(ownerKey.ToString(), typeof(TOwner), ex.CurrentVersion, ex.ExpectedVersion); throw new DomainObjectVersionException(ownerKey.ToString(), ownerType, ex.CurrentVersion, ex.ExpectedVersion);
} }
versionSnapshot = newVersion; versionSnapshot = newVersion;
@ -164,7 +166,7 @@ namespace Squidex.Infrastructure.States
} }
catch (WrongEventVersionException ex) catch (WrongEventVersionException ex)
{ {
throw new DomainObjectVersionException(ownerKey.ToString(), typeof(TOwner), ex.CurrentVersion, ex.ExpectedVersion); throw new DomainObjectVersionException(ownerKey.ToString(), ownerType, ex.CurrentVersion, ex.ExpectedVersion);
} }
versionEvents += eventArray.Length; versionEvents += eventArray.Length;
@ -180,7 +182,7 @@ namespace Squidex.Infrastructure.States
private string GetStreamName() private string GetStreamName()
{ {
return streamNameResolver.GetStreamName(typeof(TOwner), ownerKey.ToString()); return streamNameResolver.GetStreamName(ownerType, ownerKey.ToString());
} }
private bool UseSnapshots() private bool UseSnapshots()

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

@ -94,7 +94,7 @@ namespace Squidex.Infrastructure.States
{ {
Guard.NotNull(key, nameof(key)); Guard.NotNull(key, nameof(key));
var stateStore = new Store<T, TKey>(eventStore, eventDataFormatter, services, streamNameResolver); var stateStore = new Store<TKey>(eventStore, eventDataFormatter, services, streamNameResolver);
var state = (T)services.GetService(typeof(T)); var state = (T)services.GetService(typeof(T));
await state.ActivateAsync(key, stateStore); await state.ActivateAsync(key, stateStore);
@ -124,7 +124,7 @@ namespace Squidex.Infrastructure.States
} }
var state = (T)services.GetService(typeof(T)); var state = (T)services.GetService(typeof(T));
var stateStore = new Store<T, TKey>(eventStore, eventDataFormatter, services, streamNameResolver); var stateStore = new Store<TKey>(eventStore, eventDataFormatter, services, streamNameResolver);
stateObj = new ObjectHolder<T, TKey>(state, key, stateStore); stateObj = new ObjectHolder<T, TKey>(state, key, stateStore);

18
src/Squidex.Infrastructure/States/Store.cs

@ -11,7 +11,7 @@ using Squidex.Infrastructure.EventSourcing;
namespace Squidex.Infrastructure.States namespace Squidex.Infrastructure.States
{ {
internal sealed class Store<TOwner, TKey> : IStore<TKey> public sealed class Store<TKey> : IStore<TKey>
{ {
private readonly IServiceProvider services; private readonly IServiceProvider services;
private readonly IStreamNameResolver streamNameResolver; private readonly IStreamNameResolver streamNameResolver;
@ -30,32 +30,32 @@ namespace Squidex.Infrastructure.States
this.streamNameResolver = streamNameResolver; this.streamNameResolver = streamNameResolver;
} }
public IPersistence<TState> WithSnapshots<TState>(TKey key, Func<TState, Task> applySnapshot) public IPersistence<TState> WithSnapshots<TState>(Type owner, TKey key, Func<TState, Task> applySnapshot)
{ {
return CreatePersistence(key, PersistenceMode.Snapshots, applySnapshot, null); return CreatePersistence<TState>(owner, key, PersistenceMode.Snapshots, applySnapshot, null);
} }
public IPersistence<TState> WithSnapshotsAndEventSourcing<TState>(TKey key, Func<TState, Task> applySnapshot, Func<Envelope<IEvent>, Task> applyEvent) public IPersistence<TState> WithSnapshotsAndEventSourcing<TState>(Type owner, TKey key, Func<TState, Task> applySnapshot, Func<Envelope<IEvent>, Task> applyEvent)
{ {
return CreatePersistence(key, PersistenceMode.SnapshotsAndEventSourcing, applySnapshot, applyEvent); return CreatePersistence<TState>(owner, key, PersistenceMode.SnapshotsAndEventSourcing, applySnapshot, applyEvent);
} }
public IPersistence WithEventSourcing(TKey key, Func<Envelope<IEvent>, Task> applyEvent) public IPersistence WithEventSourcing(Type owner, TKey key, Func<Envelope<IEvent>, Task> applyEvent)
{ {
Guard.NotDefault(key, nameof(key)); Guard.NotDefault(key, nameof(key));
var snapshotStore = (ISnapshotStore<object, TKey>)services.GetService(typeof(ISnapshotStore<object, TKey>)); var snapshotStore = (ISnapshotStore<object, TKey>)services.GetService(typeof(ISnapshotStore<object, TKey>));
return new Persistence<TOwner, TKey>(key, eventStore, eventDataFormatter, snapshotStore, streamNameResolver, applyEvent); return new Persistence<TKey>(key, owner, eventStore, eventDataFormatter, snapshotStore, streamNameResolver, applyEvent);
} }
private IPersistence<TState> CreatePersistence<TState>(TKey key, PersistenceMode mode, Func<TState, Task> applySnapshot, Func<Envelope<IEvent>, Task> applyEvent) private IPersistence<TState> CreatePersistence<TState>(Type owner, TKey key, PersistenceMode mode, Func<TState, Task> applySnapshot, Func<Envelope<IEvent>, Task> applyEvent)
{ {
Guard.NotDefault(key, nameof(key)); Guard.NotDefault(key, nameof(key));
var snapshotStore = (ISnapshotStore<TState, TKey>)services.GetService(typeof(ISnapshotStore<TState, TKey>)); var snapshotStore = (ISnapshotStore<TState, TKey>)services.GetService(typeof(ISnapshotStore<TState, TKey>));
return new Persistence<TOwner, TState, TKey>(key, eventStore, eventDataFormatter, snapshotStore, streamNameResolver, mode, applySnapshot, applyEvent); return new Persistence<TState, TKey>(key, owner, eventStore, eventDataFormatter, snapshotStore, streamNameResolver, mode, applySnapshot, applyEvent);
} }
} }
} }

43
src/Squidex.Infrastructure/States/StoreExtensions.cs

@ -6,6 +6,7 @@
// ========================================================================== // ==========================================================================
using System; using System;
using System.Threading.Tasks;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Tasks; using Squidex.Infrastructure.Tasks;
@ -13,19 +14,49 @@ namespace Squidex.Infrastructure.States
{ {
public static class StoreExtensions public static class StoreExtensions
{ {
public static IPersistence WithEventSourcing<TKey>(this IStore<TKey> store, TKey key, Action<Envelope<IEvent>> applyEvent) public static IPersistence WithEventSourcing<TOwner, TKey>(this IStore<TKey> store, TKey key, Func<Envelope<IEvent>, Task> applyEvent)
{ {
return store.WithEventSourcing(key, applyEvent.ToAsync()); return store.WithEventSourcing(typeof(TOwner), key, applyEvent);
} }
public static IPersistence<TState> WithSnapshots<TState, TKey>(this IStore<TKey> store, TKey key, Action<TState> applySnapshot) public static IPersistence<TState> WithSnapshots<TOwner, TState, TKey>(this IStore<TKey> store, TKey key, Func<TState, Task> applySnapshot)
{ {
return store.WithSnapshots(key, applySnapshot.ToAsync()); return store.WithSnapshots<TState>(typeof(TOwner), key, applySnapshot);
} }
public static IPersistence<TState> WithSnapshotsAndEventSourcing<TState, TKey>(this IStore<TKey> store, TKey key, Action<TState> applySnapshot, Action<Envelope<IEvent>> applyEvent) public static IPersistence<TState> WithSnapshotsAndEventSourcing<TOwner, TState, TKey>(this IStore<TKey> store, TKey key, Func<TState, Task> applySnapshot, Func<Envelope<IEvent>, Task> applyEvent)
{ {
return store.WithSnapshotsAndEventSourcing(key, applySnapshot.ToAsync(), applyEvent.ToAsync()); return store.WithSnapshotsAndEventSourcing<TState>(typeof(TOwner), key, applySnapshot, applyEvent);
}
public static IPersistence WithEventSourcing<TKey>(this IStore<TKey> store, Type owner, TKey key, Action<Envelope<IEvent>> applyEvent)
{
return store.WithEventSourcing(owner, key, applyEvent.ToAsync());
}
public static IPersistence<TState> WithSnapshots<TState, TKey>(this IStore<TKey> store, Type owner, TKey key, Action<TState> applySnapshot)
{
return store.WithSnapshots<TState>(owner, key, applySnapshot.ToAsync());
}
public static IPersistence<TState> WithSnapshotsAndEventSourcing<TState, TKey>(this IStore<TKey> store, Type owner, TKey key, Action<TState> applySnapshot, Action<Envelope<IEvent>> applyEvent)
{
return store.WithSnapshotsAndEventSourcing<TState>(owner, key, applySnapshot.ToAsync(), applyEvent.ToAsync());
}
public static IPersistence WithEventSourcing<TOwner, TKey>(this IStore<TKey> store, TKey key, Action<Envelope<IEvent>> applyEvent)
{
return store.WithEventSourcing(typeof(TOwner), key, applyEvent.ToAsync());
}
public static IPersistence<TState> WithSnapshots<TOwner, TState, TKey>(this IStore<TKey> store, TKey key, Action<TState> applySnapshot)
{
return store.WithSnapshots<TState>(typeof(TOwner), key, applySnapshot.ToAsync());
}
public static IPersistence<TState> WithSnapshotsAndEventSourcing<TOwner, TState, TKey>(this IStore<TKey> store, TKey key, Action<TState> applySnapshot, Action<Envelope<IEvent>> applyEvent)
{
return store.WithSnapshotsAndEventSourcing<TState>(typeof(TOwner), key, applySnapshot.ToAsync(), applyEvent.ToAsync());
} }
} }
} }

26
src/Squidex/AppConfiguration.cs

@ -1,26 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.Extensions.Configuration;
namespace Squidex
{
public static class AppConfiguration
{
public static void AddAppConfiguration(this IConfigurationBuilder builder, string environmentName, string[] args)
{
builder.Sources.Clear();
builder.AddJsonFile("appsettings.json", true, true);
builder.AddJsonFile($"appsettings.{environmentName}.json", true);
builder.AddEnvironmentVariables();
builder.AddCommandLine(args);
}
}
}

3
src/Squidex/Areas/IdentityServer/Config/LazyClientStore.cs

@ -130,7 +130,8 @@ namespace Squidex.Areas.IdentityServer.Config
ClientSecrets = new List<Secret> { new Secret(Constants.InternalClientSecret) }, ClientSecrets = new List<Secret> { new Secret(Constants.InternalClientSecret) },
RedirectUris = new List<string> RedirectUris = new List<string>
{ {
urlsOptions.BuildUrl($"{Constants.PortalPrefix}/signin-oidc", false) urlsOptions.BuildUrl($"{Constants.PortalPrefix}/signin-oidc", false),
urlsOptions.BuildUrl($"{Constants.OrleansPrefix}/signin-oidc", false)
}, },
AccessTokenLifetime = (int)TimeSpan.FromDays(30).TotalSeconds, AccessTokenLifetime = (int)TimeSpan.FromDays(30).TotalSeconds,
AllowedGrantTypes = GrantTypes.ImplicitAndClientCredentials, AllowedGrantTypes = GrantTypes.ImplicitAndClientCredentials,

43
src/Squidex/Areas/OrleansDashboard/Middlewares/OrleansDashboardAuthenticationMiddleware.cs

@ -0,0 +1,43 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Http;
using Squidex.Shared.Identity;
namespace Squidex.Areas.OrleansDashboard.Middlewares
{
public sealed class OrleansDashboardAuthenticationMiddleware
{
private readonly RequestDelegate next;
public OrleansDashboardAuthenticationMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
var authentication = await context.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
if (!authentication.Succeeded || !authentication.Principal.IsInRole(SquidexRoles.Administrator))
{
await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties
{
RedirectUri = context.Request.PathBase + context.Request.Path
});
}
else
{
await next(context);
}
}
}
}

27
src/Squidex/Areas/OrleansDashboard/Startup.cs

@ -0,0 +1,27 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.AspNetCore.Builder;
using Orleans;
using Squidex.Areas.OrleansDashboard.Middlewares;
using Squidex.Config;
namespace Squidex.Areas.OrleansDashboard
{
public static class Startup
{
public static void ConfigureOrleansDashboard(this IApplicationBuilder app)
{
app.Map(Constants.OrleansPrefix, orleansApp =>
{
orleansApp.UseAuthentication();
orleansApp.UseMiddleware<OrleansDashboardAuthenticationMiddleware>();
orleansApp.UseOrleansDashboard();
});
}
}
}

2
src/Squidex/Config/Constants.cs

@ -17,6 +17,8 @@ namespace Squidex.Config
public static readonly string ApiScope = "squidex-api"; public static readonly string ApiScope = "squidex-api";
public static readonly string OrleansPrefix = "/orleans";
public static readonly string PortalPrefix = "/portal"; public static readonly string PortalPrefix = "/portal";
public static readonly string RoleScope = "role"; public static readonly string RoleScope = "role";

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

@ -94,6 +94,8 @@ namespace Squidex.Config.Domain
services.AddSingletonAs<Migrator>() services.AddSingletonAs<Migrator>()
.AsSelf(); .AsSelf();
services.AddSingleton(typeof(IStore<>), typeof(Store<>));
} }
} }
} }

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

@ -44,6 +44,9 @@ namespace Squidex.Config.Domain
.As<IRunnable>(); .As<IRunnable>();
services.AddSingletonAs<ContentScheduler>() services.AddSingletonAs<ContentScheduler>()
.As<IRunnable>(); .As<IRunnable>();
services.AddSingletonAs<EventConsumerBootstrap>()
.As<IRunnable>();
} }
var exposeSourceUrl = config.GetOptionalValue("assetStore:exposeSourceUrl", true); var exposeSourceUrl = config.GetOptionalValue("assetStore:exposeSourceUrl", true);
@ -55,8 +58,7 @@ namespace Squidex.Config.Domain
.As<IGraphQLUrlGenerator>(); .As<IGraphQLUrlGenerator>();
services.AddSingletonAs<StateFactory>() services.AddSingletonAs<StateFactory>()
.As<IInitializable>() .As<IStateFactory>().As<IInitializable>();
.As<IStateFactory>();
services.AddSingletonAs(c => c.GetService<IOptions<MyUsageOptions>>()?.Value?.Plans.OrEmpty()); services.AddSingletonAs(c => c.GetService<IOptions<MyUsageOptions>>()?.Value?.Plans.OrEmpty());
@ -112,7 +114,7 @@ namespace Squidex.Config.Domain
.As<IRuleActionHandler>(); .As<IRuleActionHandler>();
services.AddSingletonAs<OrleansEventNotifier>() services.AddSingletonAs<OrleansEventNotifier>()
.As<IEventNotifier>(); .As<IEventNotifier>().As<IInitializable>();
services.AddSingletonAs<RuleEnqueuer>() services.AddSingletonAs<RuleEnqueuer>()
.As<IEventConsumer>(); .As<IEventConsumer>();

41
src/Squidex/Config/Orleans/ClientServices.cs

@ -1,41 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Microsoft.Extensions.DependencyInjection;
using Orleans;
using Squidex.Infrastructure.EventSourcing.Grains;
namespace Squidex.Config.Orleans
{
public static class ClientServices
{
public static void AddAppClient(this IServiceCollection services)
{
services.AddSingletonAs(c => c.GetRequiredService<IClusterClient>())
.As<IGrainFactory>();
services.AddSingletonAs(c =>
{
var client = new ClientBuilder()
.ConfigureApplicationParts(builder =>
{
builder.AddApplicationPart(typeof(EventConsumerGrain).Assembly);
})
.UseStaticGatewayListProvider(options =>
{
options.Gateways.Add(new Uri("gwy.tcp://127.0.0.1:40000/0"));
})
.Build();
client.Connect().Wait();
return client;
});
}
}
}

50
src/Squidex/Config/Orleans/ClientWrapper.cs

@ -0,0 +1,50 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using Orleans;
using Orleans.Runtime.Configuration;
using Squidex.Infrastructure;
namespace Squidex.Config.Orleans
{
public sealed class ClientWrapper : IInitializable, IDisposable
{
private readonly IClusterClient client;
public IClusterClient Client
{
get { return client; }
}
public ClientWrapper()
{
client = new ClientBuilder()
.UseConfiguration(ClientConfiguration.LocalhostSilo())
.UseDashboard()
.ConfigureApplicationParts(builder =>
{
builder.AddApplicationPart(SquidexInfrastructure.Assembly);
})
.UseStaticGatewayListProvider(options =>
{
options.Gateways.Add(new Uri("gwy.tcp://127.0.0.1:40000/0"));
})
.Build();
}
public void Initialize()
{
client.Connect().Wait();
}
public void Dispose()
{
client.Close().Wait();
}
}
}

40
src/Squidex/Config/Orleans/OrleansServices.cs

@ -0,0 +1,40 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschränkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.Extensions.DependencyInjection;
using Orleans;
using Squidex.Infrastructure;
namespace Squidex.Config.Orleans
{
public static class OrleansServices
{
public static void AddOrleansSilo(this IServiceCollection services)
{
services.AddSingletonAs<SiloWrapper>()
.As<IInitializable>();
}
public static void AddOrleansClient(this IServiceCollection services)
{
services.AddServicesForSelfHostedDashboard(null, options =>
{
options.HideTrace = true;
});
services.AddSingletonAs<ClientWrapper>()
.As<IInitializable>()
.AsSelf();
services.AddSingletonAs(c => c.GetRequiredService<ClientWrapper>().Client)
.As<IClusterClient>();
services.AddSingletonAs(c => c.GetRequiredService<ClientWrapper>().Client)
.As<IGrainFactory>();
}
}
}

32
src/Squidex/Config/Orleans/SiloServices.cs

@ -13,6 +13,7 @@ using Microsoft.Extensions.DependencyInjection;
using Orleans; using Orleans;
using Orleans.Runtime; using Orleans.Runtime;
using Orleans.Runtime.Configuration; using Orleans.Runtime.Configuration;
using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing.Grains; using Squidex.Infrastructure.EventSourcing.Grains;
namespace Squidex.Config.Orleans namespace Squidex.Config.Orleans
@ -21,10 +22,6 @@ namespace Squidex.Config.Orleans
{ {
public static void AddAppSiloServices(this IServiceCollection services, IConfiguration config) public static void AddAppSiloServices(this IServiceCollection services, IConfiguration config)
{ {
services.AddSingletonAs<EventConsumerBootstrap>()
.As<ILifecycleParticipant<ISiloLifecycle>>();
/*
var clusterConfiguration = var clusterConfiguration =
services.Where(x => x.ServiceType == typeof(ClusterConfiguration)) services.Where(x => x.ServiceType == typeof(ClusterConfiguration))
.Select(x => x.ImplementationInstance) .Select(x => x.ImplementationInstance)
@ -33,8 +30,6 @@ namespace Squidex.Config.Orleans
if (clusterConfiguration != null) if (clusterConfiguration != null)
{ {
clusterConfiguration.Globals.RegisterBootstrapProvider<EventConsumerBootstrap>("EventConsumers");
var ipConfig = config.GetRequiredValue("orleans:hostNameOrIPAddress"); var ipConfig = config.GetRequiredValue("orleans:hostNameOrIPAddress");
if (ipConfig.Equals("Host", StringComparison.OrdinalIgnoreCase)) if (ipConfig.Equals("Host", StringComparison.OrdinalIgnoreCase))
@ -51,7 +46,30 @@ namespace Squidex.Config.Orleans
clusterConfiguration.Defaults.PropagateActivityId = true; clusterConfiguration.Defaults.PropagateActivityId = true;
clusterConfiguration.Defaults.ProxyGatewayEndpoint = new IPEndPoint(IPAddress.Any, 40000); clusterConfiguration.Defaults.ProxyGatewayEndpoint = new IPEndPoint(IPAddress.Any, 40000);
clusterConfiguration.Defaults.HostNameOrIPAddress = ipConfig; clusterConfiguration.Defaults.HostNameOrIPAddress = ipConfig;
}*/ }
config.ConfigureByOption("store:type", new Options
{
["MongoDB"] = () =>
{
var mongoConfiguration = config.GetRequiredValue("store:mongoDb:configuration");
var mongoDatabaseName = config.GetRequiredValue("store:mongoDb:database");
services.AddMongoDBMembershipTable(c =>
{
c.ConnectionString = mongoConfiguration;
c.CollectionPrefix = "Orleans_";
c.DatabaseName = mongoDatabaseName;
});
services.AddMongoDBReminders(c =>
{
c.ConnectionString = mongoConfiguration;
c.CollectionPrefix = "Orleans_";
c.DatabaseName = mongoDatabaseName;
});
}
});
} }
} }
} }

90
src/Squidex/Config/Orleans/SiloWrapper.cs

@ -0,0 +1,90 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using System;
using System.IO;
using Microsoft.Extensions.Configuration;
using Orleans;
using Orleans.Hosting;
using Orleans.Runtime.Configuration;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Log.Adapter;
namespace Squidex.Config.Orleans
{
public class SiloWrapper : IInitializable, IDisposable
{
private readonly ISiloHost silo;
internal sealed class Source : IConfigurationSource
{
private readonly IConfigurationProvider configurationProvider;
public Source(IConfigurationProvider configurationProvider)
{
this.configurationProvider = configurationProvider;
}
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return configurationProvider;
}
}
public SiloWrapper(IConfiguration configuration)
{
silo = SiloHostBuilder.CreateDefault()
.UseConfiguration(ClusterConfiguration.LocalhostPrimarySilo(33333))
.UseContentRoot(Directory.GetCurrentDirectory())
.UseDashboard(options =>
{
options.HostSelf = false;
})
.ConfigureApplicationParts(builder =>
{
builder.AddApplicationPart(SquidexInfrastructure.Assembly);
})
.ConfigureLogging(builder =>
{
builder.AddSemanticLog();
})
.ConfigureServices((context, services) =>
{
services.AddAppSiloServices(context.Configuration);
services.AddAppServices(context.Configuration);
})
.ConfigureAppConfiguration((hostContext, builder) =>
{
if (configuration is IConfigurationRoot root)
{
foreach (var provider in root.Providers)
{
builder.Add(new Source(provider));
}
}
})
.Build();
}
public void Initialize()
{
silo.StartAsync().Wait();
}
public void Dispose()
{
silo.StopAsync().Wait();
}
private static string GetEnvironment()
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
return environment ?? "Development";
}
}
}

59
src/Squidex/Program.cs

@ -5,14 +5,12 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using System;
using System.IO; using System.IO;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Orleans; using Orleans;
using Orleans.Hosting; using Orleans.Hosting;
using Orleans.Runtime.Configuration;
using Squidex.Config.Orleans; using Squidex.Config.Orleans;
using Squidex.Infrastructure.EventSourcing.Grains;
using Squidex.Infrastructure.Log.Adapter; using Squidex.Infrastructure.Log.Adapter;
namespace Squidex namespace Squidex
@ -21,59 +19,28 @@ namespace Squidex
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
var silo = new SiloHostBuilder() new WebHostBuilder()
.UseConfiguration(ClusterConfiguration.LocalhostPrimarySilo(33333)) .UseKestrel(k => { k.AddServerHeader = false; })
.UseContentRoot(Directory.GetCurrentDirectory()) .UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureServices((context, services) => .UseIISIntegration()
{ .UseStartup<WebStartup>()
services.AddAppSiloServices(context.Configuration);
services.AddAppServices(context.Configuration);
})
.ConfigureApplicationParts(builder =>
{
builder.AddApplicationPart(typeof(EventConsumerManagerGrain).Assembly);
})
.ConfigureLogging(builder => .ConfigureLogging(builder =>
{ {
builder.AddSemanticLog(); builder.AddSemanticLog();
}) })
.ConfigureAppConfiguration((hostContext, builder) => .ConfigureAppConfiguration((hostContext, builder) =>
{ {
builder.AddAppConfiguration(GetEnvironment(), args); builder.Sources.Clear();
})
.Build();
silo.StartAsync().Wait(); builder.AddJsonFile("appsettings.json", true, true);
builder.AddJsonFile($"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", true);
try builder.AddEnvironmentVariables();
{
new WebHostBuilder()
.UseKestrel(k => { k.AddServerHeader = false; })
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<WebStartup>()
.ConfigureLogging(builder =>
{
builder.AddSemanticLog();
})
.ConfigureAppConfiguration((hostContext, builder) =>
{
builder.AddAppConfiguration(hostContext.HostingEnvironment.EnvironmentName, args);
})
.Build()
.Run();
}
finally
{
silo.StopAsync().Wait();
}
}
private static string GetEnvironment()
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
return environment ?? "Development"; builder.AddCommandLine(args);
})
.Build()
.Run();
} }
} }
} }

1
src/Squidex/Squidex.csproj

@ -79,6 +79,7 @@
<PackageReference Include="NodaTime.Serialization.JsonNet" Version="2.0.0" /> <PackageReference Include="NodaTime.Serialization.JsonNet" Version="2.0.0" />
<PackageReference Include="NSwag.AspNetCore" Version="11.12.16" /> <PackageReference Include="NSwag.AspNetCore" Version="11.12.16" />
<PackageReference Include="OpenCover" Version="4.6.519" /> <PackageReference Include="OpenCover" Version="4.6.519" />
<PackageReference Include="Orleans.Providers.MongoDB" Version="2.0.0-preview2" />
<PackageReference Include="OrleansDashboard" Version="2.0.0-beta4" /> <PackageReference Include="OrleansDashboard" Version="2.0.0-beta4" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" />
<PackageReference Include="ReportGenerator" Version="3.1.1" /> <PackageReference Include="ReportGenerator" Version="3.1.1" />

5
src/Squidex/WebStartup.cs

@ -13,6 +13,7 @@ using Microsoft.Extensions.DependencyInjection;
using Squidex.Areas.Api; using Squidex.Areas.Api;
using Squidex.Areas.Frontend; using Squidex.Areas.Frontend;
using Squidex.Areas.IdentityServer; using Squidex.Areas.IdentityServer;
using Squidex.Areas.OrleansDashboard;
using Squidex.Areas.Portal; using Squidex.Areas.Portal;
using Squidex.Config.Domain; using Squidex.Config.Domain;
using Squidex.Config.Orleans; using Squidex.Config.Orleans;
@ -31,7 +32,8 @@ namespace Squidex
public IServiceProvider ConfigureServices(IServiceCollection services) public IServiceProvider ConfigureServices(IServiceCollection services)
{ {
services.AddAppClient(); services.AddOrleansSilo();
services.AddOrleansClient();
services.AddAppServices(configuration); services.AddAppServices(configuration);
return services.BuildServiceProvider(); return services.BuildServiceProvider();
@ -50,6 +52,7 @@ namespace Squidex
app.ConfigureApi(); app.ConfigureApi();
app.ConfigurePortal(); app.ConfigurePortal();
app.ConfigureOrleansDashboard();
app.ConfigureIdentityServer(); app.ConfigureIdentityServer();
app.ConfigureFrontend(); app.ConfigureFrontend();

10
src/Squidex/appsettings.json

@ -42,12 +42,20 @@
} }
}, },
"orleans": {
/*
* Define the IP address or host name that is used for inter-silo communication.
*
* Special values: FirstIPAddressOfHost, Host
*/
"hostNameOrIPAddress": "localhost"
},
"logging": { "logging": {
/* /*
* Setting the flag to true, enables well formatteds json logs. * Setting the flag to true, enables well formatteds json logs.
*/ */
"human": true "human": true
}, },
/* /*

Loading…
Cancel
Save