import 'package:votianlt_app/services/developer.dart' as developer; /// A lightweight in-app message bus ("dart_mq") for pub/sub style communication. /// // Usage: // final mq = DartMQ(); // final sub = mq.subscribe('connection/status', (isOnline) { /* ... */ }); // mq.publish('connection/status', true); // sub.cancel(); class DartMQ { DartMQ._internal(); static final DartMQ _instance = DartMQ._internal(); factory DartMQ() => _instance; final Map> _subscribers = {}; /// Subscribe to a topic. Returns a cancellable subscription handle. DartMQSubscription subscribe(String topic, void Function(T data) handler) { final sub = _DartMQSubscriber(topic: topic, handler: handler); final list = _subscribers.putIfAbsent(topic, () => <_DartMQSubscriber>[]); list.add(sub); return DartMQSubscription._(this, sub); } /// Publish a message to a topic. If no subscribers exist, this is a no-op. void publish(String topic, T data) { final list = _subscribers[topic]; if (list == null || list.isEmpty) return; // Make a defensive copy to allow cancellation during iteration. final current = List<_DartMQSubscriber>.from(list); for (final s in current) { // Only deliver if types match; otherwise, try dynamic fallback if (s is _DartMQSubscriber) { try { s.handler(data); } catch (e, stackTrace) { developer.log( 'Error delivering message to subscriber on topic "$topic": $e', ); developer.log('Stack trace: $stackTrace'); } } else { // Fallback delivery for handlers expecting dynamic or different T try { final dynamicHandler = s.handler as dynamic; dynamicHandler(data); } catch (e, stackTrace) { developer.log( 'Error delivering dynamic message to subscriber on topic "$topic": $e', ); developer.log('Stack trace: $stackTrace'); } } } } void _cancel(_DartMQSubscriber subscriber) { final list = _subscribers[subscriber.topic]; if (list == null) return; list.remove(subscriber); if (list.isEmpty) { _subscribers.remove(subscriber.topic); } } } /// Cancellable subscription handle class DartMQSubscription { final DartMQ _mq; final _DartMQSubscriber _subscriber; bool _isCancelled = false; DartMQSubscription._(this._mq, this._subscriber); void cancel() { if (_isCancelled) return; _isCancelled = true; _mq._cancel(_subscriber); } } class _DartMQSubscriber { final String topic; final void Function(T data) handler; _DartMQSubscriber({required this.topic, required this.handler}); } /// Common topics used in the app class MQTopics { static const connectionStatus = 'connection/status'; // bool static const authResponse = 'auth/response'; // Map static const jobsResponse = 'jobs/response'; // List static const taskEvents = 'task/events'; // Map static const jobsUpdated = 'app/jobsUpdated'; // void/null static const jobDeleted = 'job/deleted'; // Map {jobId, jobNumber, deletedAt} static const jobCreated = 'job/created'; // Map - full job data static const chatIncoming = 'chat/incoming'; // ChatMessage static const chatOutgoing = 'chat/outgoing'; // ChatMessage }