emit<T extends ModuleEvent> method
void
emit<T extends ModuleEvent>(
- T event
Emit an event to all subscribers with built-in rate limiting protection.
Implementation
void emit<T extends ModuleEvent>(T event) {
// Check rate limit per source module and event type
final rateLimitKey = '${event.sourceModuleId}:${T.toString()}';
if (!_checkRateLimit(rateLimitKey)) {
AirAudit().log(
type: AuditType.securityViolation,
action: 'event_rate_limit_exceeded',
moduleId: event.sourceModuleId,
context: {'eventType': T.toString()},
severity: AuditSeverity.medium,
success: false,
);
return;
}
// Check permission to emit
if (!PermissionChecker().checkPermission(
event.sourceModuleId,
Permission.eventEmit,
resource: T.toString(),
)) {
return;
}
AirLogger.debug(
'Emitting ${event.runtimeType}',
context: {'source': event.sourceModuleId},
);
// Add to history
_eventHistory.add(event);
if (_eventHistory.length > _maxHistorySize) {
_eventHistory.removeAt(0);
}
// Notify subscribers
final subs = _subscriptions[T];
if (subs == null || subs.isEmpty) {
AirLogger.debug('No subscribers for ${event.runtimeType}');
return;
}
// Create copy of active subscribers to iterate safely, then clean up cancelled/expired
final activeSubs = subs
.where((s) => !s.isCancelled && !s.isExpired)
.toList();
subs.removeWhere((s) => s.isCancelled || s.isExpired);
for (final subscription in activeSubs) {
if (subscription.subscriberModuleId != null) {
SecureServiceRegistry().recordInteraction(
ModuleInteraction(
sourceId: event.sourceModuleId,
targetId: subscription.subscriberModuleId!,
type: InteractionType.event,
detail: T.toString(),
),
);
}
try {
(subscription.callback as void Function(T))(event);
} catch (e) {
AirLogger.error('Error in subscriber ${subscription.id}', error: e);
}
}
notifyListeners();
}