acceptConnection method

S? acceptConnection(
  1. TransportConnection connection, {
  2. String? sessionId,
})

Register connection as a new session and return it.

Returns null — after closing connection — when this host cannot take it: it was disposed, it was stopped, or sessionId is already in use. Closing is the point: the caller handed over a live socket, and a refusal that left it open would leak it for the lifetime of the process.

sessionId overrides the generated identifier. Only pass one that is unguessable — it is echoed to the client and used as a broadcast identity, so a predictable id lets a peer impersonate another.

Implementation

S? acceptConnection(
  TransportConnection connection, {
  String? sessionId,
}) {
  if (_state == SessionHostState.disposed) {
    // Refused without an event: `dispose` closed `serverEvents`, so there
    // is nobody left to tell. Closing the connection is the part that
    // matters — the caller handed over a live socket.
    unawaited(tryCatchIgnore(connection.close));
    return null;
  }

  if (_state == SessionHostState.stopped) {
    return _refuseConnection(
      connection,
      'the host is stopped',
    );
  }

  if (_state == SessionHostState.idle) {
    if (ownsTransport) {
      // A host that owns its transport cannot be handed a connection before
      // it has started: something is accepting on its behalf.
      return _refuseConnection(connection, 'the host is not started');
    }
    // Embedded in another server: the connection is the start signal.
    _markRunning();
  }

  final id = sessionId ?? generateSessionId();

  if (_sessions.containsKey(id)) {
    return _refuseConnection(
      connection,
      'session id $id is already in use',
    );
  }

  final session = createSession(id: id, connection: connection);
  _sessions[id] = session;

  addServerEvent(
    ServerEvent(
      type: ServerEventType.clientConnected,
      message: 'Client connected with session id: $id',
      data: {
        'clientId': id,
      },
    ),
  );

  session.events.listen(
    handleSessionEvent,
    onDone: () {
      handleSessionClosed(id);
    },
    onError: (dynamic error) => handleSessionError(id, error),
  );

  return session;
}