Skip to content

Commit ed6de07

Browse files
💾 Feat(ConfigManager): 重构配置管理,提取公共属性更新逻辑至 ApplyConfig 方法
💾 Feat(EventService): 引入类型化事件处理器,优化事件订阅与取消逻辑 💾 Feat(WorkflowScriptService): 初始化 BlockScriptParser 时注册内置函数
1 parent 11f86a1 commit ed6de07

4 files changed

Lines changed: 51 additions & 170 deletions

File tree

KitX Clients/KitX Core/KitX.Core/Configuration/ConfigManager.cs

Lines changed: 16 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,7 @@ private void ReloadConfigFile<T>(string fileName) where T : class
210210
if (config != null)
211211
{
212212
_configs[typeof(T).Name] = config;
213-
214-
// Update the public properties
215-
if (typeof(T) == typeof(AppConfig))
216-
AppConfig = config as IAppConfig ?? new AppConfig();
217-
else if (typeof(T) == typeof(PluginsConfig))
218-
PluginsConfig = config as IPluginsConfig ?? new PluginsConfig();
219-
else if (typeof(T) == typeof(SecurityConfig))
220-
SecurityConfig = config as ISecurityConfig ?? new SecurityConfig();
213+
ApplyConfig(config);
221214

222215
Log.Information("Reloaded config file {FileName}", fileName);
223216
}
@@ -365,14 +358,7 @@ public void Reload()
365358
if (config != null)
366359
{
367360
_configs[typeof(T).Name] = config;
368-
369-
// Update the public properties
370-
if (typeof(T) == typeof(AppConfig))
371-
AppConfig = config as IAppConfig ?? new AppConfig();
372-
else if (typeof(T) == typeof(PluginsConfig))
373-
PluginsConfig = config as IPluginsConfig ?? new PluginsConfig();
374-
else if (typeof(T) == typeof(SecurityConfig))
375-
SecurityConfig = config as ISecurityConfig ?? new SecurityConfig();
361+
ApplyConfig(config);
376362
}
377363
}
378364
else
@@ -383,14 +369,7 @@ public void Reload()
383369

384370
// Save default config
385371
SaveConfigFile(config, fileName);
386-
387-
// Update the public properties
388-
if (typeof(T) == typeof(AppConfig))
389-
AppConfig = config as IAppConfig ?? new AppConfig();
390-
else if (typeof(T) == typeof(PluginsConfig))
391-
PluginsConfig = config as IPluginsConfig ?? new PluginsConfig();
392-
else if (typeof(T) == typeof(SecurityConfig))
393-
SecurityConfig = config as ISecurityConfig ?? new SecurityConfig();
372+
ApplyConfig(config);
394373
}
395374
}
396375
catch (Exception ex)
@@ -399,6 +378,19 @@ public void Reload()
399378
}
400379
}
401380

381+
/// <summary>
382+
/// Updates the public config properties based on the config object's type
383+
/// </summary>
384+
private void ApplyConfig(object config)
385+
{
386+
if (config is IAppConfig appConfig)
387+
AppConfig = appConfig;
388+
else if (config is IPluginsConfig pluginsConfig)
389+
PluginsConfig = pluginsConfig;
390+
else if (config is ISecurityConfig securityConfig)
391+
SecurityConfig = securityConfig;
392+
}
393+
402394
/// <summary>
403395
/// Saves config file
404396
/// </summary>
Lines changed: 31 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.ComponentModel;
43
using System.Threading;
54
using KitX.Core.Contract.Event;
6-
using KitX.Shared.CSharp.Device;
75
using Serilog;
86

97
namespace KitX.Core.Event;
@@ -27,6 +25,11 @@ public class EventService : IEventService
2725
/// </summary>
2826
private readonly object _lock = new();
2927

28+
/// <summary>
29+
/// Maps (eventName, originalHandler) to wrapper lambda for typed subscribe/unsubscribe
30+
/// </summary>
31+
private readonly Dictionary<(string eventName, Delegate handler), EventHandler<EventArgs>> _typedWrapperMap = new();
32+
3033
/// <summary>
3134
/// Thread-local counter to track publish depth for recursion detection
3235
/// </summary>
@@ -95,12 +98,18 @@ public void Publish(string eventName, EventArgs args)
9598

9699
try
97100
{
98-
if (_eventHandlers.TryGetValue(eventName, out var handlers))
101+
// Take a snapshot of handlers under lock to avoid concurrent modification
102+
List<EventHandler<EventArgs>> snapshot;
103+
lock (_lock)
99104
{
100-
foreach (var handler in handlers)
101-
{
102-
handler.Invoke(this, args);
103-
}
105+
if (!_eventHandlers.TryGetValue(eventName, out var handlers))
106+
return;
107+
snapshot = new List<EventHandler<EventArgs>>(handlers);
108+
}
109+
110+
foreach (var handler in snapshot)
111+
{
112+
handler.Invoke(this, args);
104113
}
105114
}
106115
finally
@@ -125,13 +134,16 @@ public void Subscribe<TEventArgs>(string eventName, EventHandler<TEventArgs> han
125134
_eventHandlers[eventName] = new List<EventHandler<EventArgs>>();
126135
}
127136

128-
_eventHandlers[eventName].Add((sender, args) =>
137+
EventHandler<EventArgs> wrapper = (sender, args) =>
129138
{
130139
if (args is TEventArgs typedArgs)
131140
{
132141
handler(sender, typedArgs);
133142
}
134-
});
143+
};
144+
145+
_typedWrapperMap[(eventName, handler)] = wrapper;
146+
_eventHandlers[eventName].Add(wrapper);
135147
}
136148
}
137149

@@ -144,11 +156,17 @@ public void Subscribe<TEventArgs>(string eventName, EventHandler<TEventArgs> han
144156
public void Unsubscribe<TEventArgs>(string eventName, EventHandler<TEventArgs> handler)
145157
where TEventArgs : EventArgs
146158
{
147-
if (_eventHandlers.TryGetValue(eventName, out var handlers))
159+
lock (_lock)
148160
{
149-
// Note: Exact handler removal is not supported in this implementation
150-
// The handler wrapper makes exact matching difficult
151-
// Consider using a different approach for production
161+
var key = (eventName, handler);
162+
if (_typedWrapperMap.TryGetValue(key, out var wrapper))
163+
{
164+
if (_eventHandlers.TryGetValue(eventName, out var handlers))
165+
{
166+
handlers.Remove(wrapper);
167+
}
168+
_typedWrapperMap.Remove(key);
169+
}
152170
}
153171
}
154172

@@ -165,135 +183,4 @@ public void Publish<TEventArgs>(string eventName, TEventArgs args)
165183
Publish(eventName, (EventArgs)args);
166184
}
167185

168-
/// <summary>
169-
/// Invokes a static event dynamically (legacy support)
170-
/// </summary>
171-
/// <param name="eventName">The event name</param>
172-
/// <param name="objects">Optional parameters</param>
173-
[Obsolete("Use IEventService.Publish with event names instead")]
174-
public static void Invoke(string eventName, object[]? objects = null)
175-
{
176-
var type = typeof(EventService);
177-
178-
var eventField = type.GetField(eventName, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
179-
180-
if (eventField is null || !typeof(Delegate).IsAssignableFrom(eventField.FieldType))
181-
{
182-
throw new ArgumentException($"No event found with the name '{eventName}'.", nameof(eventName));
183-
}
184-
185-
var @delegate = eventField.GetValue(null) as Delegate;
186-
187-
@delegate?.DynamicInvoke(objects);
188-
}
189-
190-
#region Static Events (Legacy Support)
191-
192-
#pragma warning disable CS0067 // Event is never used
193-
194-
/// <summary>
195-
/// Language changed event
196-
/// </summary>
197-
[Obsolete("Use IEventService with EventNames.LanguageChanged instead")]
198-
public static event Action LanguageChanged = () => { };
199-
200-
/// <summary>
201-
/// Greeting text interval updated event
202-
/// </summary>
203-
[Obsolete("Use IEventService with EventNames.GreetingTextIntervalUpdated instead")]
204-
public static event Action GreetingTextIntervalUpdated = () => { };
205-
206-
/// <summary>
207-
/// App config changed event
208-
/// </summary>
209-
[Obsolete("Use IEventService with EventNames.AppConfigChanged instead")]
210-
public static event Action AppConfigChanged = () => { };
211-
212-
/// <summary>
213-
/// Plugins config changed event
214-
/// </summary>
215-
[Obsolete("Use IEventService with EventNames.PluginsConfigChanged instead")]
216-
public static event Action PluginsConfigChanged = () => { };
217-
218-
/// <summary>
219-
/// Mica opacity changed event
220-
/// </summary>
221-
[Obsolete("Use IEventService with EventNames.MicaOpacityChanged instead")]
222-
public static event Action MicaOpacityChanged = () => { };
223-
224-
/// <summary>
225-
/// Develop settings changed event
226-
/// </summary>
227-
[Obsolete("Use IEventService with EventNames.DevelopSettingsChanged instead")]
228-
public static event Action DevelopSettingsChanged = () => { };
229-
230-
/// <summary>
231-
/// Log config updated event
232-
/// </summary>
233-
[Obsolete("Use IEventService with EventNames.LogConfigUpdated instead")]
234-
public static event Action LogConfigUpdated = () => { };
235-
236-
/// <summary>
237-
/// Theme config changed event
238-
/// </summary>
239-
[Obsolete("Use IEventService with EventNames.ThemeConfigChanged instead")]
240-
public static event Action ThemeConfigChanged = () => { };
241-
242-
/// <summary>
243-
/// Use statistics changed event
244-
/// </summary>
245-
[Obsolete("Use IEventService with EventNames.UseStatisticsChanged instead")]
246-
public static event Action UseStatisticsChanged = () => { };
247-
248-
/// <summary>
249-
/// Devices server port changed event
250-
/// </summary>
251-
[Obsolete("Use IEventService with EventNames.DevicesServerPortChanged instead")]
252-
public static event Action<int> DevicesServerPortChanged = port => { };
253-
254-
/// <summary>
255-
/// Plugins server port changed event
256-
/// </summary>
257-
[Obsolete("Use IEventService with EventNames.PluginsServerPortChanged instead")]
258-
public static event Action<int> PluginsServerPortChanged = port => { };
259-
260-
/// <summary>
261-
/// Activities updated event
262-
/// </summary>
263-
[Obsolete("Use IEventService with EventNames.OnActivitiesUpdated instead")]
264-
public static event Action OnActivitiesUpdated = () => { };
265-
266-
/// <summary>
267-
/// Receive cancel exchanging device key event
268-
/// </summary>
269-
[Obsolete("Use IEventService with EventNames.OnReceiveCancelExchangingDeviceKey instead")]
270-
public static event Action OnReceiveCancelExchangingDeviceKey = () => { };
271-
272-
/// <summary>
273-
/// Exiting event
274-
/// </summary>
275-
[Obsolete("Use IEventService with EventNames.OnExiting instead")]
276-
public static event Action OnExiting = () => { };
277-
278-
/// <summary>
279-
/// Receiving device info event
280-
/// </summary>
281-
[Obsolete("Use IEventService with EventNames.OnReceivingDeviceInfo instead")]
282-
public static event Action<DeviceInfo> OnReceivingDeviceInfo = _ => { };
283-
284-
/// <summary>
285-
/// Config hot reloaded event
286-
/// </summary>
287-
[Obsolete("Use IEventService with EventNames.OnConfigHotReloaded instead")]
288-
public static event Action OnConfigHotReloaded = () => { };
289-
290-
/// <summary>
291-
/// Accepting device key event
292-
/// </summary>
293-
[Obsolete("Use IEventService with EventNames.OnAcceptingDeviceKey instead")]
294-
public static event Action<string> OnAcceptingDeviceKey = _ => { };
295-
296-
#pragma warning restore CS0067 // Event is never used
297-
298-
#endregion
299186
}

KitX Clients/KitX Core/KitX.Core/Workflow/WorkflowScriptService.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using Kscript.CSharp.Parser;
1616
using KitX.Core.Contract.Workflow;
1717
using KitX.Core.Device;
18+
using KitX.Core.Workflow.BlockScripting;
1819
using KitX.Shared.CSharp.Plugin;
1920
using Serilog;
2021
using CTask = System.Threading.Tasks.Task;
@@ -689,7 +690,8 @@ public string MergeHelperFunctions(string mainCode, List<HelperFunction> helperF
689690
/// Gets the block script parser
690691
/// </summary>
691692
private BlockScripting.BlockScriptParser BlockScriptParser =>
692-
_blockScriptParser ??= new BlockScripting.BlockScriptParser();
693+
_blockScriptParser ??= new BlockScripting.BlockScriptParser(
694+
BuiltinFunctionRegistry.Discover(typeof(BuiltinFunctionRegistry).Assembly));
693695

694696
/// <summary>
695697
/// Gets the block script executor (initialized with plugin manager)

KitX Clients/KitX Dashboard

0 commit comments

Comments
 (0)