connect method Null safety

Future<User> connect(
  1. {required String userId,
  2. String? nickname,
  3. String? accessToken,
  4. String? apiHost,
  5. String? wsHost,
  6. bool reconnect = false}
)

Connect websocket with given userId

apiHost and wsHost are optional in case to connect own server

Implementation

Future<User> connect({
  required String userId,
  String? nickname,
  String? accessToken,
  String? apiHost,
  String? wsHost,
  bool reconnect = false,
}) async {
  if (userId.isEmpty) {
    throw InvalidParameterError();
  }

  userId = userId.trim();
  String? sessionKey;

  logger.i('Attempting to connecting with $userId');
  // already connected
  if (_state.connected &&
      _webSocket?.isConnected() == true &&
      _state.userId == userId &&
      _state.currentUser != null) {
    logger.i('already connected with $userId, return user');
    return _state.currentUser!;
  }

  // is already in progress to connect
  if ((_state.connecting || _state.reconnecting) &&
      _state.userId == userId &&
      _loginCompleter != null &&
      !_forceReconnect) {
    logger.i('waiting to connect previous call with $userId');
    return _loginCompleter!.future;
  }

  if (reconnect) {
    sessionKey = await _sessionManager.getSessionKey();
    if (sessionKey == null || sessionKey.isEmpty) {
      ConnectionManager.flushCompleters(error: ConnectionRequiredError());
      _eventManager.notifyReconnectionFailed();
      throw ConnectionFailedError();
    }
    _eventManager.notifyReconnectionStarted();
  } else {
    // start from clean slate
    logger.i('clearing out previous connection');
    await logout();
  }

  // This has to be above any await for concurrent situation
  if (!_forceReconnect) _loginCompleter = Completer();
  await _webSocket?.close();

  _state.userId = userId;
  _state.connecting = true;

  _webSocket = WebSocketClient(
    onConnect: _onWebSocketConnect,
    onDisconnect: _onWebSocketDisconnect,
    onData: _onWebSocketData,
    onError: _onWebSocketError,
  );

  _sessionManager.setAccessToken(accessToken);

  final apiHostUrl =
      reconnect ? _state.apiHost! : apiHost ?? _getDefaultApiHost();
  final wsHostUrl =
      reconnect ? _state.wsHost! : wsHost ?? _getDefaultWsHost();

  _state
    ..reconnecting = reconnect
    ..apiHost = apiHostUrl
    ..wsHost = wsHostUrl;

  _api.initialize(baseUrl: apiHostUrl, headers: {
    'SB-User-Agent': _sbUserAgent,
    'SendBird': _sendbirdHeader,
  });

  var params = {
    if (nickname != null && nickname != '') 'nickname': nickname,
    if (reconnect && sessionKey != null)
      'key': sessionKey
    else
      'user_id': userId,
    'SB-User-Agent': _sbUserAgent,
    'include_extra_data': _extraDatas.join(','),
    'expiring_session': _eventManager.getSessionHandler() != null ? '1' : '0',
    'include_poll_details': '1',
    if (accessToken != null) 'access_token': accessToken,
  };
  params.addAll(_webSocketParams);

  final fullWsHost = wsHostUrl + '/?' + Uri(queryParameters: params).query;

  logger.i('websocket connecting.. ');
  try {
    await _webSocket?.connect(fullWsHost);
  } catch (e) {
    _state.connecting = false;
    _state.reconnecting = false;
    _loginCompleter = null;
    _forceReconnect = false;
    rethrow;
  }

  final user = await _loginCompleter!.future.timeout(
      Duration(seconds: options.connectionTimeout), onTimeout: () async {
    logger.e('login timeout');
    await logout();
    throw LoginTimeoutError();
  });

  logger.i('websocket connected and get user from sendbird server');
  ConnectionManager.flushCompleters(
      error: reconnect ? null : ConnectionClosedError());

  if (!registered) {
    _ambiguate(WidgetsBinding.instance)?.addObserver(this);
    registered = true;
  }

  _loginCompleter = null;
  _reconnectTimer = null;
  _forceReconnect = false;
  return user;
}