prepare method

Runs policy and reserves one pending connection.

Implementation

Future<AcpPreparedWebSocketUpgrade> prepare(
  AcpWebSocketUpgradeContext context,
) async {
  if (_isClosed) {
    throw StateError('ACP WebSocket server is closed');
  }
  final stopwatch = Stopwatch()..start();
  final AcpWebSocketUpgradePolicy? policy = _upgradePolicy;
  if (policy != null) {
    bool allowed;
    try {
      allowed = await Future<bool>.sync(
        () => policy(context),
      ).timeout(_remaining(stopwatch));
    } on Object {
      throw const AcpWebSocketUpgradeRejected();
    }
    if (!allowed) {
      throw const AcpWebSocketUpgradeRejected();
    }
  }

  if (_isClosed) {
    throw StateError('ACP WebSocket server is closed');
  }
  final String connectionId = _registry.reserveConnectionId();
  final Future<AcpServerConnectionState> factoryFuture =
      Future<AcpServerConnectionState>.sync(
        () => _createConnection(connectionId),
      );
  AcpServerConnectionState? connection;
  try {
    connection = await factoryFuture.timeout(_remaining(stopwatch));
  } on Object {
    _registry.releaseConnectionId(connectionId);
    unawaited(
      factoryFuture.then<void>(
        (AcpServerConnectionState lateConnection) =>
            lateConnection.close('upgrade preparation failed'),
        onError: (Object _, StackTrace _) {},
      ),
    );
    rethrow;
  }
  if (connection.connectionId != connectionId) {
    _registry.releaseConnectionId(connectionId);
    await connection.close('mismatched connection ID');
    throw StateError('Connection factory returned a mismatched ID');
  }
  if (_isClosed) {
    _registry.releaseConnectionId(connectionId);
    await connection.close('server closed');
    throw StateError('ACP WebSocket server is closed');
  }
  try {
    _registry.addReservedPending(connection);
  } on Object {
    _registry.releaseConnectionId(connectionId);
    await connection.close('upgrade preparation failed');
    rethrow;
  }
  final prepared = AcpPreparedWebSocketUpgrade._(
    connectionId: connectionId,
    connection: connection,
    owner: this,
    timeout: _limits.initializeTimeout,
  );
  _prepared.add(prepared);
  return prepared;
}