Skip to content

Commit 256e51c

Browse files
authoredFeb 12, 2025··
Start to open for logging customization. (ZeraGmbH/websam#936) (ZeraGmbH#117)
* Manual depedency update - getting strange! * More abstractions to support generic logging. * Open engine to customize logging.
1 parent d3b305f commit 256e51c

13 files changed

+112
-47
lines changed
 

‎Library/BlocklyDIExtensions.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using BlocklyNet.Core;
22
using BlocklyNet.Extensions.Builder;
33
using BlocklyNet.Scripting.Engine;
4+
using BlocklyNet.Scripting.Logging;
45
using Microsoft.Extensions.DependencyInjection;
56

67
namespace BlocklyNet;
@@ -15,15 +16,17 @@ public static class BlocklyDIExtensions
1516
/// </summary>
1617
/// <param name="services">Dependency injection services.</param>
1718
/// <param name="xml">Unset to use JSON serialization instead of the default XML.</param>
18-
public static void UseBlocklyNet(this IServiceCollection services, bool xml = true) => services.UseBlocklyNet<ScriptEngine>(xml);
19+
public static void UseBlocklyNet(this IServiceCollection services, bool xml = true)
20+
=> services.UseBlocklyNet<ScriptEngine<ScriptLoggingResult>, ScriptLoggingResult>(xml);
1921

2022
/// <summary>
2123
/// Configure the dependency injection environment.
2224
/// </summary>
2325
/// <typeparam name="TEngine">Engine implementation to use.</typeparam>
26+
/// <typeparam name="TLogType">Type of the logging entires used by this very script engine..</typeparam>
2427
/// <param name="services">Dependency injection services.</param>
2528
/// <param name="xml">Unset to use JSON serialization instead of the default XML.</param>
26-
public static void UseBlocklyNet<TEngine>(this IServiceCollection services, bool xml = true) where TEngine : ScriptEngine
29+
public static void UseBlocklyNet<TEngine, TLogType>(this IServiceCollection services, bool xml = true) where TEngine : ScriptEngine<TLogType> where TLogType : ScriptLoggingResult, new()
2730
{
2831
/* Single management instance for all known models. */
2932
services.AddSingleton<IScriptModels, ScriptModels>();

‎Library/BlocklyNet.csproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
</PropertyGroup>
1212

1313
<ItemGroup>
14-
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.1" />
15-
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.1" />
14+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
15+
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.2" />
1616
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
1717
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.12.19" PrivateAssets="all" />
1818
</ItemGroup>

‎Library/Scripting/Engine/IScriptSite.cs

+32-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using BlocklyNet.Core.Model;
2+
using BlocklyNet.Scripting.Logging;
23
using Microsoft.Extensions.Logging;
34

45
namespace BlocklyNet.Scripting.Engine;
@@ -33,16 +34,6 @@ public interface IScriptSite
3334
/// </summary>
3435
bool MustPause { get; }
3536

36-
/// <summary>
37-
/// Report the currently running script.
38-
/// </summary>
39-
IScript? CurrentScript { get; }
40-
41-
/// <summary>
42-
/// Report the outer script.
43-
/// </summary>
44-
IScript? MainScript { get; }
45-
4637
/// <summary>
4738
/// Set progress information.
4839
/// </summary>
@@ -106,4 +97,35 @@ public interface IScriptSite
10697
/// <param name="index">Zero-based index of the group.</param>
10798
/// <returns>Information on the group.</returns>
10899
GroupStatus GetGroupStatus(int index);
100+
101+
/// <summary>
102+
/// Report the currently running script.
103+
/// </summary>
104+
IScript? CurrentScript { get; }
105+
106+
/// <summary>
107+
/// Report the outer script.
108+
/// </summary>
109+
IScript? MainScript { get; }
110+
111+
/// <summary>
112+
/// Update the current log entry.
113+
/// </summary>
114+
Task UpdateLogAsync();
115+
}
116+
117+
/// <summary>
118+
///
119+
/// </summary>
120+
public interface IScriptSite<TLogType> : IScriptSite where TLogType : ScriptLoggingResult, new()
121+
{
122+
/// <summary>
123+
/// Report the currently running script.
124+
/// </summary>
125+
new IScript<TLogType>? CurrentScript { get; }
126+
127+
/// <summary>
128+
/// Report the outer script.
129+
/// </summary>
130+
new IScript<TLogType>? MainScript { get; }
109131
}

‎Library/Scripting/Engine/ScriptEngine.Input.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace BlocklyNet.Scripting.Engine;
77

8-
public partial class ScriptEngine
8+
partial class ScriptEngine<TLogType>
99
{
1010
/// <summary>
1111
/// Current active user reply.

‎Library/Scripting/Engine/ScriptEngine.Nested.cs

+20-11
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55

66
namespace BlocklyNet.Scripting.Engine;
77

8-
public partial class ScriptEngine
8+
partial class ScriptEngine<TLogType>
99
{
1010
/// <summary>
1111
/// Helper class to manage nested script calls.
1212
/// </summary>
13-
protected class ScriptSite : IScriptSite, IGroupManagerSite
13+
protected class ScriptSite : IScriptSite<TLogType>, IGroupManagerSite
1414
{
1515
/// <summary>
1616
///
@@ -19,7 +19,7 @@ protected class ScriptSite : IScriptSite, IGroupManagerSite
1919
/// <param name="parent">Parent script.</param>
2020
/// <param name="depth">Nestring depth of the script, at least 1.</param>
2121
/// <param name="groupManager">Group management for this nested script only.</param>
22-
public ScriptSite(ScriptEngine engine, IScript? parent, int depth, ISiteGroupManager groupManager)
22+
public ScriptSite(ScriptEngine<TLogType> engine, IScript<TLogType>? parent, int depth, ISiteGroupManager groupManager)
2323
{
2424
_depth = depth;
2525
_engine = engine;
@@ -44,7 +44,7 @@ public ScriptSite(ScriptEngine engine, IScript? parent, int depth, ISiteGroupMan
4444
/// <summary>
4545
/// The script starting this script.
4646
/// </summary>
47-
protected readonly IScript? Parent;
47+
protected readonly IScript<TLogType>? Parent;
4848

4949
/// <summary>
5050
/// Synchronize access to the result.
@@ -70,7 +70,7 @@ public ScriptSite(ScriptEngine engine, IScript? parent, int depth, ISiteGroupMan
7070
/// <summary>
7171
/// The main script engine.
7272
/// </summary>
73-
private readonly ScriptEngine _engine;
73+
private readonly ScriptEngine<TLogType> _engine;
7474

7575
/// <inheritdoc/>
7676
public IServiceProvider ServiceProvider => _engine.ServiceProvider;
@@ -85,10 +85,16 @@ public ScriptSite(ScriptEngine engine, IScript? parent, int depth, ISiteGroupMan
8585
public bool MustPause => _engine.MustPause;
8686

8787
/// <inheritdoc/>
88-
public IScript? CurrentScript { get; private set; }
88+
public IScript<TLogType>? CurrentScript { get; private set; }
8989

9090
/// <inheritdoc/>
91-
public IScript? MainScript => _engine.MainScript;
91+
public IScript<TLogType>? MainScript => _engine.MainScript;
92+
93+
/// <inheritdoc/>
94+
IScript? IScriptSite.CurrentScript => CurrentScript;
95+
96+
/// <inheritdoc/>
97+
IScript? IScriptSite.MainScript => MainScript;
9298

9399
/// <inheritdoc/>
94100
public Task<object?> EvaluateAsync(string scriptAsXml, Dictionary<string, object?> presets)
@@ -154,7 +160,7 @@ public void Start(StartScript request, StartScriptOptions? options = null)
154160
try
155161
{
156162
/* Create the script instance from the configuration model. */
157-
if (Activator.CreateInstance(request.GetScriptType(), request, this, options) is not Script script)
163+
if (Activator.CreateInstance(request.GetScriptType(), request, this, options) is not IScriptInstance<TLogType> script)
158164
throw new ArgumentException("bad script for '{Name}' request.", request.Name);
159165

160166
/* Start the background execution of the script. */
@@ -171,7 +177,7 @@ public void Start(StartScript request, StartScriptOptions? options = null)
171177
/// <summary>
172178
/// Process the script.
173179
/// </summary>
174-
private async Task RunScriptAsync(Script script)
180+
private async Task RunScriptAsync(IScriptInstance<TLogType> script)
175181
{
176182
try
177183
{
@@ -218,6 +224,9 @@ private async Task RunScriptAsync(Script script)
218224

219225
/// <inheritdoc/>
220226
public virtual Task DoneExecuteGroupAsync(GroupStatus status) => Task.CompletedTask;
227+
228+
/// <inheritdoc/>
229+
public Task UpdateLogAsync() => CurrentScript == null ? Task.CompletedTask : _engine.UpdateResultLogEntryAsync(CurrentScript, Parent, false);
221230
}
222231

223232
/// <summary>
@@ -227,7 +236,7 @@ private async Task RunScriptAsync(Script script)
227236
/// <param name="depth">Nesting depth.</param>
228237
/// <param name="groupManager">Execution group management helper.</param>
229238
/// <returns>The new site.</returns>
230-
protected virtual ScriptSite CreateSite(IScript? parent, int depth, IGroupManager groupManager)
239+
protected virtual ScriptSite CreateSite(IScript<TLogType>? parent, int depth, IGroupManager groupManager)
231240
=> new(this, parent, depth, groupManager);
232241

233242
/// <summary>
@@ -240,7 +249,7 @@ protected virtual ScriptSite CreateSite(IScript? parent, int depth, IGroupManage
240249
/// <param name="depth">Nestring depth of the child.</param>
241250
/// <param name="groupManager">Parent group manager to allow for any-depth nesting.</param>
242251
/// <returns>Task on the result.</returns>
243-
protected virtual async Task<TResult> StartChildAsync<TResult>(StartScript request, IScript? parent, StartScriptOptions? options, int depth, ISiteGroupManager groupManager)
252+
protected virtual async Task<TResult> StartChildAsync<TResult>(StartScript request, IScript<TLogType>? parent, StartScriptOptions? options, int depth, ISiteGroupManager groupManager)
244253
{
245254
/* Create execution context. */
246255
var site = CreateSite(parent, depth + 1, await groupManager.CreateNestedAsync((request as IStartGenericScript)?.ScriptId ?? string.Empty, request.Name));

‎Library/Scripting/Engine/ScriptEngine.Notifications.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
namespace BlocklyNet.Scripting.Engine;
44

5-
public partial class ScriptEngine
5+
partial class ScriptEngine<TLogType>
66
{
77
/// <summary>
88
///
99
/// </summary>
1010
/// <param name="script"></param>
1111
/// <returns></returns>
12-
protected virtual ScriptInformation CreateStartNotification(Script script)
12+
protected virtual ScriptInformation CreateStartNotification(IScriptInstance script)
1313
=> new()
1414
{
1515
JobId = script.JobId,

‎Library/Scripting/Engine/ScriptEngine.Progress.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace BlocklyNet.Scripting.Engine;
44

5-
public partial class ScriptEngine
5+
partial class ScriptEngine<TLogType>
66
{
77
/// <summary>
88
/// Child progress information - nested by depth.

‎Library/Scripting/Engine/ScriptEngine.cs

+28-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1-
using System.Reflection;
2-
using System.Security.Cryptography;
3-
using System.Text;
41
using BlocklyNet.Core.Model;
2+
using BlocklyNet.Scripting.Logging;
53
using BlocklyNet.Scripting.Parsing;
64
using BlocklyNet.User;
75
using Microsoft.Extensions.DependencyInjection;
86
using Microsoft.Extensions.Logging;
7+
using System.Reflection;
8+
using System.Security.Cryptography;
9+
using System.Text;
910

1011
namespace BlocklyNet.Scripting.Engine;
1112

1213
/// <summary>
1314
/// The script execution engine. There can be at most one active
1415
/// script at any time.
1516
/// </summary>
16-
public partial class ScriptEngine : IScriptEngine, IScriptSite, IGroupManagerSite, IDisposable
17+
public partial class ScriptEngine<TLogType> : IScriptEngine, IScriptSite<TLogType>, IGroupManagerSite, IDisposable where TLogType : ScriptLoggingResult, new()
1718
{
1819
/// <summary>
1920
///
@@ -27,7 +28,7 @@ public ScriptEngine(
2728
IServiceProvider rootProvider,
2829
IScriptParser parser,
2930
IGroupManager groupManager,
30-
ILogger<ScriptEngine> logger,
31+
ILogger<ScriptEngine<TLogType>> logger,
3132
IScriptEngineNotifySink? context = null
3233
)
3334
{
@@ -60,7 +61,7 @@ public ScriptEngine(
6061
/// <summary>
6162
/// The active script.
6263
/// </summary>
63-
private IScriptInstance? _active;
64+
private IScriptInstance<TLogType>? _active;
6465

6566
/// <summary>
6667
/// Set when the one and only script is done.
@@ -91,10 +92,16 @@ public ScriptEngine(
9192
private CancellationTokenSource _pause = new();
9293

9394
/// <inheritdoc />
94-
public IScript? CurrentScript => _active;
95+
IScript? IScriptSite.CurrentScript => CurrentScript;
96+
97+
/// <inheritdoc />
98+
IScript? IScriptSite.MainScript => MainScript;
9599

96100
/// <inheritdoc />
97-
public IScript? MainScript => _active;
101+
public IScript<TLogType>? CurrentScript => _active;
102+
103+
/// <inheritdoc />
104+
public IScript<TLogType>? MainScript => _active;
98105

99106
/// <summary>
100107
/// Last progress seen.
@@ -147,7 +154,7 @@ public virtual async Task<string> StartAsync(StartScript request, string userTok
147154
try
148155
{
149156
/* Try to create the script instance. */
150-
if (Activator.CreateInstance(request.GetScriptType(), request, this, options) is not Script script)
157+
if (Activator.CreateInstance(request.GetScriptType(), request, this, options) is not IScriptInstance<TLogType> script)
151158
throw new ArgumentException("bad script for '{Name}' request.", request.Name);
152159

153160
using (Lock.Wait())
@@ -539,4 +546,16 @@ public async Task<GroupStatus> EndGroupAsync(GroupResult result)
539546

540547
/// <inheritdoc/>
541548
public virtual Task DoneExecuteGroupAsync(GroupStatus status) => Task.CompletedTask;
549+
550+
/// <inheritdoc/>
551+
public Task UpdateLogAsync() => CurrentScript == null ? Task.CompletedTask : UpdateResultLogEntryAsync(CurrentScript, null, false);
552+
553+
/// <summary>
554+
///
555+
/// </summary>
556+
/// <param name="script"></param>
557+
/// <param name="parent"></param>
558+
/// <param name="final"></param>
559+
/// <returns></returns>
560+
protected virtual Task UpdateResultLogEntryAsync(IScript<TLogType> script, IScript<TLogType>? parent, bool final) => Task.CompletedTask;
542561
}

‎Library/Scripting/IScriptInstance.cs

+9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using BlocklyNet.Scripting.Logging;
2+
13
namespace BlocklyNet.Scripting;
24

35
/// <summary>
@@ -21,3 +23,10 @@ public interface IScriptInstance : IScript
2123
/// </summary>
2224
StartScript GetRequest();
2325
}
26+
27+
/// <summary>
28+
///
29+
/// </summary>
30+
public interface IScriptInstance<TLogType> : IScript<TLogType>, IScriptInstance where TLogType : ScriptLoggingResult, new()
31+
{
32+
}

‎Library/Scripting/Logging/IScriptLogModifier.cs

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using System.Reflection;
2-
31
namespace BlocklyNet.Scripting.Logging;
42

53
/// <summary>

‎Library/Scripting/ScriptCommon.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace BlocklyNet.Scripting;
77
/// <summary>
88
/// Describes an active script.
99
/// </summary>
10-
public abstract class Script<TOption, TLogType, TModifierType> : Script, IScript<TLogType>
10+
public abstract class Script<TOption, TLogType, TModifierType> : Script, IScriptInstance<TLogType>
1111
where TOption : StartScriptOptions
1212
where TLogType : ScriptLoggingResult, new()
1313
where TModifierType : IScriptLogModifier

‎Tests/BlocklyNetTests.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13-
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.1" />
13+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.2" />
1414
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
1515
<PackageReference Include="Moq" Version="4.20.72" />
1616
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

‎Tests/CoreEx/ScriptParserTests.cs

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using BlocklyNet.Core;
22
using BlocklyNet.Extensions.Builder;
33
using BlocklyNet.Scripting.Engine;
4+
using BlocklyNet.Scripting.Logging;
45
using BlocklyNet.Scripting.Parsing;
56
using Microsoft.Extensions.DependencyInjection;
67
using Microsoft.Extensions.Logging.Abstractions;
@@ -11,6 +12,10 @@ namespace BlocklyNetTests.CoreEx;
1112
[TestFixture]
1213
public class ScriptParserTests
1314
{
15+
private class TestEngine(IServiceProvider rootProvider)
16+
: ScriptEngine<ScriptLoggingResult>(rootProvider, rootProvider.GetRequiredService<IScriptParser>(), new GroupManager(), new NullLogger<TestEngine>())
17+
{ }
18+
1419
private ServiceProvider Services = null!;
1520

1621
[SetUp]
@@ -155,7 +160,7 @@ public async Task Can_Parse_And_Compile_Xml_Script_Async()
155160
</xml>
156161
";
157162

158-
var engine = new ScriptEngine(Services, Services.GetRequiredService<IScriptParser>(), new GroupManager(), new NullLogger<ScriptEngine>(), null);
163+
var engine = new TestEngine(Services);
159164

160165
await engine.EvaluateAsync(xml, []);
161166
}
@@ -250,7 +255,7 @@ public async Task Can_Evaluate_With_Variables_Async(double? a)
250255
</xml>
251256
";
252257

253-
var engine = new ScriptEngine(Services, Services.GetRequiredService<IScriptParser>(), new GroupManager(), new NullLogger<ScriptEngine>(), null);
258+
var engine = new TestEngine(Services);
254259

255260
var presets = new Dictionary<string, object?> { { "d", "Jochen" } };
256261

@@ -299,7 +304,7 @@ public async Task Can_Execute_Generic_Http_Request_Async()
299304
</xml>
300305
";
301306

302-
var engine = new ScriptEngine(Services, Services.GetRequiredService<IScriptParser>(), new GroupManager(), new NullLogger<ScriptEngine>(), null);
307+
var engine = new TestEngine(Services);
303308

304309
var body = await engine.EvaluateAsync(xml, []);
305310

@@ -420,7 +425,7 @@ public async Task Can_Execute_Try_Catch_Finally_Async()
420425
</xml>
421426
";
422427

423-
var engine = new ScriptEngine(Services, Services.GetRequiredService<IScriptParser>(), new GroupManager(), new NullLogger<ScriptEngine>(), null);
428+
var engine = new TestEngine(Services);
424429

425430
var vars = (IList<object>)(await engine.EvaluateAsync(xml, []))!;
426431

@@ -454,7 +459,7 @@ public void Can_Provide_Variable_Types()
454459
</xml>
455460
";
456461

457-
var engine = new ScriptEngine(Services, Services.GetRequiredService<IScriptParser>(), new GroupManager(), new NullLogger<ScriptEngine>(), null);
462+
var engine = new TestEngine(Services);
458463
var parsed = engine.Parser.Parse(xml);
459464

460465
Assert.That(parsed.GetVariableType("result"), Is.EqualTo("something"));

0 commit comments

Comments
 (0)
Please sign in to comment.