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;
}