start static method
Future<Session>
start(
- String? realm,
- AbstractTransport transport, {
- String? authId,
- String? authRole,
- Map<
String, dynamic> ? authExtra, - List<
AbstractAuthentication> ? authMethods, - 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;
}