start static method

Future<Session> start(
  1. String? realm,
  2. AbstractTransport transport, {
  3. String? authId,
  4. String? authRole,
  5. Map<String, dynamic>? authExtra,
  6. List<AbstractAuthentication>? authMethods,
  7. Duration? reconnect,
})

Starting the session will also start the authentication process.

Implementation

static Future<Session> start(String? realm, AbstractTransport transport,
    {String? authId,
    String? authRole,
    Map<String, dynamic>? authExtra,
    List<AbstractAuthentication>? authMethods,
    Duration? reconnect}) async {
  /// Initialize the session object with the realm it belongs to
  final session = Session(realm, transport);

  /// Initialize the sub protocol with a hello message
  final hello = Hello(realm, details_package.Details.forHello());
  if (authId != null) {
    hello.details.authid = authId;
  }
  if (authRole != null) {
    hello.details.authrole = authRole;
  }
  if (authExtra != null) {
    hello.details.authextra = authExtra;
  }

  if (authMethods != null && authMethods.isNotEmpty) {
    await authMethods[0].hello(realm, hello.details);
    hello.details.authmethods = authMethods
        .map<String>((authMethod) => authMethod.getName())
        .toList();
  }

  /// Either return the welcome or execute a challenge before and eventually return the welcome after this
  var welcomeCompleter = Completer<Session>();
  session._transportStreamSubscription = transport.receive()!.listen(
      (message) {
        if (message is Challenge) {
          final foundAuthMethod = authMethods
              ?.where((authenticationMethod) =>
                  authenticationMethod.getName() == message.authMethod)
              .first;
          if (foundAuthMethod != null) {
            try {
              foundAuthMethod
                  .challenge(message.extra)
                  .then((authenticate) => session.authenticate(authenticate),
                      onError: (error) {
                session._transport.send(Abort(Error.authorizationFailed,
                    message: error.toString()));
                session._transport.close();
              });
            } catch (exception) {
              try {
                transport.close();
              } catch (ignore) {/* my be already closed */}
              welcomeCompleter.completeError(Abort(Error.authorizationFailed,
                  message: exception.toString()));
            }
          } else {
            final goodbye = Goodbye(
                GoodbyeMessage('Authmethod $foundAuthMethod not supported'),
                Goodbye.reasonGoodbyeAndOut);
            session._transport.send(goodbye);
            welcomeCompleter.completeError(goodbye);
          }
        } else if (message is Welcome) {
          session.id = message.sessionId;

          if ((session.realm ?? message.details.realm) == null) {
            welcomeCompleter.completeError(Abort(Error.authorizationFailed,
                message:
                    'No realm specified! Neither by the client nor by the router'));
            return;
          }
          if (message.details.realm == null) {
            if (_logger.level <= Level.INFO) {
              _logger.info('Warning! No realm returned by the router');
            }
          } else {
            session.realm = message.details.realm;
          }

          session.authId = message.details.authid;
          session.authRole = message.details.authrole;
          session.authMethod = message.details.authmethod;
          session.authProvider = message.details.authprovider;
          session.authExtra = message.details.authextra;
          session._transportStreamSubscription.onData((message) {
            session._openSessionStreamController.add(message);
          });
          session._transportStreamSubscription.onDone(() {
            session._openSessionStreamController.close();
          });
          welcomeCompleter.complete(session);
        } else if (message is Abort) {
          try {
            transport.close();
          } catch (ignore) {/* my be already closed */}
          welcomeCompleter.completeError(message);
        } else if (message is Goodbye) {
          try {
            transport.close();
          } catch (ignore) {/* my be already closed */}
        }
      },
      cancelOnError: true,
      onError: (error) {
        _logger.warning(error);
        transport.close(error: error);
      },
      onDone: () => transport.close());
  if (!transport.isReady) {
    await transport.onReady;
  }
  transport.send(hello);
  return welcomeCompleter.future;
}