mqtt_client icon indicating copy to clipboard operation
mqtt_client copied to clipboard

Support WebAssembly compilation

Open NotTsunami opened this issue 1 year ago • 4 comments

This is a PR to address #503 and support WebAssembly compilation. Due to the testing required and additional work to be done, this PR was opened as a draft.

What this commit does:

  • Upgrades dependencies to their minimum necessary version to support pkg:web. This should support pkg:web 0.4.2 <= 0.5.1, so Flutter users on Flutter 3.19.5 should be able to use the project, as well as Flutter users on Flutter master
    • As a follow up to this, it pushes the required Dart version to at least 3.3.0. This is shipped with Flutter 3.19, so this is fine, but this definitely requires a major version increase from this library.
  • d7eec87d5f151e09d006fab73a68346202d31719 is reverted because I do not believe this is necessary (it is also a blocker in moving to pkg:web). MqttBrowserClient is a class purely targeted for browsers, so it should not be handling non-browser environments. I am currently using mqtt_client in a monorepo solution that targets desktop + web, and was able to solve #509 using conditional imports.
    • The new way to use conditional imports is to check against dart.library.js_interop instead of dart.html, so the universal example is updated to reflect that (see https://dart.dev/interop/js-interop/package-web#conditional-imports).
  • The old example/aws_iot_cognito.dart is deleted, and the sigv4 dependency is removed. AWS Amplify is the suggested framework for working with AWS now, along with it being first party. The recently added aws_iot_cognito_amplify.dart does a lot of heavy lifting and showcases how to use MQTT with AWS. Dropping example/aws_iot_cognito.dart is probably acceptable.

What work still needs to get done:

  • Testing! And more testing. This needs to be thoroughly tested in multiple environments and workflows to ensure nothing is broken. WebAssembly compilation for Flutter is very new, and has a lot of moving parts, hence why the version constraint on pkg:web is so tight. It can probably be loosened in the future.
  • ~~In example/aws_iot_cognito_amplify.dart, the portion regarding the policy attachment has been commented out as it relied on the now-removed sigv4 dependency. I'm not familiar enough with AWS or AWS Amplify to know if this portion is still necessary or how to update it with AWS Amplify functions.~~

NotTsunami avatar Apr 03 '24 19:04 NotTsunami

I should have the bandwidth to do some proper testing on this during this coming weekend (as well as resolve the conflict). I'm still not familiar enough with AWS to know rather the policy attachment code is still necessary/how to fix.

NotTsunami avatar Apr 23 '24 20:04 NotTsunami

Ok thanks leave AWS for now we can address this later when we know we have a good working package.

shamblett avatar Apr 24 '24 06:04 shamblett

@shamblett Hey Steve. I'm back on this again because we have returned to using MQTT at my work, so I am able to work on this as an extension of my work. I rebased this yesterday and reapplied the changes, but I'm noticing something very odd. We are using the nanomq broker (version 0.22.2), and I am unable to connect like normal on the web side at all (Not using webassembly yet - just the regular Flutter web compiler). My connection setup looks like:

Future<void> initializeClient(String mClientID) async {
  final connMessage = MqttConnectMessage()
      .withClientIdentifier(mClientID)
      .withWillTopic('will')
      .withWillMessage('Client disconnected unexpectedly')
      .withWillQos(MqttQos.atLeastOnce)
      .startClean();

  client = MqttBrowserClient('ws://127.0.0.1/mqtt', mClientID)
    ..onConnected = onConnected
    ..onDisconnected = onDisconnected
    ..onUnsubscribed = onUnsubscribed
    ..onSubscribed = onSubscribed
    ..onSubscribeFail = onSubscribeFail
    ..pongCallback = pong
    ..keepAlivePeriod = 60
    ..port = 8083
    ..connectionMessage = connMessage
    ..autoReconnect = true
    ..websocketProtocols = MqttClientConstants.protocolsSingleDefault
    ..setProtocolV311();

  dPrint('MQTT_LOGS:: MQTT client connecting....');

  try {
    await client?.connect();
  } catch (e) {
    dPrint('MQTT_LOGS:: $e');
  }
}

I enabled logging, and I noticed the protocol version in the connection string was 3 instead of the expected 4. I changed the default in mqtt_client_protocol.dart to the V311 constants, and it instantly connected. Is there any reason it might not be respecting setProtocolV311()?

Aside from that, I'm still getting an exception when compiling to WebAssembly even with the local change to mqtt_client_protocol.dart, so this still isn't ready yet. I did clean up the AWS implementation to fully drop sigv4, but I don't have an environment to test this (yet).

NotTsunami avatar Aug 09 '24 15:08 NotTsunami

Hi Tyler.

Setting the ..setProtocolV311(); should work however whilst checking I've noticed a bug in the code, this only works if you declare your connect message after creating your client, i.e. in your code above put the connmessage after the browserclient creation.

I'll fix this, also I think I'll make 311 the default rather than 3, some brokers(as you have seen) are more sensitive to this than others. Most users/brokers will expect 311 these days.

Thanks for the web assembly work BTW. Please post any client logs you may have if you want me to look at anything.

shamblett avatar Aug 09 '24 15:08 shamblett

Merged this, any further work identified will be carried out on branch issue503

shamblett avatar Nov 12 '24 10:11 shamblett