260 lines
7.3 KiB
Dart
260 lines
7.3 KiB
Dart
import 'dart:io';
|
|
import 'dart:isolate';
|
|
import 'dart:async';
|
|
|
|
import 'package:dart_framework/data/isolate_data.dart';
|
|
import 'package:dart_framework/platform/process.dart';
|
|
|
|
/// ********************** Test ************************* ///
|
|
void test() {
|
|
var initData = {"param0": "value0"};
|
|
var id = IsolateManager.create<IsolateTemplate>(IsolateTemplate(), initData,
|
|
(isoEvent, data) async {
|
|
print('[Manager] OnInnerEvent - type: ${isoEvent.name}');
|
|
if (isoEvent == IsolateEvent.ready) {
|
|
int id = data as int;
|
|
IsolateManager.sendBroadcast(IsoMessege('test1', message: 'initData1'));
|
|
|
|
await Future.delayed(Duration(seconds: 2));
|
|
|
|
IsolateManager.send(id, IsoMessege('test2', message: 'data2'));
|
|
//will not arrive, addListener once
|
|
IsolateManager.send(id, IsoMessege('test1', message: 'data1'));
|
|
|
|
await Future.delayed(Duration(seconds: 5));
|
|
|
|
IsolateManager.exit(id);
|
|
} else if (isoEvent == IsolateEvent.exit) {
|
|
print('[Manager] Isolate is exited.');
|
|
}
|
|
}, (message) {
|
|
//Custom message
|
|
print(
|
|
'[Manager] OnMessage - type: ${message.type}, message: ${message.message}');
|
|
});
|
|
}
|
|
|
|
class IsolateTemplate extends IsolateBase {
|
|
@override
|
|
void onReady(Object? initData) async {
|
|
print('[IsolateTemplate] onReady - initData: $initData');
|
|
addEventListener('test1', onTest1Handler, executeOnce: true);
|
|
addEventListener('test2', onTest2Handler);
|
|
}
|
|
|
|
void onTest1Handler(Object? data) async {
|
|
print('[IsolateTemplate] OnTest1Handler: $data');
|
|
var dir = Platform.isWindows ? 'dir' : 'ls -l';
|
|
ProcessExecutor.run(StringBuffer(dir));
|
|
await delayTest();
|
|
}
|
|
|
|
Future delayTest() async {
|
|
await Future.delayed(Duration(seconds: 5));
|
|
send(IsoMessege('delayedCutomMessage', message: 'This is message'));
|
|
}
|
|
|
|
void onTest2Handler(Object? data) {
|
|
print('[IsolateTemplate] OnTest2Handler: $data');
|
|
}
|
|
}
|
|
|
|
/// ********************** Define *********************** ///
|
|
class _IsolateInnerEvent {
|
|
static const String ready = '_IsolateInnerEvent.Ready';
|
|
static const String exit = '_IsolateInnerEvent.Exit';
|
|
}
|
|
|
|
class _IsolateConstructData {
|
|
late int id;
|
|
late SendPort mainIsoSender;
|
|
late Object? initData;
|
|
_IsolateConstructData(this.id, this.mainIsoSender, this.initData);
|
|
}
|
|
|
|
class IsolateManager {
|
|
IsolateManager._privateConstructor();
|
|
static final IsolateManager _instance = IsolateManager._privateConstructor();
|
|
static IsolateManager get instance => _instance;
|
|
|
|
static int _nonce = 0;
|
|
static int get nonce {
|
|
if (_nonce == double.maxFinite.toInt()) {
|
|
_nonce = 0;
|
|
} else {
|
|
_nonce++;
|
|
}
|
|
return _nonce;
|
|
}
|
|
|
|
final Map<int, IsolateBase> _isoMap = {};
|
|
final Map<int, Map<String, Function(Object?)>> _innerEventMap = {};
|
|
|
|
static void create<T extends IsolateBase>(
|
|
T inst,
|
|
Object? initData,
|
|
Function(IsolateEvent, Object?) isolateEventListener,
|
|
Function(IsoMessege) messageListener) async {
|
|
var id = nonce;
|
|
instance._create<T>(
|
|
inst, initData, id, isolateEventListener, messageListener);
|
|
}
|
|
|
|
void _create<T extends IsolateBase>(
|
|
T inst,
|
|
Object? initData,
|
|
int id,
|
|
Function(IsolateEvent, Object?) isolateEventListener,
|
|
Function(IsoMessege) messageListener) async {
|
|
final isoListener = ReceivePort();
|
|
inst.id = id;
|
|
_isoMap[id] = inst;
|
|
_addInnerEvent(id, _IsolateInnerEvent.ready, (message) {
|
|
inst.isoListener = message as SendPort;
|
|
isolateEventListener(IsolateEvent.ready, id);
|
|
});
|
|
await Isolate.spawn(inst.initialize,
|
|
_IsolateConstructData(id, isoListener.sendPort, initData));
|
|
await for (IsoMessege message in isoListener) {
|
|
if (message.type == _IsolateInnerEvent.exit) {
|
|
isolateEventListener(IsolateEvent.exit, null);
|
|
break;
|
|
} else if (_filterInnerEvent(id, message)) {
|
|
messageListener(message);
|
|
}
|
|
}
|
|
isoListener.close();
|
|
_isoMap.remove(id);
|
|
}
|
|
|
|
void _addInnerEvent(int id, String type, Function(Object?) listener) {
|
|
Map<String, Function(Object?)>? eventMap;
|
|
if (!_innerEventMap.containsKey(id)) {
|
|
eventMap = {};
|
|
_innerEventMap[id] = eventMap;
|
|
}
|
|
eventMap![type] = listener;
|
|
}
|
|
|
|
bool _filterInnerEvent(int id, IsoMessege message) {
|
|
var isNotExist = true;
|
|
if (_innerEventMap.containsKey(id) &&
|
|
_innerEventMap[id]!.containsKey(message.type)) {
|
|
isNotExist = false;
|
|
_innerEventMap[id]![message.type]!(message.message);
|
|
}
|
|
return isNotExist;
|
|
}
|
|
|
|
static void sendBroadcast(IsoMessege message) {
|
|
var entries = instance._isoMap.entries;
|
|
for (var entry in entries) {
|
|
entry.value.insertEvent(message);
|
|
}
|
|
}
|
|
|
|
static void send(int id, IsoMessege message) {
|
|
var map = instance._isoMap;
|
|
if (map.containsKey(id)) {
|
|
map[id]?.insertEvent(message);
|
|
}
|
|
}
|
|
|
|
static void exit(int id) {
|
|
var map = instance._isoMap;
|
|
if (map.containsKey(id)) {
|
|
map[id]!.insertEvent(IsoMessege(_IsolateInnerEvent.exit));
|
|
}
|
|
}
|
|
}
|
|
|
|
class _IsolateEventListener {
|
|
late bool executeOnce;
|
|
late Function(Object?) listener;
|
|
_IsolateEventListener(this.listener, this.executeOnce);
|
|
}
|
|
|
|
class IsolateBase {
|
|
late int id;
|
|
late ReceivePort _mainIsoListener;
|
|
late SendPort _mainIsoSender;
|
|
late SendPort isoListener;
|
|
final Map<String, List<_IsolateEventListener>> _eventMap = {};
|
|
final List<_IsolateEventListener> _removeList = [];
|
|
|
|
// ignore: library_private_types_in_public_api
|
|
Future<void> initialize(_IsolateConstructData initData) async {
|
|
id = initData.id;
|
|
_mainIsoListener = ReceivePort();
|
|
_mainIsoSender = initData.mainIsoSender;
|
|
send(IsoMessege(_IsolateInnerEvent.ready,
|
|
message: _mainIsoListener.sendPort));
|
|
onReady(initData.initData);
|
|
await for (IsoMessege message in _mainIsoListener) {
|
|
if (message.type == _IsolateInnerEvent.exit) {
|
|
send(IsoMessege(_IsolateInnerEvent.exit));
|
|
break;
|
|
} else {
|
|
_onEvent(message);
|
|
}
|
|
}
|
|
Isolate.exit(_mainIsoSender);
|
|
}
|
|
|
|
void onReady(Object? initData) async {}
|
|
|
|
void send(IsoMessege message) {
|
|
_mainIsoSender.send(message);
|
|
}
|
|
|
|
void _onEvent(IsoMessege message) {
|
|
if (_eventMap.containsKey(message.type)) {
|
|
var list = _eventMap[message.type]!;
|
|
for (var item in list) {
|
|
item.listener(message.message);
|
|
if (item.executeOnce) {
|
|
_removeList.add(item);
|
|
}
|
|
}
|
|
if (_removeList.isNotEmpty) {
|
|
for (var item in _removeList) {
|
|
removeEventListener(message.type, item.listener);
|
|
}
|
|
_removeList.clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
void addEventListener(String type, Function(Object?) listener,
|
|
{bool executeOnce = false}) {
|
|
List<_IsolateEventListener> list;
|
|
if (_eventMap.containsKey(type)) {
|
|
list = _eventMap[type]!;
|
|
} else {
|
|
list = [];
|
|
_eventMap[type] = list;
|
|
}
|
|
list.add(_IsolateEventListener(listener, executeOnce));
|
|
}
|
|
|
|
void removeEventListener(String type, Function(Object?) listener) {
|
|
if (_eventMap.containsKey(type)) {
|
|
var list = _eventMap[type]!;
|
|
for (int i = 0; i < list.length; ++i) {
|
|
var item = list[i];
|
|
if (item.listener == listener) {
|
|
list.removeAt(i);
|
|
--i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void insertEvent(IsoMessege message) {
|
|
isoListener.send(message);
|
|
}
|
|
|
|
void exit() {
|
|
IsolateManager.exit(id);
|
|
}
|
|
}
|