ctoolbox/workspace/ipc_old/
dispatch.rs

1//! IPC dispatch logic for workspace services.
2
3use crate::formats::base64::bytes_to_standard_base64;
4use crate::utilities::ipc::Channel;
5use crate::utilities::process::ProcessManager;
6use crate::utilities::serde_value::{get_as_bytes, get_as_u64};
7use crate::utilities::{json, send_message};
8use crate::workspace::ipc_old::IPC_API;
9use crate::{json_value, renderer};
10use serde_json::Value;
11use std::sync::Arc;
12use std::sync::Mutex;
13
14mod db;
15
16pub fn dispatch_call(
17    service_name: &str,
18    to_channel: &Channel,
19    msgid: u64,
20    method: &str,
21    args: &str,
22) {
23    if IPC_API.contains_key(service_name) {
24        let Some(allowed_methods) = IPC_API.get(service_name) else {
25            let response = json!({
26                "type": "response",
27                "msgid": msgid,
28                "error": format!("Service {service_name} not allowed"),
29            });
30            send_message(to_channel, &response.to_string());
31            return;
32        };
33        if allowed_methods.contains(&method) {
34            // Parse args as serde_json::Value
35            let args_value: Value = match serde_json::from_str(args) {
36                Ok(val) => val,
37                Err(e) => {
38                    let response = json!({
39                        "type": "response",
40                        "msgid": msgid,
41                        "error": format!("Invalid args: {}", e),
42                    });
43                    send_message(to_channel, &response.to_string());
44                    return;
45                }
46            };
47
48            let result = ipc_call_method(method, &args_value, None);
49
50            let response = json!({
51                "type": "response",
52                "msgid": msgid,
53                "content": result,
54            });
55            send_message(to_channel, &response.to_string());
56
57            return;
58        }
59    }
60    let response = json!({
61        "type": "response",
62        "msgid": msgid,
63        "error": format!("Method {method} not allowed or not implemented for {service_name}"),
64    });
65    send_message(to_channel, &response.to_string());
66}
67
68/// Dispatches an IPC method call with structured arguments.
69#[allow(clippy::too_many_lines)]
70pub fn ipc_call_method(
71    method: &str,
72    args: &Value,
73    process_manager: Option<Arc<Mutex<ProcessManager>>>,
74) -> Value {
75    match method {
76        // IO
77        "start_local_web_ui" => {
78            json_value!({ "value" => crate::io::webui::start_webui_server() })
79        }
80
81        // Database operations
82        "get_str_u64" => {
83            let db = args.get("db").and_then(Value::as_str).unwrap_or_default();
84            let key =
85                args.get("key").and_then(Value::as_str).unwrap_or_default();
86            if let Some(val) = db::get_str_u64(db, key) {
87                json_value!({ "value" => val })
88            } else {
89                json_value!({ "none" => true })
90            }
91        }
92        "get_all_u64_keys" => {
93            let db = args.get("db").and_then(Value::as_str).unwrap_or_default();
94            match db::get_all_u64_keys(db) {
95                Ok(val) => json_value!({ "value" => val }),
96                Err(e) => {
97                    json_value!({ "error" => format!("{}: {:?}", e.to_string(), e) })
98                }
99            }
100        }
101        "put_str_u64" => {
102            let db = args.get("db").and_then(Value::as_str).unwrap_or_default();
103            let key =
104                args.get("key").and_then(Value::as_str).unwrap_or_default();
105            let value = args.get("value").and_then(Value::as_u64).unwrap_or(0);
106            match db::put_str_u64(db, key, value) {
107                Ok(()) => json_value!({ "value" => "ok" }),
108                Err(e) => {
109                    json_value!({ "error" => format!("{}: {:?}", e.to_string(), e) })
110                }
111            }
112        }
113        "delete_str_u64" => {
114            let db = args.get("db").and_then(Value::as_str).unwrap_or_default();
115            let key =
116                args.get("key").and_then(Value::as_str).unwrap_or_default();
117            match db::delete_str_u64(db, key) {
118                Ok(()) => json_value!({ "value" => "ok" }),
119                Err(e) => {
120                    json_value!({ "error" => format!("{}: {:?}", e.to_string(), e) })
121                }
122            }
123        }
124        "get_u64_str" => {
125            let db = args.get("db").and_then(Value::as_str).unwrap_or_default();
126            let key = args.get("key").and_then(Value::as_u64).unwrap_or(0);
127            if let Some(val) = db::get_u64_str(db, key) {
128                json_value!({ "value" => val })
129            } else {
130                json_value!({ "none" => true })
131            }
132        }
133        "put_u64_str" => {
134            let db = args.get("db").and_then(Value::as_str).unwrap_or_default();
135            let key = args.get("key").and_then(Value::as_u64).unwrap_or(0);
136            let value = args
137                .get("value")
138                .and_then(Value::as_str)
139                .unwrap_or_default();
140            match db::put_u64_str(db, key, value) {
141                Ok(()) => json_value!({ "value" => "ok" }),
142                Err(e) => {
143                    json_value!({ "error" => format!("{}: {:?}", e.to_string(), e) })
144                }
145            }
146        }
147        "delete_u64_str" => {
148            let db = args.get("db").and_then(Value::as_str).unwrap_or_default();
149            let key = args.get("key").and_then(Value::as_u64).unwrap_or(0);
150            match db::delete_u64_str(db, key) {
151                Ok(()) => json_value!({ "value" => "ok" }),
152                Err(e) => {
153                    json_value!({ "error" => format!("{}: {:?}", e.to_string(), e) })
154                }
155            }
156        }
157        "get_u64_bytes" => {
158            let db = args.get("db").and_then(Value::as_str).unwrap_or_default();
159            let key = args.get("key").and_then(Value::as_u64).unwrap_or(0);
160            if let Some(val) = db::get_u64_bytes(db, key) {
161                json_value!({ "value" => bytes_to_standard_base64(&val) })
162            } else {
163                json_value!({ "none" => true })
164            }
165        }
166        "put_u64_bytes" => {
167            let db = args.get("db").and_then(Value::as_str).unwrap_or_default();
168            let key = get_as_u64(args, "key").unwrap_or(0);
169            let value = get_as_bytes(args, "value").unwrap_or_default();
170            match db::put_u64_bytes(db, key, &value) {
171                Ok(()) => json_value!({ "value" => "ok" }),
172                Err(e) => {
173                    json_value!({ "error" => format!("{}: {:?}", e.to_string(), e) })
174                }
175            }
176        }
177        "delete_u64_bytes" => {
178            let db = args.get("db").and_then(Value::as_str).unwrap_or_default();
179            let key = args.get("key").and_then(Value::as_u64).unwrap_or(0);
180            match db::delete_u64_bytes(db, key) {
181                Ok(()) => json_value!({ "value" => "ok" }),
182                Err(e) => {
183                    json_value!({ "error" => format!("{}: {:?}", e.to_string(), e) })
184                }
185            }
186        }
187
188        // Renderer
189        "test_echo" => {
190            json_value!({ "value" => renderer::test_echo(args.to_string().as_str()) })
191        }
192        // Workspace calls are handled by the server, not the usual IPC path
193        "workspace_restart" => {
194            if let Some(pm) = process_manager {
195                crate::workspace::workspace_restart(&pm);
196                json_value!({ "value" => "" })
197            } else {
198                json_value!({ "error" => "process manager required" })
199            }
200        }
201        "workspace_shutdown" => {
202            if let Some(pm) = process_manager {
203                crate::workspace::workspace_shutdown(&pm);
204                json_value!({ "value" => "" })
205            } else {
206                json_value!({ "error" => "process manager required" })
207            }
208        }
209        &_ => {
210            json_value!({ "error" => format!("Method {method} not allowed or not implemented") })
211        }
212    }
213}