connect method

Future<void> connect()

Connect to Lavalink WebSocket

Implementation

Future<void> connect() async {
  if (_isConnecting || _socket != null) {
    LavalinkLogger.warning('Already connected or connecting', tag: 'WebSocket');
    return;
  }

  _isConnecting = true;
  _intentionallyClosed = false;

  int retries = 0;
  const maxRetries = 5;
  Duration delay = Duration(seconds: 1);

  while (retries < maxRetries) {
    try {
      final uri = '${useSSL ? 'wss' : 'ws'}://$host:$port/v4/websocket';

      LavalinkLogger.info(
        'Connecting to Lavalink WebSocket: $uri (attempt ${retries + 1}/$maxRetries)',
        tag: 'WebSocket',
      );

      _socket = await WebSocket.connect(
        uri,
        headers: {
          'Authorization': password,
          'User-Id': userId,
          'Client-Name': 'Milter/1.0',
        },
      ).timeout(
        Duration(seconds: 15),
        onTimeout: () {
          throw TimeoutException('WebSocket connection timeout after 15 seconds');
        },
      );

      LavalinkLogger.info('✅ WebSocket connected successfully!', tag: 'WebSocket');
      _reconnectAttempts = 0;
      _startHeartbeat();

      _socket!.listen(
        _handleMessage,
        onError: _handleError,
        onDone: _handleClose,
        cancelOnError: false,
      );

      _isConnecting = false;
      return; // Success!

    } on SocketException catch (e) {
      retries++;
      LavalinkLogger.error(
        'SocketException (attempt $retries/$maxRetries): ${e.message}',
        tag: 'WebSocket',
        error: e,
      );

      if (retries >= maxRetries) {
        _isConnecting = false;
        throw LavalinkConnectionException(
          'Failed to connect to Lavalink WebSocket after $maxRetries attempts.\n'
          'URL: ws://$host:$port/v4/websocket\n'
          'Error: ${e.message}\n\n'
          'Troubleshooting:\n'
          '1. Make sure Lavalink is running (check with: netstat -an | findstr :2333)\n'
          '2. Verify host and port in your config\n'
          '3. Check Lavalink logs for errors\n'
          '4. Ensure no firewall is blocking port $port',
          cause: e,
        );
      }

      LavalinkLogger.info('Retrying in ${delay.inSeconds} seconds...', tag: 'WebSocket');
      await Future.delayed(delay);
      delay *= 2; // Exponential backoff

    } on TimeoutException catch (e) {
      retries++;
      LavalinkLogger.error(
        'Connection timeout (attempt $retries/$maxRetries)',
        tag: 'WebSocket',
        error: e,
      );

      if (retries >= maxRetries) {
        _isConnecting = false;
        throw LavalinkConnectionException(
          'WebSocket connection timeout after $maxRetries attempts.\n'
          'URL: ws://$host:$port/v4/websocket\n\n'
          'Lavalink may be slow to respond or not running properly.\n'
          'Check Lavalink logs and server status.',
          cause: e,
        );
      }

      await Future.delayed(delay);
      delay *= 2;

    } catch (e) {
      _isConnecting = false;
      LavalinkLogger.error(
        'Unexpected error while connecting to WebSocket',
        tag: 'WebSocket',
        error: e,
      );
      throw LavalinkException(
        'WebSocket connection error: $e\n'
        'Host: $host:$port\n'
        'SSL: $useSSL\n\n'
        'Make sure Lavalink is running and accessible.',
        cause: e,
      );
    }
  }

  _isConnecting = false;
}