Skip to content

Commit

Permalink
Do not throw error when call function after disposed
Browse files Browse the repository at this point in the history
  • Loading branch information
littleGnAl committed Mar 10, 2023
1 parent 15c6e38 commit 0fa19c2
Show file tree
Hide file tree
Showing 2 changed files with 196 additions and 1 deletion.
57 changes: 56 additions & 1 deletion lib/src/iris_method_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class IrisMethodCall {
}

const int kBasicResultLength = 64 * 1024;
const int kDisposedIrisMethodCallReturnCode = 1000;
const Map<String, int> kDisposedIrisMethodCallData = {'result': 0};

class CallApiResult {
CallApiResult(
Expand Down Expand Up @@ -120,22 +122,37 @@ void freePointer(ffi.Pointer<ffi.Void> ptr) {
}

class _Messenger implements DisposableObject {
const _Messenger(this.requestPort, this.responseQueue);
_Messenger(this.requestPort, this.responseQueue);
final SendPort requestPort;
final StreamQueue<dynamic> responseQueue;
bool _isDisposed = false;

Future<CallApiResult> send(_Request request) async {
if (_isDisposed) {
return CallApiResult(
irisReturnCode: kDisposedIrisMethodCallReturnCode,
data: kDisposedIrisMethodCallData);
}
requestPort.send(request);
return await responseQueue.next;
}

Future<List<CallApiResult>> listSend(_Request request) async {
if (_isDisposed) {
return [
CallApiResult(
irisReturnCode: kDisposedIrisMethodCallReturnCode,
data: kDisposedIrisMethodCallData)
];
}
requestPort.send(request);
return await responseQueue.next;
}

@override
Future<void> dispose() async {
if (!_isDisposed) return;
_isDisposed = true;
requestPort.send(null);
await responseQueue.cancel();
}
Expand Down Expand Up @@ -446,6 +463,10 @@ class IrisMethodChannel {
messenger = _Messenger(requestPort, responseQueue);

evntSubscription = eventPort.listen((message) {
if (!_initilized) {
return;
}

final eventMessage = IrisEvent.parseMessage(message);

bool handled = false;
Expand Down Expand Up @@ -479,6 +500,11 @@ class IrisMethodChannel {
}

Future<CallApiResult> invokeMethod(IrisMethodCall methodCall) async {
if (!_initilized) {
return CallApiResult(
irisReturnCode: kDisposedIrisMethodCallReturnCode,
data: kDisposedIrisMethodCallData);
}
final CallApiResult result =
await messenger.send(_ApiCallRequest(methodCall));

Expand All @@ -487,6 +513,14 @@ class IrisMethodChannel {

Future<List<CallApiResult>> invokeMethodList(
List<IrisMethodCall> methodCalls) async {
if (!_initilized) {
return methodCalls
.map((e) => CallApiResult(
irisReturnCode: kDisposedIrisMethodCallReturnCode,
data: kDisposedIrisMethodCallData))
.toList();
}

final List<CallApiResult> result =
await messenger.listSend(_ApiCallListRequest(methodCalls));

Expand All @@ -495,6 +529,7 @@ class IrisMethodChannel {

Future<void> dispose() async {
if (!_initilized) return;
_initilized = false;
_hotRestartFinalizer.dispose();
await scopedEventHandlers.clear();
await evntSubscription.cancel();
Expand All @@ -504,6 +539,12 @@ class IrisMethodChannel {

Future<CallApiResult> registerEventHandler(
ScopedEvent scopedEvent, String params) async {
if (!_initilized) {
return CallApiResult(
irisReturnCode: kDisposedIrisMethodCallReturnCode,
data: kDisposedIrisMethodCallData);
}

final DisposableScopedObjects subScopedObjects = scopedEventHandlers
.putIfAbsent(scopedEvent.scopedKey, () => DisposableScopedObjects());
final eventKey = _EventHandlerHolderKey(
Expand Down Expand Up @@ -537,6 +578,12 @@ class IrisMethodChannel {

Future<CallApiResult> unregisterEventHandler(
ScopedEvent scopedEvent, String params) async {
if (!_initilized) {
return CallApiResult(
irisReturnCode: kDisposedIrisMethodCallReturnCode,
data: kDisposedIrisMethodCallData);
}

final DisposableScopedObjects? subScopedObjects =
scopedEventHandlers.get(scopedEvent.scopedKey);
final eventKey = _EventHandlerHolderKey(
Expand Down Expand Up @@ -565,6 +612,10 @@ class IrisMethodChannel {
}

Future<void> unregisterEventHandlers(TypedScopedKey scopedKey) async {
if (!_initilized) {
return;
}

final DisposableScopedObjects? subScopedObjects =
scopedEventHandlers.remove(scopedKey);
if (subScopedObjects != null) {
Expand Down Expand Up @@ -594,6 +645,10 @@ class IrisMethodChannel {
}

int getNativeHandle() {
if (!_initilized) {
return 0;
}

return _nativeHandle;
}

Expand Down
140 changes: 140 additions & 0 deletions test/iris_method_channel_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,146 @@ void main() {
await irisMethodChannel.dispose();
});

test('invokeMethod after disposed', () async {
final irisMethodChannel = IrisMethodChannel();
await irisMethodChannel.initilize(nativeBindingsProvider);
await irisMethodChannel.dispose();
final callApiResult = await irisMethodChannel
.invokeMethod(const IrisMethodCall('a_func_name', 'params'));
final callRecord1 = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'a_func_name');
expect(callRecord1.length, 0);

expect(callApiResult.irisReturnCode, kDisposedIrisMethodCallReturnCode);
expect(callApiResult.data, kDisposedIrisMethodCallData);
});

test('invokeMethodList after disposed', () async {
final irisMethodChannel = IrisMethodChannel();
await irisMethodChannel.initilize(nativeBindingsProvider);
await irisMethodChannel.dispose();
const methodCalls = [
IrisMethodCall('a_func_name', 'params'),
IrisMethodCall('a_func_name2', 'params')
];

final callApiResult = await irisMethodChannel.invokeMethodList(methodCalls);

final callRecord1 = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'a_func_name');
expect(callRecord1.length, 0);

final callRecord2 = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'a_func_name2');
expect(callRecord2.length, 0);

expect(callApiResult[0].irisReturnCode, kDisposedIrisMethodCallReturnCode);
expect(callApiResult[0].data, kDisposedIrisMethodCallData);

expect(callApiResult[1].irisReturnCode, kDisposedIrisMethodCallReturnCode);
expect(callApiResult[1].data, kDisposedIrisMethodCallData);
});

test('registerEventHandler after disposed', () async {
final irisMethodChannel = IrisMethodChannel();
await irisMethodChannel.initilize(nativeBindingsProvider);
await irisMethodChannel.dispose();

const key = TypedScopedKey(_TestEventLoopEventHandler);
final eventHandler = _TestEventLoopEventHandler();
await irisMethodChannel.registerEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler',
unregisterName: 'unregisterEventHandler',
handler: eventHandler),
jsonEncode({}));

final DisposableScopedObjects? subScopedObjects =
irisMethodChannel.scopedEventHandlers.get(key);
expect(subScopedObjects, isNull);

final registerEventHandlerCallRecord = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'registerEventHandler');
expect(registerEventHandlerCallRecord.length, 0);
});

test('unregisterEventHandler after disposed', () async {
final _FakeNativeBindingDelegateMessenger messenger =
_FakeNativeBindingDelegateMessenger();
final _FakeNativeBindingDelegate nativeBindingDelegate =
_FakeNativeBindingDelegate(
messenger.getSendPort(),
);
final _FakeIrisEvent irisEvent = _FakeIrisEvent(messenger.getSendPort());
final NativeBindingsProvider nativeBindingsProvider =
_FakeNativeBindingDelegateProvider(nativeBindingDelegate, irisEvent);

final irisMethodChannel = IrisMethodChannel();
await irisMethodChannel.initilize(nativeBindingsProvider);
await irisMethodChannel.dispose();

const key = TypedScopedKey(_TestEventLoopEventHandler);
final eventHandler = _TestEventLoopEventHandler();
await irisMethodChannel.registerEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler',
unregisterName: 'unregisterEventHandler',
handler: eventHandler),
jsonEncode({}));
await irisMethodChannel.unregisterEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler',
unregisterName: 'unregisterEventHandler',
handler: eventHandler),
jsonEncode({}));

final DisposableScopedObjects? subScopedObjects =
irisMethodChannel.scopedEventHandlers.get(key);
expect(subScopedObjects, isNull);

final registerEventHandlerCallRecord = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'unregisterEventHandler');
expect(registerEventHandlerCallRecord.length, 0);
});

test('unregisterEventHandlers after disposed', () async {
final _FakeNativeBindingDelegateMessenger messenger =
_FakeNativeBindingDelegateMessenger();
final _FakeNativeBindingDelegate nativeBindingDelegate =
_FakeNativeBindingDelegate(
messenger.getSendPort(),
);
final _FakeIrisEvent irisEvent = _FakeIrisEvent(messenger.getSendPort());
final NativeBindingsProvider nativeBindingsProvider =
_FakeNativeBindingDelegateProvider(nativeBindingDelegate, irisEvent);

final irisMethodChannel = IrisMethodChannel();
await irisMethodChannel.initilize(nativeBindingsProvider);
await irisMethodChannel.dispose();

const key = TypedScopedKey(_TestEventLoopEventHandler);
final eventHandler = _TestEventLoopEventHandler();
await irisMethodChannel.registerEventHandler(
ScopedEvent(
scopedKey: key,
registerName: 'registerEventHandler',
unregisterName: 'unregisterEventHandler',
handler: eventHandler),
jsonEncode({}));
await irisMethodChannel.unregisterEventHandlers(key);

final DisposableScopedObjects? subScopedObjects =
irisMethodChannel.scopedEventHandlers.get(key);
expect(subScopedObjects, isNull);

final registerEventHandlerCallRecord = messenger.callApiRecords
.where((e) => e.methodCall.funcName == 'unregisterEventHandler');
expect(registerEventHandlerCallRecord.length, 0);
});

test('registerEventHandler 2 times', () async {
final irisMethodChannel = IrisMethodChannel();
await irisMethodChannel.initilize(nativeBindingsProvider);
Expand Down

0 comments on commit 0fa19c2

Please sign in to comment.