Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The underlying connection was closed before the hub handshake could complete. #114

Open
MrAzimzadeh opened this issue Sep 19, 2024 · 1 comment

Comments

@MrAzimzadeh
Copy link

Full Code

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:legalis/api/api_service.dart';
import 'package:legalis/provider/chat/chat_detail_provider.dart';
import 'package:legalis/provider/communication/communication_provider.dart';
import 'package:logger/logger.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:signalr_netcore/itransport.dart';
import 'package:signalr_netcore/json_hub_protocol.dart';
import 'package:signalr_netcore/signalr_client.dart';

class ChatPage extends StatefulWidget {
  ChatPage({super.key, required this.id});

  final String? id;

  @override
  State<ChatPage> createState() => _ChatPageState();
}

class _ChatPageState extends State<ChatPage> {
  late TextEditingController _controller;
  late HubConnection _hubConnection;
  bool _isConnected = false;

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController();
    _initSignalR();
  }

  Future<void> _initSignalR() async {
    ApiService apiService = ApiService();
    JsonHubProtocol protocol = JsonHubProtocol();
    _hubConnection = HubConnectionBuilder()
        .withUrl(
          "https://legalis-api.webconsole.az/hubaction",
          options: HttpConnectionOptions(
            transport: HttpTransportType.WebSockets,
            accessTokenFactory: () async {
              return await _getAccessToken(apiService) ?? '';
            },
            skipNegotiation: true,
            logger: null,
          ),
        )
        .withAutomaticReconnect()
        .build();

    // SignalR bağlantısını başlatmayı deneyin
    await _startConnection();
  }

  Future<String?> _getAccessToken(ApiService apiService) async {
    try {
      String? accessToken = await apiService.getAccessToken();
      Logger().i("Access Token: $accessToken");
      return accessToken;
    } catch (e) {
      Logger().d("Error fetching access token: $e");
      return null;
    }
  }

  Future<void> _startConnection() async {
    try {
      _hubConnection.onclose(({error}) => _onConnectionClose(error));
      _hubConnection.on("ReceiveMessage", (message) {
        Logger().i("Received: $message");
      });

      await _hubConnection.start();
      _isConnected = true;
      Logger().i("SignalR connected.");
      setState(() {});
    } catch (e) {
      Logger().e("Error starting SignalR connection: $e");
      await _retryConnection();
    }
  }

  void _onConnectionClose(Exception? error) {
    _isConnected = false;
    if (error != null) {
      Logger().e("Connection closed with error: $error");
      _retryConnection();
    } else {
      Logger().i("Connection closed gracefully.");
    }
    setState(() {});
  }

  Future<void> _retryConnection() async {
    const int maxRetries = 5;
    int retryCount = 0;

    while (retryCount < maxRetries && !_isConnected) {
      try {
        Logger().i("Retrying SignalR connection: Attempt ${retryCount + 1}");
        await _hubConnection.start();
        _isConnected = true;
        Logger().i("SignalR reconnected successfully.");
        break;
      } catch (e) {
        Logger().e("Retry $retryCount failed: $e");
        retryCount++;
        await Future.delayed(Duration(seconds: 5));
      }
    }

    if (!_isConnected) {
      Logger().e("Failed to reconnect after $maxRetries attempts.");
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    _hubConnection.stop(); // Bağlantıyı kapatmayı unutmayın
    super.dispose();
  }

  Future<String> refreshToken() async {
    final _prefs = await SharedPreferences.getInstance();
    ApiService apiService = ApiService();
    await apiService.init();
    var refreshToken = _prefs.getString('refresh_token');
    if (refreshToken != null) {
      try {
        final response = await apiService.dio.post(
          'Auth/refresh-token-login',
          data: {'refreshToken': refreshToken},
        );

        if (response.statusCode == 200) {
          final newAccessToken = response.data['access_token'];
          _prefs.setString('access_token', newAccessToken);
          _prefs.setString('refresh_token', response.data['refresh_token']);
          return newAccessToken;
        } else {
          throw Exception('Failed to refresh token: ${response.statusCode}');
        }
      } catch (e) {
        Logger().e("Error refreshing token: $e");
        throw e;
      }
    }
    throw Exception('Refresh token is null');
  }

  Future<void> sendMessage(String message, {required String receiverId}) async {
    if (_isConnected) {
      await _hubConnection.invoke("SendMessage",
          args: [message, receiverId]).onError((error, stackTrace) {
        Logger().e("Error sending message: $error");
      });
    } else {
      Logger().e("Cannot send message: Not connected to the server.");
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF000E2B),
      appBar: AppBar(
        elevation: 0,
        automaticallyImplyLeading: false,
        leadingWidth: 0,
        shadowColor: Colors.transparent,
        foregroundColor: Colors.transparent,
        surfaceTintColor: Colors.transparent,
        backgroundColor: const Color(0xFF000E2B),
        title: Row(
          children: [
            Container(
              width: 14,
              height: 14,
              decoration: const ShapeDecoration(
                color: Color(0xFF34A853),
                shape: OvalBorder(),
              ),
            ),
            const SizedBox(width: 10),
            const Expanded(
              child: SizedBox(
                child: Text(
                  'Məhəmməd Məhəmməd Məhəmməd Məhəmməd Məhəmməd Məhəmməd Vekil',
                  style: TextStyle(
                    color: Colors.white,
                    overflow: TextOverflow.ellipsis,
                    fontSize: 20,
                    fontWeight: FontWeight.w600,
                    letterSpacing: 0.38,
                  ),
                ),
              ),
            ),
          ],
        ),
        actions: [
          GestureDetector(
            onTap: () {
              context.pushNamed('callpage', queryParameters: {'id': '1'});
            },
            child: Container(
              width: 46,
              height: 46,
              margin: const EdgeInsets.only(right: 20),
              child: SvgPicture.asset('assets/icons/call_user.svg'),
            ),
          )
        ],
      ),
      body: SafeArea(
        child: Container(
          padding: const EdgeInsets.symmetric(horizontal: 20),
          child: Column(
            children: [
              Expanded(
                child: Column(
                  children: [
                    Expanded(
                      child: Consumer<ChatDetailProvider>(
                        builder: (context, provider, child) {
                          return ListView.builder(
                            padding: const EdgeInsets.only(
                              top: 20,
                            ),
                            reverse: true,
                            itemCount: provider.chatList.length,
                            itemBuilder: (context, index) {
                              bool isSameUser = index > 0 &&
                                  provider.chatList[index].isMe ==
                                      provider.chatList[index - 1].isMe;
                              return Align(
                                alignment: provider.chatList[index].isMe
                                    ? Alignment.centerRight
                                    : Alignment.centerLeft,
                                child: Stack(
                                  children: [
                                    Container(
                                      padding: EdgeInsets.only(
                                        top: 12,
                                        left: 10,
                                        bottom: provider.chatList[index].isMe
                                            ? 13
                                            : 13,
                                        right: 7,
                                      ),
                                      margin: EdgeInsets.only(
                                        bottom: isSameUser ? 5 : 10,
                                        top: isSameUser ? 5 : 10,
                                      ),
                                      width: MediaQuery.of(context).size.width *
                                          0.6,
                                      decoration: BoxDecoration(
                                        color: provider.chatList[index].isMe
                                            ? const Color.fromRGBO(3, 44, 96, 1)
                                            : const Color(0xFF3467E4),
                                        borderRadius: BorderRadius.only(
                                          topLeft: const Radius.circular(20),
                                          topRight: const Radius.circular(20),
                                          bottomRight:
                                              provider.chatList[index].isMe
                                                  ? Radius.zero
                                                  : const Radius.circular(20),
                                          bottomLeft:
                                              provider.chatList[index].isMe
                                                  ? const Radius.circular(20)
                                                  : Radius.zero,
                                        ),
                                      ),
                                      child: Text(
                                        provider.chatList[index].txt,
                                        style: const TextStyle(
                                          color: Colors.white,
                                          fontSize: 16,
                                          fontWeight: FontWeight.w500,
                                        ),
                                      ),
                                    ),
                                  ],
                                ),
                              );
                            },
                          );
                        },
                      ),
                    ),
                    Align(
                      alignment: Alignment.bottomCenter,
                      child: Consumer<CommunicationProvider>(
                        builder: (context, provider, child) {
                          return provider.isConnected
                              ? Container(
                                  margin: const EdgeInsets.only(
                                      left: 0, right: 0, bottom: 16),
                                  child: Row(
                                    mainAxisAlignment:
                                        MainAxisAlignment.spaceBetween,
                                    children: [
                                      Expanded(
                                        child: Container(
                                          margin:
                                              const EdgeInsets.only(right: 11),
                                          constraints: const BoxConstraints(
                                            minHeight: 52,
                                            maxHeight: 100,
                                          ),
                                          child: TextField(
                                            controller: _controller,
                                            cursorColor: Colors.white,
                                            maxLines: 3,
                                            minLines: 1,
                                            keyboardType:
                                                TextInputType.multiline,
                                            style: const TextStyle(
                                              color: Colors.white,
                                              fontSize: 18,
                                              fontWeight: FontWeight.w400,
                                            ),
                                            decoration: InputDecoration(
                                              hintText:
                                                  '${AppLocalizations.of(context)?.enterMessage}...',
                                              hintStyle: const TextStyle(
                                                color: Color(0xFFABB0BC),
                                                fontSize: 18,
                                                fontWeight: FontWeight.w400,
                                              ),
                                              border: OutlineInputBorder(
                                                borderRadius:
                                                    BorderRadius.circular(20),
                                                borderSide: BorderSide.none,
                                              ),
                                              filled: true,
                                              fillColor: const Color.fromRGBO(
                                                  51, 62, 85, 1),
                                            ),
                                          ),
                                        ),
                                      ),
                                      GestureDetector(
                                        onTap: () {
                                          if (_controller.text.isNotEmpty) {
                                            Provider.of<ChatDetailProvider>(
                                                    context,
                                                    listen: false)
                                                .sendMessage(_controller.text,
                                                    receiverId:
                                                        widget.id ?? '');
                                            _controller.clear();
                                          }
                                        },
                                        child: Container(
                                          width: 52,
                                          height: 52,
                                          child: SvgPicture.asset(
                                            'assets/icons/send_icon.svg',
                                            width: 52,
                                            height: 52,
                                          ),
                                        ),
                                      ),
                                    ],
                                  ),
                                )
                              : Container(
                                  width: MediaQuery.of(context).size.width,
                                  height: 44,
                                  alignment: Alignment.center,
                                  margin: const EdgeInsets.only(
                                      left: 0, right: 0, bottom: 16),
                                  padding: const EdgeInsets.all(10),
                                  decoration: ShapeDecoration(
                                    color: const Color(0xFF6A6A6A),
                                    shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(10),
                                    ),
                                  ),
                                  child: const Text(
                                    'Bu söhbət artıq yekunlaşıb.',
                                    style: TextStyle(
                                      color: Colors.white,
                                      fontSize: 16,
                                      fontWeight: FontWeight.w500,
                                    ),
                                  ),
                                );
                        },
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
@MrAzimzadeh
Copy link
Author

My Logs
────────────────────────────────────────────────────────────
E/flutter (21550): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: WebSocketChannelException: Instance of 'WebSocketException'
E/flutter (21550):
I/flutter (21550): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): │ #0 _ChatPageState._retryConnection (package:legalis/screens/pages/message/chat_page.dart:110:18)
I/flutter (21550): │ #1
I/flutter (21550): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter (21550): │ ⛔ Retry 2 failed: The underlying connection was closed before the hub handshake could complete.
I/flutter (21550): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): │ #0 _ChatPageState._retryConnection (package:legalis/screens/pages/message/chat_page.dart:104:18)
I/flutter (21550): │ #1
I/flutter (21550): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter (21550): │ 💡 Retrying SignalR connection: Attempt 4
I/flutter (21550): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): │ #0 _ChatPageState._getAccessToken (package:legalis/screens/pages/message/chat_page.dart:62:16)
I/flutter (21550): │ #1
I/flutter (21550): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter (21550): │ 💡 Access Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZWdoZ2hTYWxhbV84ODA3YmVkNC1jYjIzLTRiYmYtYWEwMi01YzdlNjI3NDdiNGIiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6ImRiMTk1NjRiLWViODctNDUxYS1hODA5LWUxZjlmNmU3MjI1ZSIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6InNhbGFtQGdtYWlsLmNvbSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluIiwiZXhwIjoxNzI2NzU0NjExLCJpc3MiOiJodHRwczovL2xhd3llci5heiIsImF1ZCI6Imh0dHBzOi8vbGF3eWVyLmF6In0.Bi8hc1Lm-0VEgc7Dy-mbzUPI2mFY-zsLyrvUezGdNXI
I/flutter (21550): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
E/flutter (21550): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: WebSocketChannelException: Instance of 'WebSocketException'
E/flutter (21550):
I/flutter (21550): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): │ #0 _ChatPageState._retryConnection (package:legalis/screens/pages/message/chat_page.dart:110:18)
I/flutter (21550): │ #1
I/flutter (21550): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter (21550): │ ⛔ Retry 3 failed: The underlying connection was closed before the hub handshake could complete.
I/flutter (21550): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): │ #0 _ChatPageState._retryConnection (package:legalis/screens/pages/message/chat_page.dart:104:18)
I/flutter (21550): │ #1
I/flutter (21550): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter (21550): │ 💡 Retrying SignalR connection: Attempt 5
I/flutter (21550): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): │ #0 _ChatPageState._getAccessToken (package:legalis/screens/pages/message/chat_page.dart:62:16)
I/flutter (21550): │ #1
I/flutter (21550): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter (21550): │ 💡 Access Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiZWdoZ2hTYWxhbV84ODA3YmVkNC1jYjIzLTRiYmYtYWEwMi01YzdlNjI3NDdiNGIiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6ImRiMTk1NjRiLWViODctNDUxYS1hODA5LWUxZjlmNmU3MjI1ZSIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6InNhbGFtQGdtYWlsLmNvbSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvcm9sZSI6IkFkbWluIiwiZXhwIjoxNzI2NzU0NjExLCJpc3MiOiJodHRwczovL2xhd3llci5heiIsImF1ZCI6Imh0dHBzOi8vbGF3eWVyLmF6In0.Bi8hc1Lm-0VEgc7Dy-mbzUPI2mFY-zsLyrvUezGdNXI
I/flutter (21550): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
E/flutter (21550): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: WebSocketChannelException: Instance of 'WebSocketException'
E/flutter (21550):
I/flutter (21550): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): │ #0 _ChatPageState._retryConnection (package:legalis/screens/pages/message/chat_page.dart:110:18)
I/flutter (21550): │ #1
I/flutter (21550): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter (21550): │ ⛔ Retry 4 failed: The underlying connection was closed before the hub handshake could complete.
I/flutter (21550): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter (21550): │ #0 _ChatPageState._retryConnection (package:legalis/screens/pages/message/chat_page.dart:117:16)
I/flutter (21550): │ #1
I/flutter (21550): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter (21550): │ ⛔ Failed to reconnect after 5 attempts.
I/flutter (21550): └─────────────────────────────────────────

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant