1use std::net::SocketAddr;
4use std::path::PathBuf;
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
11pub struct BrowserTranscript {
12 pub latest_seq: u64,
13 pub presentation_key: String,
17 pub window_start_seq: u64,
22 pub reset: bool,
23 pub entries: Vec<BrowserTranscriptEntry>,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
27pub struct BrowserTranscriptEntry {
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub command_id: Option<String>,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 pub stable_id: Option<String>,
34 pub id: u64,
35 pub updated_seq: u64,
36 pub role: &'static str,
37 pub label: String,
38 pub recorded_at_ms: Option<i64>,
39 pub lines: Vec<String>,
40 pub glyph: &'static str,
44 pub tone: &'static str,
47 #[serde(default, skip_serializing_if = "Option::is_none")]
49 pub tool_status: Option<&'static str>,
50 #[serde(default, skip_serializing_if = "Vec::is_empty")]
55 pub diffstats: Vec<BrowserDiffStat>,
56}
57
58impl BrowserTranscriptEntry {
59 pub fn identity(&self) -> String {
60 self.stable_id
61 .clone()
62 .unwrap_or_else(|| format!("ordinal:{}", self.id))
63 }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
68pub struct BrowserDiffStat {
69 pub path: String,
70 pub insertions: u32,
71 pub deletions: u32,
72}
73
74#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
75pub enum WebViewerAccess {
76 Starting,
77 Ready {
78 viewer_url: String,
79 viewer_code: String,
80 qr_login_url: Option<String>,
81 fallback_reason: Option<String>,
82 #[serde(default)]
88 certificate_sha256: Option<String>,
89 },
90 Failed {
91 address: SocketAddr,
92 message: String,
93 port_conflict: bool,
94 },
95 Unavailable(String),
96}
97
98impl std::fmt::Debug for WebViewerAccess {
99 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 match self {
101 Self::Starting => formatter.write_str("Starting"),
102 Self::Ready {
103 viewer_url,
104 fallback_reason,
105 ..
106 } => formatter
107 .debug_struct("Ready")
108 .field("viewer_url", viewer_url)
109 .field("credentials", &"[redacted]")
110 .field("fallback_reason", fallback_reason)
111 .finish(),
112 Self::Failed {
113 address,
114 message,
115 port_conflict,
116 } => formatter
117 .debug_struct("Failed")
118 .field("address", address)
119 .field("message", message)
120 .field("port_conflict", port_conflict)
121 .finish(),
122 Self::Unavailable(message) => {
123 formatter.debug_tuple("Unavailable").field(message).finish()
124 }
125 }
126 }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
131pub struct WebListenerProcess {
132 pub pid: u32,
133 pub name: String,
134 pub executable: PathBuf,
135 pub started_at: u64,
136 pub stop_disabled_reason: Option<String>,
137}
138
139#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
140pub enum WebViewerRecovery {
141 Retry,
142 AnotherPort,
143 StopAndRetry(WebListenerProcess),
144}