platform/packages/pub_sub/lib/src/isolate/server.dart

254 lines
6.9 KiB
Dart
Raw Normal View History

2021-03-08 12:56:39 +00:00
import 'dart:async';
import 'dart:isolate';
import 'package:uuid/uuid.dart';
2021-05-15 11:20:33 +00:00
import '../../angel3_pub_sub.dart';
2021-03-08 12:56:39 +00:00
/// A [Adapter] implementation that communicates via [SendPort]s and [ReceivePort]s.
class IsolateAdapter extends Adapter {
final Map<String, SendPort> _clients = {};
final StreamController<PublishRequest> _onPublish =
2021-05-01 01:54:59 +00:00
StreamController<PublishRequest>();
2021-03-08 12:56:39 +00:00
final StreamController<SubscriptionRequest> _onSubscribe =
2021-05-01 01:54:59 +00:00
StreamController<SubscriptionRequest>();
2021-03-08 12:56:39 +00:00
final StreamController<UnsubscriptionRequest> _onUnsubscribe =
2021-05-01 01:54:59 +00:00
StreamController<UnsubscriptionRequest>();
final Uuid _uuid = Uuid();
2021-03-08 12:56:39 +00:00
/// A [ReceivePort] on which to listen for incoming data.
2021-05-01 01:54:59 +00:00
final ReceivePort receivePort = ReceivePort();
2021-03-08 12:56:39 +00:00
@override
Stream<PublishRequest> get onPublish => _onPublish.stream;
@override
Stream<SubscriptionRequest> get onSubscribe => _onSubscribe.stream;
@override
Stream<UnsubscriptionRequest> get onUnsubscribe => _onUnsubscribe.stream;
@override
Future close() {
receivePort.close();
_clients.clear();
_onPublish.close();
_onSubscribe.close();
_onUnsubscribe.close();
2021-05-01 01:54:59 +00:00
return Future.value();
2021-03-08 12:56:39 +00:00
}
@override
void start() {
receivePort.listen((data) {
if (data is SendPort) {
var id = _uuid.v4();
_clients[id] = data;
data.send({'status': true, 'id': id});
} else if (data is Map &&
data['id'] is String &&
data['request_id'] is String &&
data['method'] is String &&
data['params'] is Map) {
2021-05-01 01:54:59 +00:00
var id = data['id'] as String?,
requestId = data['request_id'] as String?,
method = data['method'] as String?;
var params = data['params'] as Map?;
var sp = _clients[id!];
2021-03-08 12:56:39 +00:00
if (sp == null) {
// There's nobody to respond to, so don't send anything to anyone. Oops.
} else if (method == 'publish') {
2021-05-01 01:54:59 +00:00
if (_isValidClientId(params!['client_id']) &&
2021-03-08 12:56:39 +00:00
params['event_name'] is String &&
params.containsKey('value')) {
2021-05-01 01:54:59 +00:00
var clientId = params['client_id'] as String?,
eventName = params['event_name'] as String?;
2021-03-08 12:56:39 +00:00
var value = params['value'];
2021-05-01 01:54:59 +00:00
var rq = _IsolatePublishRequestImpl(
2021-03-08 12:56:39 +00:00
requestId, clientId, eventName, value, sp);
_onPublish.add(rq);
} else {
sp.send({
'status': false,
'request_id': requestId,
'error_message': 'Expected client_id, event_name, and value.'
});
}
} else if (method == 'subscribe') {
2021-05-01 01:54:59 +00:00
if (_isValidClientId(params!['client_id']) &&
2021-03-08 12:56:39 +00:00
params['event_name'] is String) {
2021-05-01 01:54:59 +00:00
var clientId = params['client_id'] as String?,
eventName = params['event_name'] as String?;
var rq = _IsolateSubscriptionRequestImpl(
2021-03-08 12:56:39 +00:00
clientId, eventName, sp, requestId, _uuid);
_onSubscribe.add(rq);
} else {
sp.send({
'status': false,
'request_id': requestId,
'error_message': 'Expected client_id, and event_name.'
});
}
} else if (method == 'unsubscribe') {
2021-05-01 01:54:59 +00:00
if (_isValidClientId(params!['client_id']) &&
2021-03-08 12:56:39 +00:00
params['subscription_id'] is String) {
2021-05-01 01:54:59 +00:00
var clientId = params['client_id'] as String?,
subscriptionId = params['subscription_id'] as String?;
var rq = _IsolateUnsubscriptionRequestImpl(
2021-03-08 12:56:39 +00:00
clientId, subscriptionId, sp, requestId);
_onUnsubscribe.add(rq);
} else {
sp.send({
'status': false,
'request_id': requestId,
'error_message': 'Expected client_id, and subscription_id.'
});
}
} else {
sp.send({
'status': false,
'request_id': requestId,
'error_message':
'Unrecognized method "$method". Or, you omitted id, request_id, method, or params.'
});
}
}
});
}
bool _isValidClientId(id) => id == null || id is String;
@override
bool isTrustedPublishRequest(PublishRequest request) {
// Isolate clients are considered trusted, because they are
// running in the same process as the central server.
return true;
}
@override
bool isTrustedSubscriptionRequest(SubscriptionRequest request) {
return true;
}
}
class _IsolatePublishRequestImpl extends PublishRequest {
@override
2021-05-01 01:54:59 +00:00
final String? clientId;
2021-03-08 12:56:39 +00:00
@override
2021-05-01 01:54:59 +00:00
final String? eventName;
2021-03-08 12:56:39 +00:00
@override
final value;
final SendPort sendPort;
2021-05-01 01:54:59 +00:00
final String? requestId;
2021-03-08 12:56:39 +00:00
_IsolatePublishRequestImpl(
this.requestId, this.clientId, this.eventName, this.value, this.sendPort);
@override
void accept(PublishResponse response) {
sendPort.send({
'status': true,
'request_id': requestId,
'result': {
'listeners': response.listeners,
'client_id': response.clientId
}
});
}
@override
void reject(String errorMessage) {
sendPort.send({
'status': false,
'request_id': requestId,
'error_message': errorMessage
});
}
}
class _IsolateSubscriptionRequestImpl extends SubscriptionRequest {
@override
2021-05-01 01:54:59 +00:00
final String? clientId;
2021-03-08 12:56:39 +00:00
@override
2021-05-01 01:54:59 +00:00
final String? eventName;
2021-03-08 12:56:39 +00:00
final SendPort sendPort;
2021-05-01 01:54:59 +00:00
final String? requestId;
2021-03-08 12:56:39 +00:00
final Uuid _uuid;
_IsolateSubscriptionRequestImpl(
this.clientId, this.eventName, this.sendPort, this.requestId, this._uuid);
@override
void reject(String errorMessage) {
sendPort.send({
'status': false,
'request_id': requestId,
'error_message': errorMessage
});
}
@override
2021-05-01 01:54:59 +00:00
FutureOr<Subscription> accept(String? clientId) {
2021-03-08 12:56:39 +00:00
var id = _uuid.v4();
sendPort.send({
'status': true,
'request_id': requestId,
'result': {'subscription_id': id, 'client_id': clientId}
});
2021-05-01 01:54:59 +00:00
return _IsolateSubscriptionImpl(clientId, id, eventName, sendPort);
2021-03-08 12:56:39 +00:00
}
}
class _IsolateSubscriptionImpl extends Subscription {
@override
2021-05-01 01:54:59 +00:00
final String? clientId, id;
2021-03-08 12:56:39 +00:00
2021-05-01 01:54:59 +00:00
final String? eventName;
2021-03-08 12:56:39 +00:00
final SendPort sendPort;
_IsolateSubscriptionImpl(
this.clientId, this.id, this.eventName, this.sendPort);
@override
void dispatch(event) {
sendPort.send([eventName, event]);
}
}
class _IsolateUnsubscriptionRequestImpl extends UnsubscriptionRequest {
@override
2021-05-01 01:54:59 +00:00
final String? clientId;
2021-03-08 12:56:39 +00:00
@override
2021-05-01 01:54:59 +00:00
final String? subscriptionId;
2021-03-08 12:56:39 +00:00
final SendPort sendPort;
2021-05-01 01:54:59 +00:00
final String? requestId;
2021-03-08 12:56:39 +00:00
_IsolateUnsubscriptionRequestImpl(
this.clientId, this.subscriptionId, this.sendPort, this.requestId);
@override
void reject(String errorMessage) {
sendPort.send({
'status': false,
'request_id': requestId,
'error_message': errorMessage
});
}
@override
void accept() {
sendPort.send({'status': true, 'request_id': requestId, 'result': {}});
}
}