listen<T> method

ZenSubscription listen<T>(
  1. dynamic provider,
  2. void listener(
    1. T
    )
)

Enhanced listen with comprehensive memory protection

Implementation

ZenSubscription listen<T>(
  dynamic provider,
  void Function(T) listener,
) {
  // Memory protection - prevent runaway subscriptions
  _checkMemoryPressure();

  final Type type = T;
  final String? tag = _extractTag(provider);
  final key = _getKey(type, tag);

  // Validate listener count per key
  final existingListeners = _listeners[key];
  if (existingListeners != null &&
      existingListeners.length >= _maxListenersPerKey) {
    ZenLogger.logWarning(
        'High listener count (${existingListeners.length}) for $type:$tag. Potential memory leak?');
  }

  _listeners.putIfAbsent(key, () => <VoidCallback>{});

  // Create resilient callback using findOrNull to avoid exceptions
  void callback() {
    try {
      final instance = Zen.findOrNull<T>(tag: tag);
      if (instance != null) {
        listener(instance);
      }
    } catch (e, stack) {
      _errorCount++;
      ZenLogger.logError('Error in listener callback for $T', e, stack);
    }
  }

  _listeners[key]!.add(callback);

  // Safe initial notification
  final current = Zen.findOrNull<T>(tag: tag);
  if (current != null) {
    try {
      listener(current);
    } catch (e, stack) {
      _errorCount++;
      ZenLogger.logError('Error in initial listener call for $T', e, stack);
    }
  }

  // Return enhanced subscription with cleanup tracking
  return ZenSubscription(() {
    final listenerSet = _listeners[key];
    if (listenerSet != null) {
      listenerSet.remove(callback);

      // Automatic cleanup of empty listener sets
      if (listenerSet.isEmpty) {
        _listeners.remove(key);
      }
    }
  });
}