(
&self,
sandbox_id: &str,
target: relay_open::Target,
service_id: String,
session_wait_timeout: Duration,
)
| 254 | } |
| 255 | |
| 256 | pub async fn open_relay_with_target( |
| 257 | &self, |
| 258 | sandbox_id: &str, |
| 259 | target: relay_open::Target, |
| 260 | service_id: String, |
| 261 | session_wait_timeout: Duration, |
| 262 | ) -> Result< |
| 263 | ( |
| 264 | String, |
| 265 | oneshot::Receiver<Result<tokio::io::DuplexStream, Status>>, |
| 266 | ), |
| 267 | Status, |
| 268 | > { |
| 269 | let tx = self |
| 270 | .wait_for_session(sandbox_id, session_wait_timeout) |
| 271 | .await?; |
| 272 | |
| 273 | let channel_id = Uuid::new_v4().to_string(); |
| 274 | let relay_open = RelayOpen { |
| 275 | channel_id: channel_id.clone(), |
| 276 | target: Some(target), |
| 277 | service_id, |
| 278 | }; |
| 279 | |
| 280 | // Register the pending relay before sending RelayOpen to avoid a race. |
| 281 | // Both caps are checked and the insert happens under a single lock hold |
| 282 | // so two concurrent calls can't both observe "under the cap" and then |
| 283 | // both insert past it. |
| 284 | let (relay_tx, relay_rx) = oneshot::channel(); |
| 285 | { |
| 286 | let mut pending = self.pending_relays.lock().unwrap(); |
| 287 | if pending.len() >= MAX_PENDING_RELAYS { |
| 288 | return Err(Status::resource_exhausted(format!( |
| 289 | "gateway relay capacity reached ({MAX_PENDING_RELAYS} in flight)" |
| 290 | ))); |
| 291 | } |
| 292 | let per_sandbox = pending |
| 293 | .values() |
| 294 | .filter(|p| p.sandbox_id == sandbox_id) |
| 295 | .count(); |
| 296 | if per_sandbox >= MAX_PENDING_RELAYS_PER_SANDBOX { |
| 297 | return Err(Status::resource_exhausted(format!( |
| 298 | "per-sandbox relay limit reached ({MAX_PENDING_RELAYS_PER_SANDBOX} in flight for {sandbox_id})" |
| 299 | ))); |
| 300 | } |
| 301 | pending.insert( |
| 302 | channel_id.clone(), |
| 303 | PendingRelay { |
| 304 | sender: relay_tx, |
| 305 | sandbox_id: sandbox_id.to_string(), |
| 306 | relay_open: relay_open.clone(), |
| 307 | created_at: Instant::now(), |
| 308 | }, |
| 309 | ); |
| 310 | } |
| 311 | |
| 312 | let msg = GatewayMessage { |
| 313 | payload: Some(gateway_message::Payload::RelayOpen(relay_open)), |
no test coverage detected