emit<T extends ModuleEvent> method

void emit<T extends ModuleEvent>(
  1. 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();
}