shamblett / coap

A Coap package for dart
Other
16 stars 13 forks source link

Unhandled Exception: Bad state: Cannot add new events after calling close #8

Closed thejoker101 closed 3 years ago

thejoker101 commented 3 years ago

I'm trying to use this package in a flutter app. I'm using the example here - coap/example/flutter/lib/main.dart. When I press the Floating Action Button, it connects to my simple node.js server and displays the response text. However, if I press that button again, I get the exception below. Actually, it appears to be in some sort of Timer, so it just repeats the same error over and over again.

[   +8 ms] E/flutter (22091): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: Bad state: Cannot add new events after calling close
[        ] E/flutter (22091): #0      _BroadcastStreamController.add (dart:async/broadcast_stream_controller.dart:249:24)
[        ] E/flutter (22091): #1      EventBus.fire (package:event_bus/event_bus.dart:61:22)
[        ] E/flutter (22091): #2      CoapEventBus.fire (package:coap/src/event/coap_event_bus.dart:153:17)
[        ] E/flutter (22091): #3      CoapEndPoint.sendRequest (package:coap/src/net/coap_endpoint.dart:177:15)
[        ] E/flutter (22091): #4      CoapStackBottomLayer.sendRequest (package:coap/src/stack/coap_layer_stack.dart:110:21)
[        ] E/flutter (22091): #5      CoapNextLayer.sendRequest (package:coap/src/stack/coap_layer_stack.dart:20:10)
[        ] E/flutter (22091): #6      CoapAbstractLayer.sendRequest (package:coap/src/stack/coap_abstract_layer.dart:18:15)
[        ] E/flutter (22091): #7      CoapReliabilityLayer.sendRequest (package:coap/src/stack/coap_reliability_layer.dart:140:11)
[        ] E/flutter (22091): #8      CoapNextLayer.sendRequest (package:coap/src/stack/coap_layer_stack.dart:20:10)
[        ] E/flutter (22091): #9      CoapAbstractLayer.sendRequest (package:coap/src/stack/coap_abstract_layer.dart:18:15)
[        ] E/flutter (22091): #10     CoapTokenLayer.sendRequest (package:coap/src/stack/coap_token_layer.dart:28:11)
[        ] E/flutter (22091): #11     CoapNextLayer.sendRequest (package:coap/src/stack/coap_layer_stack.dart:20:10)
[        ] E/flutter (22091): #12     CoapAbstractLayer.sendRequest (package:coap/src/stack/coap_abstract_layer.dart:18:15)
[        ] E/flutter (22091): #13     CoapBlockwiseLayer.sendRequest (package:coap/src/stack/coap_blockwise_layer.dart:56:13)
[        ] E/flutter (22091): #14     CoapNextLayer.sendRequest (package:coap/src/stack/coap_layer_stack.dart:20:10)
[        ] E/flutter (22091): #15     CoapAbstractLayer.sendRequest (package:coap/src/stack/coap_abstract_layer.dart:18:15)
[        ] E/flutter (22091): #16     CoapNextLayer.sendRequest (package:coap/src/stack/coap_layer_stack.dart:20:10)
[        ] E/flutter (22091): #17     CoapAbstractLayer.sendRequest (package:coap/src/stack/coap_abstract_layer.dart:18:15)
[        ] E/flutter (22091): #18     CoapStackTopLayer.sendRequest (package:coap/src/stack/coap_layer_stack.dart:66:11)
[        ] E/flutter (22091): #19     CoapLayerStack.sendRequest (package:coap/src/stack/coap_layer_stack.dart:136:17)
[        ] E/flutter (22091): #20     CoapEndPoint.sendEpRequest.<anonymous closure> (package:coap/src/net/coap_endpoint.dart:82:37)
[        ] E/flutter (22091): #21     CoapExecutor.start.<anonymous closure> (package:coap/src/threading/coap_executor.dart:18:11)
[        ] E/flutter (22091): #22     _Executor.scheduleTask (package:executor/src/executor_impl.dart:61:29)
[        ] E/flutter (22091): <asynchronous suspension>
[        ] E/flutter (22091): #23     CoapExecutor.start (package:coap/src/threading/coap_executor.dart:17:14)
[        ] E/flutter (22091): #24     CoapEndPoint.sendEpRequest (package:coap/src/net/coap_endpoint.dart:82:14)
[        ] E/flutter (22091): #25     CoapRequest.send (package:coap/src/coap_request.dart:120:14)
[        ] E/flutter (22091): #26     CoapClient.send (package:coap/src/coap_client.dart:271:20)
[        ] E/flutter (22091): <asynchronous suspension>
[        ] E/flutter (22091): #27     CoapClient.get (package:coap/src/coap_client.dart:109:12)
[        ] E/flutter (22091): #28     _CoapScreenState._loadData (package:bbqtech/ui/test/coap.dart:264:50)
[        ] E/flutter (22091): #29     _CoapScreenState._buildTestButton.<anonymous closure> (package:bbqtech/ui/test/coap.dart:243:24)
[        ] E/flutter (22091): #30     _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:993:19)
[        ] E/flutter (22091): #31     _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:1111:38)
[        ] E/flutter (22091): #32     GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:183:24)
[        ] E/flutter (22091): #33     TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:598:11)
[        ] E/flutter (22091): #34     BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:287:5)
[        ] E/flutter (22091): #35     BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:222:7)
[        ] E/flutter (22091): #36     PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:476:9)
[        ] E/flutter (22091): #37     PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:77:12)
[        ] E/flutter (22091): #38     PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:122:9)
[        ] E/flutter (22091): #39     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
[        ] E/flutter (22091): #40     PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:120:18)
[        ] E/flutter (22091): #41     PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:106:7)
[        ] E/flutter (22091): #42     GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:358:19)
[        ] E/flutter (22091): #43     GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:338:22)
[        ] E/flutter (22091): #44     RendererBinding.dispatchEvent (package:flutter/src/rendering/binding.dart:267:11)
[        ] E/flutter (22091): #45     GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:295:7)
[        ] E/flutter (22091): #46     GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:240:7)
[        ] E/flutter (22091): #47     GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:213:7)
[        ] E/flutter (22091): #48     _rootRunUnary (dart:async/zone.dart:1206:13)
[        ] E/flutter (22091): #49     _CustomZone.runUnary (dart:async/zone.dart:1100:19)
[        ] E/flutter (22091): #50     _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
[        ] E/flutter (22091): #51     _invoke1 (dart:ui/hooks.dart:265:10)
[        ] E/flutter (22091): #52     _dispatchPointerDataPacket (dart:ui/hooks.dart:174:5)
thejoker101 commented 3 years ago

I think it might be this bit here in coap_event_bus.dart:

  void fire(dynamic event) {
    if (!_destroyed) {
      lastEvent = event;
      _eventBus.fire(event);
    } else {
      _log.warn('Event Bus - attempting to raise event on '
          'destroyed event bus : $event');
    }
  }

It looks like _destroyed is never set to true in destroy()

thejoker101 commented 3 years ago

Changing _destroy to be bool _destroyed = false; and modifying destroy() to look like this

/// Destroy
  void destroy() {
    _eventBus.destroy();
    _destroyed = true;
  }

does fix the exception, however things are still not correct it seems. These warnings are still in the logs:

[        ] I/flutter ( 9248): 2020-10-15 15:23:39.436: INFO: >> Reliability - sending request, failed transmission count: 0
[        ] I/flutter ( 9248): 2020-10-15 15:23:39.436: INFO: >> Reliability - Retransmission timeout is 3444 ms
[        ] I/flutter ( 9248): 2020-10-15 15:23:39.437: INFO: >> Matcher - Stored open request by KeyID[32090]) + KeyToken[00001634]
[        ] I/flutter ( 9248): 2020-10-15 15:23:39.438: WARNING: >> Event Bus - attempting to raise event on destroyed event bus : Instance of 'CoapSendingRequestEvent'
[ +199 ms] I/flutter ( 9248): 2020-10-15 15:23:39.637: WARNING: >> Event Bus - attempting to raise event on destroyed event bus : Instance of 'CoapDataReceivedEvent'
[+3242 ms] I/flutter ( 9248): 2020-10-15 15:23:42.882: WARNING: >> Reliability - Retransmission timeout elapsed
[        ] I/flutter ( 9248): 2020-10-15 15:23:42.882: WARNING: >> Reliability - Timeout: retransmit message, failed count: 1 message: 32090
thejoker101 commented 3 years ago

My guess is the issue is because the _eventBus is a static singleton that's being reused.

shamblett commented 3 years ago

OK, the flutter example didn't come from me, it was added by user @pedromassango on #5 I'm not a flutter user so have no idea if this still works or has ever worked for that matter, may be better to contact him directly on how this is supposed to work.

You right in the fact that the event bus can't be re-used, the package is not intended for multiple instantiations at the moment, in my other packages the event bus is instance specific, I've not got round to updating this [package yet.

thejoker101 commented 3 years ago

OK, the flutter example didn't come from me, it was added by user @pedromassango on #5 I'm not a flutter user so have no idea if this still works or has ever worked for that matter, may be better to contact him directly on how this is supposed to work.

You right in the fact that the event bus can't be re-used, the package is not intended for multiple instantiations at the moment, in my other packages the event bus is instance specific, I've not got round to updating this [package yet.

Thanks, I was thinking the issue was more with the example flutter code. I'll close this issue.

FWIW, if anyone else comes across this page and has this issue. I modified the Flutter example as below and now you can click the load button all you want without Exceptions.

import 'package:coap/coap.dart';
import 'package:flutter/material.dart';
import 'config/coap_config.dart';

void main() => runApp(MyApp());

/// make linter happy
class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     title: 'Flutter Demo',
     theme: ThemeData(
       primarySwatch: Colors.blue,
     ),
     home: MyHomePage(),
   );
 }
}

/// make linter happy
class MyHomePage extends StatefulWidget {
 @override
 _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
 String _data;
 bool _isLoading = false;

 final _config = CoapConfig();

 final host = 'coap.me';

 // Client
 CoapClient _client;

 @override
 void didChangeDependencies() {
   super.didChangeDependencies();

   _client = CoapClient(
       Uri(scheme: 'coap', host: _host, port: _config.defaultPort), _config);
 }

 Future<void> _loadData() async {
   try {
     // Create the request for the get request
     final CoapRequest request = CoapRequest.newGet();

     request.addUriPath('hello');
     _client.request = request;

     setState(() => _isLoading = true);

     final CoapResponse response = await _client.get();
     setState(() {
       _isLoading = false;
       _data = response?.payloadString ?? 'No Data';
     });

   } catch (e) {
     log.e("Caught Error Doing COAP Stuff", e);
   }
 }

 @override
 Widget build(BuildContext context) => Scaffold(
     appBar: AppBar(
       title: const Text('Flutter CoAP'),
     ),
     body: Center(
       child: Builder(
         builder: (_) {
           if (_isLoading) {
             return const CircularProgressIndicator();
           }

           if (_data != null) {
             return Text('Response:\n $_data',
               textAlign: TextAlign.center,
               style: const TextStyle(fontSize: 18)
             );
           }
           return const Text('Press the button to load data');
         },
       ),
     ),
     floatingActionButton: FloatingActionButton(
       onPressed: _loadData,
       tooltip: 'Load',
       child: Icon(Icons.cloud_download),
     ),
   );
}
pedromassango commented 3 years ago

Hi @thejoker101 so the issue is not related to the code sample right?

thejoker101 commented 3 years ago

Hi @thejoker101 so the issue is not related to the code sample right?

The example here is what I changed with the code above.

The main difference is moving the _client instantiation out of _loadData and not calling client.close(); at the end of _loadData because once it's closed, it can't be re-used.

anayajoshi commented 3 years ago

Hi @thejoker101 so the issue is not related to the code sample right?

The example here is what I changed with the code above.

The main difference is moving the _client instantiation out of _loadData and not calling client.close(); at the end of _loadData because once it's closed, it can't be re-used.

I have tried this for put request. But after, it works for sometime. But after sometime, after about 20-25 requests, the app does not send commands, also the coap server gets hang. Please guide.