electron-infra-kit 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +302 -0
- package/README.zh-CN.md +308 -0
- package/dist/core/error/WindowError.d.ts +56 -0
- package/dist/core/error/WindowError.js +71 -0
- package/dist/core/error/WindowError.js.map +1 -0
- package/dist/core/error/WindowError.mjs +71 -0
- package/dist/core/error/WindowError.mjs.map +1 -0
- package/dist/core/ipc/IpcHandler.d.ts +48 -0
- package/dist/core/ipc/IpcHandler.js +59 -0
- package/dist/core/ipc/IpcHandler.js.map +1 -0
- package/dist/core/ipc/IpcHandler.mjs +59 -0
- package/dist/core/ipc/IpcHandler.mjs.map +1 -0
- package/dist/core/ipc/IpcRouter.d.ts +70 -0
- package/dist/core/ipc/IpcRouter.js +143 -0
- package/dist/core/ipc/IpcRouter.js.map +1 -0
- package/dist/core/ipc/IpcRouter.mjs +143 -0
- package/dist/core/ipc/IpcRouter.mjs.map +1 -0
- package/dist/core/ipc/index.d.ts +3 -0
- package/dist/core/ipc/index.js +1 -0
- package/dist/core/ipc/index.js.map +1 -0
- package/dist/core/ipc/index.mjs +1 -0
- package/dist/core/ipc/index.mjs.map +1 -0
- package/dist/core/ipc/ipc-router.type.d.ts +73 -0
- package/dist/core/ipc/transport/index.d.ts +65 -0
- package/dist/core/ipc/transport/index.js +229 -0
- package/dist/core/ipc/transport/index.js.map +1 -0
- package/dist/core/ipc/transport/index.mjs +229 -0
- package/dist/core/ipc/transport/index.mjs.map +1 -0
- package/dist/core/ipc/transport/ipc.type.d.ts +36 -0
- package/dist/core/lifecycle/LifecycleManager.d.ts +66 -0
- package/dist/core/lifecycle/LifecycleManager.js +140 -0
- package/dist/core/lifecycle/LifecycleManager.js.map +1 -0
- package/dist/core/lifecycle/LifecycleManager.mjs +140 -0
- package/dist/core/lifecycle/LifecycleManager.mjs.map +1 -0
- package/dist/core/message-bus/MessageBus.d.ts +282 -0
- package/dist/core/message-bus/MessageBus.js +677 -0
- package/dist/core/message-bus/MessageBus.js.map +1 -0
- package/dist/core/message-bus/MessageBus.mjs +677 -0
- package/dist/core/message-bus/MessageBus.mjs.map +1 -0
- package/dist/core/message-bus/MessageBusClient.d.ts +100 -0
- package/dist/core/message-bus/MessageBusClient.js +280 -0
- package/dist/core/message-bus/MessageBusClient.js.map +1 -0
- package/dist/core/message-bus/MessageBusClient.mjs +280 -0
- package/dist/core/message-bus/MessageBusClient.mjs.map +1 -0
- package/dist/core/message-bus/core/DataStoreManager.d.ts +51 -0
- package/dist/core/message-bus/core/DataStoreManager.js +94 -0
- package/dist/core/message-bus/core/DataStoreManager.js.map +1 -0
- package/dist/core/message-bus/core/DataStoreManager.mjs +94 -0
- package/dist/core/message-bus/core/DataStoreManager.mjs.map +1 -0
- package/dist/core/message-bus/core/ManagedPort.d.ts +26 -0
- package/dist/core/message-bus/core/ManagedPort.js +55 -0
- package/dist/core/message-bus/core/ManagedPort.js.map +1 -0
- package/dist/core/message-bus/core/ManagedPort.mjs +55 -0
- package/dist/core/message-bus/core/ManagedPort.mjs.map +1 -0
- package/dist/core/message-bus/core/PortManager.d.ts +47 -0
- package/dist/core/message-bus/core/PortManager.js +114 -0
- package/dist/core/message-bus/core/PortManager.js.map +1 -0
- package/dist/core/message-bus/core/PortManager.mjs +114 -0
- package/dist/core/message-bus/core/PortManager.mjs.map +1 -0
- package/dist/core/message-bus/core/SubscriptionManager.d.ts +36 -0
- package/dist/core/message-bus/core/SubscriptionManager.js +78 -0
- package/dist/core/message-bus/core/SubscriptionManager.js.map +1 -0
- package/dist/core/message-bus/core/SubscriptionManager.mjs +78 -0
- package/dist/core/message-bus/core/SubscriptionManager.mjs.map +1 -0
- package/dist/core/message-bus/core/TransactionManager.d.ts +54 -0
- package/dist/core/message-bus/core/TransactionManager.js +95 -0
- package/dist/core/message-bus/core/TransactionManager.js.map +1 -0
- package/dist/core/message-bus/core/TransactionManager.mjs +95 -0
- package/dist/core/message-bus/core/TransactionManager.mjs.map +1 -0
- package/dist/core/message-bus/core/index.d.ts +5 -0
- package/dist/core/message-bus/index.d.ts +4 -0
- package/dist/core/message-bus/index.js +1 -0
- package/dist/core/message-bus/index.js.map +1 -0
- package/dist/core/message-bus/index.mjs +1 -0
- package/dist/core/message-bus/index.mjs.map +1 -0
- package/dist/core/message-bus/message-bus.type.d.ts +143 -0
- package/dist/core/message-bus/message-bus.type.js +26 -0
- package/dist/core/message-bus/message-bus.type.js.map +1 -0
- package/dist/core/message-bus/message-bus.type.mjs +26 -0
- package/dist/core/message-bus/message-bus.type.mjs.map +1 -0
- package/dist/core/message-bus/preload.d.ts +16 -0
- package/dist/core/message-bus/preload.js +27 -0
- package/dist/core/message-bus/preload.js.map +1 -0
- package/dist/core/message-bus/preload.mjs +27 -0
- package/dist/core/message-bus/preload.mjs.map +1 -0
- package/dist/core/message-bus/transport/ITransport.d.ts +40 -0
- package/dist/core/message-bus/transport/IpcTransport.d.ts +18 -0
- package/dist/core/message-bus/transport/IpcTransport.js +60 -0
- package/dist/core/message-bus/transport/IpcTransport.js.map +1 -0
- package/dist/core/message-bus/transport/IpcTransport.mjs +60 -0
- package/dist/core/message-bus/transport/IpcTransport.mjs.map +1 -0
- package/dist/core/message-bus/transport/MessagePortTransport.d.ts +15 -0
- package/dist/core/message-bus/transport/MessagePortTransport.js +35 -0
- package/dist/core/message-bus/transport/MessagePortTransport.js.map +1 -0
- package/dist/core/message-bus/transport/MessagePortTransport.mjs +35 -0
- package/dist/core/message-bus/transport/MessagePortTransport.mjs.map +1 -0
- package/dist/core/message-bus/transport/index.d.ts +3 -0
- package/dist/core/window/IpcSetup.d.ts +50 -0
- package/dist/core/window/IpcSetup.js +96 -0
- package/dist/core/window/IpcSetup.js.map +1 -0
- package/dist/core/window/IpcSetup.mjs +96 -0
- package/dist/core/window/IpcSetup.mjs.map +1 -0
- package/dist/core/window/WindowCreator.d.ts +66 -0
- package/dist/core/window/WindowCreator.js +168 -0
- package/dist/core/window/WindowCreator.js.map +1 -0
- package/dist/core/window/WindowCreator.mjs +168 -0
- package/dist/core/window/WindowCreator.mjs.map +1 -0
- package/dist/core/window/WindowManager.d.ts +214 -0
- package/dist/core/window/WindowManager.js +583 -0
- package/dist/core/window/WindowManager.js.map +1 -0
- package/dist/core/window/WindowManager.mjs +583 -0
- package/dist/core/window/WindowManager.mjs.map +1 -0
- package/dist/core/window/WindowStore.d.ts +136 -0
- package/dist/core/window/WindowStore.js +436 -0
- package/dist/core/window/WindowStore.js.map +1 -0
- package/dist/core/window/WindowStore.mjs +436 -0
- package/dist/core/window/WindowStore.mjs.map +1 -0
- package/dist/core/window/constants.d.ts +17 -0
- package/dist/core/window/constants.js +15 -0
- package/dist/core/window/constants.js.map +1 -0
- package/dist/core/window/constants.mjs +15 -0
- package/dist/core/window/constants.mjs.map +1 -0
- package/dist/core/window/core/MetricsManager.d.ts +14 -0
- package/dist/core/window/core/MetricsManager.js +27 -0
- package/dist/core/window/core/MetricsManager.js.map +1 -0
- package/dist/core/window/core/MetricsManager.mjs +27 -0
- package/dist/core/window/core/MetricsManager.mjs.map +1 -0
- package/dist/core/window/core/PluginExecutor.d.ts +22 -0
- package/dist/core/window/core/PluginExecutor.js +110 -0
- package/dist/core/window/core/PluginExecutor.js.map +1 -0
- package/dist/core/window/core/PluginExecutor.mjs +110 -0
- package/dist/core/window/core/PluginExecutor.mjs.map +1 -0
- package/dist/core/window/core/WindowContextManager.d.ts +26 -0
- package/dist/core/window/core/WindowContextManager.js +59 -0
- package/dist/core/window/core/WindowContextManager.js.map +1 -0
- package/dist/core/window/core/WindowContextManager.mjs +59 -0
- package/dist/core/window/core/WindowContextManager.mjs.map +1 -0
- package/dist/core/window/core/WindowLifecycle.d.ts +15 -0
- package/dist/core/window/core/WindowLifecycle.js +150 -0
- package/dist/core/window/core/WindowLifecycle.js.map +1 -0
- package/dist/core/window/core/WindowLifecycle.mjs +150 -0
- package/dist/core/window/core/WindowLifecycle.mjs.map +1 -0
- package/dist/core/window/core/WindowOperator.d.ts +90 -0
- package/dist/core/window/core/WindowOperator.js +154 -0
- package/dist/core/window/core/WindowOperator.js.map +1 -0
- package/dist/core/window/core/WindowOperator.mjs +154 -0
- package/dist/core/window/core/WindowOperator.mjs.map +1 -0
- package/dist/core/window/core/WindowRegistry.d.ts +168 -0
- package/dist/core/window/core/WindowRegistry.js +331 -0
- package/dist/core/window/core/WindowRegistry.js.map +1 -0
- package/dist/core/window/core/WindowRegistry.mjs +331 -0
- package/dist/core/window/core/WindowRegistry.mjs.map +1 -0
- package/dist/core/window/core/WindowStateManager.d.ts +40 -0
- package/dist/core/window/core/WindowStateManager.js +110 -0
- package/dist/core/window/core/WindowStateManager.js.map +1 -0
- package/dist/core/window/core/WindowStateManager.mjs +110 -0
- package/dist/core/window/core/WindowStateManager.mjs.map +1 -0
- package/dist/core/window/index.d.ts +7 -0
- package/dist/core/window/index.js +1 -0
- package/dist/core/window/index.js.map +1 -0
- package/dist/core/window/index.mjs +1 -0
- package/dist/core/window/index.mjs.map +1 -0
- package/dist/core/window/window-manager.schema.d.ts +50 -0
- package/dist/core/window/window-manager.schema.js +87 -0
- package/dist/core/window/window-manager.schema.js.map +1 -0
- package/dist/core/window/window-manager.schema.mjs +87 -0
- package/dist/core/window/window-manager.schema.mjs.map +1 -0
- package/dist/core/window/window-manager.type.d.ts +365 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +33 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.umd.js +1 -0
- package/dist/infrastructure/config/ConfigManager.d.ts +133 -0
- package/dist/infrastructure/config/ConfigManager.js +218 -0
- package/dist/infrastructure/config/ConfigManager.js.map +1 -0
- package/dist/infrastructure/config/ConfigManager.mjs +218 -0
- package/dist/infrastructure/config/ConfigManager.mjs.map +1 -0
- package/dist/infrastructure/config/index.d.ts +1 -0
- package/dist/infrastructure/debug/EnhancedDebugHelper.d.ts +106 -0
- package/dist/infrastructure/debug/EnhancedDebugHelper.js +218 -0
- package/dist/infrastructure/debug/EnhancedDebugHelper.js.map +1 -0
- package/dist/infrastructure/debug/EnhancedDebugHelper.mjs +218 -0
- package/dist/infrastructure/debug/EnhancedDebugHelper.mjs.map +1 -0
- package/dist/infrastructure/debug/PerformanceMonitor.d.ts +45 -0
- package/dist/infrastructure/debug/PerformanceMonitor.js +67 -0
- package/dist/infrastructure/debug/PerformanceMonitor.js.map +1 -0
- package/dist/infrastructure/debug/PerformanceMonitor.mjs +67 -0
- package/dist/infrastructure/debug/PerformanceMonitor.mjs.map +1 -0
- package/dist/infrastructure/debug/index.d.ts +22 -0
- package/dist/infrastructure/debug/index.js +47 -0
- package/dist/infrastructure/debug/index.js.map +1 -0
- package/dist/infrastructure/debug/index.mjs +47 -0
- package/dist/infrastructure/debug/index.mjs.map +1 -0
- package/dist/infrastructure/errors/ErrorCodes.d.ts +74 -0
- package/dist/infrastructure/errors/ErrorCodes.js +78 -0
- package/dist/infrastructure/errors/ErrorCodes.js.map +1 -0
- package/dist/infrastructure/errors/ErrorCodes.mjs +78 -0
- package/dist/infrastructure/errors/ErrorCodes.mjs.map +1 -0
- package/dist/infrastructure/errors/StandardError.d.ts +61 -0
- package/dist/infrastructure/errors/StandardError.js +84 -0
- package/dist/infrastructure/errors/StandardError.js.map +1 -0
- package/dist/infrastructure/errors/StandardError.mjs +84 -0
- package/dist/infrastructure/errors/StandardError.mjs.map +1 -0
- package/dist/infrastructure/errors/index.d.ts +13 -0
- package/dist/infrastructure/errors/index.js +24 -0
- package/dist/infrastructure/errors/index.js.map +1 -0
- package/dist/infrastructure/errors/index.mjs +24 -0
- package/dist/infrastructure/errors/index.mjs.map +1 -0
- package/dist/infrastructure/logger/ElectronLogger.d.ts +39 -0
- package/dist/infrastructure/logger/ElectronLogger.js +65 -0
- package/dist/infrastructure/logger/ElectronLogger.js.map +1 -0
- package/dist/infrastructure/logger/ElectronLogger.mjs +65 -0
- package/dist/infrastructure/logger/ElectronLogger.mjs.map +1 -0
- package/dist/infrastructure/logger/index.d.ts +2 -0
- package/dist/infrastructure/logger/logger.type.d.ts +8 -0
- package/dist/internal/types/BrandedTypes.d.ts +64 -0
- package/dist/internal/types/BrandedTypes.js +54 -0
- package/dist/internal/types/BrandedTypes.js.map +1 -0
- package/dist/internal/types/BrandedTypes.mjs +54 -0
- package/dist/internal/types/BrandedTypes.mjs.map +1 -0
- package/dist/internal/types/PerformanceOptions.d.ts +87 -0
- package/dist/internal/types/branded.d.ts +42 -0
- package/dist/internal/utils/MessageDispatcher.d.ts +67 -0
- package/dist/internal/utils/MessageDispatcher.js +96 -0
- package/dist/internal/utils/MessageDispatcher.js.map +1 -0
- package/dist/internal/utils/MessageDispatcher.mjs +96 -0
- package/dist/internal/utils/MessageDispatcher.mjs.map +1 -0
- package/dist/internal/utils/RateLimiter.d.ts +41 -0
- package/dist/internal/utils/RateLimiter.js +83 -0
- package/dist/internal/utils/RateLimiter.js.map +1 -0
- package/dist/internal/utils/RateLimiter.mjs +83 -0
- package/dist/internal/utils/RateLimiter.mjs.map +1 -0
- package/dist/internal/utils/StateKeeper.d.ts +125 -0
- package/dist/internal/utils/StateKeeper.js +334 -0
- package/dist/internal/utils/StateKeeper.js.map +1 -0
- package/dist/internal/utils/StateKeeper.mjs +334 -0
- package/dist/internal/utils/StateKeeper.mjs.map +1 -0
- package/dist/internal/utils/branded-helpers.d.ts +33 -0
- package/dist/internal/utils/index.d.ts +5 -0
- package/dist/preload/index.d.ts +45 -0
- package/dist/preload/index.js +91 -0
- package/dist/preload/index.js.map +1 -0
- package/dist/preload/index.mjs +91 -0
- package/dist/preload/index.mjs.map +1 -0
- package/dist/preload/preload.type.d.ts +15 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/types.mjs +1 -0
- package/dist/types.mjs.map +1 -0
- package/package.json +143 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {ElectronLogger}from'../../infrastructure/logger/ElectronLogger.mjs';/**
|
|
2
|
+
* Message Dispatcher - Generic event/message dispatching utility
|
|
3
|
+
* 消息分发器 - 通用的事件/消息分发工具
|
|
4
|
+
*
|
|
5
|
+
* Unifies the message dispatching logic across different bridges (MessageBus, IpcRouter).
|
|
6
|
+
* 统一不同桥接器(MessageBus, IpcRouter)的消息分发逻辑。
|
|
7
|
+
*
|
|
8
|
+
* @template Context - The context type passed to handlers (传递给处理器的上下文类型)
|
|
9
|
+
*/
|
|
10
|
+
class MessageDispatcher {
|
|
11
|
+
// Store handler along with optional metadata (like validation schema)
|
|
12
|
+
handlers = new Map();
|
|
13
|
+
logger;
|
|
14
|
+
errorHandler;
|
|
15
|
+
constructor(name, logger, errorHandler) {
|
|
16
|
+
this.logger = logger || new ElectronLogger({ appName: name });
|
|
17
|
+
this.errorHandler = errorHandler;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Register a handler
|
|
21
|
+
* 注册处理器
|
|
22
|
+
* @param name - Handler name (处理器名称)
|
|
23
|
+
* @param handler - Handler function (处理函数)
|
|
24
|
+
* @param metadata - Optional metadata (e.g., validation schema)
|
|
25
|
+
*/
|
|
26
|
+
register(name, handler, metadata) {
|
|
27
|
+
if (this.handlers.has(name)) {
|
|
28
|
+
this.logger.warn(`Handler "${name}" is being overwritten / 处理器 "${name}" 被覆盖`);
|
|
29
|
+
}
|
|
30
|
+
this.handlers.set(name, { callback: handler, metadata });
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Unregister a handler
|
|
34
|
+
* 注销处理器
|
|
35
|
+
* @param name - Handler name (处理器名称)
|
|
36
|
+
* @returns True if removed (如果移除成功返回 true)
|
|
37
|
+
*/
|
|
38
|
+
unregister(name) {
|
|
39
|
+
return this.handlers.delete(name);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get handler metadata
|
|
43
|
+
* 获取处理器元数据
|
|
44
|
+
*/
|
|
45
|
+
getMetadata(name) {
|
|
46
|
+
return this.handlers.get(name)?.metadata;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Dispatch a message to a handler
|
|
50
|
+
* 分发消息给处理器
|
|
51
|
+
* @param name - Handler name (处理器名称)
|
|
52
|
+
* @param context - Context to pass to handler (传递给处理器的上下文)
|
|
53
|
+
* @param data - Data to pass to handler (传递给处理器的数据)
|
|
54
|
+
* @returns Handler result (处理器结果)
|
|
55
|
+
* @throws Error if handler execution fails (如果处理器执行失败抛出错误)
|
|
56
|
+
*/
|
|
57
|
+
dispatch(name, context, data) {
|
|
58
|
+
const entry = this.handlers.get(name);
|
|
59
|
+
if (!entry) {
|
|
60
|
+
this.logger.warn(`No handler found for "${name}" / 未找到处理器 "${name}"`);
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return entry.callback(context, data);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
this.logger.error(`Error in handler "${name}": ${error} / 处理器 "${name}" 执行错误: ${error}`);
|
|
68
|
+
if (this.errorHandler) {
|
|
69
|
+
return this.errorHandler(error, name);
|
|
70
|
+
}
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Check if handler exists
|
|
76
|
+
* 检查处理器是否存在
|
|
77
|
+
* @param name - Handler name (处理器名称)
|
|
78
|
+
*/
|
|
79
|
+
has(name) {
|
|
80
|
+
return this.handlers.has(name);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get all registered handler names
|
|
84
|
+
* 获取所有注册的处理器名称
|
|
85
|
+
*/
|
|
86
|
+
getHandlerNames() {
|
|
87
|
+
return Array.from(this.handlers.keys());
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Clear all handlers
|
|
91
|
+
* 清空所有处理器
|
|
92
|
+
*/
|
|
93
|
+
clear() {
|
|
94
|
+
this.handlers.clear();
|
|
95
|
+
}
|
|
96
|
+
}export{MessageDispatcher};//# sourceMappingURL=MessageDispatcher.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageDispatcher.mjs","sources":["../../../src/internal/utils/MessageDispatcher.ts"],"sourcesContent":["import { Logger, ILogger } from '@/infrastructure/logger';\n\n/**\n * Handler Callback Type\n * 处理器回调类型\n */\nexport type HandlerCallback<Context, T = any, R = any> = (\n context: Context,\n data: T\n) => R | Promise<R>;\n\n/**\n * Message Dispatcher - Generic event/message dispatching utility\n * 消息分发器 - 通用的事件/消息分发工具\n *\n * Unifies the message dispatching logic across different bridges (MessageBus, IpcRouter).\n * 统一不同桥接器(MessageBus, IpcRouter)的消息分发逻辑。\n *\n * @template Context - The context type passed to handlers (传递给处理器的上下文类型)\n */\nexport class MessageDispatcher<Context = any> {\n // Store handler along with optional metadata (like validation schema)\n private handlers = new Map<\n string,\n {\n callback: HandlerCallback<Context, any, any>;\n metadata?: any;\n }\n >();\n private logger: ILogger;\n private errorHandler?: (error: any, name: string) => any;\n\n constructor(name: string, logger?: ILogger, errorHandler?: (error: any, name: string) => any) {\n this.logger = logger || new Logger({ appName: name });\n this.errorHandler = errorHandler;\n }\n\n /**\n * Register a handler\n * 注册处理器\n * @param name - Handler name (处理器名称)\n * @param handler - Handler function (处理函数)\n * @param metadata - Optional metadata (e.g., validation schema)\n */\n register<T = any, R = any>(\n name: string,\n handler: HandlerCallback<Context, T, R>,\n metadata?: any\n ): void {\n if (this.handlers.has(name)) {\n this.logger.warn(`Handler \"${name}\" is being overwritten / 处理器 \"${name}\" 被覆盖`);\n }\n this.handlers.set(name, { callback: handler, metadata });\n }\n\n /**\n * Unregister a handler\n * 注销处理器\n * @param name - Handler name (处理器名称)\n * @returns True if removed (如果移除成功返回 true)\n */\n unregister(name: string): boolean {\n return this.handlers.delete(name);\n }\n\n /**\n * Get handler metadata\n * 获取处理器元数据\n */\n getMetadata(name: string): any | undefined {\n return this.handlers.get(name)?.metadata;\n }\n\n /**\n * Dispatch a message to a handler\n * 分发消息给处理器\n * @param name - Handler name (处理器名称)\n * @param context - Context to pass to handler (传递给处理器的上下文)\n * @param data - Data to pass to handler (传递给处理器的数据)\n * @returns Handler result (处理器结果)\n * @throws Error if handler execution fails (如果处理器执行失败抛出错误)\n */\n dispatch<T = any, R = any>(name: string, context: Context, data: T): R | undefined {\n const entry = this.handlers.get(name);\n if (!entry) {\n this.logger.warn(`No handler found for \"${name}\" / 未找到处理器 \"${name}\"`);\n return undefined;\n }\n\n try {\n return entry.callback(context, data);\n } catch (error) {\n this.logger.error(\n `Error in handler \"${name}\": ${error} / 处理器 \"${name}\" 执行错误: ${error}`\n );\n if (this.errorHandler) {\n return this.errorHandler(error, name);\n }\n throw error;\n }\n }\n\n /**\n * Check if handler exists\n * 检查处理器是否存在\n * @param name - Handler name (处理器名称)\n */\n has(name: string): boolean {\n return this.handlers.has(name);\n }\n\n /**\n * Get all registered handler names\n * 获取所有注册的处理器名称\n */\n getHandlerNames(): string[] {\n return Array.from(this.handlers.keys());\n }\n\n /**\n * Clear all handlers\n * 清空所有处理器\n */\n clear(): void {\n this.handlers.clear();\n }\n}\n"],"names":["Logger"],"mappings":"4EAWA;;;;;;;;AAQG;MACU,iBAAiB,CAAA;;AAEpB,IAAA,QAAQ,GAAG,IAAI,GAAG,EAMvB;AACK,IAAA,MAAM;AACN,IAAA,YAAY;AAEpB,IAAA,WAAA,CAAY,IAAY,EAAE,MAAgB,EAAE,YAAgD,EAAA;AAC1F,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,IAAIA,cAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACrD,QAAA,IAAI,CAAC,YAAY,GAAG,YAAY;IAClC;AAEA;;;;;;AAMG;AACH,IAAA,QAAQ,CACN,IAAY,EACZ,OAAuC,EACvC,QAAc,EAAA;QAEd,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA,SAAA,EAAY,IAAI,CAAA,8BAAA,EAAiC,IAAI,CAAA,KAAA,CAAO,CAAC;QAChF;AACA,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC1D;AAEA;;;;;AAKG;AACH,IAAA,UAAU,CAAC,IAAY,EAAA;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC;IACnC;AAEA;;;AAGG;AACH,IAAA,WAAW,CAAC,IAAY,EAAA;QACtB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ;IAC1C;AAEA;;;;;;;;AAQG;AACH,IAAA,QAAQ,CAAmB,IAAY,EAAE,OAAgB,EAAE,IAAO,EAAA;QAChE,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;QACrC,IAAI,CAAC,KAAK,EAAE;YACV,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA,sBAAA,EAAyB,IAAI,CAAA,YAAA,EAAe,IAAI,CAAA,CAAA,CAAG,CAAC;AACrE,YAAA,OAAO,SAAS;QAClB;AAEA,QAAA,IAAI;YACF,OAAO,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;QACtC;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,CAAA,kBAAA,EAAqB,IAAI,CAAA,GAAA,EAAM,KAAK,WAAW,IAAI,CAAA,QAAA,EAAW,KAAK,CAAA,CAAE,CACtE;AACD,YAAA,IAAI,IAAI,CAAC,YAAY,EAAE;gBACrB,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC;YACvC;AACA,YAAA,MAAM,KAAK;QACb;IACF;AAEA;;;;AAIG;AACH,IAAA,GAAG,CAAC,IAAY,EAAA;QACd,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;IAChC;AAEA;;;AAGG;IACH,eAAe,GAAA;QACb,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzC;AAEA;;;AAGG;IACH,KAAK,GAAA;AACH,QAAA,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE;IACvB;AACD"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ILogger } from '@/infrastructure/logger';
|
|
2
|
+
export interface RateLimitConfig {
|
|
3
|
+
limit: number;
|
|
4
|
+
interval: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class RateLimiter {
|
|
7
|
+
private limits;
|
|
8
|
+
private state;
|
|
9
|
+
private defaultLimit;
|
|
10
|
+
private logger?;
|
|
11
|
+
private cleanupTimer;
|
|
12
|
+
private cleanupInterval;
|
|
13
|
+
constructor(options?: {
|
|
14
|
+
logger?: ILogger;
|
|
15
|
+
defaultLimit?: RateLimitConfig;
|
|
16
|
+
cleanupInterval?: number;
|
|
17
|
+
});
|
|
18
|
+
private startCleanup;
|
|
19
|
+
stopCleanup(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Set rate limit for a specific key pattern
|
|
22
|
+
* @param keyPattern - The key pattern to limit (e.g., "handlerName")
|
|
23
|
+
* @param config - Rate limit configuration
|
|
24
|
+
*/
|
|
25
|
+
setLimit(keyPattern: string, config: RateLimitConfig): void;
|
|
26
|
+
/**
|
|
27
|
+
* Check if the action is allowed for the given key
|
|
28
|
+
* @param key - Unique key for the action (e.g., "windowId:handlerName")
|
|
29
|
+
* @param ruleKey - Key to lookup configuration (e.g., "handlerName")
|
|
30
|
+
* @returns true if allowed, false if rate limit exceeded
|
|
31
|
+
*/
|
|
32
|
+
check(key: string, ruleKey: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Clear all state
|
|
35
|
+
*/
|
|
36
|
+
clear(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Clean up expired entries to prevent memory leaks
|
|
39
|
+
*/
|
|
40
|
+
cleanup(): void;
|
|
41
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';class RateLimiter {
|
|
2
|
+
limits = new Map();
|
|
3
|
+
state = new Map();
|
|
4
|
+
defaultLimit = null;
|
|
5
|
+
logger;
|
|
6
|
+
cleanupTimer = null;
|
|
7
|
+
cleanupInterval;
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.logger = options.logger;
|
|
10
|
+
this.defaultLimit = options.defaultLimit || null;
|
|
11
|
+
this.cleanupInterval = options.cleanupInterval || 60000;
|
|
12
|
+
this.startCleanup();
|
|
13
|
+
}
|
|
14
|
+
startCleanup() {
|
|
15
|
+
if (this.cleanupTimer)
|
|
16
|
+
return;
|
|
17
|
+
this.cleanupTimer = setInterval(() => {
|
|
18
|
+
this.cleanup();
|
|
19
|
+
}, this.cleanupInterval);
|
|
20
|
+
// Unref to prevent preventing process exit
|
|
21
|
+
this.cleanupTimer.unref();
|
|
22
|
+
}
|
|
23
|
+
stopCleanup() {
|
|
24
|
+
if (this.cleanupTimer) {
|
|
25
|
+
clearInterval(this.cleanupTimer);
|
|
26
|
+
this.cleanupTimer = null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Set rate limit for a specific key pattern
|
|
31
|
+
* @param keyPattern - The key pattern to limit (e.g., "handlerName")
|
|
32
|
+
* @param config - Rate limit configuration
|
|
33
|
+
*/
|
|
34
|
+
setLimit(keyPattern, config) {
|
|
35
|
+
this.limits.set(keyPattern, config);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if the action is allowed for the given key
|
|
39
|
+
* @param key - Unique key for the action (e.g., "windowId:handlerName")
|
|
40
|
+
* @param ruleKey - Key to lookup configuration (e.g., "handlerName")
|
|
41
|
+
* @returns true if allowed, false if rate limit exceeded
|
|
42
|
+
*/
|
|
43
|
+
check(key, ruleKey) {
|
|
44
|
+
const config = this.limits.get(ruleKey) || this.defaultLimit;
|
|
45
|
+
// If no limit configured, allow
|
|
46
|
+
if (!config)
|
|
47
|
+
return true;
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
let record = this.state.get(key);
|
|
50
|
+
if (!record || now > record.resetTime) {
|
|
51
|
+
record = {
|
|
52
|
+
count: 0,
|
|
53
|
+
resetTime: now + config.interval,
|
|
54
|
+
};
|
|
55
|
+
this.state.set(key, record);
|
|
56
|
+
}
|
|
57
|
+
if (record.count >= config.limit) {
|
|
58
|
+
if (this.logger) {
|
|
59
|
+
this.logger.warn(`Rate limit exceeded for ${key} (Rule: ${ruleKey}, Limit: ${config.limit}/${config.interval}ms)`);
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
record.count++;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Clear all state
|
|
68
|
+
*/
|
|
69
|
+
clear() {
|
|
70
|
+
this.state.clear();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Clean up expired entries to prevent memory leaks
|
|
74
|
+
*/
|
|
75
|
+
cleanup() {
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
for (const [key, record] of this.state.entries()) {
|
|
78
|
+
if (now > record.resetTime) {
|
|
79
|
+
this.state.delete(key);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}exports.RateLimiter=RateLimiter;//# sourceMappingURL=RateLimiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiter.js","sources":["../../../src/internal/utils/RateLimiter.ts"],"sourcesContent":["import { ILogger } from '@/infrastructure/logger';\n\nexport interface RateLimitConfig {\n limit: number;\n interval: number; // in milliseconds\n}\n\ninterface RateLimitState {\n count: number;\n resetTime: number;\n}\n\nexport class RateLimiter {\n private limits = new Map<string, RateLimitConfig>();\n private state = new Map<string, RateLimitState>();\n private defaultLimit: RateLimitConfig | null = null;\n private logger?: ILogger;\n\n private cleanupTimer: NodeJS.Timeout | null = null;\n private cleanupInterval: number;\n\n constructor(\n options: {\n logger?: ILogger;\n defaultLimit?: RateLimitConfig;\n cleanupInterval?: number; // default: 60000ms (1 minute)\n } = {}\n ) {\n this.logger = options.logger;\n this.defaultLimit = options.defaultLimit || null;\n this.cleanupInterval = options.cleanupInterval || 60000;\n\n this.startCleanup();\n }\n\n private startCleanup() {\n if (this.cleanupTimer) return;\n this.cleanupTimer = setInterval(() => {\n this.cleanup();\n }, this.cleanupInterval);\n // Unref to prevent preventing process exit\n this.cleanupTimer.unref();\n }\n\n stopCleanup() {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = null;\n }\n }\n\n /**\n * Set rate limit for a specific key pattern\n * @param keyPattern - The key pattern to limit (e.g., \"handlerName\")\n * @param config - Rate limit configuration\n */\n setLimit(keyPattern: string, config: RateLimitConfig): void {\n this.limits.set(keyPattern, config);\n }\n\n /**\n * Check if the action is allowed for the given key\n * @param key - Unique key for the action (e.g., \"windowId:handlerName\")\n * @param ruleKey - Key to lookup configuration (e.g., \"handlerName\")\n * @returns true if allowed, false if rate limit exceeded\n */\n check(key: string, ruleKey: string): boolean {\n const config = this.limits.get(ruleKey) || this.defaultLimit;\n\n // If no limit configured, allow\n if (!config) return true;\n\n const now = Date.now();\n let record = this.state.get(key);\n\n if (!record || now > record.resetTime) {\n record = {\n count: 0,\n resetTime: now + config.interval,\n };\n this.state.set(key, record);\n }\n\n if (record.count >= config.limit) {\n if (this.logger) {\n this.logger.warn(\n `Rate limit exceeded for ${key} (Rule: ${ruleKey}, Limit: ${config.limit}/${config.interval}ms)`\n );\n }\n return false;\n }\n\n record.count++;\n return true;\n }\n\n /**\n * Clear all state\n */\n clear(): void {\n this.state.clear();\n }\n\n /**\n * Clean up expired entries to prevent memory leaks\n */\n cleanup(): void {\n const now = Date.now();\n for (const [key, record] of this.state.entries()) {\n if (now > record.resetTime) {\n this.state.delete(key);\n }\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
class RateLimiter {
|
|
2
|
+
limits = new Map();
|
|
3
|
+
state = new Map();
|
|
4
|
+
defaultLimit = null;
|
|
5
|
+
logger;
|
|
6
|
+
cleanupTimer = null;
|
|
7
|
+
cleanupInterval;
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.logger = options.logger;
|
|
10
|
+
this.defaultLimit = options.defaultLimit || null;
|
|
11
|
+
this.cleanupInterval = options.cleanupInterval || 60000;
|
|
12
|
+
this.startCleanup();
|
|
13
|
+
}
|
|
14
|
+
startCleanup() {
|
|
15
|
+
if (this.cleanupTimer)
|
|
16
|
+
return;
|
|
17
|
+
this.cleanupTimer = setInterval(() => {
|
|
18
|
+
this.cleanup();
|
|
19
|
+
}, this.cleanupInterval);
|
|
20
|
+
// Unref to prevent preventing process exit
|
|
21
|
+
this.cleanupTimer.unref();
|
|
22
|
+
}
|
|
23
|
+
stopCleanup() {
|
|
24
|
+
if (this.cleanupTimer) {
|
|
25
|
+
clearInterval(this.cleanupTimer);
|
|
26
|
+
this.cleanupTimer = null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Set rate limit for a specific key pattern
|
|
31
|
+
* @param keyPattern - The key pattern to limit (e.g., "handlerName")
|
|
32
|
+
* @param config - Rate limit configuration
|
|
33
|
+
*/
|
|
34
|
+
setLimit(keyPattern, config) {
|
|
35
|
+
this.limits.set(keyPattern, config);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Check if the action is allowed for the given key
|
|
39
|
+
* @param key - Unique key for the action (e.g., "windowId:handlerName")
|
|
40
|
+
* @param ruleKey - Key to lookup configuration (e.g., "handlerName")
|
|
41
|
+
* @returns true if allowed, false if rate limit exceeded
|
|
42
|
+
*/
|
|
43
|
+
check(key, ruleKey) {
|
|
44
|
+
const config = this.limits.get(ruleKey) || this.defaultLimit;
|
|
45
|
+
// If no limit configured, allow
|
|
46
|
+
if (!config)
|
|
47
|
+
return true;
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
let record = this.state.get(key);
|
|
50
|
+
if (!record || now > record.resetTime) {
|
|
51
|
+
record = {
|
|
52
|
+
count: 0,
|
|
53
|
+
resetTime: now + config.interval,
|
|
54
|
+
};
|
|
55
|
+
this.state.set(key, record);
|
|
56
|
+
}
|
|
57
|
+
if (record.count >= config.limit) {
|
|
58
|
+
if (this.logger) {
|
|
59
|
+
this.logger.warn(`Rate limit exceeded for ${key} (Rule: ${ruleKey}, Limit: ${config.limit}/${config.interval}ms)`);
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
record.count++;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Clear all state
|
|
68
|
+
*/
|
|
69
|
+
clear() {
|
|
70
|
+
this.state.clear();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Clean up expired entries to prevent memory leaks
|
|
74
|
+
*/
|
|
75
|
+
cleanup() {
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
for (const [key, record] of this.state.entries()) {
|
|
78
|
+
if (now > record.resetTime) {
|
|
79
|
+
this.state.delete(key);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}export{RateLimiter};//# sourceMappingURL=RateLimiter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RateLimiter.mjs","sources":["../../../src/internal/utils/RateLimiter.ts"],"sourcesContent":["import { ILogger } from '@/infrastructure/logger';\n\nexport interface RateLimitConfig {\n limit: number;\n interval: number; // in milliseconds\n}\n\ninterface RateLimitState {\n count: number;\n resetTime: number;\n}\n\nexport class RateLimiter {\n private limits = new Map<string, RateLimitConfig>();\n private state = new Map<string, RateLimitState>();\n private defaultLimit: RateLimitConfig | null = null;\n private logger?: ILogger;\n\n private cleanupTimer: NodeJS.Timeout | null = null;\n private cleanupInterval: number;\n\n constructor(\n options: {\n logger?: ILogger;\n defaultLimit?: RateLimitConfig;\n cleanupInterval?: number; // default: 60000ms (1 minute)\n } = {}\n ) {\n this.logger = options.logger;\n this.defaultLimit = options.defaultLimit || null;\n this.cleanupInterval = options.cleanupInterval || 60000;\n\n this.startCleanup();\n }\n\n private startCleanup() {\n if (this.cleanupTimer) return;\n this.cleanupTimer = setInterval(() => {\n this.cleanup();\n }, this.cleanupInterval);\n // Unref to prevent preventing process exit\n this.cleanupTimer.unref();\n }\n\n stopCleanup() {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = null;\n }\n }\n\n /**\n * Set rate limit for a specific key pattern\n * @param keyPattern - The key pattern to limit (e.g., \"handlerName\")\n * @param config - Rate limit configuration\n */\n setLimit(keyPattern: string, config: RateLimitConfig): void {\n this.limits.set(keyPattern, config);\n }\n\n /**\n * Check if the action is allowed for the given key\n * @param key - Unique key for the action (e.g., \"windowId:handlerName\")\n * @param ruleKey - Key to lookup configuration (e.g., \"handlerName\")\n * @returns true if allowed, false if rate limit exceeded\n */\n check(key: string, ruleKey: string): boolean {\n const config = this.limits.get(ruleKey) || this.defaultLimit;\n\n // If no limit configured, allow\n if (!config) return true;\n\n const now = Date.now();\n let record = this.state.get(key);\n\n if (!record || now > record.resetTime) {\n record = {\n count: 0,\n resetTime: now + config.interval,\n };\n this.state.set(key, record);\n }\n\n if (record.count >= config.limit) {\n if (this.logger) {\n this.logger.warn(\n `Rate limit exceeded for ${key} (Rule: ${ruleKey}, Limit: ${config.limit}/${config.interval}ms)`\n );\n }\n return false;\n }\n\n record.count++;\n return true;\n }\n\n /**\n * Clear all state\n */\n clear(): void {\n this.state.clear();\n }\n\n /**\n * Clean up expired entries to prevent memory leaks\n */\n cleanup(): void {\n const now = Date.now();\n for (const [key, record] of this.state.entries()) {\n if (now > record.resetTime) {\n this.state.delete(key);\n }\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StateKeeper.ts
|
|
3
|
+
* 窗口状态管理器,负责持久化和恢复 Electron 窗口的位置、大小等状态
|
|
4
|
+
*
|
|
5
|
+
* 主要功能:
|
|
6
|
+
* - 保存窗口状态到文件系统
|
|
7
|
+
* - 从文件系统加载窗口状态
|
|
8
|
+
* - 验证窗口状态的有效性(确保窗口在可用显示器范围内)
|
|
9
|
+
* - 支持延迟保存机制,避免频繁 IO 操作
|
|
10
|
+
*/
|
|
11
|
+
import { ILogger } from '@/infrastructure/logger';
|
|
12
|
+
/**
|
|
13
|
+
* 窗口状态接口,定义了需要持久化的窗口属性
|
|
14
|
+
*/
|
|
15
|
+
export interface WindowState {
|
|
16
|
+
x?: number;
|
|
17
|
+
y?: number;
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
isMaximized: boolean;
|
|
21
|
+
isFullScreen: boolean;
|
|
22
|
+
displayBounds?: Electron.Rectangle;
|
|
23
|
+
groups?: string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* StateKeeper Configuration Options
|
|
27
|
+
* StateKeeper 配置选项
|
|
28
|
+
*/
|
|
29
|
+
export interface StateKeeperOptions {
|
|
30
|
+
/**
|
|
31
|
+
* Delay before saving state to disk (in milliseconds)
|
|
32
|
+
* 保存状态到磁盘前的延迟时间(毫秒)
|
|
33
|
+
* @default 500
|
|
34
|
+
*/
|
|
35
|
+
saveDelay?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Save strategy: 'debounce' or 'throttle'
|
|
38
|
+
* 保存策略:'debounce'(防抖)或 'throttle'(节流)
|
|
39
|
+
* @default 'debounce'
|
|
40
|
+
*/
|
|
41
|
+
saveStrategy?: 'debounce' | 'throttle';
|
|
42
|
+
/**
|
|
43
|
+
* Custom logger instance
|
|
44
|
+
* 自定义日志实例
|
|
45
|
+
*/
|
|
46
|
+
logger?: ILogger;
|
|
47
|
+
/**
|
|
48
|
+
* Custom state file path
|
|
49
|
+
* 自定义状态文件路径
|
|
50
|
+
*/
|
|
51
|
+
stateFilePath?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 窗口状态管理器类
|
|
55
|
+
* 实现了窗口状态的持久化存储和加载功能
|
|
56
|
+
*/
|
|
57
|
+
export default class StateKeeper {
|
|
58
|
+
private stateFile;
|
|
59
|
+
private state;
|
|
60
|
+
private logger;
|
|
61
|
+
private saveTimer;
|
|
62
|
+
private throttleLastSave;
|
|
63
|
+
private readonly saveDelay;
|
|
64
|
+
private readonly saveStrategy;
|
|
65
|
+
private static activeFiles;
|
|
66
|
+
private hasLock;
|
|
67
|
+
private isWriting;
|
|
68
|
+
private pendingWrite;
|
|
69
|
+
private lastSavedHash;
|
|
70
|
+
/**
|
|
71
|
+
* 构造函数
|
|
72
|
+
* @param options 配置选项
|
|
73
|
+
*/
|
|
74
|
+
constructor(options?: StateKeeperOptions);
|
|
75
|
+
/**
|
|
76
|
+
* 从文件加载窗口状态
|
|
77
|
+
* 私有方法,仅在构造函数中调用
|
|
78
|
+
*/
|
|
79
|
+
private loadState;
|
|
80
|
+
/**
|
|
81
|
+
* 保存指定窗口的状态
|
|
82
|
+
* @param windowName 窗口名称,用于标识不同窗口的状态
|
|
83
|
+
* @param windowState 窗口状态对象
|
|
84
|
+
*/
|
|
85
|
+
saveState(windowName: string, windowState: WindowState): void;
|
|
86
|
+
/**
|
|
87
|
+
* 立即同步保存状态(不使用延迟)
|
|
88
|
+
*/
|
|
89
|
+
flushSync(): void;
|
|
90
|
+
/**
|
|
91
|
+
* 将内存中的状态持久化到文件
|
|
92
|
+
* 私有方法,使用延迟保存机制避免频繁 IO 操作
|
|
93
|
+
*/
|
|
94
|
+
private persist;
|
|
95
|
+
/**
|
|
96
|
+
* 执行实际的保存操作
|
|
97
|
+
* 私有方法
|
|
98
|
+
*/
|
|
99
|
+
private performSave;
|
|
100
|
+
/**
|
|
101
|
+
* 获取指定窗口的状态
|
|
102
|
+
* @param windowName 窗口名称
|
|
103
|
+
* @param defaultWidth 默认宽度,当没有保存状态或状态无效时使用
|
|
104
|
+
* @param defaultHeight 默认高度,当没有保存状态或状态无效时使用
|
|
105
|
+
* @returns 窗口状态对象
|
|
106
|
+
*/
|
|
107
|
+
getWindowState(windowName: string, defaultWidth?: number, defaultHeight?: number): WindowState;
|
|
108
|
+
/**
|
|
109
|
+
* 验证窗口状态是否有效
|
|
110
|
+
* 主要检查窗口是否在当前可用显示器范围内
|
|
111
|
+
* @param state 要验证的窗口状态
|
|
112
|
+
* @returns 状态是否有效
|
|
113
|
+
*/
|
|
114
|
+
private isValidState;
|
|
115
|
+
/**
|
|
116
|
+
* 移除指定窗口的状态
|
|
117
|
+
* @param windowName 窗口名称
|
|
118
|
+
*/
|
|
119
|
+
removeState(windowName: string): void;
|
|
120
|
+
/**
|
|
121
|
+
* Dispose StateKeeper instance
|
|
122
|
+
* 释放 StateKeeper 实例
|
|
123
|
+
*/
|
|
124
|
+
dispose(): void;
|
|
125
|
+
}
|