dart-lang / web_socket_channel

StreamChannel wrappers for WebSockets.
https://pub.dev/packages/web_socket_channel
BSD 3-Clause "New" or "Revised" License
424 stars 112 forks source link

There is not way to get acknowledgement of sent messages. #373

Open shahbazhashmi opened 5 months ago

shahbazhashmi commented 5 months ago

Below is my code. Everything work like a charm but there is no way to know if my message is sent to server or not. I want to know that because sometimes I send message but the server does not forward it to the recipient. Plugin like https://pub.dev/packages/websocket_universal already support that but I do not want to go with that as it is not well maintained and has very less stars.

class WebSocketBloc {
  static WebSocketBloc of(final BuildContext context) => Provider.of(context);

  final _wsUrl = 'ws://${baseIp}ws/chat/';
  WebSocketChannel? _channel;

  ValueListenable<WsChatResponse?> get message => _message;
  final ValueNotifier<WsChatResponse?> _message = ValueNotifier(null);

  ValueListenable<bool> get isChannelConnected => _isChannelConnected;
  final ValueNotifier<bool> _isChannelConnected = ValueNotifier(false);

  static const _tag = 'WebSocketBloc';

  // make sure that this method called on entry point of internal app features
  Future<void> initChat(
    final int myUserId,
  ) async {
    try {
      if (_isChannelConnected.value) {
        logD(_tag, message: 'WS is already connected');
        return;
      }
      _channel = WebSocketChannel.connect(
        Uri.parse('$_wsUrl$myUserId/'),
      );
      await _channel?.ready;
      _isChannelConnected.value = true;
      logD(_tag, message: 'WS connected');

      _channel?.stream.listen((final message) {
        logD(_tag, message: 'message received - $message');
        try {
          final jsonString = message as String?;
          if (jsonString == null) {
            throw Exception('got null message');
          }
          final response = WsChatResponse.fromJsonString(jsonString);
          _message.value = response;
          logD(_tag, message: 'message published - $message');
        } catch (e) {
          logE(_tag, message: e.toString());
        }
      });
    } catch (e) {
      logE(_tag, message: e.toString());
    }
  }

  bool sendMessage(final WsChatRequest chatRequest) {
    if (!_isChannelConnected.value) {
      return false;
    }
    logD(_tag, message: 'message sent - ${chatRequest.text}');
    final request = chatRequest.toJsonEncodedString();
    _channel?.sink.add(request);
    return true;
  }

  Future<void> dispose() async {
    _isChannelConnected.value = false;
    logD(_tag, message: 'WS disposed');
    await _channel?.sink.close();
    _channel = null;
  }
}
leeyisoft commented 3 months ago

websocket sends and delivers messages asynchronously and does not have a synchronous response like http requests do, so you need to implement the message acknowledgment mechanism yourself