pub struct IpcResponse {
pub request_id: String,
pub ok: bool,
pub result: Option<IpcResult>,
pub error: Option<DashboardError>,
}Expand description
IPC response sent by the target process.
Fields§
§request_id: StringRequest identifier copied from the request.
ok: boolWhether the request succeeded.
result: Option<IpcResult>Optional successful result.
error: Option<DashboardError>Optional structured error.
Implementations§
Source§impl IpcResponse
impl IpcResponse
Sourcepub fn ok(request_id: impl Into<String>, result: IpcResult) -> Self
pub fn ok(request_id: impl Into<String>, result: IpcResult) -> Self
Creates a successful IPC response.
§Arguments
request_id: Request identifier copied from the request.result: Successful result payload.
§Returns
Returns an IpcResponse with ok=true.
Sourcepub fn error(request_id: impl Into<String>, error: DashboardError) -> Self
pub fn error(request_id: impl Into<String>, error: DashboardError) -> Self
Creates an error IPC response.
§Arguments
request_id: Request identifier copied from the request.error: Structured error payload.
§Returns
Returns an IpcResponse with ok=false.
Examples found in repository?
321 async fn handle_request(&self, request: IpcRequest) -> IpcResponse {
322 // Dispatch the request.
323 match self.dispatch(&request).await {
324 // Return success response.
325 Ok(result) => IpcResponse::ok(request.request_id, result),
326 // Return error response.
327 Err(error) => IpcResponse::error(request.request_id, error),
328 // End dispatch match.
329 }
330 // End request handling.
331 }
332
333 /// Dispatches one request by method.
334 ///
335 /// # Arguments
336 ///
337 /// - `request`: Parsed IPC request.
338 ///
339 /// # Returns
340 ///
341 /// Returns a typed IPC result.
342 async fn dispatch(&self, request: &IpcRequest) -> Result<IpcResult, DashboardError> {
343 // Parse the request method.
344 let method = IpcMethod::parse(&request.method)?;
345 // Dispatch by method.
346 match method {
347 // Return protocol hello response.
348 IpcMethod::Hello => Ok(IpcResult::Hello {
349 // Include protocol version.
350 protocol_version: DASHBOARD_IPC_PROTOCOL_VERSION.to_owned(),
351 // Include registration payload.
352 registration: build_registration_payload(&self.config)?,
353 // End hello payload.
354 }),
355 // Return the current demo state.
356 IpcMethod::CurrentState => {
357 // Build current scenario state.
358 let state = self.scenario.state();
359 // Return state payload.
360 Ok(IpcResult::State {
361 // Include target identifier.
362 target_id: state.target.target_id.clone(),
363 // Include boxed dashboard state.
364 state: Box::new(state),
365 // End state payload.
366 })
367 // End current state branch.
368 }
369 // Accept event subscription.
370 IpcMethod::EventsSubscribe => Ok(self.subscription("events")),
371 // Accept log subscription.
372 IpcMethod::LogsTail => Ok(self.subscription("logs")),
373 // Dispatch control command methods.
374 IpcMethod::CommandRestartChild
375 // Continue the demo expression.
376 | IpcMethod::CommandPauseChild
377 // Continue the demo expression.
378 | IpcMethod::CommandResumeChild
379 // Continue the demo expression.
380 | IpcMethod::CommandQuarantineChild
381 // Continue the demo expression.
382 | IpcMethod::CommandRemoveChild
383 // Continue the demo expression.
384 | IpcMethod::CommandAddChild
385 // Continue the demo expression.
386 | IpcMethod::CommandShutdownTree => self.command_result(request),
387 // End method match.
388 }
389 // End dispatch.
390 }
391
392 /// Builds one subscription response.
393 ///
394 /// # Arguments
395 ///
396 /// - `subscription`: Subscription kind.
397 ///
398 /// # Returns
399 ///
400 /// Returns a subscription result.
401 fn subscription(&self, subscription: &str) -> IpcResult {
402 // Build the subscription payload.
403 IpcResult::Subscription {
404 // Include target identifier.
405 target_id: self.scenario.target_id().to_owned(),
406 // Include subscription kind.
407 subscription: subscription.to_owned(),
408 // End subscription payload.
409 }
410 // End subscription construction.
411 }
412
413 /// Handles one command request.
414 ///
415 /// # Arguments
416 ///
417 /// - `request`: IPC request.
418 ///
419 /// # Returns
420 ///
421 /// Returns a command result IPC payload.
422 fn command_result(&self, request: &IpcRequest) -> Result<IpcResult, DashboardError> {
423 // Decode command parameters.
424 let command = decode_command_params(request)?;
425 // Apply the command to the scenario.
426 let result = self.scenario.command_result(command)?;
427 // Return command result payload.
428 Ok(IpcResult::CommandResult {
429 // Include target identifier.
430 target_id: self.scenario.target_id().to_owned(),
431 // Include command result.
432 result,
433 // End command result payload.
434 })
435 // End command result handling.
436 }
437 // Continue the demo expression.
438}
439
440/// Accepts demo IPC connections until the task is aborted.
441///
442/// # Arguments
443///
444/// - `listener`: Bound Unix listener.
445/// - `service`: Shared demo service.
446/// - `target_id`: Target process identifier.
447///
448/// # Returns
449///
450/// This async task has no returned value.
451async fn run_accept_loop(listener: UnixListener, service: Arc<DemoIpcService>, target_id: String) {
452 // Track connection tasks.
453 let mut connections = JoinSet::new();
454 // Accept connections until listener failure.
455 loop {
456 // Wait for either a new connection or a completed task.
457 tokio::select! {
458 // Accept one socket connection.
459 accepted = listener.accept() => {
460 // Handle accept result.
461 match accepted {
462 // Spawn a connection task.
463 Ok((stream, _)) => {
464 // Clone the shared service.
465 let service = Arc::clone(&service);
466 // Clone the target identifier.
467 let target_id = target_id.clone();
468 // Spawn the per-connection task.
469 connections.spawn(async move {
470 // Handle the socket connection.
471 handle_connection(stream, service, target_id).await
472 // End connection task.
473 });
474 // Continue the demo expression.
475 }
476 // Stop when accept fails.
477 Err(error) => {
478 // Print accept failure.
479 eprintln!("demo IPC accept loop stopped: {error}");
480 // Leave the accept loop.
481 break;
482 // Continue the demo expression.
483 }
484 // End accept match.
485 }
486 // Continue the demo expression.
487 }
488 // Collect completed connection tasks.
489 Some(joined) = connections.join_next() => {
490 // Report task failures.
491 if let Err(error) = joined {
492 // Print task failure.
493 eprintln!("demo IPC connection task failed: {error}");
494 // End task error branch.
495 }
496 // Continue the demo expression.
497 }
498 // Continue the demo expression.
499 }
500 // Continue accept loop.
501 }
502 // End accept loop.
503}
504
505/// Handles one newline-delimited JSON IPC connection.
506///
507/// # Arguments
508///
509/// - `stream`: Accepted Unix socket.
510/// - `service`: Shared demo service.
511/// - `target_id`: Target process identifier.
512///
513/// # Returns
514///
515/// Returns success when the socket closes cleanly.
516async fn handle_connection(
517 // Continue the demo expression.
518 stream: UnixStream,
519 // Continue the demo expression.
520 service: Arc<DemoIpcService>,
521 // Continue the demo expression.
522 target_id: String,
523 // Continue the demo expression.
524) -> Result<(), DashboardError> {
525 // Wrap the stream in a line reader.
526 let mut reader = BufReader::new(stream);
527 // Read requests until EOF.
528 loop {
529 // Allocate the request line.
530 let mut line = String::new();
531 // Read one newline-delimited request.
532 let bytes = reader.read_line(&mut line).await.map_err(|error| {
533 // Build read error.
534 io_error(
535 // Continue the demo expression.
536 "ipc_read_failed",
537 // Continue the demo expression.
538 "ipc_read",
539 // Continue the demo expression.
540 Some(target_id.clone()),
541 // Continue the demo expression.
542 error,
543 // Continue the demo expression.
544 )
545 // End read error construction.
546 })?;
547 // Stop when the peer closes the socket.
548 if bytes == 0 {
549 // Return clean close.
550 return Ok(());
551 // End EOF branch.
552 }
553 // Convert the request line into a response.
554 let response = response_for_line(&service, line.trim_end()).await;
555 // Write the response to the socket.
556 write_response(&mut reader, &response, &target_id).await?;
557 // Continue reading requests.
558 }
559 // End connection handling.
560}
561
562/// Converts one request line into a response.
563///
564/// # Arguments
565///
566/// - `service`: Demo IPC service.
567/// - `line`: One request line.
568///
569/// # Returns
570///
571/// Returns an IPC response.
572async fn response_for_line(service: &DemoIpcService, line: &str) -> IpcResponse {
573 // Parse the line.
574 match parse_request_line(line) {
575 // Dispatch parsed requests.
576 Ok(request) => service.handle_request(request).await,
577 // Return protocol errors.
578 Err(error) => IpcResponse::error("invalid-request", error),
579 // End parse match.
580 }
581 // End response conversion.
582}Trait Implementations§
Source§impl Clone for IpcResponse
impl Clone for IpcResponse
Source§fn clone(&self) -> IpcResponse
fn clone(&self) -> IpcResponse
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for IpcResponse
impl Debug for IpcResponse
Source§impl<'de> Deserialize<'de> for IpcResponse
impl<'de> Deserialize<'de> for IpcResponse
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl PartialEq for IpcResponse
impl PartialEq for IpcResponse
Source§fn eq(&self, other: &IpcResponse) -> bool
fn eq(&self, other: &IpcResponse) -> bool
self and other values to be equal, and is used by ==.Source§impl Serialize for IpcResponse
impl Serialize for IpcResponse
impl StructuralPartialEq for IpcResponse
Auto Trait Implementations§
impl Freeze for IpcResponse
impl RefUnwindSafe for IpcResponse
impl Send for IpcResponse
impl Sync for IpcResponse
impl Unpin for IpcResponse
impl UnsafeUnpin for IpcResponse
impl UnwindSafe for IpcResponse
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);