pitchfork_cli/cli/
json_output.rs1use crate::log_store::LogEntry;
2use serde::Serialize;
3
4#[derive(Serialize)]
5pub struct JsonListEntry {
6 pub id: String,
7 pub namespace: String,
8 pub name: String,
9 pub pid: Option<u32>,
10 pub status: String,
11 pub disabled: bool,
12 pub available: bool,
13 pub proxy_url: Option<String>,
14 pub error: Option<String>,
15 #[serde(skip_serializing_if = "Option::is_none")]
16 pub active_port: Option<u16>,
17 pub port: Vec<u16>,
18}
19
20#[derive(Serialize)]
21pub struct JsonStatusEntry {
22 pub id: String,
23 pub namespace: String,
24 pub name: String,
25 pub pid: Option<u32>,
26 pub status: String,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub active_port: Option<u16>,
29 pub port: Vec<u16>,
30 pub proxy_url: Option<String>,
31}
32
33#[derive(Serialize)]
34pub struct JsonLogEntry {
35 #[serde(skip_serializing_if = "is_zero_id")]
39 pub id: i64,
40 pub timestamp: String,
41 pub daemon_id: String,
42 pub message: String,
43 #[serde(skip_serializing_if = "Option::is_none")]
44 pub level: Option<String>,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub msg: Option<String>,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub logger: Option<String>,
49 #[serde(skip_serializing_if = "Option::is_none")]
52 pub fields: Option<serde_json::Value>,
53}
54
55fn is_zero_id(id: &i64) -> bool {
56 *id == 0
57}
58
59impl From<LogEntry> for JsonLogEntry {
60 fn from(e: LogEntry) -> Self {
61 let fields = e
62 .fields_json
63 .as_deref()
64 .and_then(|s| serde_json::from_str(s).ok());
65 JsonLogEntry {
66 id: e.id,
67 timestamp: e.timestamp.format("%Y-%m-%d %H:%M:%S").to_string(),
68 daemon_id: e.daemon_id,
69 message: console::strip_ansi_codes(&e.message).to_string(),
70 level: e.level,
71 msg: e.msg,
72 logger: e.logger,
73 fields,
74 }
75 }
76}
77
78#[derive(Serialize)]
79pub struct JsonDaemonConfigEntry {
80 pub id: String,
81 pub run: String,
82}
83
84#[derive(Serialize)]
85pub struct JsonProxyStatus {
86 pub enabled: bool,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub scheme: Option<String>,
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub tld: Option<String>,
91 #[serde(skip_serializing_if = "Option::is_none")]
92 pub port: Option<u16>,
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub lan: Option<JsonLanInfo>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub tls_cert: Option<String>,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub trusted: Option<bool>,
99 pub slugs: Vec<JsonSlugEntry>,
100}
101
102#[derive(Serialize)]
103pub struct JsonLanInfo {
104 pub enabled: bool,
105 pub ip: String,
106}
107
108#[derive(Serialize)]
109pub struct JsonSlugEntry {
110 pub slug: String,
111 pub url: String,
112 pub dir: String,
113 pub daemon: String,
114 pub status: String,
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub port: Option<u16>,
117}
118
119#[derive(Serialize)]
120pub struct JsonSupervisorStatus {
121 pub status: &'static str,
122 #[serde(skip_serializing_if = "Option::is_none")]
123 pub web_ui: Option<String>,
124 #[serde(skip_serializing_if = "Option::is_none")]
125 pub error: Option<String>,
126}
127
128#[derive(Serialize)]
129pub struct JsonSettingEntry {
130 pub key: String,
131 pub value: String,
132 #[serde(skip_serializing_if = "Option::is_none")]
133 pub default: Option<&'static str>,
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub r#type: Option<&'static str>,
136 #[serde(skip_serializing_if = "Option::is_none")]
137 pub env_var: Option<&'static str>,
138}
139
140pub fn print_json<T: Serialize>(value: &T) -> crate::Result<()> {
141 let json = serde_json::to_string_pretty(value)
142 .map_err(|e| miette::miette!("failed to serialize JSON: {e}"))?;
143 println!("{json}");
144 Ok(())
145}