mirror of https://github.com/Squidex/squidex.git
committed by
GitHub
134 changed files with 2174 additions and 1928 deletions
Binary file not shown.
@ -0,0 +1 @@ |
|||||
|
oeHEL1XH6DwEv4Rk6JjAABzcpTdBI3Zmoz3tyn+20vBUcvsdmKQMFp8I1rBZmAeOJ9NSvvRYf8LHDM2UtRTbvw== |
||||
@ -0,0 +1,25 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd"> |
||||
|
<metadata> |
||||
|
<id>OrleansDashboard</id> |
||||
|
<version>2.0.0-rc1</version> |
||||
|
<authors>OrleansContrib</authors> |
||||
|
<owners>OrleansContrib</owners> |
||||
|
<requireLicenseAcceptance>false</requireLicenseAcceptance> |
||||
|
<licenseUrl>https://opensource.org/licenses/MIT</licenseUrl> |
||||
|
<projectUrl>https://github.com/OrleansContrib/OrleansDashboard</projectUrl> |
||||
|
<iconUrl>http://dotnet.github.io/orleans/assets/logo.png</iconUrl> |
||||
|
<description>An admin dashboard for Microsoft Orleans</description> |
||||
|
<copyright>Copyright © 2017</copyright> |
||||
|
<tags>orleans dashboard metrics monitor</tags> |
||||
|
<repository url="https://github.com/OrleansContrib/OrleansDashboard" /> |
||||
|
<dependencies> |
||||
|
<group targetFramework=".NETStandard2.0"> |
||||
|
<dependency id="Microsoft.AspNetCore" version="2.0.1" exclude="Build,Analyzers" /> |
||||
|
<dependency id="Microsoft.Orleans.Core" version="2.0.0-rc1" exclude="Build,Analyzers" /> |
||||
|
<dependency id="Microsoft.Orleans.OrleansCodeGenerator.Build" version="2.0.0-rc1" exclude="Build,Analyzers" /> |
||||
|
<dependency id="Microsoft.Orleans.OrleansRuntime" version="2.0.0-rc1" exclude="Build,Analyzers" /> |
||||
|
</group> |
||||
|
</dependencies> |
||||
|
</metadata> |
||||
|
</package> |
||||
@ -0,0 +1,18 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Infrastructure.Commands; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Apps |
||||
|
{ |
||||
|
public interface IAppGrain : IDomainObjectGrain |
||||
|
{ |
||||
|
Task<J<IAppEntity>> GetStateAsync(); |
||||
|
} |
||||
|
} |
||||
@ -1,13 +1,15 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
namespace Squidex.Infrastructure.EventSourcing.Grains.Messages |
using Squidex.Infrastructure.Commands; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Assets |
||||
{ |
{ |
||||
public sealed class GetStatesRequest |
public interface IAssetGrain : IDomainObjectGrain |
||||
{ |
{ |
||||
} |
} |
||||
} |
} |
||||
@ -1,14 +1,15 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
namespace Squidex.Infrastructure.EventSourcing.Grains.Messages |
using Squidex.Infrastructure.Commands; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Contents |
||||
{ |
{ |
||||
public sealed class StopConsumerMessage |
public interface IContentGrain : IDomainObjectGrain |
||||
{ |
{ |
||||
public string ConsumerName { get; set; } |
|
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Contents |
||||
|
{ |
||||
|
public interface IContentSchedulerGrain : IBackgroundGrain |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -1,14 +1,15 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
namespace Squidex.Infrastructure.States |
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Rules |
||||
{ |
{ |
||||
public sealed class InvalidateMessage |
public interface IRuleDequeuerGrain : IBackgroundGrain |
||||
{ |
{ |
||||
public string Key { get; set; } |
|
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Infrastructure.Commands; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Rules |
||||
|
{ |
||||
|
public interface IRuleGrain : IDomainObjectGrain |
||||
|
{ |
||||
|
Task<J<IRuleEntity>> GetStateAsync(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Infrastructure.Commands; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Schemas |
||||
|
{ |
||||
|
public interface ISchemaGrain : IDomainObjectGrain |
||||
|
{ |
||||
|
Task<J<ISchemaEntity>> GetStateAsync(); |
||||
|
} |
||||
|
} |
||||
@ -1,14 +1,16 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
namespace Squidex.Infrastructure.EventSourcing.Grains.Messages |
using System.Reflection; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities |
||||
{ |
{ |
||||
public sealed class ResetConsumerMessage |
public sealed class SquidexEntities |
||||
{ |
{ |
||||
public string ConsumerName { get; set; } |
public static readonly Assembly Assembly = typeof(SquidexEntities).Assembly; |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Orleans; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Commands |
||||
|
{ |
||||
|
public static class DomainObjectGrainFormatter |
||||
|
{ |
||||
|
public static string Format(IGrainCallContext context) |
||||
|
{ |
||||
|
if (context.Method == null) |
||||
|
{ |
||||
|
return "Unknown"; |
||||
|
} |
||||
|
|
||||
|
if (string.Equals(context.Method.Name, nameof(IDomainObjectGrain.ExecuteAsync), StringComparison.CurrentCultureIgnoreCase) && |
||||
|
context.Arguments?.Length == 1 && |
||||
|
context.Arguments[0] != null) |
||||
|
{ |
||||
|
var argumentFullName = context.Arguments[0].ToString(); |
||||
|
var argumentParts = argumentFullName.Split('.'); |
||||
|
var argumentName = argumentParts[argumentParts.Length - 1]; |
||||
|
|
||||
|
return $"{nameof(IDomainObjectGrain.ExecuteAsync)}({argumentName})"; |
||||
|
} |
||||
|
|
||||
|
return context.Method.Name; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,63 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using Squidex.Infrastructure.States; |
|
||||
using Squidex.Infrastructure.Tasks; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.Commands |
|
||||
{ |
|
||||
public class SyncedGrainCommandMiddleware<TCommand, TGrain> : ICommandMiddleware where TCommand : IAggregateCommand where TGrain : IDomainObjectGrain |
|
||||
{ |
|
||||
private readonly AsyncLockPool lockPool = new AsyncLockPool(10000); |
|
||||
private readonly IStateFactory stateFactory; |
|
||||
|
|
||||
public SyncedGrainCommandMiddleware(IStateFactory stateFactory) |
|
||||
{ |
|
||||
Guard.NotNull(stateFactory, nameof(stateFactory)); |
|
||||
|
|
||||
this.stateFactory = stateFactory; |
|
||||
} |
|
||||
|
|
||||
public async virtual Task HandleAsync(CommandContext context, Func<Task> next) |
|
||||
{ |
|
||||
if (context.Command is TCommand typedCommand) |
|
||||
{ |
|
||||
var result = await ExecuteCommandAsync(typedCommand); |
|
||||
|
|
||||
context.Complete(result); |
|
||||
} |
|
||||
|
|
||||
await next(); |
|
||||
} |
|
||||
|
|
||||
protected async Task<object> ExecuteCommandAsync(TCommand typedCommand) |
|
||||
{ |
|
||||
var id = typedCommand.AggregateId; |
|
||||
|
|
||||
using (await lockPool.LockAsync(typedCommand.AggregateId)) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
var grain = await stateFactory.GetSingleAsync<TGrain>(id); |
|
||||
|
|
||||
var result = await grain.ExecuteAsync(typedCommand); |
|
||||
|
|
||||
stateFactory.Synchronize<TGrain, Guid>(id); |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
stateFactory.Remove<TGrain, Guid>(id); |
|
||||
throw; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,40 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.EventSourcing |
|
||||
{ |
|
||||
public sealed class DefaultEventNotifier : IEventNotifier |
|
||||
{ |
|
||||
private static readonly string ChannelName = typeof(DefaultEventNotifier).Name; |
|
||||
|
|
||||
private readonly IPubSub pubsub; |
|
||||
|
|
||||
public sealed class EventNotification |
|
||||
{ |
|
||||
public string StreamName { get; set; } |
|
||||
} |
|
||||
|
|
||||
public DefaultEventNotifier(IPubSub pubsub) |
|
||||
{ |
|
||||
Guard.NotNull(pubsub, nameof(pubsub)); |
|
||||
|
|
||||
this.pubsub = pubsub; |
|
||||
} |
|
||||
|
|
||||
public void NotifyEventsStored(string streamName) |
|
||||
{ |
|
||||
pubsub.Publish(new EventNotification { StreamName = streamName }, true); |
|
||||
} |
|
||||
|
|
||||
public IDisposable Subscribe(Action<string> handler) |
|
||||
{ |
|
||||
return pubsub.Subscribe<EventNotification>(x => handler?.Invoke(x.StreamName)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,90 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Threading.Tasks; |
|
||||
using Squidex.Infrastructure.EventSourcing.Grains.Messages; |
|
||||
using Squidex.Infrastructure.States; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.EventSourcing.Grains |
|
||||
{ |
|
||||
public sealed class EventConsumerGrainManager : DisposableObjectBase, IRunnable |
|
||||
{ |
|
||||
private readonly IStateFactory factory; |
|
||||
private readonly IPubSub pubSub; |
|
||||
private readonly List<IEventConsumer> consumers; |
|
||||
private readonly List<IDisposable> subscriptions = new List<IDisposable>(); |
|
||||
|
|
||||
public EventConsumerGrainManager(IEnumerable<IEventConsumer> consumers, IPubSub pubSub, IStateFactory factory) |
|
||||
{ |
|
||||
Guard.NotNull(pubSub, nameof(pubSub)); |
|
||||
Guard.NotNull(factory, nameof(factory)); |
|
||||
Guard.NotNull(consumers, nameof(consumers)); |
|
||||
|
|
||||
this.pubSub = pubSub; |
|
||||
this.factory = factory; |
|
||||
this.consumers = consumers.ToList(); |
|
||||
} |
|
||||
|
|
||||
public void Run() |
|
||||
{ |
|
||||
var actors = new Dictionary<string, EventConsumerGrain>(); |
|
||||
|
|
||||
foreach (var consumer in consumers) |
|
||||
{ |
|
||||
var actor = factory.CreateAsync<EventConsumerGrain>(consumer.Name).Result; |
|
||||
|
|
||||
actors[consumer.Name] = actor; |
|
||||
actor.Activate(consumer); |
|
||||
} |
|
||||
|
|
||||
subscriptions.Add(pubSub.Subscribe<StartConsumerMessage>(m => |
|
||||
{ |
|
||||
if (actors.TryGetValue(m.ConsumerName, out var actor)) |
|
||||
{ |
|
||||
actor.Start(); |
|
||||
} |
|
||||
})); |
|
||||
|
|
||||
subscriptions.Add(pubSub.Subscribe<StopConsumerMessage>(m => |
|
||||
{ |
|
||||
if (actors.TryGetValue(m.ConsumerName, out var actor)) |
|
||||
{ |
|
||||
actor.Stop(); |
|
||||
} |
|
||||
})); |
|
||||
|
|
||||
subscriptions.Add(pubSub.Subscribe<ResetConsumerMessage>(m => |
|
||||
{ |
|
||||
if (actors.TryGetValue(m.ConsumerName, out var actor)) |
|
||||
{ |
|
||||
actor.Reset(); |
|
||||
} |
|
||||
})); |
|
||||
|
|
||||
subscriptions.Add(pubSub.ReceiveAsync<GetStatesRequest, GetStatesResponse>(request => |
|
||||
{ |
|
||||
var states = actors.Values.Select(x => x.GetState()).ToArray(); |
|
||||
|
|
||||
return Task.FromResult(new GetStatesResponse { States = states }); |
|
||||
})); |
|
||||
} |
|
||||
|
|
||||
protected override void DisposeObject(bool disposing) |
|
||||
{ |
|
||||
if (disposing) |
|
||||
{ |
|
||||
foreach (var subscription in subscriptions) |
|
||||
{ |
|
||||
subscription.Dispose(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,104 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text.RegularExpressions; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
using Orleans.Concurrency; |
||||
|
using Orleans.Core; |
||||
|
using Orleans.Runtime; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.EventSourcing.Grains |
||||
|
{ |
||||
|
public class EventConsumerManagerGrain : Grain, IEventConsumerManagerGrain, IRemindable |
||||
|
{ |
||||
|
private readonly IEnumerable<IEventConsumer> eventConsumers; |
||||
|
|
||||
|
public EventConsumerManagerGrain(IEnumerable<IEventConsumer> eventConsumers) |
||||
|
: this(eventConsumers, null, null) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected EventConsumerManagerGrain( |
||||
|
IEnumerable<IEventConsumer> eventConsumers, |
||||
|
IGrainIdentity identity, |
||||
|
IGrainRuntime runtime) |
||||
|
: base(identity, runtime) |
||||
|
{ |
||||
|
Guard.NotNull(eventConsumers, nameof(eventConsumers)); |
||||
|
|
||||
|
this.eventConsumers = eventConsumers; |
||||
|
} |
||||
|
|
||||
|
public override Task OnActivateAsync() |
||||
|
{ |
||||
|
DelayDeactivation(TimeSpan.FromDays(1)); |
||||
|
|
||||
|
RegisterOrUpdateReminder("Default", TimeSpan.Zero, TimeSpan.FromMinutes(10)); |
||||
|
RegisterTimer(x => ActivateAsync(null), null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); |
||||
|
|
||||
|
return Task.FromResult(true); |
||||
|
} |
||||
|
|
||||
|
public Task ActivateAsync(string streamName) |
||||
|
{ |
||||
|
var tasks = |
||||
|
eventConsumers |
||||
|
.Where(c => streamName == null || Regex.IsMatch(streamName, c.EventsFilter)) |
||||
|
.Select(c => GrainFactory.GetGrain<IEventConsumerGrain>(c.Name)) |
||||
|
.Select(c => c.ActivateAsync()); |
||||
|
|
||||
|
return Task.WhenAll(tasks); |
||||
|
} |
||||
|
|
||||
|
public async Task<Immutable<List<EventConsumerInfo>>> GetConsumersAsync() |
||||
|
{ |
||||
|
var tasks = |
||||
|
eventConsumers |
||||
|
.Select(c => GrainFactory.GetGrain<IEventConsumerGrain>(c.Name)) |
||||
|
.Select(c => c.GetStateAsync()); |
||||
|
|
||||
|
var consumerInfos = await Task.WhenAll(tasks); |
||||
|
|
||||
|
return new Immutable<List<EventConsumerInfo>>(consumerInfos.Select(r => r.Value).ToList()); |
||||
|
} |
||||
|
|
||||
|
public Task ResetAsync(string consumerName) |
||||
|
{ |
||||
|
var eventConsumer = GrainFactory.GetGrain<IEventConsumerGrain>(consumerName); |
||||
|
|
||||
|
return eventConsumer.ResetAsync(); |
||||
|
} |
||||
|
|
||||
|
public Task StartAsync(string consumerName) |
||||
|
{ |
||||
|
var eventConsumer = GrainFactory.GetGrain<IEventConsumerGrain>(consumerName); |
||||
|
|
||||
|
return eventConsumer.StartAsync(); |
||||
|
} |
||||
|
|
||||
|
public Task StopAsync(string consumerName) |
||||
|
{ |
||||
|
var eventConsumer = GrainFactory.GetGrain<IEventConsumerGrain>(consumerName); |
||||
|
|
||||
|
return eventConsumer.StopAsync(); |
||||
|
} |
||||
|
|
||||
|
public Task ActivateAsync() |
||||
|
{ |
||||
|
return ActivateAsync(null); |
||||
|
} |
||||
|
|
||||
|
public Task ReceiveReminder(string reminderName, TickStatus status) |
||||
|
{ |
||||
|
return ActivateAsync(null); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans.Concurrency; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.EventSourcing.Grains |
||||
|
{ |
||||
|
public interface IEventConsumerGrain : IBackgroundGrain |
||||
|
{ |
||||
|
Task<Immutable<EventConsumerInfo>> GetStateAsync(); |
||||
|
|
||||
|
Task StopAsync(); |
||||
|
|
||||
|
Task StartAsync(); |
||||
|
|
||||
|
Task ResetAsync(); |
||||
|
|
||||
|
Task OnEventAsync(Immutable<IEventSubscription> subscription, Immutable<StoredEvent> storedEvent); |
||||
|
|
||||
|
Task OnErrorAsync(Immutable<IEventSubscription> subscription, Immutable<Exception> exception); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans.Concurrency; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.EventSourcing.Grains |
||||
|
{ |
||||
|
public interface IEventConsumerManagerGrain : IBackgroundGrain |
||||
|
{ |
||||
|
Task ActivateAsync(string streamName); |
||||
|
|
||||
|
Task StopAsync(string consumerName); |
||||
|
|
||||
|
Task StartAsync(string consumerName); |
||||
|
|
||||
|
Task ResetAsync(string consumerName); |
||||
|
|
||||
|
Task<Immutable<List<EventConsumerInfo>>> GetConsumersAsync(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Orleans; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.EventSourcing.Grains |
||||
|
{ |
||||
|
public sealed class OrleansEventNotifier : IEventNotifier, IInitializable |
||||
|
{ |
||||
|
private readonly IGrainFactory factory; |
||||
|
private IEventConsumerManagerGrain eventConsumerManagerGrain; |
||||
|
|
||||
|
public OrleansEventNotifier(IGrainFactory factory) |
||||
|
{ |
||||
|
Guard.NotNull(factory, nameof(factory)); |
||||
|
|
||||
|
this.factory = factory; |
||||
|
} |
||||
|
|
||||
|
public void Initialize() |
||||
|
{ |
||||
|
eventConsumerManagerGrain = factory.GetGrain<IEventConsumerManagerGrain>("Default"); |
||||
|
} |
||||
|
|
||||
|
public void NotifyEventsStored(string streamName) |
||||
|
{ |
||||
|
eventConsumerManagerGrain?.ActivateAsync(streamName); |
||||
|
} |
||||
|
|
||||
|
public IDisposable Subscribe(Action<string> handler) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans.Concurrency; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.EventSourcing.Grains |
||||
|
{ |
||||
|
internal sealed class WrapperSubscription : IEventSubscriber |
||||
|
{ |
||||
|
private readonly IEventConsumerGrain grain; |
||||
|
private readonly TaskScheduler scheduler; |
||||
|
|
||||
|
public WrapperSubscription(IEventConsumerGrain grain, TaskScheduler scheduler) |
||||
|
{ |
||||
|
this.grain = grain; |
||||
|
|
||||
|
this.scheduler = scheduler ?? TaskScheduler.Default; |
||||
|
} |
||||
|
|
||||
|
public Task OnEventAsync(IEventSubscription subscription, StoredEvent storedEvent) |
||||
|
{ |
||||
|
return Dispatch(() => grain.OnEventAsync(subscription.AsImmutable(), storedEvent.AsImmutable())); |
||||
|
} |
||||
|
|
||||
|
public Task OnErrorAsync(IEventSubscription subscription, Exception exception) |
||||
|
{ |
||||
|
return Dispatch(() => grain.OnErrorAsync(subscription.AsImmutable(), exception.AsImmutable())); |
||||
|
} |
||||
|
|
||||
|
private Task Dispatch(Func<Task> task) |
||||
|
{ |
||||
|
return Task<Task>.Factory.StartNew(() => task(), CancellationToken.None, TaskCreationOptions.None, scheduler).Unwrap(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
using Orleans.Runtime; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Orleans |
||||
|
{ |
||||
|
public sealed class Bootstrap<T> : IStartupTask where T : IBackgroundGrain |
||||
|
{ |
||||
|
private readonly IGrainFactory grainFactory; |
||||
|
|
||||
|
public Bootstrap(IGrainFactory grainFactory) |
||||
|
{ |
||||
|
Guard.NotNull(grainFactory, nameof(grainFactory)); |
||||
|
|
||||
|
this.grainFactory = grainFactory; |
||||
|
} |
||||
|
|
||||
|
public Task Execute(CancellationToken cancellationToken) |
||||
|
{ |
||||
|
var grain = grainFactory.GetGrain<T>("Default"); |
||||
|
|
||||
|
return grain.ActivateAsync(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
using Squidex.Infrastructure.Tasks; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Orleans |
||||
|
{ |
||||
|
public abstract class GrainOfGuid : Grain |
||||
|
{ |
||||
|
public override Task OnActivateAsync() |
||||
|
{ |
||||
|
return OnActivateAsync(this.GetPrimaryKey()); |
||||
|
} |
||||
|
|
||||
|
public virtual Task OnActivateAsync(Guid key) |
||||
|
{ |
||||
|
return TaskHelper.Done; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
using Squidex.Infrastructure.Tasks; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Orleans |
||||
|
{ |
||||
|
public abstract class GrainOfString : Grain |
||||
|
{ |
||||
|
public override Task OnActivateAsync() |
||||
|
{ |
||||
|
return OnActivateAsync(this.GetPrimaryKeyString()); |
||||
|
} |
||||
|
|
||||
|
public virtual Task OnActivateAsync(string key) |
||||
|
{ |
||||
|
return TaskHelper.Done; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,16 +1,17 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
|
using Orleans; |
||||
|
|
||||
namespace Squidex.Infrastructure.States |
namespace Squidex.Infrastructure.Orleans |
||||
{ |
{ |
||||
public interface IStatefulObject<TKey> |
public interface IBackgroundGrain : IGrainWithStringKey |
||||
{ |
{ |
||||
Task ActivateAsync(TKey key); |
Task ActivateAsync(); |
||||
} |
} |
||||
} |
} |
||||
@ -1,14 +1,18 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
namespace Squidex.Infrastructure.EventSourcing.Grains.Messages |
using Newtonsoft.Json; |
||||
|
|
||||
|
#pragma warning disable SA1401 // Fields must be private
|
||||
|
|
||||
|
namespace Squidex.Infrastructure.Orleans |
||||
{ |
{ |
||||
public sealed class StartConsumerMessage |
public static class J |
||||
{ |
{ |
||||
public string ConsumerName { get; set; } |
public static JsonSerializer Serializer = new JsonSerializer(); |
||||
} |
} |
||||
} |
} |
||||
@ -1,14 +1,17 @@ |
|||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Squidex Headless CMS
|
// Squidex Headless CMS
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
// All rights reserved. Licensed under the MIT license.
|
// All rights reserved. Licensed under the MIT license.
|
||||
// ==========================================================================
|
// ==========================================================================
|
||||
|
|
||||
namespace Squidex.Infrastructure.EventSourcing.Grains.Messages |
namespace Squidex.Infrastructure.Orleans |
||||
{ |
{ |
||||
public sealed class GetStatesResponse |
public static class JExtensions |
||||
{ |
{ |
||||
public EventConsumerInfo[] States { get; set; } |
public static J<T> AsJ<T>(this T value) |
||||
|
{ |
||||
|
return new J<T>(value); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
@ -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 System.Threading.Tasks; |
||||
|
using Newtonsoft.Json; |
||||
|
using Orleans.CodeGeneration; |
||||
|
using Orleans.Serialization; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Orleans |
||||
|
{ |
||||
|
public struct J<T> |
||||
|
{ |
||||
|
private readonly T value; |
||||
|
|
||||
|
public T Value |
||||
|
{ |
||||
|
get { return value; } |
||||
|
} |
||||
|
|
||||
|
[JsonConstructor] |
||||
|
public J(T value) |
||||
|
{ |
||||
|
this.value = value; |
||||
|
} |
||||
|
|
||||
|
public static implicit operator T(J<T> value) |
||||
|
{ |
||||
|
return value.value; |
||||
|
} |
||||
|
|
||||
|
public static implicit operator J<T>(T d) |
||||
|
{ |
||||
|
return new J<T>(d); |
||||
|
} |
||||
|
|
||||
|
public override string ToString() |
||||
|
{ |
||||
|
return value?.ToString() ?? string.Empty; |
||||
|
} |
||||
|
|
||||
|
public static Task<J<T>> AsTask(T value) |
||||
|
{ |
||||
|
return Task.FromResult<J<T>>(value); |
||||
|
} |
||||
|
|
||||
|
[CopierMethod] |
||||
|
public static object Copy(object input, ICopyContext context) |
||||
|
{ |
||||
|
return input; |
||||
|
} |
||||
|
|
||||
|
[SerializerMethod] |
||||
|
public static void Serialize(object input, ISerializationContext context, Type expected) |
||||
|
{ |
||||
|
var stream = new MemoryStream(); |
||||
|
|
||||
|
using (var writer = new JsonTextWriter(new StreamWriter(stream))) |
||||
|
{ |
||||
|
J.Serializer.Serialize(writer, input); |
||||
|
|
||||
|
writer.Flush(); |
||||
|
} |
||||
|
|
||||
|
var outBytes = stream.ToArray(); |
||||
|
|
||||
|
context.StreamWriter.Write(outBytes.Length); |
||||
|
context.StreamWriter.Write(outBytes); |
||||
|
} |
||||
|
|
||||
|
[DeserializerMethod] |
||||
|
public static object Deserialize(Type expected, IDeserializationContext context) |
||||
|
{ |
||||
|
var outLength = context.StreamReader.ReadInt(); |
||||
|
var outBytes = context.StreamReader.ReadBytes(outLength); |
||||
|
|
||||
|
var stream = new MemoryStream(outBytes); |
||||
|
|
||||
|
using (var reader = new JsonTextReader(new StreamReader(stream))) |
||||
|
{ |
||||
|
return J.Serializer.Deserialize(reader, expected); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,31 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.States |
|
||||
{ |
|
||||
public interface IStateFactory |
|
||||
{ |
|
||||
Task<T> GetSingleAsync<T>(string key) where T : IStatefulObject<string>; |
|
||||
|
|
||||
Task<T> GetSingleAsync<T>(Guid key) where T : IStatefulObject<Guid>; |
|
||||
|
|
||||
Task<T> GetSingleAsync<T, TKey>(TKey key) where T : IStatefulObject<TKey>; |
|
||||
|
|
||||
Task<T> CreateAsync<T>(string key) where T : IStatefulObject<string>; |
|
||||
|
|
||||
Task<T> CreateAsync<T>(Guid key) where T : IStatefulObject<Guid>; |
|
||||
|
|
||||
Task<T> CreateAsync<T, TKey>(TKey key) where T : IStatefulObject<TKey>; |
|
||||
|
|
||||
void Remove<T, TKey>(TKey key) where T : IStatefulObject<TKey>; |
|
||||
|
|
||||
void Synchronize<T, TKey>(TKey key) where T : IStatefulObject<TKey>; |
|
||||
} |
|
||||
} |
|
||||
@ -1,140 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
|
|
||||
#pragma warning disable RECS0096 // Type parameter is never used
|
|
||||
|
|
||||
namespace Squidex.Infrastructure.States |
|
||||
{ |
|
||||
public sealed class StateFactory : DisposableObjectBase, IInitializable, IStateFactory |
|
||||
{ |
|
||||
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(10); |
|
||||
private readonly IPubSub pubSub; |
|
||||
private readonly IMemoryCache statesCache; |
|
||||
private readonly IServiceProvider services; |
|
||||
private readonly object lockObject = new object(); |
|
||||
private IDisposable pubSubSubscription; |
|
||||
|
|
||||
public sealed class ObjectHolder<T, TKey> where T : IStatefulObject<TKey> |
|
||||
{ |
|
||||
private readonly Task activationTask; |
|
||||
private readonly T obj; |
|
||||
|
|
||||
public ObjectHolder(T obj, TKey key) |
|
||||
{ |
|
||||
this.obj = obj; |
|
||||
|
|
||||
activationTask = obj.ActivateAsync(key); |
|
||||
} |
|
||||
|
|
||||
public async Task<T> ActivateAsync() |
|
||||
{ |
|
||||
await activationTask; |
|
||||
|
|
||||
return obj; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public StateFactory(IPubSub pubSub, IMemoryCache statesCache, IServiceProvider services) |
|
||||
{ |
|
||||
Guard.NotNull(pubSub, nameof(pubSub)); |
|
||||
Guard.NotNull(services, nameof(services)); |
|
||||
Guard.NotNull(statesCache, nameof(statesCache)); |
|
||||
|
|
||||
this.pubSub = pubSub; |
|
||||
this.services = services; |
|
||||
this.statesCache = statesCache; |
|
||||
} |
|
||||
|
|
||||
public void Initialize() |
|
||||
{ |
|
||||
pubSubSubscription = pubSub.Subscribe<InvalidateMessage>(m => |
|
||||
{ |
|
||||
lock (lockObject) |
|
||||
{ |
|
||||
statesCache.Remove(m.Key); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
public Task<T> CreateAsync<T>(string key) where T : IStatefulObject<string> |
|
||||
{ |
|
||||
return CreateAsync<T, string>(key); |
|
||||
} |
|
||||
|
|
||||
public Task<T> CreateAsync<T>(Guid key) where T : IStatefulObject<Guid> |
|
||||
{ |
|
||||
return CreateAsync<T, Guid>(key); |
|
||||
} |
|
||||
|
|
||||
public async Task<T> CreateAsync<T, TKey>(TKey key) where T : IStatefulObject<TKey> |
|
||||
{ |
|
||||
Guard.NotNull(key, nameof(key)); |
|
||||
|
|
||||
var state = (T)services.GetService(typeof(T)); |
|
||||
|
|
||||
await state.ActivateAsync(key); |
|
||||
|
|
||||
return state; |
|
||||
} |
|
||||
|
|
||||
public Task<T> GetSingleAsync<T>(string key) where T : IStatefulObject<string> |
|
||||
{ |
|
||||
return GetSingleAsync<T, string>(key); |
|
||||
} |
|
||||
|
|
||||
public Task<T> GetSingleAsync<T>(Guid key) where T : IStatefulObject<Guid> |
|
||||
{ |
|
||||
return GetSingleAsync<T, Guid>(key); |
|
||||
} |
|
||||
|
|
||||
public Task<T> GetSingleAsync<T, TKey>(TKey key) where T : IStatefulObject<TKey> |
|
||||
{ |
|
||||
Guard.NotNull(key, nameof(key)); |
|
||||
|
|
||||
lock (lockObject) |
|
||||
{ |
|
||||
if (statesCache.TryGetValue<ObjectHolder<T, TKey>>(key, out var stateObj)) |
|
||||
{ |
|
||||
return stateObj.ActivateAsync(); |
|
||||
} |
|
||||
|
|
||||
var state = (T)services.GetService(typeof(T)); |
|
||||
|
|
||||
stateObj = new ObjectHolder<T, TKey>(state, key); |
|
||||
|
|
||||
statesCache.CreateEntry(key) |
|
||||
.SetValue(stateObj) |
|
||||
.SetAbsoluteExpiration(CacheDuration) |
|
||||
.Dispose(); |
|
||||
|
|
||||
return stateObj.ActivateAsync(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public void Remove<T, TKey>(TKey key) where T : IStatefulObject<TKey> |
|
||||
{ |
|
||||
statesCache.Remove(key); |
|
||||
} |
|
||||
|
|
||||
public void Synchronize<T, TKey>(TKey key) where T : IStatefulObject<TKey> |
|
||||
{ |
|
||||
pubSub.Publish(new InvalidateMessage { Key = key.ToString() }, false); |
|
||||
} |
|
||||
|
|
||||
protected override void DisposeObject(bool disposing) |
|
||||
{ |
|
||||
if (disposing && pubSubSubscription != null) |
|
||||
{ |
|
||||
pubSubSubscription.Dispose(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -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); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,64 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Newtonsoft.Json; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.Log; |
||||
|
using Squidex.Pipeline; |
||||
|
|
||||
|
#pragma warning disable RECS0092 // Convert field to readonly
|
||||
|
|
||||
|
namespace Squidex.Config.Domain |
||||
|
{ |
||||
|
public static class LoggingServices |
||||
|
{ |
||||
|
private static ILogChannel console = new ConsoleLogChannel(); |
||||
|
private static ILogChannel file; |
||||
|
|
||||
|
public static void AddMyLoggingServices(this IServiceCollection services, IConfiguration config) |
||||
|
{ |
||||
|
if (config.GetValue<bool>("logging:human")) |
||||
|
{ |
||||
|
services.AddSingletonAs(c => new Func<IObjectWriter>(() => new JsonLogWriter(Formatting.Indented, true))); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
services.AddSingletonAs(c => new Func<IObjectWriter>(() => new JsonLogWriter())); |
||||
|
} |
||||
|
|
||||
|
var loggingFile = config.GetValue<string>("logging:file"); |
||||
|
|
||||
|
if (!string.IsNullOrWhiteSpace(loggingFile)) |
||||
|
{ |
||||
|
services.AddSingletonAs(file ?? (file = new FileChannel(loggingFile))) |
||||
|
.As<ILogChannel>() |
||||
|
.As<IInitializable>(); |
||||
|
} |
||||
|
|
||||
|
services.AddSingletonAs(console) |
||||
|
.As<ILogChannel>(); |
||||
|
|
||||
|
services.AddSingletonAs(c => new ApplicationInfoLogAppender(typeof(Program).Assembly, Guid.NewGuid())) |
||||
|
.As<ILogAppender>(); |
||||
|
|
||||
|
services.AddSingletonAs<ActionContextLogAppender>() |
||||
|
.As<ILogAppender>(); |
||||
|
|
||||
|
services.AddSingletonAs<TimestampLogAppender>() |
||||
|
.As<ILogAppender>(); |
||||
|
|
||||
|
services.AddSingletonAs<DebugLogChannel>() |
||||
|
.As<ILogChannel>(); |
||||
|
|
||||
|
services.AddSingletonAs<SemanticLog>() |
||||
|
.As<ISemanticLog>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,40 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using Microsoft.Extensions.Configuration; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Infrastructure.Log; |
|
||||
using StackExchange.Redis; |
|
||||
|
|
||||
namespace Squidex.Config.Domain |
|
||||
{ |
|
||||
public static class PubSubServices |
|
||||
{ |
|
||||
public static void AddMyPubSubServices(this IServiceCollection services, IConfiguration config) |
|
||||
{ |
|
||||
config.ConfigureByOption("pubSub:type", new Options |
|
||||
{ |
|
||||
["InMemory"] = () => |
|
||||
{ |
|
||||
services.AddSingletonAs<InMemoryPubSub>() |
|
||||
.As<IPubSub>(); |
|
||||
}, |
|
||||
["Redis"] = () => |
|
||||
{ |
|
||||
var configuration = config.GetRequiredValue("pubsub:redis:configuration"); |
|
||||
|
|
||||
var redis = Singletons<IConnectionMultiplexer>.GetOrAddLazy(configuration, s => ConnectionMultiplexer.Connect(s)); |
|
||||
|
|
||||
services.AddSingletonAs(c => new RedisPubSub(redis, c.GetRequiredService<ISemanticLog>())) |
|
||||
.As<IPubSub>() |
|
||||
.As<IInitializable>(); |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,141 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
||||
// All rights reserved. Licensed under the MIT license.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System.Linq; |
|
||||
using Microsoft.Extensions.Configuration; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Squidex.Domain.Apps.Core.HandleRules; |
|
||||
using Squidex.Domain.Apps.Core.HandleRules.Actions; |
|
||||
using Squidex.Domain.Apps.Core.HandleRules.Triggers; |
|
||||
using Squidex.Domain.Apps.Entities; |
|
||||
using Squidex.Domain.Apps.Entities.Apps; |
|
||||
using Squidex.Domain.Apps.Entities.Apps.Services; |
|
||||
using Squidex.Domain.Apps.Entities.Apps.Services.Implementations; |
|
||||
using Squidex.Domain.Apps.Entities.Contents; |
|
||||
using Squidex.Domain.Apps.Entities.Contents.Edm; |
|
||||
using Squidex.Domain.Apps.Entities.Contents.GraphQL; |
|
||||
using Squidex.Domain.Apps.Entities.History; |
|
||||
using Squidex.Domain.Apps.Entities.Rules; |
|
||||
using Squidex.Domain.Apps.Entities.Schemas; |
|
||||
using Squidex.Domain.Users; |
|
||||
using Squidex.Infrastructure; |
|
||||
using Squidex.Infrastructure.Assets; |
|
||||
using Squidex.Infrastructure.EventSourcing; |
|
||||
using Squidex.Infrastructure.EventSourcing.Grains; |
|
||||
using Squidex.Infrastructure.States; |
|
||||
using Squidex.Pipeline; |
|
||||
|
|
||||
namespace Squidex.Config.Domain |
|
||||
{ |
|
||||
public static class ReadServices |
|
||||
{ |
|
||||
public static void AddMyReadServices(this IServiceCollection services, IConfiguration config) |
|
||||
{ |
|
||||
var consumeEvents = config.GetOptionalValue("eventStore:consume", false); |
|
||||
|
|
||||
if (consumeEvents) |
|
||||
{ |
|
||||
services.AddTransient<EventConsumerGrain>(); |
|
||||
|
|
||||
services.AddSingletonAs<EventConsumerGrainManager>() |
|
||||
.As<IRunnable>(); |
|
||||
services.AddSingletonAs<RuleDequeuer>() |
|
||||
.As<IRunnable>(); |
|
||||
services.AddSingletonAs<ContentScheduler>() |
|
||||
.As<IRunnable>(); |
|
||||
} |
|
||||
|
|
||||
var exposeSourceUrl = config.GetOptionalValue("assetStore:exposeSourceUrl", true); |
|
||||
|
|
||||
services.AddSingletonAs(c => new GraphQLUrlGenerator( |
|
||||
c.GetRequiredService<IOptions<MyUrlsOptions>>(), |
|
||||
c.GetRequiredService<IAssetStore>(), |
|
||||
exposeSourceUrl)) |
|
||||
.As<IGraphQLUrlGenerator>(); |
|
||||
|
|
||||
services.AddSingletonAs<StateFactory>() |
|
||||
.As<IInitializable>() |
|
||||
.As<IStateFactory>(); |
|
||||
|
|
||||
services.AddSingletonAs(c => c.GetService<IOptions<MyUsageOptions>>()?.Value?.Plans.OrEmpty()); |
|
||||
|
|
||||
services.AddSingletonAs<CachingGraphQLService>() |
|
||||
.As<IGraphQLService>(); |
|
||||
|
|
||||
services.AddSingletonAs<ContentQueryService>() |
|
||||
.As<IContentQueryService>(); |
|
||||
|
|
||||
services.AddSingletonAs<ConfigAppPlansProvider>() |
|
||||
.As<IAppPlansProvider>(); |
|
||||
|
|
||||
services.AddSingletonAs<AssetUserPictureStore>() |
|
||||
.As<IUserPictureStore>(); |
|
||||
|
|
||||
services.AddSingletonAs<AppHistoryEventsCreator>() |
|
||||
.As<IHistoryEventsCreator>(); |
|
||||
|
|
||||
services.AddSingletonAs<ContentHistoryEventsCreator>() |
|
||||
.As<IHistoryEventsCreator>(); |
|
||||
|
|
||||
services.AddSingletonAs<SchemaHistoryEventsCreator>() |
|
||||
.As<IHistoryEventsCreator>(); |
|
||||
|
|
||||
services.AddSingletonAs<NoopAppPlanBillingManager>() |
|
||||
.As<IAppPlanBillingManager>(); |
|
||||
|
|
||||
services.AddSingletonAs<AppProvider>() |
|
||||
.As<IAppProvider>(); |
|
||||
|
|
||||
services.AddSingletonAs<RuleEventFormatter>() |
|
||||
.AsSelf(); |
|
||||
|
|
||||
services.AddSingletonAs<AssetChangedTriggerHandler>() |
|
||||
.As<IRuleTriggerHandler>(); |
|
||||
|
|
||||
services.AddSingletonAs<ContentChangedTriggerHandler>() |
|
||||
.As<IRuleTriggerHandler>(); |
|
||||
|
|
||||
services.AddSingletonAs<AlgoliaActionHandler>() |
|
||||
.As<IRuleActionHandler>(); |
|
||||
|
|
||||
services.AddSingletonAs<AzureQueueActionHandler>() |
|
||||
.As<IRuleActionHandler>(); |
|
||||
|
|
||||
services.AddSingletonAs<ElasticSearchActionHandler>() |
|
||||
.As<IRuleActionHandler>(); |
|
||||
|
|
||||
services.AddSingletonAs<FastlyActionHandler>() |
|
||||
.As<IRuleActionHandler>(); |
|
||||
|
|
||||
services.AddSingletonAs<SlackActionHandler>() |
|
||||
.As<IRuleActionHandler>(); |
|
||||
|
|
||||
services.AddSingletonAs<WebhookActionHandler>() |
|
||||
.As<IRuleActionHandler>(); |
|
||||
|
|
||||
services.AddSingletonAs<DefaultEventNotifier>() |
|
||||
.As<IEventNotifier>(); |
|
||||
|
|
||||
services.AddSingletonAs<RuleEnqueuer>() |
|
||||
.As<IEventConsumer>(); |
|
||||
|
|
||||
services.AddSingletonAs(c => |
|
||||
{ |
|
||||
var allEventConsumers = c.GetServices<IEventConsumer>(); |
|
||||
|
|
||||
return new EventConsumerFactory(n => allEventConsumers.FirstOrDefault(x => x.Name == n)); |
|
||||
}); |
|
||||
|
|
||||
services.AddSingletonAs<EdmModelBuilder>() |
|
||||
.AsSelf(); |
|
||||
|
|
||||
services.AddSingletonAs<RuleService>() |
|
||||
.AsSelf(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,55 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Squidex.Domain.Apps.Core.HandleRules; |
||||
|
using Squidex.Domain.Apps.Core.HandleRules.Actions; |
||||
|
using Squidex.Domain.Apps.Core.HandleRules.Triggers; |
||||
|
using Squidex.Domain.Apps.Entities.Rules; |
||||
|
using Squidex.Infrastructure.EventSourcing; |
||||
|
|
||||
|
namespace Squidex.Config.Domain |
||||
|
{ |
||||
|
public static class RuleServices |
||||
|
{ |
||||
|
public static void AddMyRuleServices(this IServiceCollection services) |
||||
|
{ |
||||
|
services.AddSingletonAs<AssetChangedTriggerHandler>() |
||||
|
.As<IRuleTriggerHandler>(); |
||||
|
|
||||
|
services.AddSingletonAs<ContentChangedTriggerHandler>() |
||||
|
.As<IRuleTriggerHandler>(); |
||||
|
|
||||
|
services.AddSingletonAs<AlgoliaActionHandler>() |
||||
|
.As<IRuleActionHandler>(); |
||||
|
|
||||
|
services.AddSingletonAs<AzureQueueActionHandler>() |
||||
|
.As<IRuleActionHandler>(); |
||||
|
|
||||
|
services.AddSingletonAs<ElasticSearchActionHandler>() |
||||
|
.As<IRuleActionHandler>(); |
||||
|
|
||||
|
services.AddSingletonAs<FastlyActionHandler>() |
||||
|
.As<IRuleActionHandler>(); |
||||
|
|
||||
|
services.AddSingletonAs<SlackActionHandler>() |
||||
|
.As<IRuleActionHandler>(); |
||||
|
|
||||
|
services.AddSingletonAs<WebhookActionHandler>() |
||||
|
.As<IRuleActionHandler>(); |
||||
|
|
||||
|
services.AddSingletonAs<RuleEnqueuer>() |
||||
|
.As<IEventConsumer>(); |
||||
|
|
||||
|
services.AddSingletonAs<RuleEventFormatter>() |
||||
|
.AsSelf(); |
||||
|
|
||||
|
services.AddSingletonAs<RuleService>() |
||||
|
.AsSelf(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Squidex.Domain.Apps.Entities.Apps.Services; |
||||
|
using Squidex.Domain.Apps.Entities.Apps.Services.Implementations; |
||||
|
using Squidex.Domain.Users; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Config.Domain |
||||
|
{ |
||||
|
public static class SubscriptionServices |
||||
|
{ |
||||
|
public static void AddMySubscriptionServices(this IServiceCollection services, IConfiguration config) |
||||
|
{ |
||||
|
services.AddSingletonAs(c => c.GetService<IOptions<MyUsageOptions>>()?.Value?.Plans.OrEmpty()); |
||||
|
|
||||
|
services.AddSingletonAs<ConfigAppPlansProvider>() |
||||
|
.As<IAppPlansProvider>(); |
||||
|
|
||||
|
services.AddSingletonAs<NoopAppPlanBillingManager>() |
||||
|
.As<IAppPlanBillingManager>(); |
||||
|
|
||||
|
services.AddSingletonAs<AssetUserPictureStore>() |
||||
|
.As<IUserPictureStore>(); |
||||
|
|
||||
|
services.AddSingletonAs<NoopUserEvents>() |
||||
|
.As<IUserEvents>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,60 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Net; |
||||
|
using Orleans; |
||||
|
using Orleans.Configuration; |
||||
|
using Orleans.Runtime; |
||||
|
using Squidex.Domain.Apps.Entities; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Config.Orleans |
||||
|
{ |
||||
|
public sealed class ClientWrapper : DisposableObjectBase, IInitializable, IDisposable |
||||
|
{ |
||||
|
private readonly IClusterClient client; |
||||
|
|
||||
|
public IClusterClient Client |
||||
|
{ |
||||
|
get { return client; } |
||||
|
} |
||||
|
|
||||
|
public ClientWrapper() |
||||
|
{ |
||||
|
client = new ClientBuilder() |
||||
|
.UseDashboard() |
||||
|
.UseStaticClustering(options => |
||||
|
{ |
||||
|
options.Gateways.Add(new IPEndPoint(IPAddress.Loopback, 40000).ToGatewayUri()); |
||||
|
}) |
||||
|
.Configure<ClusterOptions>(options => |
||||
|
{ |
||||
|
options.ClusterId = "squidex"; |
||||
|
}) |
||||
|
.ConfigureApplicationParts(builder => |
||||
|
{ |
||||
|
builder.AddApplicationPart(SquidexEntities.Assembly); |
||||
|
builder.AddApplicationPart(SquidexInfrastructure.Assembly); |
||||
|
}) |
||||
|
.Build(); |
||||
|
} |
||||
|
|
||||
|
public void Initialize() |
||||
|
{ |
||||
|
client.Connect().Wait(); |
||||
|
} |
||||
|
|
||||
|
protected override void DisposeObject(bool disposing) |
||||
|
{ |
||||
|
if (disposing) |
||||
|
{ |
||||
|
client.Close().Wait(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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>(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Orleans.Hosting; |
||||
|
|
||||
|
namespace Squidex.Config.Orleans |
||||
|
{ |
||||
|
public static class SiloServices |
||||
|
{ |
||||
|
public static void AddAppSiloServices(this IServiceCollection services, IConfiguration config) |
||||
|
{ |
||||
|
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; |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,105 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Net; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
using Orleans; |
||||
|
using Orleans.Configuration; |
||||
|
using Orleans.Hosting; |
||||
|
using Squidex.Config.Domain; |
||||
|
using Squidex.Domain.Apps.Entities; |
||||
|
using Squidex.Domain.Apps.Entities.Contents; |
||||
|
using Squidex.Domain.Apps.Entities.Rules; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Squidex.Infrastructure.EventSourcing.Grains; |
||||
|
using Squidex.Infrastructure.Log.Adapter; |
||||
|
using Squidex.Infrastructure.Orleans; |
||||
|
|
||||
|
namespace Squidex.Config.Orleans |
||||
|
{ |
||||
|
public class SiloWrapper : DisposableObjectBase, 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) |
||||
|
{ |
||||
|
J.Serializer = SerializationServices.DefaultJsonSerializer; |
||||
|
|
||||
|
silo = new SiloHostBuilder() |
||||
|
.UseDashboard(options => options.HostSelf = true) |
||||
|
.AddStartupTask<Bootstrap<IContentSchedulerGrain>>() |
||||
|
.AddStartupTask<Bootstrap<IEventConsumerManagerGrain>>() |
||||
|
.AddStartupTask<Bootstrap<IRuleDequeuerGrain>>() |
||||
|
.ConfigureEndpoints(Dns.GetHostName(), 11111, 40000, listenOnAnyHostAddress: true) |
||||
|
.Configure<ClusterOptions>(options => |
||||
|
{ |
||||
|
options.ClusterId = "squidex"; |
||||
|
}) |
||||
|
.ConfigureLogging((hostingContext, builder) => |
||||
|
{ |
||||
|
builder.AddConfiguration(hostingContext.Configuration.GetSection("logging")); |
||||
|
builder.AddSemanticLog(); |
||||
|
builder.AddFilter("Orleans.Runtime.SiloControl", LogLevel.Warning); |
||||
|
}) |
||||
|
.ConfigureApplicationParts(builder => |
||||
|
{ |
||||
|
builder.AddApplicationPart(SquidexEntities.Assembly); |
||||
|
builder.AddApplicationPart(SquidexInfrastructure.Assembly); |
||||
|
}) |
||||
|
.ConfigureServices((context, services) => |
||||
|
{ |
||||
|
services.AddAppSiloServices(context.Configuration); |
||||
|
services.AddAppServices(context.Configuration); |
||||
|
|
||||
|
services.Configure<ProcessExitHandlingOptions>(options => options.FastKillOnProcessExit = false); |
||||
|
}) |
||||
|
.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(); |
||||
|
} |
||||
|
|
||||
|
protected override void DisposeObject(bool disposing) |
||||
|
{ |
||||
|
if (disposing) |
||||
|
{ |
||||
|
Task.Run(() => silo.StopAsync()).Wait(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue