import 'dart:developer'; import 'dart:io'; import 'package:hmg_qline/services/logger_service.dart'; import 'package:hmg_qline/utilities/enums.dart'; import 'package:http/io_client.dart'; import 'package:hmg_qline/constants/app_constants.dart'; import 'package:signalr_core/signalr_core.dart'; abstract class SignalrRepo { Future startHubConnection({ required String deviceIp, required Function(List?) onHubTicketCall, required Function(dynamic) onHubConfigCall, required Function(dynamic) onHubConnecting, required Function(dynamic) onHubReconnected, required Function(dynamic) onHubDisconnected, }); } class SignalrRepoImp implements SignalrRepo { HubConnection? connection; LoggerService loggerService; bool get isConnected => connection?.state == HubConnectionState.connected; SignalrRepoImp({this.connection, required this.loggerService}); @override Future startHubConnection({ required String deviceIp, required Function(List?) onHubTicketCall, required Function(dynamic) onHubConfigCall, required Function(dynamic) onHubConnecting, required Function(dynamic) onHubReconnected, required Function(dynamic) onHubDisconnected, }) async { try { String hubBaseURL = ApiConstants.baseUrlHub; if ((connection != null) && (connection!.state == HubConnectionState.connected || connection!.state == HubConnectionState.connecting)) { return true; } connection = HubConnectionBuilder() .withUrl( "$hubBaseURL?IPAddress=$deviceIp", HttpConnectionOptions( client: IOClient(HttpClient()..badCertificateCallback = (x, y, z) => true), logging: (level, message) => log(message), )) .withAutomaticReconnect() .build(); connection!.serverTimeoutInMilliseconds = 120000; int reconnectAttempts = 0; const int maxReconnectAttempts = 10; const Duration reconnectDelay = Duration(seconds: 5); connection!.onclose((exception) async { log(exception.toString()); onHubDisconnected(exception); if (reconnectAttempts < maxReconnectAttempts) { reconnectAttempts++; loggerService.logToFile(message: "SignalR reconnect attempt #$reconnectAttempts", source: "startHubConnection -> signalR_repo.dart", type: LogTypeEnum.data); await Future.delayed(reconnectDelay); try { await connection!.start(); loggerService.logToFile(message: "SignalR reconnected after disconnect", source: "startHubConnection -> signalR_repo.dart", type: LogTypeEnum.data); reconnectAttempts = 0; // Reset on success } catch (e) { loggerService.logError("Reconnect failed: $e"); } } else { loggerService.logError("Max SignalR reconnect attempts reached."); } }); connection!.onreconnecting((exception) => onHubConnecting(exception)); connection!.onreconnected((connectionId) { log(connectionId.toString()); onHubReconnected(connectionId); }); connection!.on(ApiConstants.sendQLinePatientCall, (List? message) { onHubTicketCall(message); }); connection!.on(ApiConstants.sendQLineConfig, (List? message) { onHubConfigCall(message); }); await connection!.start(); return true; } catch (e) { loggerService.logError(e.toString()); loggerService.logToFile(message: e.toString(), source: "startHubConnection -> signalR_repo.dart", type: LogTypeEnum.error); return false; } } bool getHubConnectionState() { if (connection == null) return false; log("connectionState: ${connection!.state}"); if (connection!.state == HubConnectionState.connected || connection!.state == HubConnectionState.connecting) return true; if (connection!.state == HubConnectionState.disconnected || connection!.state == HubConnectionState.disconnecting) return false; return false; } closeConnection() async { if (connection!.state == HubConnectionState.connected || connection!.state == HubConnectionState.connecting) { await connection!.stop(); } } }