1use crate::generated_protocol::v1 as generated_protocol;
2use serde::de::{self, SeqAccess, Visitor};
3use serde::ser::SerializeTuple;
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5use serde_json::Value;
6use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
7use std::error::Error;
8use std::fmt;
9
10pub use crate::wire::{OwnershipRequirement, ProtocolCodecError, RequestDirection};
11
12pub const PROTOCOL_NAME: &str = crate::wire::PROTOCOL_NAME;
13pub const PROTOCOL_VERSION: u16 = crate::wire::PROTOCOL_VERSION;
14pub const DEFAULT_MAX_FRAME_BYTES: usize = crate::wire::DEFAULT_MAX_FRAME_BYTES;
15pub const DEFAULT_COMPLETED_RESPONSE_CAP: usize = 10_000;
16pub type RequestId = crate::wire::RequestId;
17pub type ExtEnvelope = crate::wire::ExtEnvelope;
18
19fn serialize_bare_newtype_tag<S, T>(serializer: S, tag: u64, payload: &T) -> Result<S::Ok, S::Error>
20where
21 S: Serializer,
22 T: Serialize,
23{
24 let mut tuple = serializer.serialize_tuple(2)?;
25 tuple.serialize_element(&serde_bare::Uint(tag))?;
26 tuple.serialize_element(payload)?;
27 tuple.end()
28}
29
30pub fn to_generated_protocol_frame(
32 frame: &ProtocolFrame,
33) -> Result<generated_protocol::ProtocolFrame, ProtocolCodecError> {
34 Ok(match frame {
35 ProtocolFrame::Request(frame) => {
36 generated_protocol::ProtocolFrame::RequestFrame(generated_protocol::RequestFrame {
37 schema: to_generated_protocol_schema(&frame.schema),
38 request_id: frame.request_id,
39 ownership: to_generated_ownership_scope(&frame.ownership),
40 payload: to_generated_request_payload(&frame.payload)?,
41 })
42 }
43 ProtocolFrame::Response(frame) => {
44 generated_protocol::ProtocolFrame::ResponseFrame(generated_protocol::ResponseFrame {
45 schema: to_generated_protocol_schema(&frame.schema),
46 request_id: frame.request_id,
47 ownership: to_generated_ownership_scope(&frame.ownership),
48 payload: to_generated_response_payload(&frame.payload)?,
49 })
50 }
51 ProtocolFrame::Event(frame) => {
52 generated_protocol::ProtocolFrame::EventFrame(generated_protocol::EventFrame {
53 schema: to_generated_protocol_schema(&frame.schema),
54 ownership: to_generated_ownership_scope(&frame.ownership),
55 payload: to_generated_event_payload(&frame.payload),
56 })
57 }
58 ProtocolFrame::SidecarRequest(frame) => {
59 generated_protocol::ProtocolFrame::SidecarRequestFrame(
60 generated_protocol::SidecarRequestFrame {
61 schema: to_generated_protocol_schema(&frame.schema),
62 request_id: frame.request_id,
63 ownership: to_generated_ownership_scope(&frame.ownership),
64 payload: to_generated_sidecar_request_payload(&frame.payload)?,
65 },
66 )
67 }
68 ProtocolFrame::SidecarResponse(frame) => {
69 generated_protocol::ProtocolFrame::SidecarResponseFrame(
70 generated_protocol::SidecarResponseFrame {
71 schema: to_generated_protocol_schema(&frame.schema),
72 request_id: frame.request_id,
73 ownership: to_generated_ownership_scope(&frame.ownership),
74 payload: to_generated_sidecar_response_payload(&frame.payload)?,
75 },
76 )
77 }
78 })
79}
80
81pub fn from_generated_protocol_frame(
83 frame: generated_protocol::ProtocolFrame,
84) -> Result<ProtocolFrame, ProtocolCodecError> {
85 Ok(match frame {
86 generated_protocol::ProtocolFrame::RequestFrame(frame) => {
87 ProtocolFrame::Request(RequestFrame {
88 schema: from_generated_protocol_schema(frame.schema),
89 request_id: frame.request_id,
90 ownership: from_generated_ownership_scope(frame.ownership),
91 payload: from_generated_request_payload(frame.payload)?,
92 })
93 }
94 generated_protocol::ProtocolFrame::ResponseFrame(frame) => {
95 ProtocolFrame::Response(ResponseFrame {
96 schema: from_generated_protocol_schema(frame.schema),
97 request_id: frame.request_id,
98 ownership: from_generated_ownership_scope(frame.ownership),
99 payload: from_generated_response_payload(frame.payload)?,
100 })
101 }
102 generated_protocol::ProtocolFrame::EventFrame(frame) => ProtocolFrame::Event(EventFrame {
103 schema: from_generated_protocol_schema(frame.schema),
104 ownership: from_generated_ownership_scope(frame.ownership),
105 payload: from_generated_event_payload(frame.payload),
106 }),
107 generated_protocol::ProtocolFrame::SidecarRequestFrame(frame) => {
108 ProtocolFrame::SidecarRequest(SidecarRequestFrame {
109 schema: from_generated_protocol_schema(frame.schema),
110 request_id: frame.request_id,
111 ownership: from_generated_ownership_scope(frame.ownership),
112 payload: from_generated_sidecar_request_payload(frame.payload)?,
113 })
114 }
115 generated_protocol::ProtocolFrame::SidecarResponseFrame(frame) => {
116 ProtocolFrame::SidecarResponse(SidecarResponseFrame {
117 schema: from_generated_protocol_schema(frame.schema),
118 request_id: frame.request_id,
119 ownership: from_generated_ownership_scope(frame.ownership),
120 payload: from_generated_sidecar_response_payload(frame.payload)?,
121 })
122 }
123 })
124}
125
126fn to_generated_protocol_schema(schema: &ProtocolSchema) -> generated_protocol::ProtocolSchema {
127 schema.clone()
128}
129
130fn from_generated_protocol_schema(schema: generated_protocol::ProtocolSchema) -> ProtocolSchema {
131 schema
132}
133
134pub(crate) fn to_generated_ownership_scope(
139 ownership: &OwnershipScope,
140) -> generated_protocol::OwnershipScope {
141 ownership.clone()
142}
143
144pub(crate) fn from_generated_ownership_scope(
145 ownership: generated_protocol::OwnershipScope,
146) -> OwnershipScope {
147 ownership
148}
149
150fn to_generated_dispose_reason(reason: &DisposeReason) -> generated_protocol::DisposeReason {
151 match reason {
152 DisposeReason::Requested => generated_protocol::DisposeReason::Requested,
153 DisposeReason::ConnectionClosed => generated_protocol::DisposeReason::ConnectionClosed,
154 DisposeReason::HostShutdown => generated_protocol::DisposeReason::HostShutdown,
155 }
156}
157
158fn from_generated_dispose_reason(reason: generated_protocol::DisposeReason) -> DisposeReason {
159 match reason {
160 generated_protocol::DisposeReason::Requested => DisposeReason::Requested,
161 generated_protocol::DisposeReason::ConnectionClosed => DisposeReason::ConnectionClosed,
162 generated_protocol::DisposeReason::HostShutdown => DisposeReason::HostShutdown,
163 }
164}
165
166fn to_generated_filesystem_operation(
167 operation: &FilesystemOperation,
168) -> generated_protocol::FilesystemOperation {
169 match operation {
170 FilesystemOperation::Read => generated_protocol::FilesystemOperation::Read,
171 FilesystemOperation::Write => generated_protocol::FilesystemOperation::Write,
172 FilesystemOperation::Stat => generated_protocol::FilesystemOperation::Stat,
173 FilesystemOperation::ReadDir => generated_protocol::FilesystemOperation::ReadDir,
174 FilesystemOperation::Mkdir => generated_protocol::FilesystemOperation::Mkdir,
175 FilesystemOperation::Remove => generated_protocol::FilesystemOperation::Remove,
176 FilesystemOperation::Rename => generated_protocol::FilesystemOperation::Rename,
177 }
178}
179
180fn from_generated_filesystem_operation(
181 operation: generated_protocol::FilesystemOperation,
182) -> FilesystemOperation {
183 match operation {
184 generated_protocol::FilesystemOperation::Read => FilesystemOperation::Read,
185 generated_protocol::FilesystemOperation::Write => FilesystemOperation::Write,
186 generated_protocol::FilesystemOperation::Stat => FilesystemOperation::Stat,
187 generated_protocol::FilesystemOperation::ReadDir => FilesystemOperation::ReadDir,
188 generated_protocol::FilesystemOperation::Mkdir => FilesystemOperation::Mkdir,
189 generated_protocol::FilesystemOperation::Remove => FilesystemOperation::Remove,
190 generated_protocol::FilesystemOperation::Rename => FilesystemOperation::Rename,
191 }
192}
193
194fn to_generated_guest_filesystem_operation(
195 operation: &GuestFilesystemOperation,
196) -> generated_protocol::GuestFilesystemOperation {
197 match operation {
198 GuestFilesystemOperation::ReadFile => {
199 generated_protocol::GuestFilesystemOperation::ReadFile
200 }
201 GuestFilesystemOperation::WriteFile => {
202 generated_protocol::GuestFilesystemOperation::WriteFile
203 }
204 GuestFilesystemOperation::CreateDir => {
205 generated_protocol::GuestFilesystemOperation::CreateDir
206 }
207 GuestFilesystemOperation::Mkdir => generated_protocol::GuestFilesystemOperation::Mkdir,
208 GuestFilesystemOperation::Exists => generated_protocol::GuestFilesystemOperation::Exists,
209 GuestFilesystemOperation::Stat => generated_protocol::GuestFilesystemOperation::Stat,
210 GuestFilesystemOperation::Lstat => generated_protocol::GuestFilesystemOperation::Lstat,
211 GuestFilesystemOperation::ReadDir => generated_protocol::GuestFilesystemOperation::ReadDir,
212 GuestFilesystemOperation::RemoveFile => {
213 generated_protocol::GuestFilesystemOperation::RemoveFile
214 }
215 GuestFilesystemOperation::RemoveDir => {
216 generated_protocol::GuestFilesystemOperation::RemoveDir
217 }
218 GuestFilesystemOperation::Rename => generated_protocol::GuestFilesystemOperation::Rename,
219 GuestFilesystemOperation::Realpath => {
220 generated_protocol::GuestFilesystemOperation::Realpath
221 }
222 GuestFilesystemOperation::Symlink => generated_protocol::GuestFilesystemOperation::Symlink,
223 GuestFilesystemOperation::ReadLink => {
224 generated_protocol::GuestFilesystemOperation::ReadLink
225 }
226 GuestFilesystemOperation::Link => generated_protocol::GuestFilesystemOperation::Link,
227 GuestFilesystemOperation::Chmod => generated_protocol::GuestFilesystemOperation::Chmod,
228 GuestFilesystemOperation::Chown => generated_protocol::GuestFilesystemOperation::Chown,
229 GuestFilesystemOperation::Utimes => generated_protocol::GuestFilesystemOperation::Utimes,
230 GuestFilesystemOperation::Truncate => {
231 generated_protocol::GuestFilesystemOperation::Truncate
232 }
233 GuestFilesystemOperation::Pread => generated_protocol::GuestFilesystemOperation::Pread,
234 }
235}
236
237fn from_generated_guest_filesystem_operation(
238 operation: generated_protocol::GuestFilesystemOperation,
239) -> GuestFilesystemOperation {
240 match operation {
241 generated_protocol::GuestFilesystemOperation::ReadFile => {
242 GuestFilesystemOperation::ReadFile
243 }
244 generated_protocol::GuestFilesystemOperation::WriteFile => {
245 GuestFilesystemOperation::WriteFile
246 }
247 generated_protocol::GuestFilesystemOperation::CreateDir => {
248 GuestFilesystemOperation::CreateDir
249 }
250 generated_protocol::GuestFilesystemOperation::Mkdir => GuestFilesystemOperation::Mkdir,
251 generated_protocol::GuestFilesystemOperation::Exists => GuestFilesystemOperation::Exists,
252 generated_protocol::GuestFilesystemOperation::Stat => GuestFilesystemOperation::Stat,
253 generated_protocol::GuestFilesystemOperation::Lstat => GuestFilesystemOperation::Lstat,
254 generated_protocol::GuestFilesystemOperation::ReadDir => GuestFilesystemOperation::ReadDir,
255 generated_protocol::GuestFilesystemOperation::RemoveFile => {
256 GuestFilesystemOperation::RemoveFile
257 }
258 generated_protocol::GuestFilesystemOperation::RemoveDir => {
259 GuestFilesystemOperation::RemoveDir
260 }
261 generated_protocol::GuestFilesystemOperation::Rename => GuestFilesystemOperation::Rename,
262 generated_protocol::GuestFilesystemOperation::Realpath => {
263 GuestFilesystemOperation::Realpath
264 }
265 generated_protocol::GuestFilesystemOperation::Symlink => GuestFilesystemOperation::Symlink,
266 generated_protocol::GuestFilesystemOperation::ReadLink => {
267 GuestFilesystemOperation::ReadLink
268 }
269 generated_protocol::GuestFilesystemOperation::Link => GuestFilesystemOperation::Link,
270 generated_protocol::GuestFilesystemOperation::Chmod => GuestFilesystemOperation::Chmod,
271 generated_protocol::GuestFilesystemOperation::Chown => GuestFilesystemOperation::Chown,
272 generated_protocol::GuestFilesystemOperation::Utimes => GuestFilesystemOperation::Utimes,
273 generated_protocol::GuestFilesystemOperation::Truncate => {
274 GuestFilesystemOperation::Truncate
275 }
276 generated_protocol::GuestFilesystemOperation::Pread => GuestFilesystemOperation::Pread,
277 }
278}
279
280fn to_generated_permission_mode(mode: &PermissionMode) -> generated_protocol::PermissionMode {
281 mode.clone()
282}
283
284fn from_generated_permission_mode(mode: generated_protocol::PermissionMode) -> PermissionMode {
285 mode
286}
287
288fn to_generated_root_filesystem_entry_encoding(
289 encoding: &RootFilesystemEntryEncoding,
290) -> generated_protocol::RootFilesystemEntryEncoding {
291 match encoding {
292 RootFilesystemEntryEncoding::Utf8 => generated_protocol::RootFilesystemEntryEncoding::Utf8,
293 RootFilesystemEntryEncoding::Base64 => {
294 generated_protocol::RootFilesystemEntryEncoding::Base64
295 }
296 }
297}
298
299fn from_generated_root_filesystem_entry_encoding(
300 encoding: generated_protocol::RootFilesystemEntryEncoding,
301) -> RootFilesystemEntryEncoding {
302 match encoding {
303 generated_protocol::RootFilesystemEntryEncoding::Utf8 => RootFilesystemEntryEncoding::Utf8,
304 generated_protocol::RootFilesystemEntryEncoding::Base64 => {
305 RootFilesystemEntryEncoding::Base64
306 }
307 }
308}
309
310fn to_generated_stream_channel(channel: &StreamChannel) -> generated_protocol::StreamChannel {
311 match channel {
312 StreamChannel::Stdout => generated_protocol::StreamChannel::Stdout,
313 StreamChannel::Stderr => generated_protocol::StreamChannel::Stderr,
314 }
315}
316
317fn from_generated_stream_channel(channel: generated_protocol::StreamChannel) -> StreamChannel {
318 match channel {
319 generated_protocol::StreamChannel::Stdout => StreamChannel::Stdout,
320 generated_protocol::StreamChannel::Stderr => StreamChannel::Stderr,
321 }
322}
323
324fn to_generated_vm_lifecycle_state(
325 state: &VmLifecycleState,
326) -> generated_protocol::VmLifecycleState {
327 match state {
328 VmLifecycleState::Creating => generated_protocol::VmLifecycleState::Creating,
329 VmLifecycleState::Ready => generated_protocol::VmLifecycleState::Ready,
330 VmLifecycleState::Disposing => generated_protocol::VmLifecycleState::Disposing,
331 VmLifecycleState::Disposed => generated_protocol::VmLifecycleState::Disposed,
332 VmLifecycleState::Failed => generated_protocol::VmLifecycleState::Failed,
333 }
334}
335
336fn from_generated_vm_lifecycle_state(
337 state: generated_protocol::VmLifecycleState,
338) -> VmLifecycleState {
339 match state {
340 generated_protocol::VmLifecycleState::Creating => VmLifecycleState::Creating,
341 generated_protocol::VmLifecycleState::Ready => VmLifecycleState::Ready,
342 generated_protocol::VmLifecycleState::Disposing => VmLifecycleState::Disposing,
343 generated_protocol::VmLifecycleState::Disposed => VmLifecycleState::Disposed,
344 generated_protocol::VmLifecycleState::Failed => VmLifecycleState::Failed,
345 }
346}
347
348fn to_generated_guest_filesystem_stat(
349 stat: &GuestFilesystemStat,
350) -> generated_protocol::GuestFilesystemStat {
351 stat.clone()
352}
353
354fn from_generated_guest_filesystem_stat(
355 stat: generated_protocol::GuestFilesystemStat,
356) -> GuestFilesystemStat {
357 stat
358}
359
360fn to_generated_process_snapshot_entry(
361 entry: &ProcessSnapshotEntry,
362) -> generated_protocol::ProcessSnapshotEntry {
363 entry.clone()
364}
365
366fn from_generated_process_snapshot_entry(
367 entry: generated_protocol::ProcessSnapshotEntry,
368) -> ProcessSnapshotEntry {
369 entry
370}
371
372fn to_generated_ext_envelope(envelope: &ExtEnvelope) -> generated_protocol::ExtEnvelope {
373 envelope.clone()
374}
375
376fn from_generated_ext_envelope(envelope: generated_protocol::ExtEnvelope) -> ExtEnvelope {
377 envelope
378}
379
380fn to_generated_request_payload(
381 payload: &RequestPayload,
382) -> Result<generated_protocol::RequestPayload, ProtocolCodecError> {
383 Ok(match payload {
384 RequestPayload::Authenticate(inner) => {
385 generated_protocol::RequestPayload::AuthenticateRequest(inner.clone())
386 }
387 RequestPayload::OpenSession(inner) => {
388 generated_protocol::RequestPayload::OpenSessionRequest(inner.clone())
389 }
390 RequestPayload::CreateVm(inner) => {
391 generated_protocol::RequestPayload::CreateVmRequest(inner.clone())
392 }
393 RequestPayload::DisposeVm(inner) => generated_protocol::RequestPayload::DisposeVmRequest(
394 generated_protocol::DisposeVmRequest {
395 reason: to_generated_dispose_reason(&inner.reason),
396 },
397 ),
398 RequestPayload::BootstrapRootFilesystem(inner) => {
399 generated_protocol::RequestPayload::BootstrapRootFilesystemRequest(inner.clone())
400 }
401 RequestPayload::ConfigureVm(inner) => {
402 generated_protocol::RequestPayload::ConfigureVmRequest(inner.clone())
403 }
404 RequestPayload::RegisterHostCallbacks(inner) => {
405 generated_protocol::RequestPayload::RegisterHostCallbacksRequest(inner.clone())
406 }
407 RequestPayload::CreateLayer(_) => generated_protocol::RequestPayload::CreateLayerRequest,
408 RequestPayload::SealLayer(inner) => {
409 generated_protocol::RequestPayload::SealLayerRequest(inner.clone())
410 }
411 RequestPayload::ImportSnapshot(inner) => {
412 generated_protocol::RequestPayload::ImportSnapshotRequest(inner.clone())
413 }
414 RequestPayload::ExportSnapshot(inner) => {
415 generated_protocol::RequestPayload::ExportSnapshotRequest(inner.clone())
416 }
417 RequestPayload::CreateOverlay(inner) => {
418 generated_protocol::RequestPayload::CreateOverlayRequest(inner.clone())
419 }
420 RequestPayload::GuestFilesystemCall(inner) => {
421 generated_protocol::RequestPayload::GuestFilesystemCallRequest(inner.clone())
422 }
423 RequestPayload::SnapshotRootFilesystem(_) => {
424 generated_protocol::RequestPayload::SnapshotRootFilesystemRequest
425 }
426 RequestPayload::Execute(inner) => {
427 generated_protocol::RequestPayload::ExecuteRequest(inner.clone())
428 }
429 RequestPayload::WriteStdin(inner) => {
430 generated_protocol::RequestPayload::WriteStdinRequest(inner.clone())
431 }
432 RequestPayload::CloseStdin(inner) => {
433 generated_protocol::RequestPayload::CloseStdinRequest(inner.clone())
434 }
435 RequestPayload::KillProcess(inner) => {
436 generated_protocol::RequestPayload::KillProcessRequest(inner.clone())
437 }
438 RequestPayload::GetProcessSnapshot(_) => {
439 generated_protocol::RequestPayload::GetProcessSnapshotRequest
440 }
441 RequestPayload::FindListener(inner) => {
442 generated_protocol::RequestPayload::FindListenerRequest(inner.clone())
443 }
444 RequestPayload::FindBoundUdp(inner) => {
445 generated_protocol::RequestPayload::FindBoundUdpRequest(inner.clone())
446 }
447 RequestPayload::VmFetch(inner) => {
448 generated_protocol::RequestPayload::VmFetchRequest(inner.clone())
449 }
450 RequestPayload::GetSignalState(inner) => {
451 generated_protocol::RequestPayload::GetSignalStateRequest(inner.clone())
452 }
453 RequestPayload::GetZombieTimerCount(_) => {
454 generated_protocol::RequestPayload::GetZombieTimerCountRequest
455 }
456 RequestPayload::HostFilesystemCall(inner) => {
457 generated_protocol::RequestPayload::HostFilesystemCallRequest(
458 generated_protocol::HostFilesystemCallRequest {
459 operation: to_generated_filesystem_operation(&inner.operation),
460 path: inner.path.clone(),
461 payload_size_bytes: inner.payload_size_bytes,
462 },
463 )
464 }
465 RequestPayload::PersistenceLoad(inner) => {
466 generated_protocol::RequestPayload::PersistenceLoadRequest(inner.clone())
467 }
468 RequestPayload::PersistenceFlush(inner) => {
469 generated_protocol::RequestPayload::PersistenceFlushRequest(inner.clone())
470 }
471 RequestPayload::Ext(inner) => {
472 generated_protocol::RequestPayload::ExtEnvelope(to_generated_ext_envelope(inner))
473 }
474 })
475}
476
477fn from_generated_request_payload(
478 payload: generated_protocol::RequestPayload,
479) -> Result<RequestPayload, ProtocolCodecError> {
480 Ok(match payload {
481 generated_protocol::RequestPayload::AuthenticateRequest(inner) => {
482 RequestPayload::Authenticate(inner)
483 }
484 generated_protocol::RequestPayload::OpenSessionRequest(inner) => {
485 RequestPayload::OpenSession(inner)
486 }
487 generated_protocol::RequestPayload::CreateVmRequest(inner) => {
488 RequestPayload::CreateVm(inner)
489 }
490 generated_protocol::RequestPayload::DisposeVmRequest(inner) => {
491 RequestPayload::DisposeVm(DisposeVmRequest {
492 reason: from_generated_dispose_reason(inner.reason),
493 })
494 }
495 generated_protocol::RequestPayload::BootstrapRootFilesystemRequest(inner) => {
496 RequestPayload::BootstrapRootFilesystem(inner)
497 }
498 generated_protocol::RequestPayload::ConfigureVmRequest(inner) => {
499 RequestPayload::ConfigureVm(inner)
500 }
501 generated_protocol::RequestPayload::RegisterHostCallbacksRequest(inner) => {
502 RequestPayload::RegisterHostCallbacks(inner)
503 }
504 generated_protocol::RequestPayload::CreateLayerRequest => {
505 RequestPayload::CreateLayer(CreateLayerRequest {})
506 }
507 generated_protocol::RequestPayload::SealLayerRequest(inner) => {
508 RequestPayload::SealLayer(inner)
509 }
510 generated_protocol::RequestPayload::ImportSnapshotRequest(inner) => {
511 RequestPayload::ImportSnapshot(inner)
512 }
513 generated_protocol::RequestPayload::ExportSnapshotRequest(inner) => {
514 RequestPayload::ExportSnapshot(inner)
515 }
516 generated_protocol::RequestPayload::CreateOverlayRequest(inner) => {
517 RequestPayload::CreateOverlay(inner)
518 }
519 generated_protocol::RequestPayload::GuestFilesystemCallRequest(inner) => {
520 RequestPayload::GuestFilesystemCall(inner)
521 }
522 generated_protocol::RequestPayload::SnapshotRootFilesystemRequest => {
523 RequestPayload::SnapshotRootFilesystem(SnapshotRootFilesystemRequest {})
524 }
525 generated_protocol::RequestPayload::ExecuteRequest(inner) => RequestPayload::Execute(inner),
526 generated_protocol::RequestPayload::WriteStdinRequest(inner) => {
527 RequestPayload::WriteStdin(inner)
528 }
529 generated_protocol::RequestPayload::CloseStdinRequest(inner) => {
530 RequestPayload::CloseStdin(inner)
531 }
532 generated_protocol::RequestPayload::KillProcessRequest(inner) => {
533 RequestPayload::KillProcess(inner)
534 }
535 generated_protocol::RequestPayload::GetProcessSnapshotRequest => {
536 RequestPayload::GetProcessSnapshot(GetProcessSnapshotRequest {})
537 }
538 generated_protocol::RequestPayload::FindListenerRequest(inner) => {
539 RequestPayload::FindListener(inner)
540 }
541 generated_protocol::RequestPayload::FindBoundUdpRequest(inner) => {
542 RequestPayload::FindBoundUdp(inner)
543 }
544 generated_protocol::RequestPayload::VmFetchRequest(inner) => RequestPayload::VmFetch(inner),
545 generated_protocol::RequestPayload::GetSignalStateRequest(inner) => {
546 RequestPayload::GetSignalState(inner)
547 }
548 generated_protocol::RequestPayload::GetZombieTimerCountRequest => {
549 RequestPayload::GetZombieTimerCount(GetZombieTimerCountRequest {})
550 }
551 generated_protocol::RequestPayload::HostFilesystemCallRequest(inner) => {
552 RequestPayload::HostFilesystemCall(HostFilesystemCallRequest {
553 operation: from_generated_filesystem_operation(inner.operation),
554 path: inner.path,
555 payload_size_bytes: inner.payload_size_bytes,
556 })
557 }
558 generated_protocol::RequestPayload::PersistenceLoadRequest(inner) => {
559 RequestPayload::PersistenceLoad(inner)
560 }
561 generated_protocol::RequestPayload::PersistenceFlushRequest(inner) => {
562 RequestPayload::PersistenceFlush(inner)
563 }
564 generated_protocol::RequestPayload::ExtEnvelope(inner) => {
565 RequestPayload::Ext(from_generated_ext_envelope(inner))
566 }
567 })
568}
569
570fn to_generated_response_payload(
571 payload: &ResponsePayload,
572) -> Result<generated_protocol::ResponsePayload, ProtocolCodecError> {
573 Ok(match payload {
574 ResponsePayload::Authenticated(inner) => {
575 generated_protocol::ResponsePayload::AuthenticatedResponse(inner.clone())
576 }
577 ResponsePayload::SessionOpened(inner) => {
578 generated_protocol::ResponsePayload::SessionOpenedResponse(inner.clone())
579 }
580 ResponsePayload::VmCreated(inner) => {
581 generated_protocol::ResponsePayload::VmCreatedResponse(inner.clone())
582 }
583 ResponsePayload::VmDisposed(inner) => {
584 generated_protocol::ResponsePayload::VmDisposedResponse(inner.clone())
585 }
586 ResponsePayload::RootFilesystemBootstrapped(inner) => {
587 generated_protocol::ResponsePayload::RootFilesystemBootstrappedResponse(inner.clone())
588 }
589 ResponsePayload::VmConfigured(inner) => {
590 generated_protocol::ResponsePayload::VmConfiguredResponse(inner.clone())
591 }
592 ResponsePayload::HostCallbacksRegistered(inner) => {
593 generated_protocol::ResponsePayload::HostCallbacksRegisteredResponse(inner.clone())
594 }
595 ResponsePayload::LayerCreated(inner) => {
596 generated_protocol::ResponsePayload::LayerCreatedResponse(inner.clone())
597 }
598 ResponsePayload::LayerSealed(inner) => {
599 generated_protocol::ResponsePayload::LayerSealedResponse(inner.clone())
600 }
601 ResponsePayload::SnapshotImported(inner) => {
602 generated_protocol::ResponsePayload::SnapshotImportedResponse(inner.clone())
603 }
604 ResponsePayload::SnapshotExported(inner) => {
605 generated_protocol::ResponsePayload::SnapshotExportedResponse(
606 generated_protocol::SnapshotExportedResponse {
607 layer_id: inner.layer_id.clone(),
608 entries: inner.entries.clone(),
609 },
610 )
611 }
612 ResponsePayload::OverlayCreated(inner) => {
613 generated_protocol::ResponsePayload::OverlayCreatedResponse(inner.clone())
614 }
615 ResponsePayload::GuestFilesystemResult(inner) => {
616 generated_protocol::ResponsePayload::GuestFilesystemResultResponse(
617 generated_protocol::GuestFilesystemResultResponse {
618 operation: to_generated_guest_filesystem_operation(&inner.operation),
619 path: inner.path.clone(),
620 content: inner.content.clone(),
621 encoding: inner
622 .encoding
623 .as_ref()
624 .map(to_generated_root_filesystem_entry_encoding),
625 entries: inner.entries.clone(),
626 stat: inner.stat.as_ref().map(to_generated_guest_filesystem_stat),
627 exists: inner.exists,
628 target: inner.target.clone(),
629 },
630 )
631 }
632 ResponsePayload::RootFilesystemSnapshot(inner) => {
633 generated_protocol::ResponsePayload::RootFilesystemSnapshotResponse(
634 generated_protocol::RootFilesystemSnapshotResponse {
635 entries: inner.entries.clone(),
636 },
637 )
638 }
639 ResponsePayload::ProcessStarted(inner) => {
640 generated_protocol::ResponsePayload::ProcessStartedResponse(inner.clone())
641 }
642 ResponsePayload::StdinWritten(inner) => {
643 generated_protocol::ResponsePayload::StdinWrittenResponse(inner.clone())
644 }
645 ResponsePayload::StdinClosed(inner) => {
646 generated_protocol::ResponsePayload::StdinClosedResponse(inner.clone())
647 }
648 ResponsePayload::ProcessKilled(inner) => {
649 generated_protocol::ResponsePayload::ProcessKilledResponse(inner.clone())
650 }
651 ResponsePayload::ProcessSnapshot(inner) => {
652 generated_protocol::ResponsePayload::ProcessSnapshotResponse(
653 generated_protocol::ProcessSnapshotResponse {
654 processes: inner
655 .processes
656 .iter()
657 .map(to_generated_process_snapshot_entry)
658 .collect(),
659 },
660 )
661 }
662 ResponsePayload::ListenerSnapshot(inner) => {
663 generated_protocol::ResponsePayload::ListenerSnapshotResponse(inner.clone())
664 }
665 ResponsePayload::BoundUdpSnapshot(inner) => {
666 generated_protocol::ResponsePayload::BoundUdpSnapshotResponse(inner.clone())
667 }
668 ResponsePayload::VmFetchResult(inner) => {
669 generated_protocol::ResponsePayload::VmFetchResponse(inner.clone())
670 }
671 ResponsePayload::SignalState(inner) => {
672 generated_protocol::ResponsePayload::SignalStateResponse(inner.clone())
673 }
674 ResponsePayload::ZombieTimerCount(inner) => {
675 generated_protocol::ResponsePayload::ZombieTimerCountResponse(inner.clone())
676 }
677 ResponsePayload::FilesystemResult(inner) => {
678 generated_protocol::ResponsePayload::FilesystemResultResponse(
679 generated_protocol::FilesystemResultResponse {
680 operation: to_generated_filesystem_operation(&inner.operation),
681 status: inner.status.clone(),
682 payload_size_bytes: inner.payload_size_bytes,
683 },
684 )
685 }
686 ResponsePayload::PermissionDecision(inner) => {
687 generated_protocol::ResponsePayload::PermissionDecisionResponse(
688 generated_protocol::PermissionDecisionResponse {
689 capability: inner.capability.clone(),
690 decision: to_generated_permission_mode(&inner.decision),
691 },
692 )
693 }
694 ResponsePayload::PersistenceState(inner) => {
695 generated_protocol::ResponsePayload::PersistenceStateResponse(inner.clone())
696 }
697 ResponsePayload::PersistenceFlushed(inner) => {
698 generated_protocol::ResponsePayload::PersistenceFlushedResponse(inner.clone())
699 }
700 ResponsePayload::Rejected(inner) => {
701 generated_protocol::ResponsePayload::RejectedResponse(inner.clone())
702 }
703 ResponsePayload::ExtResult(inner) => {
704 generated_protocol::ResponsePayload::ExtEnvelope(to_generated_ext_envelope(inner))
705 }
706 })
707}
708
709fn from_generated_response_payload(
710 payload: generated_protocol::ResponsePayload,
711) -> Result<ResponsePayload, ProtocolCodecError> {
712 Ok(match payload {
713 generated_protocol::ResponsePayload::AuthenticatedResponse(inner) => {
714 ResponsePayload::Authenticated(inner)
715 }
716 generated_protocol::ResponsePayload::SessionOpenedResponse(inner) => {
717 ResponsePayload::SessionOpened(inner)
718 }
719 generated_protocol::ResponsePayload::VmCreatedResponse(inner) => {
720 ResponsePayload::VmCreated(inner)
721 }
722 generated_protocol::ResponsePayload::VmDisposedResponse(inner) => {
723 ResponsePayload::VmDisposed(inner)
724 }
725 generated_protocol::ResponsePayload::RootFilesystemBootstrappedResponse(inner) => {
726 ResponsePayload::RootFilesystemBootstrapped(inner)
727 }
728 generated_protocol::ResponsePayload::VmConfiguredResponse(inner) => {
729 ResponsePayload::VmConfigured(inner)
730 }
731 generated_protocol::ResponsePayload::HostCallbacksRegisteredResponse(inner) => {
732 ResponsePayload::HostCallbacksRegistered(inner)
733 }
734 generated_protocol::ResponsePayload::LayerCreatedResponse(inner) => {
735 ResponsePayload::LayerCreated(inner)
736 }
737 generated_protocol::ResponsePayload::LayerSealedResponse(inner) => {
738 ResponsePayload::LayerSealed(inner)
739 }
740 generated_protocol::ResponsePayload::SnapshotImportedResponse(inner) => {
741 ResponsePayload::SnapshotImported(inner)
742 }
743 generated_protocol::ResponsePayload::SnapshotExportedResponse(inner) => {
744 ResponsePayload::SnapshotExported(SnapshotExportedResponse {
745 layer_id: inner.layer_id,
746 entries: inner.entries,
747 })
748 }
749 generated_protocol::ResponsePayload::OverlayCreatedResponse(inner) => {
750 ResponsePayload::OverlayCreated(inner)
751 }
752 generated_protocol::ResponsePayload::GuestFilesystemResultResponse(inner) => {
753 ResponsePayload::GuestFilesystemResult(GuestFilesystemResultResponse {
754 operation: from_generated_guest_filesystem_operation(inner.operation),
755 path: inner.path,
756 content: inner.content,
757 encoding: inner
758 .encoding
759 .map(from_generated_root_filesystem_entry_encoding),
760 entries: inner.entries,
761 stat: inner.stat.map(from_generated_guest_filesystem_stat),
762 exists: inner.exists,
763 target: inner.target,
764 })
765 }
766 generated_protocol::ResponsePayload::RootFilesystemSnapshotResponse(inner) => {
767 ResponsePayload::RootFilesystemSnapshot(RootFilesystemSnapshotResponse {
768 entries: inner.entries,
769 })
770 }
771 generated_protocol::ResponsePayload::ProcessStartedResponse(inner) => {
772 ResponsePayload::ProcessStarted(inner)
773 }
774 generated_protocol::ResponsePayload::StdinWrittenResponse(inner) => {
775 ResponsePayload::StdinWritten(inner)
776 }
777 generated_protocol::ResponsePayload::StdinClosedResponse(inner) => {
778 ResponsePayload::StdinClosed(inner)
779 }
780 generated_protocol::ResponsePayload::ProcessKilledResponse(inner) => {
781 ResponsePayload::ProcessKilled(inner)
782 }
783 generated_protocol::ResponsePayload::ProcessSnapshotResponse(inner) => {
784 ResponsePayload::ProcessSnapshot(ProcessSnapshotResponse {
785 processes: inner
786 .processes
787 .into_iter()
788 .map(from_generated_process_snapshot_entry)
789 .collect(),
790 })
791 }
792 generated_protocol::ResponsePayload::ListenerSnapshotResponse(inner) => {
793 ResponsePayload::ListenerSnapshot(inner)
794 }
795 generated_protocol::ResponsePayload::BoundUdpSnapshotResponse(inner) => {
796 ResponsePayload::BoundUdpSnapshot(inner)
797 }
798 generated_protocol::ResponsePayload::VmFetchResponse(inner) => {
799 ResponsePayload::VmFetchResult(inner)
800 }
801 generated_protocol::ResponsePayload::SignalStateResponse(inner) => {
802 ResponsePayload::SignalState(inner)
803 }
804 generated_protocol::ResponsePayload::ZombieTimerCountResponse(inner) => {
805 ResponsePayload::ZombieTimerCount(inner)
806 }
807 generated_protocol::ResponsePayload::FilesystemResultResponse(inner) => {
808 ResponsePayload::FilesystemResult(FilesystemResultResponse {
809 operation: from_generated_filesystem_operation(inner.operation),
810 status: inner.status,
811 payload_size_bytes: inner.payload_size_bytes,
812 })
813 }
814 generated_protocol::ResponsePayload::PermissionDecisionResponse(inner) => {
815 ResponsePayload::PermissionDecision(PermissionDecisionResponse {
816 capability: inner.capability,
817 decision: from_generated_permission_mode(inner.decision),
818 })
819 }
820 generated_protocol::ResponsePayload::PersistenceStateResponse(inner) => {
821 ResponsePayload::PersistenceState(inner)
822 }
823 generated_protocol::ResponsePayload::PersistenceFlushedResponse(inner) => {
824 ResponsePayload::PersistenceFlushed(inner)
825 }
826 generated_protocol::ResponsePayload::RejectedResponse(inner) => {
827 ResponsePayload::Rejected(inner)
828 }
829 generated_protocol::ResponsePayload::ExtEnvelope(inner) => {
830 ResponsePayload::ExtResult(from_generated_ext_envelope(inner))
831 }
832 })
833}
834
835fn to_generated_event_payload(payload: &EventPayload) -> generated_protocol::EventPayload {
836 match payload {
837 EventPayload::VmLifecycle(inner) => generated_protocol::EventPayload::VmLifecycleEvent(
838 generated_protocol::VmLifecycleEvent {
839 state: to_generated_vm_lifecycle_state(&inner.state),
840 },
841 ),
842 EventPayload::ProcessOutput(inner) => generated_protocol::EventPayload::ProcessOutputEvent(
843 generated_protocol::ProcessOutputEvent {
844 process_id: inner.process_id.clone(),
845 channel: to_generated_stream_channel(&inner.channel),
846 chunk: inner.chunk.clone(),
847 },
848 ),
849 EventPayload::ProcessExited(inner) => {
850 generated_protocol::EventPayload::ProcessExitedEvent(inner.clone())
851 }
852 EventPayload::Structured(inner) => {
853 generated_protocol::EventPayload::StructuredEvent(inner.clone())
854 }
855 EventPayload::Ext(inner) => {
856 generated_protocol::EventPayload::ExtEnvelope(to_generated_ext_envelope(inner))
857 }
858 }
859}
860
861fn from_generated_event_payload(payload: generated_protocol::EventPayload) -> EventPayload {
862 match payload {
863 generated_protocol::EventPayload::VmLifecycleEvent(inner) => {
864 EventPayload::VmLifecycle(VmLifecycleEvent {
865 state: from_generated_vm_lifecycle_state(inner.state),
866 })
867 }
868 generated_protocol::EventPayload::ProcessOutputEvent(inner) => {
869 EventPayload::ProcessOutput(ProcessOutputEvent {
870 process_id: inner.process_id,
871 channel: from_generated_stream_channel(inner.channel),
872 chunk: inner.chunk,
873 })
874 }
875 generated_protocol::EventPayload::ProcessExitedEvent(inner) => {
876 EventPayload::ProcessExited(inner)
877 }
878 generated_protocol::EventPayload::StructuredEvent(inner) => EventPayload::Structured(inner),
879 generated_protocol::EventPayload::ExtEnvelope(inner) => {
880 EventPayload::Ext(from_generated_ext_envelope(inner))
881 }
882 }
883}
884
885fn to_generated_sidecar_request_payload(
886 payload: &SidecarRequestPayload,
887) -> Result<generated_protocol::SidecarRequestPayload, ProtocolCodecError> {
888 Ok(match payload {
889 SidecarRequestPayload::HostCallback(inner) => {
890 generated_protocol::SidecarRequestPayload::HostCallbackRequest(inner.clone())
891 }
892 SidecarRequestPayload::JsBridgeCall(inner) => {
893 generated_protocol::SidecarRequestPayload::JsBridgeCallRequest(inner.clone())
894 }
895 SidecarRequestPayload::Ext(inner) => {
896 generated_protocol::SidecarRequestPayload::ExtEnvelope(to_generated_ext_envelope(inner))
897 }
898 })
899}
900
901fn from_generated_sidecar_request_payload(
902 payload: generated_protocol::SidecarRequestPayload,
903) -> Result<SidecarRequestPayload, ProtocolCodecError> {
904 Ok(match payload {
905 generated_protocol::SidecarRequestPayload::HostCallbackRequest(inner) => {
906 SidecarRequestPayload::HostCallback(inner)
907 }
908 generated_protocol::SidecarRequestPayload::JsBridgeCallRequest(inner) => {
909 SidecarRequestPayload::JsBridgeCall(inner)
910 }
911 generated_protocol::SidecarRequestPayload::ExtEnvelope(inner) => {
912 SidecarRequestPayload::Ext(from_generated_ext_envelope(inner))
913 }
914 })
915}
916
917fn to_generated_sidecar_response_payload(
918 payload: &SidecarResponsePayload,
919) -> Result<generated_protocol::SidecarResponsePayload, ProtocolCodecError> {
920 Ok(match payload {
921 SidecarResponsePayload::HostCallbackResult(inner) => {
922 generated_protocol::SidecarResponsePayload::HostCallbackResultResponse(inner.clone())
923 }
924 SidecarResponsePayload::JsBridgeResult(inner) => {
925 generated_protocol::SidecarResponsePayload::JsBridgeResultResponse(inner.clone())
926 }
927 SidecarResponsePayload::ExtResult(inner) => {
928 generated_protocol::SidecarResponsePayload::ExtEnvelope(to_generated_ext_envelope(
929 inner,
930 ))
931 }
932 })
933}
934
935fn from_generated_sidecar_response_payload(
936 payload: generated_protocol::SidecarResponsePayload,
937) -> Result<SidecarResponsePayload, ProtocolCodecError> {
938 Ok(match payload {
939 generated_protocol::SidecarResponsePayload::HostCallbackResultResponse(inner) => {
940 SidecarResponsePayload::HostCallbackResult(inner)
941 }
942 generated_protocol::SidecarResponsePayload::JsBridgeResultResponse(inner) => {
943 SidecarResponsePayload::JsBridgeResult(inner)
944 }
945 generated_protocol::SidecarResponsePayload::ExtEnvelope(inner) => {
946 SidecarResponsePayload::ExtResult(from_generated_ext_envelope(inner))
947 }
948 })
949}
950
951macro_rules! impl_bare_newtype_union_enum {
952 (
953 $name:ident,
954 $json_name:ident,
955 $(#[$json_attr:meta])*
956 {
957 $($variant:ident($ty:ty) = $tag:literal),+ $(,)?
958 }
959 ) => {
960 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
961 $(#[$json_attr])*
962 enum $json_name {
963 $($variant($ty)),+
964 }
965
966 impl From<&$name> for $json_name {
967 fn from(value: &$name) -> Self {
968 match value {
969 $($name::$variant(inner) => Self::$variant(inner.clone()),)+
970 }
971 }
972 }
973
974 impl From<$json_name> for $name {
975 fn from(value: $json_name) -> Self {
976 match value {
977 $($json_name::$variant(inner) => Self::$variant(inner),)+
978 }
979 }
980 }
981
982 impl Serialize for $name {
983 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
984 where
985 S: Serializer,
986 {
987 if serializer.is_human_readable() {
988 $json_name::from(self).serialize(serializer)
989 } else {
990 match self {
991 $(Self::$variant(inner) => serialize_bare_newtype_tag(serializer, $tag, inner),)+
992 }
993 }
994 }
995 }
996
997 impl<'de> Deserialize<'de> for $name {
998 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
999 where
1000 D: Deserializer<'de>,
1001 {
1002 if deserializer.is_human_readable() {
1003 Ok($json_name::deserialize(deserializer)?.into())
1004 } else {
1005 struct UnionVisitor;
1006
1007 impl<'de> Visitor<'de> for UnionVisitor {
1008 type Value = $name;
1009
1010 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1011 write!(formatter, "a {} BARE union", stringify!($name))
1012 }
1013
1014 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
1015 where
1016 A: SeqAccess<'de>,
1017 {
1018 let serde_bare::Uint(tag) = seq
1019 .next_element()?
1020 .ok_or_else(|| de::Error::custom(concat!("missing ", stringify!($name), " tag")))?;
1021 match tag {
1022 $(
1023 $tag => {
1024 let payload = seq.next_element::<$ty>()?.ok_or_else(|| {
1025 de::Error::custom(format!(
1026 "missing {} payload for tag {}",
1027 stringify!($variant),
1028 $tag
1029 ))
1030 })?;
1031 Ok($name::$variant(payload))
1032 }
1033 )+
1034 _ => Err(de::Error::custom(format!(
1035 "unknown {} tag: {}",
1036 stringify!($name),
1037 tag
1038 ))),
1039 }
1040 }
1041 }
1042
1043 deserializer.deserialize_tuple(2, UnionVisitor)
1044 }
1045 }
1046 }
1047 };
1048}
1049
1050pub type ProtocolSchema = crate::wire::ProtocolSchema;
1051
1052pub type OwnershipScope = crate::wire::OwnershipScope;
1053
1054#[derive(Debug, Clone, PartialEq, Eq)]
1055pub enum ProtocolFrame {
1056 Request(RequestFrame),
1057 Response(ResponseFrame),
1058 Event(EventFrame),
1059 SidecarRequest(SidecarRequestFrame),
1060 SidecarResponse(SidecarResponseFrame),
1061}
1062
1063#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1064pub struct RequestFrame {
1065 pub schema: ProtocolSchema,
1066 pub request_id: RequestId,
1067 pub ownership: OwnershipScope,
1068 pub payload: RequestPayload,
1069}
1070
1071impl RequestFrame {
1072 pub fn new(request_id: RequestId, ownership: OwnershipScope, payload: RequestPayload) -> Self {
1073 Self {
1074 schema: ProtocolSchema::current(),
1075 request_id,
1076 ownership,
1077 payload,
1078 }
1079 }
1080}
1081
1082#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1083pub struct ResponseFrame {
1084 pub schema: ProtocolSchema,
1085 pub request_id: RequestId,
1086 pub ownership: OwnershipScope,
1087 pub payload: ResponsePayload,
1088}
1089
1090impl ResponseFrame {
1091 pub fn new(request_id: RequestId, ownership: OwnershipScope, payload: ResponsePayload) -> Self {
1092 Self {
1093 schema: ProtocolSchema::current(),
1094 request_id,
1095 ownership,
1096 payload,
1097 }
1098 }
1099}
1100
1101#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1102pub struct SidecarRequestFrame {
1103 pub schema: ProtocolSchema,
1104 pub request_id: RequestId,
1105 pub ownership: OwnershipScope,
1106 pub payload: SidecarRequestPayload,
1107}
1108
1109impl SidecarRequestFrame {
1110 pub fn new(
1111 request_id: RequestId,
1112 ownership: OwnershipScope,
1113 payload: SidecarRequestPayload,
1114 ) -> Self {
1115 Self {
1116 schema: ProtocolSchema::current(),
1117 request_id,
1118 ownership,
1119 payload,
1120 }
1121 }
1122}
1123
1124#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1125pub struct SidecarResponseFrame {
1126 pub schema: ProtocolSchema,
1127 pub request_id: RequestId,
1128 pub ownership: OwnershipScope,
1129 pub payload: SidecarResponsePayload,
1130}
1131
1132impl SidecarResponseFrame {
1133 pub fn new(
1134 request_id: RequestId,
1135 ownership: OwnershipScope,
1136 payload: SidecarResponsePayload,
1137 ) -> Self {
1138 Self {
1139 schema: ProtocolSchema::current(),
1140 request_id,
1141 ownership,
1142 payload,
1143 }
1144 }
1145}
1146
1147#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1148pub struct EventFrame {
1149 pub schema: ProtocolSchema,
1150 pub ownership: OwnershipScope,
1151 pub payload: EventPayload,
1152}
1153
1154impl EventFrame {
1155 pub fn new(ownership: OwnershipScope, payload: EventPayload) -> Self {
1156 Self {
1157 schema: ProtocolSchema::current(),
1158 ownership,
1159 payload,
1160 }
1161 }
1162}
1163
1164#[derive(Debug, Clone, PartialEq, Eq)]
1165pub enum RequestPayload {
1166 Authenticate(AuthenticateRequest),
1167 OpenSession(OpenSessionRequest),
1168 CreateVm(CreateVmRequest),
1169 DisposeVm(DisposeVmRequest),
1170 BootstrapRootFilesystem(BootstrapRootFilesystemRequest),
1171 ConfigureVm(ConfigureVmRequest),
1172 RegisterHostCallbacks(RegisterHostCallbacksRequest),
1173 CreateLayer(CreateLayerRequest),
1174 SealLayer(SealLayerRequest),
1175 ImportSnapshot(ImportSnapshotRequest),
1176 ExportSnapshot(ExportSnapshotRequest),
1177 CreateOverlay(CreateOverlayRequest),
1178 GuestFilesystemCall(GuestFilesystemCallRequest),
1179 SnapshotRootFilesystem(SnapshotRootFilesystemRequest),
1180 Execute(ExecuteRequest),
1181 WriteStdin(WriteStdinRequest),
1182 CloseStdin(CloseStdinRequest),
1183 KillProcess(KillProcessRequest),
1184 GetProcessSnapshot(GetProcessSnapshotRequest),
1185 FindListener(FindListenerRequest),
1186 FindBoundUdp(FindBoundUdpRequest),
1187 VmFetch(VmFetchRequest),
1188 GetSignalState(GetSignalStateRequest),
1189 GetZombieTimerCount(GetZombieTimerCountRequest),
1190 HostFilesystemCall(HostFilesystemCallRequest),
1191 PersistenceLoad(PersistenceLoadRequest),
1192 PersistenceFlush(PersistenceFlushRequest),
1193 Ext(ExtEnvelope),
1194}
1195
1196#[derive(Debug, Clone, PartialEq, Eq)]
1197pub enum ResponsePayload {
1198 Authenticated(AuthenticatedResponse),
1199 SessionOpened(SessionOpenedResponse),
1200 VmCreated(VmCreatedResponse),
1201 VmDisposed(VmDisposedResponse),
1202 RootFilesystemBootstrapped(RootFilesystemBootstrappedResponse),
1203 VmConfigured(VmConfiguredResponse),
1204 HostCallbacksRegistered(HostCallbacksRegisteredResponse),
1205 LayerCreated(LayerCreatedResponse),
1206 LayerSealed(LayerSealedResponse),
1207 SnapshotImported(SnapshotImportedResponse),
1208 SnapshotExported(SnapshotExportedResponse),
1209 OverlayCreated(OverlayCreatedResponse),
1210 GuestFilesystemResult(GuestFilesystemResultResponse),
1211 RootFilesystemSnapshot(RootFilesystemSnapshotResponse),
1212 ProcessStarted(ProcessStartedResponse),
1213 StdinWritten(StdinWrittenResponse),
1214 StdinClosed(StdinClosedResponse),
1215 ProcessKilled(ProcessKilledResponse),
1216 ProcessSnapshot(ProcessSnapshotResponse),
1217 ListenerSnapshot(ListenerSnapshotResponse),
1218 BoundUdpSnapshot(BoundUdpSnapshotResponse),
1219 VmFetchResult(VmFetchResponse),
1220 SignalState(SignalStateResponse),
1221 ZombieTimerCount(ZombieTimerCountResponse),
1222 FilesystemResult(FilesystemResultResponse),
1223 PermissionDecision(PermissionDecisionResponse),
1224 PersistenceState(PersistenceStateResponse),
1225 PersistenceFlushed(PersistenceFlushedResponse),
1226 Rejected(RejectedResponse),
1227 ExtResult(ExtEnvelope),
1228}
1229
1230#[derive(Debug, Clone, PartialEq, Eq)]
1231pub enum SidecarRequestPayload {
1232 HostCallback(HostCallbackRequest),
1233 JsBridgeCall(JsBridgeCallRequest),
1234 Ext(ExtEnvelope),
1235}
1236
1237#[derive(Debug, Clone, PartialEq, Eq)]
1238pub enum SidecarResponsePayload {
1239 HostCallbackResult(HostCallbackResultResponse),
1240 JsBridgeResult(JsBridgeResultResponse),
1241 ExtResult(ExtEnvelope),
1242}
1243
1244#[derive(Debug, Clone, PartialEq, Eq)]
1245pub enum EventPayload {
1246 VmLifecycle(VmLifecycleEvent),
1247 ProcessOutput(ProcessOutputEvent),
1248 ProcessExited(ProcessExitedEvent),
1249 Structured(StructuredEvent),
1250 Ext(ExtEnvelope),
1251}
1252
1253pub type SidecarPlacement = crate::wire::SidecarPlacement;
1254
1255pub type SidecarPlacementShared = crate::wire::SidecarPlacementShared;
1256
1257pub type SidecarPlacementExplicit = crate::wire::SidecarPlacementExplicit;
1258
1259pub type GuestRuntimeKind = crate::wire::GuestRuntimeKind;
1260
1261pub type DisposeReason = crate::wire::DisposeReason;
1262
1263pub type FilesystemOperation = crate::wire::FilesystemOperation;
1264
1265pub type GuestFilesystemOperation = crate::wire::GuestFilesystemOperation;
1266
1267pub type PermissionMode = crate::wire::PermissionMode;
1268
1269pub type FsPermissionRule = crate::wire::FsPermissionRule;
1270
1271pub type PatternPermissionRule = crate::wire::PatternPermissionRule;
1272
1273pub type FsPermissionRuleSet = crate::wire::FsPermissionRuleSet;
1274
1275pub type PatternPermissionRuleSet = crate::wire::PatternPermissionRuleSet;
1276
1277pub type FsPermissionScope = crate::wire::FsPermissionScope;
1278
1279pub type PatternPermissionScope = crate::wire::PatternPermissionScope;
1280
1281pub type PermissionsPolicy = crate::wire::PermissionsPolicy;
1282
1283pub type RootFilesystemEntryKind = crate::wire::RootFilesystemEntryKind;
1284
1285pub type RootFilesystemMode = crate::wire::RootFilesystemMode;
1286
1287pub type RootFilesystemLowerDescriptor = crate::wire::RootFilesystemLowerDescriptor;
1288
1289pub type SnapshotRootFilesystemLower = crate::wire::SnapshotRootFilesystemLower;
1290
1291pub type StreamChannel = crate::wire::StreamChannel;
1292
1293pub type VmLifecycleState = crate::wire::VmLifecycleState;
1294
1295pub type AuthenticateRequest = crate::wire::AuthenticateRequest;
1296
1297pub type OpenSessionRequest = crate::wire::OpenSessionRequest;
1298
1299pub type CreateVmRequest = crate::wire::CreateVmRequest;
1300
1301#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1302pub struct DisposeVmRequest {
1303 pub reason: DisposeReason,
1304}
1305
1306pub type BootstrapRootFilesystemRequest = crate::wire::BootstrapRootFilesystemRequest;
1307
1308pub type RootFilesystemDescriptor = crate::wire::RootFilesystemDescriptor;
1309
1310pub type RootFilesystemEntryEncoding = crate::wire::RootFilesystemEntryEncoding;
1311
1312pub type RootFilesystemEntry = crate::wire::RootFilesystemEntry;
1313
1314pub type ConfigureVmRequest = crate::wire::ConfigureVmRequest;
1315
1316#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
1317pub struct CreateLayerRequest {}
1318
1319pub type SealLayerRequest = crate::wire::SealLayerRequest;
1320
1321pub type ImportSnapshotRequest = crate::wire::ImportSnapshotRequest;
1322
1323pub type ExportSnapshotRequest = crate::wire::ExportSnapshotRequest;
1324
1325pub type CreateOverlayRequest = crate::wire::CreateOverlayRequest;
1326
1327pub type GuestFilesystemCallRequest = crate::wire::GuestFilesystemCallRequest;
1328
1329#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
1330pub struct SnapshotRootFilesystemRequest {}
1331
1332pub type MountDescriptor = crate::wire::MountDescriptor;
1333
1334pub type MountPluginDescriptor = crate::wire::MountPluginDescriptor;
1335
1336pub type SoftwareDescriptor = crate::wire::SoftwareDescriptor;
1337
1338pub type ProjectedModuleDescriptor = crate::wire::ProjectedModuleDescriptor;
1339
1340pub type WasmPermissionTier = crate::wire::WasmPermissionTier;
1341
1342pub type ExecuteRequest = crate::wire::ExecuteRequest;
1343
1344pub type WriteStdinRequest = crate::wire::WriteStdinRequest;
1345
1346pub type CloseStdinRequest = crate::wire::CloseStdinRequest;
1347
1348pub type KillProcessRequest = crate::wire::KillProcessRequest;
1349
1350#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
1351pub struct GetProcessSnapshotRequest {}
1352
1353pub type FindListenerRequest = crate::wire::FindListenerRequest;
1354
1355pub type FindBoundUdpRequest = crate::wire::FindBoundUdpRequest;
1356
1357pub type VmFetchRequest = crate::wire::VmFetchRequest;
1358
1359pub type GetSignalStateRequest = crate::wire::GetSignalStateRequest;
1360
1361#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
1362pub struct GetZombieTimerCountRequest {}
1363
1364pub type HostFilesystemCallRequest = crate::wire::HostFilesystemCallRequest;
1365
1366pub type PersistenceLoadRequest = crate::wire::PersistenceLoadRequest;
1367
1368pub type PersistenceFlushRequest = crate::wire::PersistenceFlushRequest;
1369
1370pub type RegisterHostCallbacksRequest = crate::wire::RegisterHostCallbacksRequest;
1371
1372pub type RegisteredHostCallbackDefinition = crate::wire::RegisteredHostCallbackDefinition;
1373
1374pub type RegisteredHostCallbackExample = crate::wire::RegisteredHostCallbackExample;
1375
1376pub type HostCallbackRequest = crate::wire::HostCallbackRequest;
1377
1378pub type JsBridgeCallRequest = crate::wire::JsBridgeCallRequest;
1379
1380pub type AuthenticatedResponse = crate::wire::AuthenticatedResponse;
1381
1382pub type SessionOpenedResponse = crate::wire::SessionOpenedResponse;
1383
1384pub type VmCreatedResponse = crate::wire::VmCreatedResponse;
1385
1386pub type VmDisposedResponse = crate::wire::VmDisposedResponse;
1387
1388pub type RootFilesystemBootstrappedResponse = crate::wire::RootFilesystemBootstrappedResponse;
1389
1390pub type VmConfiguredResponse = crate::wire::VmConfiguredResponse;
1391
1392pub type HostCallbacksRegisteredResponse = crate::wire::HostCallbacksRegisteredResponse;
1393
1394pub type GuestFilesystemStat = crate::wire::GuestFilesystemStat;
1395
1396pub type GuestFilesystemResultResponse = crate::wire::GuestFilesystemResultResponse;
1397
1398pub type RootFilesystemSnapshotResponse = crate::wire::RootFilesystemSnapshotResponse;
1399
1400pub type LayerCreatedResponse = crate::wire::LayerCreatedResponse;
1401
1402pub type LayerSealedResponse = crate::wire::LayerSealedResponse;
1403
1404pub type SnapshotImportedResponse = crate::wire::SnapshotImportedResponse;
1405
1406pub type SnapshotExportedResponse = crate::wire::SnapshotExportedResponse;
1407
1408pub type OverlayCreatedResponse = crate::wire::OverlayCreatedResponse;
1409
1410pub type ProcessStartedResponse = crate::wire::ProcessStartedResponse;
1411
1412pub type StdinWrittenResponse = crate::wire::StdinWrittenResponse;
1413
1414pub type StdinClosedResponse = crate::wire::StdinClosedResponse;
1415
1416pub type ProcessKilledResponse = crate::wire::ProcessKilledResponse;
1417
1418pub type ProcessSnapshotStatus = crate::wire::ProcessSnapshotStatus;
1419
1420pub type ProcessSnapshotEntry = crate::wire::ProcessSnapshotEntry;
1421
1422pub type ProcessSnapshotResponse = crate::wire::ProcessSnapshotResponse;
1423
1424pub type SocketStateEntry = crate::wire::SocketStateEntry;
1425
1426pub type ListenerSnapshotResponse = crate::wire::ListenerSnapshotResponse;
1427
1428pub type BoundUdpSnapshotResponse = crate::wire::BoundUdpSnapshotResponse;
1429
1430pub type VmFetchResponse = crate::wire::VmFetchResponse;
1431
1432pub type SignalDispositionAction = crate::wire::SignalDispositionAction;
1433
1434pub type SignalHandlerRegistration = crate::wire::SignalHandlerRegistration;
1435
1436pub type SignalStateResponse = crate::wire::SignalStateResponse;
1437
1438pub type ZombieTimerCountResponse = crate::wire::ZombieTimerCountResponse;
1439
1440pub type FilesystemResultResponse = crate::wire::FilesystemResultResponse;
1441
1442pub type PermissionDecisionResponse = crate::wire::PermissionDecisionResponse;
1443
1444pub type PersistenceStateResponse = crate::wire::PersistenceStateResponse;
1445
1446pub type PersistenceFlushedResponse = crate::wire::PersistenceFlushedResponse;
1447
1448pub type HostCallbackResultResponse = crate::wire::HostCallbackResultResponse;
1449
1450pub type JsBridgeResultResponse = crate::wire::JsBridgeResultResponse;
1451
1452pub type RejectedResponse = crate::wire::RejectedResponse;
1453
1454pub type VmLifecycleEvent = crate::wire::VmLifecycleEvent;
1455
1456pub type ProcessOutputEvent = crate::wire::ProcessOutputEvent;
1457
1458pub type ProcessExitedEvent = crate::wire::ProcessExitedEvent;
1459
1460pub type StructuredEvent = crate::wire::StructuredEvent;
1461
1462impl_bare_newtype_union_enum!(
1463 ProtocolFrame,
1464 JsonProtocolFrame,
1465 #[serde(tag = "frame_type", rename_all = "snake_case")]
1466 {
1467 Request(RequestFrame) = 0,
1468 Response(ResponseFrame) = 1,
1469 Event(EventFrame) = 2,
1470 SidecarRequest(SidecarRequestFrame) = 3,
1471 SidecarResponse(SidecarResponseFrame) = 4,
1472 }
1473);
1474
1475impl_bare_newtype_union_enum!(
1476 RequestPayload,
1477 JsonRequestPayload,
1478 #[serde(tag = "type", rename_all = "snake_case")]
1479 {
1480 Authenticate(AuthenticateRequest) = 0,
1481 OpenSession(OpenSessionRequest) = 1,
1482 CreateVm(CreateVmRequest) = 2,
1483 DisposeVm(DisposeVmRequest) = 3,
1484 BootstrapRootFilesystem(BootstrapRootFilesystemRequest) = 4,
1485 ConfigureVm(ConfigureVmRequest) = 5,
1486 RegisterHostCallbacks(RegisterHostCallbacksRequest) = 6,
1487 CreateLayer(CreateLayerRequest) = 7,
1488 SealLayer(SealLayerRequest) = 8,
1489 ImportSnapshot(ImportSnapshotRequest) = 9,
1490 ExportSnapshot(ExportSnapshotRequest) = 10,
1491 CreateOverlay(CreateOverlayRequest) = 11,
1492 GuestFilesystemCall(GuestFilesystemCallRequest) = 12,
1493 SnapshotRootFilesystem(SnapshotRootFilesystemRequest) = 13,
1494 Execute(ExecuteRequest) = 14,
1495 WriteStdin(WriteStdinRequest) = 15,
1496 CloseStdin(CloseStdinRequest) = 16,
1497 KillProcess(KillProcessRequest) = 17,
1498 GetProcessSnapshot(GetProcessSnapshotRequest) = 18,
1499 FindListener(FindListenerRequest) = 19,
1500 FindBoundUdp(FindBoundUdpRequest) = 20,
1501 GetSignalState(GetSignalStateRequest) = 21,
1502 GetZombieTimerCount(GetZombieTimerCountRequest) = 22,
1503 HostFilesystemCall(HostFilesystemCallRequest) = 23,
1504 PersistenceLoad(PersistenceLoadRequest) = 24,
1505 PersistenceFlush(PersistenceFlushRequest) = 25,
1506 VmFetch(VmFetchRequest) = 26,
1507 Ext(ExtEnvelope) = 27,
1508 }
1509);
1510
1511impl_bare_newtype_union_enum!(
1512 ResponsePayload,
1513 JsonResponsePayload,
1514 #[serde(tag = "type", rename_all = "snake_case")]
1515 {
1516 Authenticated(AuthenticatedResponse) = 0,
1517 SessionOpened(SessionOpenedResponse) = 1,
1518 VmCreated(VmCreatedResponse) = 2,
1519 VmDisposed(VmDisposedResponse) = 3,
1520 RootFilesystemBootstrapped(RootFilesystemBootstrappedResponse) = 4,
1521 VmConfigured(VmConfiguredResponse) = 5,
1522 HostCallbacksRegistered(HostCallbacksRegisteredResponse) = 6,
1523 LayerCreated(LayerCreatedResponse) = 7,
1524 LayerSealed(LayerSealedResponse) = 8,
1525 SnapshotImported(SnapshotImportedResponse) = 9,
1526 SnapshotExported(SnapshotExportedResponse) = 10,
1527 OverlayCreated(OverlayCreatedResponse) = 11,
1528 GuestFilesystemResult(GuestFilesystemResultResponse) = 12,
1529 RootFilesystemSnapshot(RootFilesystemSnapshotResponse) = 13,
1530 ProcessStarted(ProcessStartedResponse) = 14,
1531 StdinWritten(StdinWrittenResponse) = 15,
1532 StdinClosed(StdinClosedResponse) = 16,
1533 ProcessKilled(ProcessKilledResponse) = 17,
1534 ProcessSnapshot(ProcessSnapshotResponse) = 18,
1535 ListenerSnapshot(ListenerSnapshotResponse) = 19,
1536 BoundUdpSnapshot(BoundUdpSnapshotResponse) = 20,
1537 SignalState(SignalStateResponse) = 21,
1538 ZombieTimerCount(ZombieTimerCountResponse) = 22,
1539 FilesystemResult(FilesystemResultResponse) = 23,
1540 PermissionDecision(PermissionDecisionResponse) = 24,
1541 PersistenceState(PersistenceStateResponse) = 25,
1542 PersistenceFlushed(PersistenceFlushedResponse) = 26,
1543 Rejected(RejectedResponse) = 27,
1544 VmFetchResult(VmFetchResponse) = 28,
1545 ExtResult(ExtEnvelope) = 29,
1546 }
1547);
1548
1549impl_bare_newtype_union_enum!(
1550 SidecarRequestPayload,
1551 JsonSidecarRequestPayload,
1552 #[serde(tag = "type", rename_all = "snake_case")]
1553 {
1554 HostCallback(HostCallbackRequest) = 0,
1555 JsBridgeCall(JsBridgeCallRequest) = 1,
1556 Ext(ExtEnvelope) = 2,
1557 }
1558);
1559
1560impl_bare_newtype_union_enum!(
1561 SidecarResponsePayload,
1562 JsonSidecarResponsePayload,
1563 #[allow(clippy::enum_variant_names)]
1564 #[serde(tag = "type", rename_all = "snake_case")]
1565 {
1566 HostCallbackResult(HostCallbackResultResponse) = 0,
1567 JsBridgeResult(JsBridgeResultResponse) = 1,
1568 ExtResult(ExtEnvelope) = 2,
1569 }
1570);
1571
1572impl_bare_newtype_union_enum!(
1573 EventPayload,
1574 JsonEventPayload,
1575 #[serde(tag = "type", rename_all = "snake_case")]
1576 {
1577 VmLifecycle(VmLifecycleEvent) = 0,
1578 ProcessOutput(ProcessOutputEvent) = 1,
1579 ProcessExited(ProcessExitedEvent) = 2,
1580 Structured(StructuredEvent) = 3,
1581 Ext(ExtEnvelope) = 4,
1582 }
1583);
1584
1585fn serialize_payload(
1586 frame: &ProtocolFrame,
1587 payload_codec: NativePayloadCodec,
1588) -> Result<Vec<u8>, ProtocolCodecError> {
1589 match payload_codec {
1590 NativePayloadCodec::Json => serde_json::to_vec(frame)
1591 .map_err(|error| ProtocolCodecError::SerializeFailure(error.to_string())),
1592 NativePayloadCodec::Bare => serde_bare::to_vec(&to_generated_protocol_frame(frame)?)
1593 .map_err(|error| ProtocolCodecError::SerializeFailure(error.to_string())),
1594 }
1595}
1596
1597fn deserialize_payload(
1598 payload: &[u8],
1599 payload_codec: NativePayloadCodec,
1600) -> Result<ProtocolFrame, ProtocolCodecError> {
1601 match payload_codec {
1602 NativePayloadCodec::Json => serde_json::from_slice(payload)
1603 .map_err(|error| ProtocolCodecError::DeserializeFailure(error.to_string())),
1604 NativePayloadCodec::Bare => {
1605 let frame: generated_protocol::ProtocolFrame = serde_bare::from_slice(payload)
1606 .map_err(|error| ProtocolCodecError::DeserializeFailure(error.to_string()))?;
1607 from_generated_protocol_frame(frame)
1608 }
1609 }
1610}
1611
1612#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1613pub enum NativePayloadCodec {
1614 Json,
1615 Bare,
1616}
1617
1618impl NativePayloadCodec {
1619 pub fn sniff(payload: &[u8]) -> Self {
1620 match payload.first() {
1621 Some(b'{') => Self::Json,
1622 _ => Self::Bare,
1623 }
1624 }
1625
1626 pub fn alternate(self) -> Self {
1627 match self {
1628 Self::Json => Self::Bare,
1629 Self::Bare => Self::Json,
1630 }
1631 }
1632}
1633
1634#[derive(Debug, Clone)]
1635pub struct NativeFrameCodec {
1636 max_frame_bytes: usize,
1637 payload_codec: NativePayloadCodec,
1638}
1639
1640impl NativeFrameCodec {
1641 pub fn new(max_frame_bytes: usize) -> Self {
1642 Self::with_payload_codec(max_frame_bytes, NativePayloadCodec::Json)
1643 }
1644
1645 pub fn with_payload_codec(max_frame_bytes: usize, payload_codec: NativePayloadCodec) -> Self {
1646 Self {
1647 max_frame_bytes,
1648 payload_codec,
1649 }
1650 }
1651
1652 pub fn max_frame_bytes(&self) -> usize {
1653 self.max_frame_bytes
1654 }
1655
1656 pub fn payload_codec(&self) -> NativePayloadCodec {
1657 self.payload_codec
1658 }
1659
1660 pub fn encode(&self, frame: &ProtocolFrame) -> Result<Vec<u8>, ProtocolCodecError> {
1661 self.encode_with_codec(frame, self.payload_codec)
1662 }
1663
1664 pub fn encode_with_codec(
1665 &self,
1666 frame: &ProtocolFrame,
1667 payload_codec: NativePayloadCodec,
1668 ) -> Result<Vec<u8>, ProtocolCodecError> {
1669 validate_frame(frame)?;
1670
1671 let payload = serialize_payload(frame, payload_codec)?;
1672 if payload.len() > self.max_frame_bytes {
1673 return Err(ProtocolCodecError::FrameTooLarge {
1674 size: payload.len(),
1675 max: self.max_frame_bytes,
1676 });
1677 }
1678
1679 let length =
1680 u32::try_from(payload.len()).map_err(|_| ProtocolCodecError::FrameTooLarge {
1681 size: payload.len(),
1682 max: u32::MAX as usize,
1683 })?;
1684
1685 let mut encoded = Vec::with_capacity(4 + payload.len());
1686 encoded.extend_from_slice(&length.to_be_bytes());
1687 encoded.extend_from_slice(&payload);
1688 Ok(encoded)
1689 }
1690
1691 pub fn decode(&self, bytes: &[u8]) -> Result<ProtocolFrame, ProtocolCodecError> {
1692 self.decode_detected(bytes).map(|(frame, _)| frame)
1693 }
1694
1695 pub fn decode_with_codec(
1696 &self,
1697 bytes: &[u8],
1698 payload_codec: NativePayloadCodec,
1699 ) -> Result<ProtocolFrame, ProtocolCodecError> {
1700 let payload = self.checked_payload(bytes)?;
1701 let frame = deserialize_payload(payload, payload_codec)?;
1702 validate_frame(&frame)?;
1703 Ok(frame)
1704 }
1705
1706 pub fn decode_detected(
1707 &self,
1708 bytes: &[u8],
1709 ) -> Result<(ProtocolFrame, NativePayloadCodec), ProtocolCodecError> {
1710 let payload = self.checked_payload(bytes)?;
1711 let primary = NativePayloadCodec::sniff(payload);
1712
1713 match deserialize_payload(payload, primary) {
1714 Ok(frame) => {
1715 validate_frame(&frame)?;
1716 Ok((frame, primary))
1717 }
1718 Err(primary_error) => {
1719 let alternate = primary.alternate();
1720 let frame = deserialize_payload(payload, alternate).map_err(|_| primary_error)?;
1721 validate_frame(&frame)?;
1722 Ok((frame, alternate))
1723 }
1724 }
1725 }
1726
1727 fn checked_payload<'a>(&self, bytes: &'a [u8]) -> Result<&'a [u8], ProtocolCodecError> {
1728 if bytes.len() < 4 {
1729 return Err(ProtocolCodecError::TruncatedFrame {
1730 actual: bytes.len(),
1731 });
1732 }
1733
1734 let declared =
1735 u32::from_be_bytes(bytes[..4].try_into().expect("length prefix is four bytes"))
1736 as usize;
1737 if declared > self.max_frame_bytes {
1738 return Err(ProtocolCodecError::FrameTooLarge {
1739 size: declared,
1740 max: self.max_frame_bytes,
1741 });
1742 }
1743
1744 let actual = bytes.len() - 4;
1745 if declared != actual {
1746 return Err(ProtocolCodecError::LengthPrefixMismatch { declared, actual });
1747 }
1748 Ok(&bytes[4..])
1749 }
1750}
1751
1752impl Default for NativeFrameCodec {
1753 fn default() -> Self {
1754 Self::new(DEFAULT_MAX_FRAME_BYTES)
1755 }
1756}
1757
1758#[derive(Debug)]
1759pub struct ResponseTracker {
1760 pending: HashMap<RequestId, PendingRequest>,
1761 completed: HashSet<RequestId>,
1762 completed_order: VecDeque<RequestId>,
1763 completed_cap: usize,
1764}
1765
1766#[derive(Debug)]
1767pub struct SidecarResponseTracker {
1768 pending: HashMap<RequestId, PendingSidecarRequest>,
1769 completed: HashSet<RequestId>,
1770 completed_order: VecDeque<RequestId>,
1771 completed_cap: usize,
1772}
1773
1774impl ResponseTracker {
1775 pub fn with_completed_cap(completed_cap: usize) -> Self {
1776 Self {
1777 pending: HashMap::new(),
1778 completed: HashSet::new(),
1779 completed_order: VecDeque::new(),
1780 completed_cap: completed_cap.max(1),
1781 }
1782 }
1783
1784 pub fn completed_count(&self) -> usize {
1785 self.completed.len()
1786 }
1787
1788 pub fn register_request(&mut self, request: &RequestFrame) -> Result<(), ResponseTrackerError> {
1789 if self.pending.contains_key(&request.request_id)
1790 || self.completed.contains(&request.request_id)
1791 {
1792 return Err(ResponseTrackerError::DuplicateRequestId {
1793 request_id: request.request_id,
1794 });
1795 }
1796
1797 self.pending.insert(
1798 request.request_id,
1799 PendingRequest {
1800 ownership: request.ownership.clone(),
1801 expected_response: request.payload.expected_response(),
1802 },
1803 );
1804 Ok(())
1805 }
1806
1807 pub fn accept_response(
1808 &mut self,
1809 response: &ResponseFrame,
1810 ) -> Result<(), ResponseTrackerError> {
1811 if self.completed.contains(&response.request_id) {
1812 return Err(ResponseTrackerError::DuplicateResponse {
1813 request_id: response.request_id,
1814 });
1815 }
1816
1817 let pending = self.pending.get(&response.request_id).ok_or(
1818 ResponseTrackerError::UnmatchedResponse {
1819 request_id: response.request_id,
1820 },
1821 )?;
1822
1823 if pending.ownership != response.ownership {
1824 return Err(ResponseTrackerError::OwnershipMismatch {
1825 request_id: response.request_id,
1826 expected: Box::new(pending.ownership.clone()),
1827 actual: Box::new(response.ownership.clone()),
1828 });
1829 }
1830
1831 if !pending.expected_response.matches(&response.payload) {
1832 return Err(ResponseTrackerError::ResponseKindMismatch {
1833 request_id: response.request_id,
1834 expected: pending.expected_response.as_str().to_string(),
1835 actual: response.payload.kind_name().to_string(),
1836 });
1837 }
1838
1839 self.pending
1840 .remove(&response.request_id)
1841 .expect("pending response should still exist after validation");
1842 self.completed.insert(response.request_id);
1843 self.completed_order.push_back(response.request_id);
1844 while self.completed.len() > self.completed_cap {
1845 if let Some(evicted) = self.completed_order.pop_front() {
1846 self.completed.remove(&evicted);
1847 }
1848 }
1849 Ok(())
1850 }
1851}
1852
1853impl Default for ResponseTracker {
1854 fn default() -> Self {
1855 Self::with_completed_cap(DEFAULT_COMPLETED_RESPONSE_CAP)
1856 }
1857}
1858
1859impl SidecarResponseTracker {
1860 pub fn with_completed_cap(completed_cap: usize) -> Self {
1861 Self {
1862 pending: HashMap::new(),
1863 completed: HashSet::new(),
1864 completed_order: VecDeque::new(),
1865 completed_cap: completed_cap.max(1),
1866 }
1867 }
1868
1869 pub fn pending_count(&self) -> usize {
1870 self.pending.len()
1871 }
1872
1873 pub fn completed_count(&self) -> usize {
1874 self.completed.len()
1875 }
1876
1877 pub fn register_request(
1878 &mut self,
1879 request: &SidecarRequestFrame,
1880 ) -> Result<(), SidecarResponseTrackerError> {
1881 if self.pending.contains_key(&request.request_id)
1882 || self.completed.contains(&request.request_id)
1883 {
1884 return Err(SidecarResponseTrackerError::DuplicateRequestId {
1885 request_id: request.request_id,
1886 });
1887 }
1888
1889 self.pending.insert(
1890 request.request_id,
1891 PendingSidecarRequest {
1892 ownership: request.ownership.clone(),
1893 expected_response: request.payload.expected_response(),
1894 },
1895 );
1896 Ok(())
1897 }
1898
1899 pub fn accept_response(
1900 &mut self,
1901 response: &SidecarResponseFrame,
1902 ) -> Result<(), SidecarResponseTrackerError> {
1903 if self.completed.contains(&response.request_id) {
1904 return Err(SidecarResponseTrackerError::DuplicateResponse {
1905 request_id: response.request_id,
1906 });
1907 }
1908
1909 let pending = self.pending.get(&response.request_id).ok_or(
1910 SidecarResponseTrackerError::UnmatchedResponse {
1911 request_id: response.request_id,
1912 },
1913 )?;
1914
1915 if pending.ownership != response.ownership {
1916 return Err(SidecarResponseTrackerError::OwnershipMismatch {
1917 request_id: response.request_id,
1918 expected: Box::new(pending.ownership.clone()),
1919 actual: Box::new(response.ownership.clone()),
1920 });
1921 }
1922
1923 if !pending.expected_response.matches(&response.payload) {
1924 return Err(SidecarResponseTrackerError::ResponseKindMismatch {
1925 request_id: response.request_id,
1926 expected: pending.expected_response.as_str().to_string(),
1927 actual: response.payload.kind_name().to_string(),
1928 });
1929 }
1930
1931 self.pending
1932 .remove(&response.request_id)
1933 .expect("pending sidecar response should still exist after validation");
1934 self.completed.insert(response.request_id);
1935 self.completed_order.push_back(response.request_id);
1936 while self.completed.len() > self.completed_cap {
1937 if let Some(evicted) = self.completed_order.pop_front() {
1938 self.completed.remove(&evicted);
1939 }
1940 }
1941 Ok(())
1942 }
1943}
1944
1945impl Default for SidecarResponseTracker {
1946 fn default() -> Self {
1947 Self::with_completed_cap(DEFAULT_COMPLETED_RESPONSE_CAP)
1948 }
1949}
1950
1951#[derive(Debug, Clone, PartialEq, Eq)]
1952pub enum ResponseTrackerError {
1953 DuplicateRequestId {
1954 request_id: RequestId,
1955 },
1956 UnmatchedResponse {
1957 request_id: RequestId,
1958 },
1959 DuplicateResponse {
1960 request_id: RequestId,
1961 },
1962 OwnershipMismatch {
1963 request_id: RequestId,
1964 expected: Box<OwnershipScope>,
1965 actual: Box<OwnershipScope>,
1966 },
1967 ResponseKindMismatch {
1968 request_id: RequestId,
1969 expected: String,
1970 actual: String,
1971 },
1972}
1973
1974impl fmt::Display for ResponseTrackerError {
1975 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1976 match self {
1977 Self::DuplicateRequestId { request_id } => {
1978 write!(f, "request id {request_id} is already tracked")
1979 }
1980 Self::UnmatchedResponse { request_id } => {
1981 write!(
1982 f,
1983 "response id {request_id} does not match any pending request"
1984 )
1985 }
1986 Self::DuplicateResponse { request_id } => {
1987 write!(f, "response id {request_id} has already been completed")
1988 }
1989 Self::OwnershipMismatch {
1990 request_id,
1991 expected,
1992 actual,
1993 } => write!(
1994 f,
1995 "response id {request_id} used ownership {:?}, expected {:?}",
1996 actual, expected
1997 ),
1998 Self::ResponseKindMismatch {
1999 request_id,
2000 expected,
2001 actual,
2002 } => write!(
2003 f,
2004 "response id {request_id} carried {actual}, expected {expected}",
2005 ),
2006 }
2007 }
2008}
2009
2010impl Error for ResponseTrackerError {}
2011
2012#[derive(Debug, Clone, PartialEq, Eq)]
2013pub enum SidecarResponseTrackerError {
2014 DuplicateRequestId {
2015 request_id: RequestId,
2016 },
2017 UnmatchedResponse {
2018 request_id: RequestId,
2019 },
2020 DuplicateResponse {
2021 request_id: RequestId,
2022 },
2023 OwnershipMismatch {
2024 request_id: RequestId,
2025 expected: Box<OwnershipScope>,
2026 actual: Box<OwnershipScope>,
2027 },
2028 ResponseKindMismatch {
2029 request_id: RequestId,
2030 expected: String,
2031 actual: String,
2032 },
2033}
2034
2035impl fmt::Display for SidecarResponseTrackerError {
2036 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2037 match self {
2038 Self::DuplicateRequestId { request_id } => {
2039 write!(f, "sidecar request id {request_id} is already tracked")
2040 }
2041 Self::UnmatchedResponse { request_id } => {
2042 write!(
2043 f,
2044 "sidecar response id {request_id} does not match any pending request"
2045 )
2046 }
2047 Self::DuplicateResponse { request_id } => {
2048 write!(
2049 f,
2050 "sidecar response id {request_id} has already been completed"
2051 )
2052 }
2053 Self::OwnershipMismatch {
2054 request_id,
2055 expected,
2056 actual,
2057 } => write!(
2058 f,
2059 "sidecar response id {request_id} used ownership {:?}, expected {:?}",
2060 actual, expected
2061 ),
2062 Self::ResponseKindMismatch {
2063 request_id,
2064 expected,
2065 actual,
2066 } => write!(
2067 f,
2068 "sidecar response id {request_id} carried {actual}, expected {expected}",
2069 ),
2070 }
2071 }
2072}
2073
2074impl Error for SidecarResponseTrackerError {}
2075
2076#[derive(Debug, Clone, PartialEq, Eq)]
2077struct PendingRequest {
2078 ownership: OwnershipScope,
2079 expected_response: ExpectedResponseKind,
2080}
2081
2082#[derive(Debug, Clone, PartialEq, Eq)]
2083struct PendingSidecarRequest {
2084 ownership: OwnershipScope,
2085 expected_response: ExpectedSidecarResponseKind,
2086}
2087
2088#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2089enum ExpectedResponseKind {
2090 Authenticated,
2091 SessionOpened,
2092 VmCreated,
2093 VmDisposed,
2094 RootFilesystemBootstrapped,
2095 VmConfigured,
2096 HostCallbacksRegistered,
2097 LayerCreated,
2098 LayerSealed,
2099 SnapshotImported,
2100 SnapshotExported,
2101 OverlayCreated,
2102 GuestFilesystemResult,
2103 RootFilesystemSnapshot,
2104 ProcessStarted,
2105 StdinWritten,
2106 StdinClosed,
2107 ProcessKilled,
2108 ProcessSnapshot,
2109 ListenerSnapshot,
2110 BoundUdpSnapshot,
2111 VmFetchResult,
2112 SignalState,
2113 ZombieTimerCount,
2114 FilesystemResult,
2115 #[allow(dead_code)]
2118 PermissionDecision,
2119 PersistenceState,
2120 PersistenceFlushed,
2121 ExtResult,
2122}
2123
2124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2125enum ExpectedSidecarResponseKind {
2126 HostCallback,
2127 JsBridge,
2128 Ext,
2129}
2130
2131impl ExpectedResponseKind {
2132 fn as_str(self) -> &'static str {
2133 match self {
2134 Self::Authenticated => "authenticated",
2135 Self::SessionOpened => "session_opened",
2136 Self::VmCreated => "vm_created",
2137 Self::VmDisposed => "vm_disposed",
2138 Self::RootFilesystemBootstrapped => "root_filesystem_bootstrapped",
2139 Self::VmConfigured => "vm_configured",
2140 Self::HostCallbacksRegistered => "host_callbacks_registered",
2141 Self::LayerCreated => "layer_created",
2142 Self::LayerSealed => "layer_sealed",
2143 Self::SnapshotImported => "snapshot_imported",
2144 Self::SnapshotExported => "snapshot_exported",
2145 Self::OverlayCreated => "overlay_created",
2146 Self::GuestFilesystemResult => "guest_filesystem_result",
2147 Self::RootFilesystemSnapshot => "root_filesystem_snapshot",
2148 Self::ProcessStarted => "process_started",
2149 Self::StdinWritten => "stdin_written",
2150 Self::StdinClosed => "stdin_closed",
2151 Self::ProcessKilled => "process_killed",
2152 Self::ProcessSnapshot => "process_snapshot",
2153 Self::ListenerSnapshot => "listener_snapshot",
2154 Self::BoundUdpSnapshot => "bound_udp_snapshot",
2155 Self::VmFetchResult => "vm_fetch_result",
2156 Self::SignalState => "signal_state",
2157 Self::ZombieTimerCount => "zombie_timer_count",
2158 Self::FilesystemResult => "filesystem_result",
2159 Self::PermissionDecision => "permission_decision",
2160 Self::PersistenceState => "persistence_state",
2161 Self::PersistenceFlushed => "persistence_flushed",
2162 Self::ExtResult => "ext_result",
2163 }
2164 }
2165
2166 fn matches(self, payload: &ResponsePayload) -> bool {
2167 match payload {
2168 ResponsePayload::Rejected(_) => true,
2169 _ => payload.kind_name() == self.as_str(),
2170 }
2171 }
2172}
2173
2174impl ExpectedSidecarResponseKind {
2175 fn as_str(self) -> &'static str {
2176 match self {
2177 Self::HostCallback => "host_callback_result",
2178 Self::JsBridge => "js_bridge_result",
2179 Self::Ext => "ext_result",
2180 }
2181 }
2182
2183 fn matches(self, payload: &SidecarResponsePayload) -> bool {
2184 payload.kind_name() == self.as_str()
2185 }
2186}
2187
2188impl RequestPayload {
2189 fn ownership_requirement(&self) -> OwnershipRequirement {
2190 match self {
2191 Self::Authenticate(_) | Self::OpenSession(_) => OwnershipRequirement::Connection,
2192 Self::CreateVm(_) | Self::PersistenceLoad(_) | Self::PersistenceFlush(_) => {
2193 OwnershipRequirement::Session
2194 }
2195 Self::DisposeVm(_)
2196 | Self::BootstrapRootFilesystem(_)
2197 | Self::ConfigureVm(_)
2198 | Self::RegisterHostCallbacks(_)
2199 | Self::CreateLayer(_)
2200 | Self::SealLayer(_)
2201 | Self::ImportSnapshot(_)
2202 | Self::ExportSnapshot(_)
2203 | Self::CreateOverlay(_)
2204 | Self::GuestFilesystemCall(_)
2205 | Self::SnapshotRootFilesystem(_)
2206 | Self::Execute(_)
2207 | Self::WriteStdin(_)
2208 | Self::CloseStdin(_)
2209 | Self::KillProcess(_)
2210 | Self::GetProcessSnapshot(_)
2211 | Self::FindListener(_)
2212 | Self::FindBoundUdp(_)
2213 | Self::VmFetch(_)
2214 | Self::GetSignalState(_)
2215 | Self::GetZombieTimerCount(_)
2216 | Self::HostFilesystemCall(_) => OwnershipRequirement::Vm,
2217 Self::Ext(_) => OwnershipRequirement::Any,
2218 }
2219 }
2220
2221 fn expected_response(&self) -> ExpectedResponseKind {
2222 match self {
2223 Self::Authenticate(_) => ExpectedResponseKind::Authenticated,
2224 Self::OpenSession(_) => ExpectedResponseKind::SessionOpened,
2225 Self::CreateVm(_) => ExpectedResponseKind::VmCreated,
2226 Self::DisposeVm(_) => ExpectedResponseKind::VmDisposed,
2227 Self::BootstrapRootFilesystem(_) => ExpectedResponseKind::RootFilesystemBootstrapped,
2228 Self::ConfigureVm(_) => ExpectedResponseKind::VmConfigured,
2229 Self::RegisterHostCallbacks(_) => ExpectedResponseKind::HostCallbacksRegistered,
2230 Self::CreateLayer(_) => ExpectedResponseKind::LayerCreated,
2231 Self::SealLayer(_) => ExpectedResponseKind::LayerSealed,
2232 Self::ImportSnapshot(_) => ExpectedResponseKind::SnapshotImported,
2233 Self::ExportSnapshot(_) => ExpectedResponseKind::SnapshotExported,
2234 Self::CreateOverlay(_) => ExpectedResponseKind::OverlayCreated,
2235 Self::GuestFilesystemCall(_) => ExpectedResponseKind::GuestFilesystemResult,
2236 Self::SnapshotRootFilesystem(_) => ExpectedResponseKind::RootFilesystemSnapshot,
2237 Self::Execute(_) => ExpectedResponseKind::ProcessStarted,
2238 Self::WriteStdin(_) => ExpectedResponseKind::StdinWritten,
2239 Self::CloseStdin(_) => ExpectedResponseKind::StdinClosed,
2240 Self::KillProcess(_) => ExpectedResponseKind::ProcessKilled,
2241 Self::GetProcessSnapshot(_) => ExpectedResponseKind::ProcessSnapshot,
2242 Self::FindListener(_) => ExpectedResponseKind::ListenerSnapshot,
2243 Self::FindBoundUdp(_) => ExpectedResponseKind::BoundUdpSnapshot,
2244 Self::VmFetch(_) => ExpectedResponseKind::VmFetchResult,
2245 Self::GetSignalState(_) => ExpectedResponseKind::SignalState,
2246 Self::GetZombieTimerCount(_) => ExpectedResponseKind::ZombieTimerCount,
2247 Self::HostFilesystemCall(_) => ExpectedResponseKind::FilesystemResult,
2248 Self::PersistenceLoad(_) => ExpectedResponseKind::PersistenceState,
2249 Self::PersistenceFlush(_) => ExpectedResponseKind::PersistenceFlushed,
2250 Self::Ext(_) => ExpectedResponseKind::ExtResult,
2251 }
2252 }
2253}
2254
2255impl SidecarRequestPayload {
2256 fn ownership_requirement(&self) -> OwnershipRequirement {
2257 OwnershipRequirement::Vm
2258 }
2259
2260 fn expected_response(&self) -> ExpectedSidecarResponseKind {
2261 match self {
2262 Self::HostCallback(_) => ExpectedSidecarResponseKind::HostCallback,
2263 Self::JsBridgeCall(_) => ExpectedSidecarResponseKind::JsBridge,
2264 Self::Ext(_) => ExpectedSidecarResponseKind::Ext,
2265 }
2266 }
2267}
2268
2269impl ResponsePayload {
2270 fn ownership_requirement(&self) -> OwnershipRequirement {
2271 match self {
2272 Self::Authenticated(_) | Self::SessionOpened(_) => OwnershipRequirement::Connection,
2273 Self::VmCreated(_) | Self::PersistenceState(_) | Self::PersistenceFlushed(_) => {
2274 OwnershipRequirement::Session
2275 }
2276 Self::Rejected(_) => OwnershipRequirement::Any,
2277 Self::VmDisposed(_)
2278 | Self::RootFilesystemBootstrapped(_)
2279 | Self::VmConfigured(_)
2280 | Self::HostCallbacksRegistered(_)
2281 | Self::LayerCreated(_)
2282 | Self::LayerSealed(_)
2283 | Self::SnapshotImported(_)
2284 | Self::SnapshotExported(_)
2285 | Self::OverlayCreated(_)
2286 | Self::GuestFilesystemResult(_)
2287 | Self::RootFilesystemSnapshot(_)
2288 | Self::ProcessStarted(_)
2289 | Self::StdinWritten(_)
2290 | Self::StdinClosed(_)
2291 | Self::ProcessKilled(_)
2292 | Self::ProcessSnapshot(_)
2293 | Self::ListenerSnapshot(_)
2294 | Self::BoundUdpSnapshot(_)
2295 | Self::VmFetchResult(_)
2296 | Self::SignalState(_)
2297 | Self::ZombieTimerCount(_)
2298 | Self::FilesystemResult(_)
2299 | Self::PermissionDecision(_) => OwnershipRequirement::Vm,
2300 Self::ExtResult(_) => OwnershipRequirement::Any,
2301 }
2302 }
2303
2304 fn kind_name(&self) -> &'static str {
2305 match self {
2306 Self::Authenticated(_) => "authenticated",
2307 Self::SessionOpened(_) => "session_opened",
2308 Self::VmCreated(_) => "vm_created",
2309 Self::VmDisposed(_) => "vm_disposed",
2310 Self::RootFilesystemBootstrapped(_) => "root_filesystem_bootstrapped",
2311 Self::VmConfigured(_) => "vm_configured",
2312 Self::HostCallbacksRegistered(_) => "host_callbacks_registered",
2313 Self::LayerCreated(_) => "layer_created",
2314 Self::LayerSealed(_) => "layer_sealed",
2315 Self::SnapshotImported(_) => "snapshot_imported",
2316 Self::SnapshotExported(_) => "snapshot_exported",
2317 Self::OverlayCreated(_) => "overlay_created",
2318 Self::GuestFilesystemResult(_) => "guest_filesystem_result",
2319 Self::RootFilesystemSnapshot(_) => "root_filesystem_snapshot",
2320 Self::ProcessStarted(_) => "process_started",
2321 Self::StdinWritten(_) => "stdin_written",
2322 Self::StdinClosed(_) => "stdin_closed",
2323 Self::ProcessKilled(_) => "process_killed",
2324 Self::ProcessSnapshot(_) => "process_snapshot",
2325 Self::ListenerSnapshot(_) => "listener_snapshot",
2326 Self::BoundUdpSnapshot(_) => "bound_udp_snapshot",
2327 Self::VmFetchResult(_) => "vm_fetch_result",
2328 Self::SignalState(_) => "signal_state",
2329 Self::ZombieTimerCount(_) => "zombie_timer_count",
2330 Self::FilesystemResult(_) => "filesystem_result",
2331 Self::PermissionDecision(_) => "permission_decision",
2332 Self::PersistenceState(_) => "persistence_state",
2333 Self::PersistenceFlushed(_) => "persistence_flushed",
2334 Self::Rejected(_) => "rejected",
2335 Self::ExtResult(_) => "ext_result",
2336 }
2337 }
2338}
2339
2340impl SidecarResponsePayload {
2341 fn ownership_requirement(&self) -> OwnershipRequirement {
2342 OwnershipRequirement::Vm
2343 }
2344
2345 fn kind_name(&self) -> &'static str {
2346 match self {
2347 Self::HostCallbackResult(_) => "host_callback_result",
2348 Self::JsBridgeResult(_) => "js_bridge_result",
2349 Self::ExtResult(_) => "ext_result",
2350 }
2351 }
2352}
2353
2354impl EventPayload {
2355 fn ownership_requirement(&self) -> OwnershipRequirement {
2356 match self {
2357 Self::Structured(_) => OwnershipRequirement::SessionOrVm,
2358 Self::VmLifecycle(_) | Self::ProcessOutput(_) | Self::ProcessExited(_) => {
2359 OwnershipRequirement::Vm
2360 }
2361 Self::Ext(_) => OwnershipRequirement::Any,
2362 }
2363 }
2364}
2365
2366pub fn validate_frame(frame: &ProtocolFrame) -> Result<(), ProtocolCodecError> {
2367 match frame {
2368 ProtocolFrame::Request(request) => validate_request(request),
2369 ProtocolFrame::Response(response) => validate_response(response),
2370 ProtocolFrame::Event(event) => validate_event(event),
2371 ProtocolFrame::SidecarRequest(request) => validate_sidecar_request(request),
2372 ProtocolFrame::SidecarResponse(response) => validate_sidecar_response(response),
2373 }
2374}
2375
2376fn validate_request(request: &RequestFrame) -> Result<(), ProtocolCodecError> {
2377 validate_schema(&request.schema)?;
2378 validate_request_id_direction(request.request_id, RequestDirection::Host)?;
2379
2380 validate_ownership(&request.ownership)?;
2381 validate_requirement(request.payload.ownership_requirement(), &request.ownership)?;
2382 if let RequestPayload::Authenticate(authenticate) = &request.payload {
2383 if authenticate.auth_token.is_empty() {
2384 return Err(ProtocolCodecError::EmptyAuthToken);
2385 }
2386 }
2387
2388 Ok(())
2389}
2390
2391fn validate_response(response: &ResponseFrame) -> Result<(), ProtocolCodecError> {
2392 validate_schema(&response.schema)?;
2393 validate_request_id_direction(response.request_id, RequestDirection::Host)?;
2394
2395 validate_ownership(&response.ownership)?;
2396 validate_requirement(
2397 response.payload.ownership_requirement(),
2398 &response.ownership,
2399 )?;
2400 Ok(())
2401}
2402
2403fn validate_sidecar_request(request: &SidecarRequestFrame) -> Result<(), ProtocolCodecError> {
2404 validate_schema(&request.schema)?;
2405 validate_request_id_direction(request.request_id, RequestDirection::Sidecar)?;
2406 validate_ownership(&request.ownership)?;
2407 validate_requirement(request.payload.ownership_requirement(), &request.ownership)?;
2408 Ok(())
2409}
2410
2411fn validate_sidecar_response(response: &SidecarResponseFrame) -> Result<(), ProtocolCodecError> {
2412 validate_schema(&response.schema)?;
2413 validate_request_id_direction(response.request_id, RequestDirection::Sidecar)?;
2414 validate_ownership(&response.ownership)?;
2415 validate_requirement(
2416 response.payload.ownership_requirement(),
2417 &response.ownership,
2418 )?;
2419 Ok(())
2420}
2421
2422fn validate_event(event: &EventFrame) -> Result<(), ProtocolCodecError> {
2423 validate_schema(&event.schema)?;
2424 validate_ownership(&event.ownership)?;
2425 validate_requirement(event.payload.ownership_requirement(), &event.ownership)?;
2426 Ok(())
2427}
2428
2429fn validate_schema(schema: &ProtocolSchema) -> Result<(), ProtocolCodecError> {
2430 if schema.name != PROTOCOL_NAME || schema.version != PROTOCOL_VERSION {
2431 return Err(ProtocolCodecError::UnsupportedSchema {
2432 name: schema.name.clone(),
2433 version: schema.version,
2434 });
2435 }
2436
2437 Ok(())
2438}
2439
2440fn validate_ownership(ownership: &OwnershipScope) -> Result<(), ProtocolCodecError> {
2441 match ownership {
2442 OwnershipScope::ConnectionOwnership(inner) => {
2443 validate_non_empty("connection_id", &inner.connection_id)
2444 }
2445 OwnershipScope::SessionOwnership(inner) => {
2446 validate_non_empty("connection_id", &inner.connection_id)?;
2447 validate_non_empty("session_id", &inner.session_id)
2448 }
2449 OwnershipScope::VmOwnership(inner) => {
2450 validate_non_empty("connection_id", &inner.connection_id)?;
2451 validate_non_empty("session_id", &inner.session_id)?;
2452 validate_non_empty("vm_id", &inner.vm_id)
2453 }
2454 }
2455}
2456
2457fn validate_non_empty(field: &'static str, value: &str) -> Result<(), ProtocolCodecError> {
2458 if value.is_empty() {
2459 return Err(ProtocolCodecError::EmptyOwnershipField { field });
2460 }
2461
2462 Ok(())
2463}
2464
2465fn validate_request_id_direction(
2466 request_id: RequestId,
2467 direction: RequestDirection,
2468) -> Result<(), ProtocolCodecError> {
2469 if request_id == 0 {
2470 return Err(ProtocolCodecError::InvalidRequestId);
2471 }
2472
2473 let matches_direction = match direction {
2474 RequestDirection::Host => request_id > 0,
2475 RequestDirection::Sidecar => request_id < 0,
2476 };
2477 if matches_direction {
2478 Ok(())
2479 } else {
2480 Err(ProtocolCodecError::InvalidRequestDirection {
2481 request_id,
2482 expected: direction,
2483 })
2484 }
2485}
2486
2487fn validate_requirement(
2488 required: OwnershipRequirement,
2489 ownership: &OwnershipScope,
2490) -> Result<(), ProtocolCodecError> {
2491 let actual = match ownership {
2492 OwnershipScope::ConnectionOwnership(..) => OwnershipRequirement::Connection,
2493 OwnershipScope::SessionOwnership(..) => OwnershipRequirement::Session,
2494 OwnershipScope::VmOwnership(..) => OwnershipRequirement::Vm,
2495 };
2496
2497 let valid = match required {
2498 OwnershipRequirement::Any => true,
2499 OwnershipRequirement::Connection => {
2500 matches!(ownership, OwnershipScope::ConnectionOwnership(..))
2501 }
2502 OwnershipRequirement::Session => matches!(ownership, OwnershipScope::SessionOwnership(..)),
2503 OwnershipRequirement::Vm => matches!(ownership, OwnershipScope::VmOwnership(..)),
2504 OwnershipRequirement::SessionOrVm => {
2505 matches!(
2506 ownership,
2507 OwnershipScope::SessionOwnership(..) | OwnershipScope::VmOwnership(..)
2508 )
2509 }
2510 };
2511
2512 if valid {
2513 Ok(())
2514 } else {
2515 Err(ProtocolCodecError::InvalidOwnershipScope { required, actual })
2516 }
2517}
2518
2519#[derive(Debug, Deserialize, Default)]
2524pub struct JavascriptChildProcessSpawnOptions {
2525 #[serde(default)]
2526 pub cwd: Option<String>,
2527 #[serde(default)]
2528 pub env: BTreeMap<String, String>,
2529 #[serde(rename = "internalBootstrapEnv", default)]
2530 pub internal_bootstrap_env: BTreeMap<String, String>,
2531 #[serde(default)]
2532 pub input: Option<Value>,
2533 #[serde(default)]
2534 pub shell: bool,
2535 #[serde(default)]
2536 pub detached: bool,
2537 #[serde(default)]
2538 pub stdio: Vec<String>,
2539 #[serde(default)]
2540 pub timeout: Option<u64>,
2541 #[serde(rename = "killSignal", default)]
2542 pub kill_signal: Option<String>,
2543}
2544
2545#[derive(Debug, Deserialize)]
2546pub struct JavascriptChildProcessSpawnRequest {
2547 pub command: String,
2548 #[serde(default)]
2549 pub args: Vec<String>,
2550 #[serde(default)]
2551 pub options: JavascriptChildProcessSpawnOptions,
2552}
2553
2554#[derive(Debug, Deserialize)]
2555pub struct JavascriptNetConnectRequest {
2556 #[serde(default)]
2557 pub host: Option<String>,
2558 #[serde(default)]
2559 pub port: Option<u16>,
2560 #[serde(default)]
2561 pub path: Option<String>,
2562 #[serde(rename = "localAddress", default)]
2563 pub local_address: Option<String>,
2564 #[serde(rename = "localPort", default)]
2565 pub local_port: Option<u16>,
2566 #[serde(rename = "localReservation", default)]
2567 pub local_reservation: Option<String>,
2568}
2569
2570#[derive(Debug, Deserialize)]
2571pub struct JavascriptNetReserveTcpPortRequest {
2572 #[serde(default)]
2573 pub host: Option<String>,
2574 #[serde(default)]
2575 pub port: Option<u16>,
2576}
2577
2578#[derive(Debug, Deserialize)]
2579pub struct JavascriptNetListenRequest {
2580 #[serde(default)]
2581 pub host: Option<String>,
2582 #[serde(default)]
2583 pub port: Option<u16>,
2584 #[serde(default)]
2585 pub path: Option<String>,
2586 #[serde(default)]
2587 pub backlog: Option<u32>,
2588 #[serde(rename = "localReservation", default)]
2589 pub local_reservation: Option<String>,
2590}
2591
2592#[derive(Debug, Deserialize)]
2593pub struct JavascriptDgramCreateSocketRequest {
2594 #[serde(rename = "type")]
2595 pub socket_type: String,
2596}
2597
2598#[derive(Debug, Deserialize)]
2599pub struct JavascriptDgramBindRequest {
2600 #[serde(default)]
2601 pub address: Option<String>,
2602 #[serde(default)]
2603 pub port: u16,
2604}
2605
2606#[derive(Debug, Deserialize)]
2607pub struct JavascriptDgramSendRequest {
2608 #[serde(default)]
2609 pub address: Option<String>,
2610 pub port: u16,
2611}
2612
2613#[derive(Debug, Deserialize)]
2614pub struct JavascriptDnsLookupRequest {
2615 pub hostname: String,
2616 #[serde(default)]
2617 pub family: Option<u8>,
2618}
2619
2620#[derive(Debug, Deserialize)]
2621pub struct JavascriptDnsResolveRequest {
2622 pub hostname: String,
2623 #[serde(default)]
2624 pub rrtype: Option<String>,
2625}