mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
4.7 KiB
174 lines
4.7 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using Jint;
|
|
using Squidex.Infrastructure.Tasks;
|
|
using Squidex.Text;
|
|
|
|
namespace Squidex.Domain.Apps.Core.Scripting
|
|
{
|
|
public abstract class ScriptExecutionContext : ScriptContext
|
|
{
|
|
public Engine Engine { get; }
|
|
|
|
protected ScriptExecutionContext(Engine engine)
|
|
{
|
|
Engine = engine;
|
|
}
|
|
|
|
public abstract void Schedule(Func<IScheduler, CancellationToken, Task> action);
|
|
}
|
|
|
|
#pragma warning disable MA0048 // File name must match type name
|
|
public interface IScheduler
|
|
#pragma warning restore MA0048 // File name must match type name
|
|
{
|
|
void Run(Action? action);
|
|
|
|
void Run<T>(Action<T>? action, T argument);
|
|
}
|
|
|
|
public sealed class ScriptExecutionContext<T> : ScriptExecutionContext, IScheduler
|
|
{
|
|
private readonly TaskCompletionSource<T?> tcs = new TaskCompletionSource<T?>();
|
|
private readonly CancellationToken cancellationToken;
|
|
private int pendingTasks;
|
|
|
|
public bool IsCompleted
|
|
{
|
|
get => tcs.Task.Status == TaskStatus.RanToCompletion || tcs.Task.Status == TaskStatus.Faulted;
|
|
}
|
|
|
|
internal ScriptExecutionContext(Engine engine, CancellationToken cancellationToken)
|
|
: base(engine)
|
|
{
|
|
this.cancellationToken = cancellationToken;
|
|
}
|
|
|
|
public Task<T?> CompleteAsync()
|
|
{
|
|
if (pendingTasks <= 0)
|
|
{
|
|
tcs.TrySetResult(default);
|
|
}
|
|
|
|
return tcs.Task.WithCancellation(cancellationToken);
|
|
}
|
|
|
|
public void Complete(T value)
|
|
{
|
|
tcs.TrySetResult(value);
|
|
}
|
|
|
|
public override void Schedule(Func<IScheduler, CancellationToken, Task> action)
|
|
{
|
|
if (IsCompleted)
|
|
{
|
|
return;
|
|
}
|
|
|
|
async Task ScheduleAsync()
|
|
{
|
|
try
|
|
{
|
|
Interlocked.Increment(ref pendingTasks);
|
|
|
|
await action(this, cancellationToken);
|
|
|
|
if (Interlocked.Decrement(ref pendingTasks) <= 0)
|
|
{
|
|
tcs.TrySetResult(default);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
tcs.TrySetException(ex);
|
|
}
|
|
}
|
|
|
|
ScheduleAsync().Forget();
|
|
}
|
|
|
|
public ScriptExecutionContext<T> ExtendAsync(IEnumerable<IJintExtension> extensions)
|
|
{
|
|
foreach (var extension in extensions)
|
|
{
|
|
extension.ExtendAsync(this);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
public ScriptExecutionContext<T> Extend(IEnumerable<IJintExtension> extensions)
|
|
{
|
|
foreach (var extension in extensions)
|
|
{
|
|
extension.Extend(this);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
public ScriptExecutionContext<T> Extend(ScriptVars vars, ScriptOptions options)
|
|
{
|
|
var engine = Engine;
|
|
|
|
if (options.AsContext)
|
|
{
|
|
var contextInstance = new WritableContext(engine, vars);
|
|
|
|
foreach (var (key, value) in vars.Where(x => x.Value != null))
|
|
{
|
|
this[key.ToCamelCase()] = value;
|
|
}
|
|
|
|
engine.SetValue("ctx", contextInstance);
|
|
engine.SetValue("context", contextInstance);
|
|
}
|
|
else
|
|
{
|
|
foreach (var (key, value) in vars)
|
|
{
|
|
var property = key.ToCamelCase();
|
|
|
|
if (value != null)
|
|
{
|
|
engine.SetValue(property, value);
|
|
|
|
this[property] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
engine.SetValue("async", true);
|
|
|
|
return this;
|
|
}
|
|
|
|
void IScheduler.Run(Action? action)
|
|
{
|
|
if (IsCompleted || action == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Engine.ResetConstraints();
|
|
action();
|
|
}
|
|
|
|
void IScheduler.Run<TArg>(Action<TArg>? action, TArg argument)
|
|
{
|
|
if (IsCompleted || action == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Engine.ResetConstraints();
|
|
action(argument);
|
|
}
|
|
}
|
|
}
|
|
|