1use serde::{Deserialize, Serialize};
7
8use crate::ipc::{ExportKind, JobEvent, JobSnapshot, ProjectInfo, ResultsSummary};
9
10pub const API_VERSION: u32 = 1;
12pub const DEFAULT_PORT: u16 = 4712;
14pub const TOKEN_FILE: &str = "local-api-token";
16pub const CALL_PATH: &str = "/v1/call";
18pub const STATUS_PATH: &str = "/v1/status";
20pub const EVENTS_PATH: &str = "/v1/events";
22
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25pub struct Status {
26 pub api: u32,
28 pub app_name: String,
30 pub app_version: String,
32 pub library_version: String,
34 pub project: Option<ProjectInfo>,
36 pub jobs: Vec<JobSnapshot>,
38 pub results: Option<ResultsSummary>,
40 pub last_export: Option<LastExport>,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
46pub struct LastExport {
47 pub kind: ExportKind,
49 pub folder: String,
51 pub mimo: bool,
53 pub mode: String,
55 #[serde(default)]
58 pub design_name: Option<String>,
59 #[serde(default)]
61 pub design_id: Option<String>,
62 pub time: String,
64}
65
66#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
68#[serde(tag = "kind", rename_all = "snake_case")]
69pub enum ServerEvent {
70 Job { event: JobEvent },
72 Changed { method: String },
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct MethodAccess {
79 pub ui_only: bool,
81 pub mutates: bool,
83}
84
85const fn entry(method: &'static str, ui_only: bool, mutates: bool) -> (&'static str, MethodAccess) {
86 (method, MethodAccess { ui_only, mutates })
87}
88
89const ACCESS: &[(&str, MethodAccess)] = &[
90 entry("bootstrap", false, false),
91 entry("project_new", false, true),
92 entry("project_open", false, true),
93 entry("project_save", false, true),
94 entry("project_info", false, false),
95 entry("sample_load", false, true),
96 entry("calibrate", false, true),
97 entry("recommend_xo", false, true),
98 entry("mimo", false, true),
99 entry("results", false, false),
100 entry("export", false, true),
101 entry("job_cancel", false, true),
102 entry("jobs", false, false),
103 entry("measure_methods", false, false),
104 entry("measure_configure", false, true),
105 entry("measure_config_get", false, false),
106 entry("measurement_records", false, false),
107 entry("mic_calibration_get", false, false),
108 entry("mic_calibration_set", false, true),
109 entry("mic_calibration_clear", false, true),
110 entry("mic_calibration_attach", false, true),
111 entry("levels_get", false, false),
112 entry("levels_fill_defaults", false, true),
113 entry("level_stop", false, true),
114 entry("measure_position", false, true),
115 entry("position_clear", false, true),
116 entry("undo", false, true),
117 entry("rew_launch", true, true),
118 entry("mdat_scan", false, false),
119 entry("mdat_import", false, true),
120 entry("config_get", false, false),
121 entry("config_apply_preset", false, true),
122 entry("config_set_sub_count", false, true),
123 entry("config_set_speaker", false, true),
124 entry("config_add_speaker", false, true),
125 entry("config_remove_speaker", false, true),
126 entry("config_renumber", false, true),
127 entry("config_validate", false, false),
128 entry("patch_sheet_csv", false, true),
129 entry("dsp_get", false, false),
130 entry("dsp_set", false, true),
131 entry("layout_get", false, false),
132 entry("layout_set", false, true),
133 entry("position_estimate", false, false),
134 entry("target_get", false, false),
135 entry("target_set_points", false, true),
136 entry("target_apply_preset", false, true),
137 entry("target_save", false, true),
138 entry("target_load", false, true),
139 entry("calibration_settings_get", false, false),
140 entry("calibration_settings_set", false, true),
141 entry("calibration_settings_edit", false, true),
142 entry("sub_warnings", false, false),
143 entry("rew_info", false, false),
144 entry("rew_driver_set", false, true),
145 entry("mode_spec", false, false),
146 entry("app_settings_get", false, false),
147 entry("app_settings_set", false, true),
148 entry("apply_status", false, false),
149 entry("apply_camilla", false, true),
150 entry("apply_eqapo", false, true),
151 entry("revert_eqapo", false, true),
152 entry("apply_settings_set", false, true),
153 entry("host_install", true, true),
154 entry("host_uninstall", true, true),
155 entry("host_stop_managing", false, true),
156 entry("update_status", false, false),
158 entry("update_check", true, false),
159 entry("update_download", true, true),
160 entry("update_restart", true, true),
161 entry("update_notice_dismiss", true, true),
162 entry("update_open_release", true, false),
163 entry("compute_status", false, false),
164 entry("open_gpu_help", true, false),
165 entry("measurement_curves", false, false),
166 entry("result_curves", false, false),
167 entry("result_lines", false, false),
168 entry("sub_take_values", false, true),
169 entry("dialog_open_project", true, false),
170 entry("dialog_save_project", true, false),
171 entry("dialog_pick_mdat", true, false),
172 entry("dialog_pick_folder", true, false),
173 entry("dialog_save_file", true, false),
174 entry("dialog_open_file", true, false),
175 entry("open_folder", true, true),
176 entry("level_monitor_start", false, true),
177 entry("level_monitor_stop", false, true),
178 entry("level_play", false, true),
179 entry("status_watch_start", false, true),
180 entry("status_watch_stop", false, true),
181 entry("export_folder_get", false, false),
182 entry("export_folder_set", false, true),
183 entry("local_api_status", true, false),
184 entry("local_api_token_regenerate", true, true),
185];
186
187pub fn access(method: &str) -> Option<MethodAccess> {
189 ACCESS
190 .iter()
191 .find_map(|(name, value)| (*name == method).then_some(*value))
192}
193
194#[cfg(test)]
195mod tests {
196 use std::collections::BTreeSet;
197
198 use super::*;
199 use crate::ipc::Request;
200
201 #[test]
202 fn access_table_covers_every_request_method_exactly() {
203 let known = Request::METHODS.iter().copied().collect::<BTreeSet<_>>();
204 let listed = ACCESS.iter().map(|(name, _)| *name).collect::<Vec<_>>();
205 let unique = listed.iter().copied().collect::<BTreeSet<_>>();
206 assert_eq!(listed.len(), unique.len(), "duplicate access-table method");
207 assert_eq!(unique, known);
208 for method in Request::METHODS {
209 assert!(access(method).is_some(), "missing {method}");
210 }
211 }
212}