refactor: Projektstruktur in app/ und backend/ aufgeteilt
This commit is contained in:
100
app/lib/services/dart_mq.dart
Normal file
100
app/lib/services/dart_mq.dart
Normal file
@@ -0,0 +1,100 @@
|
||||
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<bool>('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<String, List<_DartMQSubscriber>> _subscribers = {};
|
||||
|
||||
/// Subscribe to a topic. Returns a cancellable subscription handle.
|
||||
DartMQSubscription subscribe<T>(String topic, void Function(T data) handler) {
|
||||
final sub = _DartMQSubscriber<T>(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<T>(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<T>) {
|
||||
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<T> {
|
||||
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<String, dynamic>
|
||||
static const jobsResponse = 'jobs/response'; // List<dynamic>
|
||||
static const taskEvents = 'task/events'; // Map<String, dynamic>
|
||||
static const jobsUpdated = 'app/jobsUpdated'; // void/null
|
||||
static const jobDeleted = 'job/deleted'; // Map<String, dynamic> {jobId, jobNumber, deletedAt}
|
||||
static const jobCreated = 'job/created'; // Map<String, dynamic> - full job data
|
||||
static const chatIncoming = 'chat/incoming'; // ChatMessage
|
||||
static const chatOutgoing = 'chat/outgoing'; // ChatMessage
|
||||
}
|
||||
Reference in New Issue
Block a user