1use crate::error::BridgeError;
4use crate::host::ParameterHost;
5use serde::Serialize;
6use wavecraft_protocol::{
7 GetAllParametersResult, GetMeterFrameResult, GetParameterParams, GetParameterResult,
8 IpcRequest, IpcResponse, METHOD_GET_ALL_PARAMETERS, METHOD_GET_METER_FRAME,
9 METHOD_GET_PARAMETER, METHOD_REQUEST_RESIZE, METHOD_SET_PARAMETER, RequestId,
10 RequestResizeParams, RequestResizeResult, SetParameterParams, SetParameterResult,
11};
12
13pub struct IpcHandler<H: ParameterHost> {
15 host: H,
16}
17
18impl<H: ParameterHost> IpcHandler<H> {
19 pub fn new(host: H) -> Self {
21 Self { host }
22 }
23
24 pub fn handle_request(&self, request: IpcRequest) -> IpcResponse {
29 let result = match request.method.as_str() {
30 METHOD_GET_PARAMETER => self.handle_get_parameter(&request),
31 METHOD_SET_PARAMETER => self.handle_set_parameter(&request),
32 METHOD_GET_ALL_PARAMETERS => self.handle_get_all_parameters(&request),
33 METHOD_GET_METER_FRAME => self.handle_get_meter_frame(&request),
34 METHOD_REQUEST_RESIZE => self.handle_request_resize(&request),
35 "ping" => self.handle_ping(&request),
36 _ => Err(BridgeError::UnknownMethod(request.method.clone())),
37 };
38
39 match result {
40 Ok(response) => response,
41 Err(err) => IpcResponse::error(request.id, err.to_ipc_error()),
42 }
43 }
44
45 pub fn handle_json(&self, json: &str) -> String {
49 let request: IpcRequest = match serde_json::from_str(json) {
51 Ok(req) => req,
52 Err(_e) => {
53 let response = IpcResponse::error(
55 RequestId::Number(0),
56 wavecraft_protocol::IpcError::parse_error(),
57 );
58 return serde_json::to_string(&response)
61 .expect("IpcResponse serialization is infallible");
62 }
63 };
64
65 let response = self.handle_request(request);
67
68 serde_json::to_string(&response).expect("IpcResponse serialization is infallible")
70 }
71
72 fn handle_get_parameter(&self, request: &IpcRequest) -> Result<IpcResponse, BridgeError> {
77 let params: GetParameterParams = match &request.params {
79 Some(value) => serde_json::from_value(value.clone())?,
80 None => {
81 return Err(BridgeError::InvalidParams {
82 method: METHOD_GET_PARAMETER.to_string(),
83 reason: "Missing params".to_string(),
84 });
85 }
86 };
87
88 let param_info = self
90 .host
91 .get_parameter(¶ms.id)
92 .ok_or_else(|| BridgeError::ParameterNotFound(params.id.clone()))?;
93
94 let result = GetParameterResult {
96 id: param_info.id,
97 value: param_info.value,
98 };
99
100 Ok(IpcResponse::success(request.id.clone(), result))
101 }
102
103 fn handle_set_parameter(&self, request: &IpcRequest) -> Result<IpcResponse, BridgeError> {
104 let params: SetParameterParams = match &request.params {
106 Some(value) => serde_json::from_value(value.clone())?,
107 None => {
108 return Err(BridgeError::InvalidParams {
109 method: METHOD_SET_PARAMETER.to_string(),
110 reason: "Missing params".to_string(),
111 });
112 }
113 };
114
115 if !(0.0..=1.0).contains(¶ms.value) {
117 return Err(BridgeError::ParameterOutOfRange {
118 id: params.id.clone(),
119 value: params.value,
120 });
121 }
122
123 self.host.set_parameter(¶ms.id, params.value)?;
125
126 Ok(IpcResponse::success(
128 request.id.clone(),
129 SetParameterResult {},
130 ))
131 }
132
133 fn handle_get_all_parameters(&self, request: &IpcRequest) -> Result<IpcResponse, BridgeError> {
134 let parameters = self.host.get_all_parameters();
135
136 let result = GetAllParametersResult { parameters };
137
138 Ok(IpcResponse::success(request.id.clone(), result))
139 }
140
141 fn handle_get_meter_frame(&self, request: &IpcRequest) -> Result<IpcResponse, BridgeError> {
142 let frame = self.host.get_meter_frame();
144
145 let result = GetMeterFrameResult { frame };
146
147 Ok(IpcResponse::success(request.id.clone(), result))
148 }
149
150 fn handle_request_resize(&self, request: &IpcRequest) -> Result<IpcResponse, BridgeError> {
151 let params: RequestResizeParams = match &request.params {
153 Some(value) => serde_json::from_value(value.clone())?,
154 None => {
155 return Err(BridgeError::InvalidParams {
156 method: METHOD_REQUEST_RESIZE.to_string(),
157 reason: "Missing params".to_string(),
158 });
159 }
160 };
161
162 let accepted = self.host.request_resize(params.width, params.height);
164
165 let result = RequestResizeResult { accepted };
166
167 Ok(IpcResponse::success(request.id.clone(), result))
168 }
169
170 fn handle_ping(&self, request: &IpcRequest) -> Result<IpcResponse, BridgeError> {
171 #[derive(Serialize)]
173 struct PingResult {
174 pong: bool,
175 }
176
177 Ok(IpcResponse::success(
178 request.id.clone(),
179 PingResult { pong: true },
180 ))
181 }
182}
183
184#[cfg(test)]
189mod tests {
190 use super::*;
191 use wavecraft_protocol::{MeterFrame, ParameterInfo, ParameterType, RequestId};
192
193 struct MockHost {
195 params: Vec<ParameterInfo>,
196 }
197
198 impl MockHost {
199 fn new() -> Self {
200 Self {
201 params: vec![
202 ParameterInfo {
203 id: "gain".to_string(),
204 name: "Gain".to_string(),
205 param_type: ParameterType::Float,
206 value: 0.5,
207 default: 0.7,
208 unit: Some("dB".to_string()),
209 group: None,
210 },
211 ParameterInfo {
212 id: "bypass".to_string(),
213 name: "Bypass".to_string(),
214 param_type: ParameterType::Bool,
215 value: 0.0,
216 default: 0.0,
217 unit: None,
218 group: None,
219 },
220 ],
221 }
222 }
223 }
224
225 impl ParameterHost for MockHost {
226 fn get_parameter(&self, id: &str) -> Option<ParameterInfo> {
227 self.params.iter().find(|p| p.id == id).cloned()
228 }
229
230 fn set_parameter(&self, id: &str, _value: f32) -> Result<(), BridgeError> {
231 if !self.params.iter().any(|p| p.id == id) {
233 return Err(BridgeError::ParameterNotFound(id.to_string()));
234 }
235 Ok(())
237 }
238
239 fn get_all_parameters(&self) -> Vec<ParameterInfo> {
240 self.params.clone()
241 }
242
243 fn get_meter_frame(&self) -> Option<MeterFrame> {
244 None
246 }
247
248 fn request_resize(&self, _width: u32, _height: u32) -> bool {
249 true
251 }
252 }
253
254 #[test]
255 fn test_get_parameter_success() {
256 let handler = IpcHandler::new(MockHost::new());
257
258 let request = IpcRequest::new(
259 RequestId::Number(1),
260 METHOD_GET_PARAMETER,
261 Some(serde_json::json!({"id": "gain"})),
262 );
263
264 let response = handler.handle_request(request);
265
266 assert!(response.result.is_some());
267 assert!(response.error.is_none());
268
269 let result: GetParameterResult = serde_json::from_value(response.result.unwrap()).unwrap();
270 assert_eq!(result.id, "gain");
271 assert_eq!(result.value, 0.5);
272 }
273
274 #[test]
275 fn test_get_parameter_not_found() {
276 let handler = IpcHandler::new(MockHost::new());
277
278 let request = IpcRequest::new(
279 RequestId::Number(2),
280 METHOD_GET_PARAMETER,
281 Some(serde_json::json!({"id": "unknown"})),
282 );
283
284 let response = handler.handle_request(request);
285
286 assert!(response.error.is_some());
287 assert!(response.result.is_none());
288
289 let error = response.error.unwrap();
290 assert_eq!(error.code, wavecraft_protocol::ERROR_PARAM_NOT_FOUND);
291 }
292
293 #[test]
294 fn test_set_parameter_success() {
295 let handler = IpcHandler::new(MockHost::new());
296
297 let request = IpcRequest::new(
298 RequestId::Number(3),
299 METHOD_SET_PARAMETER,
300 Some(serde_json::json!({"id": "gain", "value": 0.8})),
301 );
302
303 let response = handler.handle_request(request);
304
305 assert!(response.result.is_some());
306 assert!(response.error.is_none());
307 }
308
309 #[test]
310 fn test_set_parameter_out_of_range() {
311 let handler = IpcHandler::new(MockHost::new());
312
313 let request = IpcRequest::new(
314 RequestId::Number(4),
315 METHOD_SET_PARAMETER,
316 Some(serde_json::json!({"id": "gain", "value": 1.5})),
317 );
318
319 let response = handler.handle_request(request);
320
321 assert!(response.error.is_some());
322 assert!(response.result.is_none());
323
324 let error = response.error.unwrap();
325 assert_eq!(error.code, wavecraft_protocol::ERROR_PARAM_OUT_OF_RANGE);
326 }
327
328 #[test]
329 fn test_unknown_method() {
330 let handler = IpcHandler::new(MockHost::new());
331
332 let request = IpcRequest::new(RequestId::Number(5), "unknownMethod", None);
333
334 let response = handler.handle_request(request);
335
336 assert!(response.error.is_some());
337 let error = response.error.unwrap();
338 assert_eq!(error.code, wavecraft_protocol::ERROR_METHOD_NOT_FOUND);
339 }
340
341 #[test]
342 fn test_ping() {
343 let handler = IpcHandler::new(MockHost::new());
344
345 let request = IpcRequest::new(RequestId::String("ping-1".to_string()), "ping", None);
346
347 let response = handler.handle_request(request);
348
349 assert!(response.result.is_some());
350 assert!(response.error.is_none());
351 }
352
353 #[test]
354 fn test_get_all_parameters() {
355 let handler = IpcHandler::new(MockHost::new());
356
357 let request = IpcRequest::new(RequestId::Number(6), METHOD_GET_ALL_PARAMETERS, None);
358
359 let response = handler.handle_request(request);
360
361 assert!(response.result.is_some());
362
363 let result: GetAllParametersResult =
364 serde_json::from_value(response.result.unwrap()).unwrap();
365 assert_eq!(result.parameters.len(), 2);
366 }
367
368 #[test]
369 fn test_handle_json() {
370 let handler = IpcHandler::new(MockHost::new());
371
372 let json = r#"{"jsonrpc":"2.0","id":1,"method":"getParameter","params":{"id":"gain"}}"#;
373 let response_json = handler.handle_json(json);
374
375 assert!(response_json.contains("\"result\""));
376 assert!(!response_json.contains("\"error\""));
377 }
378
379 #[test]
380 fn test_handle_json_parse_error() {
381 let handler = IpcHandler::new(MockHost::new());
382
383 let json = r#"{"invalid json"#;
384 let response_json = handler.handle_json(json);
385
386 assert!(response_json.contains("\"error\""));
387 }
388}