IncludeCPP 3.3.20__py3-none-any.whl → 3.4.2__py3-none-any.whl

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.
@@ -0,0 +1,621 @@
1
+ """
2
+ CSSL Event System
3
+ Handles @event.* registrations and dispatching for CSSL scripts
4
+ """
5
+
6
+ from enum import Enum, auto
7
+ from dataclasses import dataclass, field
8
+ from typing import Callable, Dict, List, Any, Optional, Set
9
+ import threading
10
+ import time
11
+
12
+
13
+ class EventCategory(Enum):
14
+ """Event categories for CSSL"""
15
+ BOOT = "Boot"
16
+ SYSTEM = "System"
17
+ VSRAM = "VSRam"
18
+ SERVICE = "Service"
19
+ KERNEL = "Kernel"
20
+ NETWORK = "Network"
21
+ USER = "User"
22
+ WHEEL = "Wheel"
23
+ CUSTOM = "Custom"
24
+
25
+
26
+ class EventType(Enum):
27
+ """All supported CSSL events"""
28
+ # Boot Events
29
+ BOOTING = ("Boot", "Booting")
30
+ BOOTED = ("Boot", "Booted")
31
+ EARLY_BOOT = ("Boot", "EarlyBoot")
32
+ LATE_BOOT = ("Boot", "LateBoot")
33
+
34
+ # System Events
35
+ SHUTDOWN = ("System", "Shutdown")
36
+ RESTART = ("System", "Restart")
37
+ SUSPEND = ("System", "Suspend")
38
+ RESUME = ("System", "Resume")
39
+ ERROR = ("System", "Error")
40
+ CRITICAL = ("System", "Critical")
41
+
42
+ # VSRAM Events
43
+ VSRAM_SWITCHED = ("VSRam", "Switched")
44
+ VSRAM_FULL = ("VSRam", "Full")
45
+ VSRAM_CRITICAL = ("VSRam", "Critical")
46
+ VSRAM_SET = ("VSRam", "Set")
47
+ VSRAM_GET = ("VSRam", "Get")
48
+ VSRAM_DELETE = ("VSRam", "Delete")
49
+ VSRAM_UPDATE = ("VSRam", "Update")
50
+
51
+ # Service Events
52
+ SERVICE_START = ("Service", "Start")
53
+ SERVICE_STOP = ("Service", "Stop")
54
+ SERVICE_ERROR = ("Service", "Error")
55
+ SERVICE_COMPLETE = ("Service", "Complete")
56
+ SERVICE_TIMEOUT = ("Service", "Timeout")
57
+
58
+ # Kernel Events
59
+ KERNEL_INIT = ("Kernel", "Init")
60
+ KERNEL_READY = ("Kernel", "Ready")
61
+ KERNEL_ERROR = ("Kernel", "Error")
62
+ KERNEL_COMMAND = ("Kernel", "Command")
63
+
64
+ # Network Events
65
+ NETWORK_CONNECT = ("Network", "Connect")
66
+ NETWORK_DISCONNECT = ("Network", "Disconnect")
67
+ NETWORK_ERROR = ("Network", "Error")
68
+ NETWORK_DATA = ("Network", "Data")
69
+ NETWORK_UPDATE = ("Network", "Update")
70
+
71
+ # User Events
72
+ USER_LOGIN = ("User", "Login")
73
+ USER_LOGOUT = ("User", "Logout")
74
+ USER_CREATE = ("User", "Create")
75
+ USER_DELETE = ("User", "Delete")
76
+ USER_CHANGE = ("User", "Change")
77
+
78
+ # Wheel Events
79
+ WHEEL_CHANGE = ("Wheel", "Change")
80
+ WHEEL_READ = ("Wheel", "Read")
81
+ WHEEL_WRITE = ("Wheel", "Write")
82
+ WHEEL_INIT = ("Wheel", "Init")
83
+
84
+ def __init__(self, category: str, name: str):
85
+ self._category = category
86
+ self._event_name = name
87
+
88
+ @property
89
+ def category(self) -> str:
90
+ return self._category
91
+
92
+ @property
93
+ def event_name(self) -> str:
94
+ return self._event_name
95
+
96
+ @property
97
+ def full_name(self) -> str:
98
+ return f"@event.{self._category}.{self._event_name}"
99
+
100
+ @classmethod
101
+ def from_string(cls, event_string: str) -> Optional['EventType']:
102
+ """Parse event string like '@event.Boot.Booting' to EventType"""
103
+ if not event_string.startswith('@event.'):
104
+ return None
105
+
106
+ parts = event_string[7:].split('.')
107
+ if len(parts) == 1:
108
+ # Short form: @event.Booting
109
+ for event in cls:
110
+ if event.event_name == parts[0]:
111
+ return event
112
+ elif len(parts) == 2:
113
+ # Full form: @event.Boot.Booting
114
+ category, name = parts
115
+ for event in cls:
116
+ if event.category == category and event.event_name == name:
117
+ return event
118
+
119
+ return None
120
+
121
+
122
+ @dataclass
123
+ class EventData:
124
+ """Data passed to event handlers"""
125
+ event_type: EventType
126
+ timestamp: float = field(default_factory=time.time)
127
+ source: str = ""
128
+ data: Dict[str, Any] = field(default_factory=dict)
129
+ cancelled: bool = False
130
+
131
+ def cancel(self):
132
+ """Cancel event propagation"""
133
+ self.cancelled = True
134
+
135
+ def get(self, key: str, default: Any = None) -> Any:
136
+ """Get data value"""
137
+ return self.data.get(key, default)
138
+
139
+ def set(self, key: str, value: Any):
140
+ """Set data value"""
141
+ self.data[key] = value
142
+
143
+
144
+ @dataclass
145
+ class EventHandler:
146
+ """Registered event handler"""
147
+ callback: Callable[[EventData], Any]
148
+ priority: int = 0
149
+ once: bool = False
150
+ filter_func: Optional[Callable[[EventData], bool]] = None
151
+ service_name: str = ""
152
+ handler_id: str = ""
153
+
154
+
155
+ class CSSLEventManager:
156
+ """
157
+ Central event manager for CSSL
158
+ Handles registration, deregistration, and dispatching of events
159
+ """
160
+
161
+ def __init__(self):
162
+ self._handlers: Dict[EventType, List[EventHandler]] = {}
163
+ self._custom_handlers: Dict[str, List[EventHandler]] = {}
164
+ self._lock = threading.RLock()
165
+ self._handler_counter = 0
166
+ self._event_history: List[EventData] = []
167
+ self._max_history = 100
168
+ self._enabled = True
169
+ self._blocked_events: Set[EventType] = set()
170
+
171
+ def _generate_handler_id(self) -> str:
172
+ """Generate unique handler ID"""
173
+ self._handler_counter += 1
174
+ return f"handler_{self._handler_counter}_{time.time()}"
175
+
176
+ def register(self,
177
+ event_type: EventType,
178
+ callback: Callable[[EventData], Any],
179
+ priority: int = 0,
180
+ once: bool = False,
181
+ filter_func: Optional[Callable[[EventData], bool]] = None,
182
+ service_name: str = "") -> str:
183
+ """
184
+ Register an event handler
185
+
186
+ Args:
187
+ event_type: The event type to listen for
188
+ callback: Function to call when event fires
189
+ priority: Higher priority handlers run first (default 0)
190
+ once: If True, handler is removed after first execution
191
+ filter_func: Optional filter function, handler only runs if filter returns True
192
+ service_name: Name of the service registering this handler
193
+
194
+ Returns:
195
+ Handler ID for later deregistration
196
+ """
197
+ with self._lock:
198
+ handler_id = self._generate_handler_id()
199
+ handler = EventHandler(
200
+ callback=callback,
201
+ priority=priority,
202
+ once=once,
203
+ filter_func=filter_func,
204
+ service_name=service_name,
205
+ handler_id=handler_id
206
+ )
207
+
208
+ if event_type not in self._handlers:
209
+ self._handlers[event_type] = []
210
+
211
+ self._handlers[event_type].append(handler)
212
+ # Sort by priority (higher first)
213
+ self._handlers[event_type].sort(key=lambda h: -h.priority)
214
+
215
+ return handler_id
216
+
217
+ def register_custom(self,
218
+ event_name: str,
219
+ callback: Callable[[EventData], Any],
220
+ priority: int = 0,
221
+ once: bool = False,
222
+ service_name: str = "") -> str:
223
+ """Register a custom event handler"""
224
+ with self._lock:
225
+ handler_id = self._generate_handler_id()
226
+ handler = EventHandler(
227
+ callback=callback,
228
+ priority=priority,
229
+ once=once,
230
+ service_name=service_name,
231
+ handler_id=handler_id
232
+ )
233
+
234
+ if event_name not in self._custom_handlers:
235
+ self._custom_handlers[event_name] = []
236
+
237
+ self._custom_handlers[event_name].append(handler)
238
+ self._custom_handlers[event_name].sort(key=lambda h: -h.priority)
239
+
240
+ return handler_id
241
+
242
+ def unregister(self, handler_id: str) -> bool:
243
+ """Remove a handler by ID"""
244
+ with self._lock:
245
+ # Check standard handlers
246
+ for event_type in self._handlers:
247
+ handlers = self._handlers[event_type]
248
+ for i, handler in enumerate(handlers):
249
+ if handler.handler_id == handler_id:
250
+ handlers.pop(i)
251
+ return True
252
+
253
+ # Check custom handlers
254
+ for event_name in self._custom_handlers:
255
+ handlers = self._custom_handlers[event_name]
256
+ for i, handler in enumerate(handlers):
257
+ if handler.handler_id == handler_id:
258
+ handlers.pop(i)
259
+ return True
260
+
261
+ return False
262
+
263
+ def unregister_service(self, service_name: str) -> int:
264
+ """Remove all handlers registered by a service"""
265
+ count = 0
266
+ with self._lock:
267
+ for event_type in self._handlers:
268
+ original_len = len(self._handlers[event_type])
269
+ self._handlers[event_type] = [
270
+ h for h in self._handlers[event_type]
271
+ if h.service_name != service_name
272
+ ]
273
+ count += original_len - len(self._handlers[event_type])
274
+
275
+ for event_name in self._custom_handlers:
276
+ original_len = len(self._custom_handlers[event_name])
277
+ self._custom_handlers[event_name] = [
278
+ h for h in self._custom_handlers[event_name]
279
+ if h.service_name != service_name
280
+ ]
281
+ count += original_len - len(self._custom_handlers[event_name])
282
+
283
+ return count
284
+
285
+ def emit(self,
286
+ event_type: EventType,
287
+ source: str = "",
288
+ data: Optional[Dict[str, Any]] = None,
289
+ sync: bool = True) -> EventData:
290
+ """
291
+ Emit an event
292
+
293
+ Args:
294
+ event_type: The event to emit
295
+ source: Source identifier
296
+ data: Event data dictionary
297
+ sync: If True, run handlers synchronously
298
+
299
+ Returns:
300
+ EventData object with results
301
+ """
302
+ if not self._enabled:
303
+ return EventData(event_type=event_type)
304
+
305
+ if event_type in self._blocked_events:
306
+ return EventData(event_type=event_type, cancelled=True)
307
+
308
+ event_data = EventData(
309
+ event_type=event_type,
310
+ source=source,
311
+ data=data or {}
312
+ )
313
+
314
+ if sync:
315
+ self._dispatch(event_data)
316
+ else:
317
+ thread = threading.Thread(
318
+ target=self._dispatch,
319
+ args=(event_data,),
320
+ daemon=True
321
+ )
322
+ thread.start()
323
+
324
+ # Add to history
325
+ with self._lock:
326
+ self._event_history.append(event_data)
327
+ if len(self._event_history) > self._max_history:
328
+ self._event_history.pop(0)
329
+
330
+ return event_data
331
+
332
+ def emit_custom(self,
333
+ event_name: str,
334
+ source: str = "",
335
+ data: Optional[Dict[str, Any]] = None) -> bool:
336
+ """Emit a custom event"""
337
+ if not self._enabled or event_name not in self._custom_handlers:
338
+ return False
339
+
340
+ event_data = EventData(
341
+ event_type=EventType.BOOTING, # Placeholder for custom
342
+ source=source,
343
+ data=data or {}
344
+ )
345
+ event_data.data['_custom_event_name'] = event_name
346
+
347
+ handlers_to_remove = []
348
+
349
+ with self._lock:
350
+ handlers = self._custom_handlers.get(event_name, [])[:]
351
+
352
+ for handler in handlers:
353
+ if event_data.cancelled:
354
+ break
355
+
356
+ try:
357
+ handler.callback(event_data)
358
+ if handler.once:
359
+ handlers_to_remove.append(handler.handler_id)
360
+ except Exception as e:
361
+ print(f"CSSL Event Handler Error [{event_name}]: {e}")
362
+
363
+ for handler_id in handlers_to_remove:
364
+ self.unregister(handler_id)
365
+
366
+ return True
367
+
368
+ def _dispatch(self, event_data: EventData):
369
+ """Internal dispatch method"""
370
+ handlers_to_remove = []
371
+
372
+ with self._lock:
373
+ handlers = self._handlers.get(event_data.event_type, [])[:]
374
+
375
+ for handler in handlers:
376
+ if event_data.cancelled:
377
+ break
378
+
379
+ # Check filter
380
+ if handler.filter_func:
381
+ try:
382
+ if not handler.filter_func(event_data):
383
+ continue
384
+ except Exception:
385
+ continue
386
+
387
+ try:
388
+ handler.callback(event_data)
389
+ if handler.once:
390
+ handlers_to_remove.append(handler.handler_id)
391
+ except Exception as e:
392
+ print(f"CSSL Event Handler Error [{event_data.event_type.full_name}]: {e}")
393
+
394
+ for handler_id in handlers_to_remove:
395
+ self.unregister(handler_id)
396
+
397
+ def block_event(self, event_type: EventType):
398
+ """Block an event from being emitted"""
399
+ self._blocked_events.add(event_type)
400
+
401
+ def unblock_event(self, event_type: EventType):
402
+ """Unblock an event"""
403
+ self._blocked_events.discard(event_type)
404
+
405
+ def enable(self):
406
+ """Enable event system"""
407
+ self._enabled = True
408
+
409
+ def disable(self):
410
+ """Disable event system (no events will be dispatched)"""
411
+ self._enabled = False
412
+
413
+ def get_handlers(self, event_type: EventType) -> List[EventHandler]:
414
+ """Get all handlers for an event type"""
415
+ with self._lock:
416
+ return self._handlers.get(event_type, [])[:]
417
+
418
+ def get_history(self, count: int = 10) -> List[EventData]:
419
+ """Get recent event history"""
420
+ with self._lock:
421
+ return self._event_history[-count:]
422
+
423
+ def clear_history(self):
424
+ """Clear event history"""
425
+ with self._lock:
426
+ self._event_history.clear()
427
+
428
+ def get_stats(self) -> Dict[str, Any]:
429
+ """Get event system statistics"""
430
+ with self._lock:
431
+ total_handlers = sum(len(h) for h in self._handlers.values())
432
+ total_custom = sum(len(h) for h in self._custom_handlers.values())
433
+
434
+ return {
435
+ 'enabled': self._enabled,
436
+ 'total_handlers': total_handlers,
437
+ 'custom_handlers': total_custom,
438
+ 'blocked_events': len(self._blocked_events),
439
+ 'history_size': len(self._event_history),
440
+ 'event_types_with_handlers': len(self._handlers),
441
+ 'custom_event_types': len(self._custom_handlers)
442
+ }
443
+
444
+
445
+ class EventDecorators:
446
+ """
447
+ Decorator factory for CSSL event handlers
448
+ Used to register class methods as event handlers
449
+ """
450
+
451
+ def __init__(self, event_manager: CSSLEventManager):
452
+ self._manager = event_manager
453
+
454
+ def on(self, event_type: EventType, priority: int = 0):
455
+ """Decorator to register a method as an event handler"""
456
+ def decorator(func):
457
+ self._manager.register(
458
+ event_type=event_type,
459
+ callback=func,
460
+ priority=priority
461
+ )
462
+ return func
463
+ return decorator
464
+
465
+ def once(self, event_type: EventType, priority: int = 0):
466
+ """Decorator to register a one-time event handler"""
467
+ def decorator(func):
468
+ self._manager.register(
469
+ event_type=event_type,
470
+ callback=func,
471
+ priority=priority,
472
+ once=True
473
+ )
474
+ return func
475
+ return decorator
476
+
477
+
478
+ # Global event manager instance
479
+ _global_event_manager: Optional[CSSLEventManager] = None
480
+
481
+
482
+ def get_event_manager() -> CSSLEventManager:
483
+ """Get the global event manager instance"""
484
+ global _global_event_manager
485
+ if _global_event_manager is None:
486
+ _global_event_manager = CSSLEventManager()
487
+ return _global_event_manager
488
+
489
+
490
+ def set_event_manager(manager: CSSLEventManager):
491
+ """Set the global event manager instance"""
492
+ global _global_event_manager
493
+ _global_event_manager = manager
494
+
495
+
496
+ # Convenience functions for common events
497
+ def emit_boot_event(event_name: str, data: Optional[Dict[str, Any]] = None) -> EventData:
498
+ """Emit a boot event"""
499
+ event_map = {
500
+ 'Booting': EventType.BOOTING,
501
+ 'Booted': EventType.BOOTED,
502
+ 'EarlyBoot': EventType.EARLY_BOOT,
503
+ 'LateBoot': EventType.LATE_BOOT
504
+ }
505
+ event_type = event_map.get(event_name)
506
+ if event_type:
507
+ return get_event_manager().emit(event_type, source="boot", data=data)
508
+ return EventData(event_type=EventType.BOOTING)
509
+
510
+
511
+ def emit_system_event(event_name: str, data: Optional[Dict[str, Any]] = None) -> EventData:
512
+ """Emit a system event"""
513
+ event_map = {
514
+ 'Shutdown': EventType.SHUTDOWN,
515
+ 'Restart': EventType.RESTART,
516
+ 'Suspend': EventType.SUSPEND,
517
+ 'Resume': EventType.RESUME,
518
+ 'Error': EventType.ERROR,
519
+ 'Critical': EventType.CRITICAL
520
+ }
521
+ event_type = event_map.get(event_name)
522
+ if event_type:
523
+ return get_event_manager().emit(event_type, source="system", data=data)
524
+ return EventData(event_type=EventType.SHUTDOWN)
525
+
526
+
527
+ def emit_vsram_event(event_name: str, data: Optional[Dict[str, Any]] = None) -> EventData:
528
+ """Emit a VSRAM event"""
529
+ event_map = {
530
+ 'Switched': EventType.VSRAM_SWITCHED,
531
+ 'Full': EventType.VSRAM_FULL,
532
+ 'Critical': EventType.VSRAM_CRITICAL,
533
+ 'Set': EventType.VSRAM_SET,
534
+ 'Get': EventType.VSRAM_GET,
535
+ 'Delete': EventType.VSRAM_DELETE,
536
+ 'Update': EventType.VSRAM_UPDATE
537
+ }
538
+ event_type = event_map.get(event_name)
539
+ if event_type:
540
+ return get_event_manager().emit(event_type, source="vsram", data=data)
541
+ return EventData(event_type=EventType.VSRAM_SET)
542
+
543
+
544
+ def emit_service_event(event_name: str, service: str = "", data: Optional[Dict[str, Any]] = None) -> EventData:
545
+ """Emit a service event"""
546
+ event_map = {
547
+ 'Start': EventType.SERVICE_START,
548
+ 'Stop': EventType.SERVICE_STOP,
549
+ 'Error': EventType.SERVICE_ERROR,
550
+ 'Complete': EventType.SERVICE_COMPLETE,
551
+ 'Timeout': EventType.SERVICE_TIMEOUT
552
+ }
553
+ event_type = event_map.get(event_name)
554
+ if event_type:
555
+ event_data = data or {}
556
+ event_data['service'] = service
557
+ return get_event_manager().emit(event_type, source="service", data=event_data)
558
+ return EventData(event_type=EventType.SERVICE_START)
559
+
560
+
561
+ def emit_kernel_event(event_name: str, data: Optional[Dict[str, Any]] = None) -> EventData:
562
+ """Emit a kernel event"""
563
+ event_map = {
564
+ 'Init': EventType.KERNEL_INIT,
565
+ 'Ready': EventType.KERNEL_READY,
566
+ 'Error': EventType.KERNEL_ERROR,
567
+ 'Command': EventType.KERNEL_COMMAND
568
+ }
569
+ event_type = event_map.get(event_name)
570
+ if event_type:
571
+ return get_event_manager().emit(event_type, source="kernel", data=data)
572
+ return EventData(event_type=EventType.KERNEL_INIT)
573
+
574
+
575
+ def emit_network_event(event_name: str, data: Optional[Dict[str, Any]] = None) -> EventData:
576
+ """Emit a network event"""
577
+ event_map = {
578
+ 'Connect': EventType.NETWORK_CONNECT,
579
+ 'Disconnect': EventType.NETWORK_DISCONNECT,
580
+ 'Error': EventType.NETWORK_ERROR,
581
+ 'Data': EventType.NETWORK_DATA,
582
+ 'Update': EventType.NETWORK_UPDATE
583
+ }
584
+ event_type = event_map.get(event_name)
585
+ if event_type:
586
+ return get_event_manager().emit(event_type, source="network", data=data)
587
+ return EventData(event_type=EventType.NETWORK_CONNECT)
588
+
589
+
590
+ def emit_user_event(event_name: str, username: str = "", data: Optional[Dict[str, Any]] = None) -> EventData:
591
+ """Emit a user event"""
592
+ event_map = {
593
+ 'Login': EventType.USER_LOGIN,
594
+ 'Logout': EventType.USER_LOGOUT,
595
+ 'Create': EventType.USER_CREATE,
596
+ 'Delete': EventType.USER_DELETE,
597
+ 'Change': EventType.USER_CHANGE
598
+ }
599
+ event_type = event_map.get(event_name)
600
+ if event_type:
601
+ event_data = data or {}
602
+ event_data['username'] = username
603
+ return get_event_manager().emit(event_type, source="user", data=event_data)
604
+ return EventData(event_type=EventType.USER_LOGIN)
605
+
606
+
607
+ def emit_wheel_event(event_name: str, wheel: str = "", key: str = "", data: Optional[Dict[str, Any]] = None) -> EventData:
608
+ """Emit a wheel event"""
609
+ event_map = {
610
+ 'Change': EventType.WHEEL_CHANGE,
611
+ 'Read': EventType.WHEEL_READ,
612
+ 'Write': EventType.WHEEL_WRITE,
613
+ 'Init': EventType.WHEEL_INIT
614
+ }
615
+ event_type = event_map.get(event_name)
616
+ if event_type:
617
+ event_data = data or {}
618
+ event_data['wheel'] = wheel
619
+ event_data['key'] = key
620
+ return get_event_manager().emit(event_type, source="wheel", data=event_data)
621
+ return EventData(event_type=EventType.WHEEL_CHANGE)