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
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// 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
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// 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
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// 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
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// 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
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
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
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// 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
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// 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