1use serde::{Deserialize, Serialize};
82use std::collections::HashMap;
83use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
84use std::sync::Arc;
85use tokio::sync::{mpsc, oneshot, Mutex};
86
87use crate::error::{ClaudeError, Result};
88use crate::types::{HookEvent, PermissionRequest, PermissionResult, RequestId};
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(tag = "type")]
93pub enum ControlMessage {
94 #[serde(rename = "request")]
96 Request(ControlRequest),
97 #[serde(rename = "response")]
99 Response(ControlResponse),
100 #[serde(rename = "init")]
102 Init(InitRequest),
103 #[serde(rename = "init_response")]
105 InitResponse(InitResponse),
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize)]
110#[serde(tag = "method", content = "params")]
111pub enum ControlRequest {
112 #[serde(rename = "interrupt")]
114 Interrupt {
115 id: RequestId,
117 },
118 #[serde(rename = "send_message")]
120 SendMessage {
121 id: RequestId,
123 content: String,
125 },
126 #[serde(rename = "hook_response")]
128 HookResponse {
129 id: RequestId,
131 hook_id: String,
133 response: serde_json::Value,
135 },
136 #[serde(rename = "permission_response")]
138 PermissionResponse {
139 id: RequestId,
141 request_id: RequestId,
143 result: PermissionResult,
145 },
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
150#[serde(tag = "status")]
151pub enum ControlResponse {
152 #[serde(rename = "success")]
154 Success {
155 id: RequestId,
157 data: Option<serde_json::Value>,
159 },
160 #[serde(rename = "error")]
162 Error {
163 id: RequestId,
165 message: String,
167 code: Option<String>,
169 },
170 #[serde(rename = "hook")]
172 Hook {
173 id: String,
175 event: HookEvent,
177 },
178 #[serde(rename = "permission")]
180 Permission {
181 id: RequestId,
183 request: PermissionRequest,
185 },
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
190pub struct InitRequest {
191 pub protocol_version: String,
193 pub sdk_version: String,
195 pub capabilities: ClientCapabilities,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
201pub struct ClientCapabilities {
202 pub bidirectional: bool,
204 pub hooks: bool,
206 pub permissions: bool,
208 pub interrupts: bool,
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct InitResponse {
215 pub protocol_version: String,
217 pub cli_version: String,
219 pub capabilities: ServerCapabilities,
221 pub session_id: String,
223}
224
225#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct ServerCapabilities {
228 pub streaming: bool,
230 pub tools: bool,
232 pub mcp: bool,
234}
235
236struct PendingRequest {
238 response_tx: oneshot::Sender<ControlResponse>,
240}
241
242pub struct ProtocolHandler {
244 next_request_id: Arc<AtomicU64>,
246 pending_requests: Arc<Mutex<HashMap<RequestId, PendingRequest>>>,
248 initialized: Arc<AtomicBool>,
250 hook_tx: Option<mpsc::UnboundedSender<(String, HookEvent)>>,
252 permission_tx: Option<mpsc::UnboundedSender<(RequestId, PermissionRequest)>>,
254}
255
256impl ProtocolHandler {
257 pub fn new() -> Self {
259 Self {
260 next_request_id: Arc::new(AtomicU64::new(1)),
261 pending_requests: Arc::new(Mutex::new(HashMap::new())),
262 initialized: Arc::new(AtomicBool::new(false)),
263 hook_tx: None,
264 permission_tx: None,
265 }
266 }
267
268 pub fn set_hook_channel(&mut self, tx: mpsc::UnboundedSender<(String, HookEvent)>) {
270 self.hook_tx = Some(tx);
271 }
272
273 pub fn set_permission_channel(
275 &mut self,
276 tx: mpsc::UnboundedSender<(RequestId, PermissionRequest)>,
277 ) {
278 self.permission_tx = Some(tx);
279 }
280
281 pub fn is_initialized(&self) -> bool {
283 self.initialized.load(Ordering::SeqCst)
284 }
285
286 pub fn set_initialized(&self, value: bool) {
288 self.initialized.store(value, Ordering::SeqCst);
289 }
290
291 fn next_id(&self) -> RequestId {
293 let id = self.next_request_id.fetch_add(1, Ordering::SeqCst);
294 RequestId::new(format!("req-{id}"))
295 }
296
297 pub fn create_init_request(&self) -> InitRequest {
299 InitRequest {
300 protocol_version: "1.0".to_string(),
301 sdk_version: crate::VERSION.to_string(),
302 capabilities: ClientCapabilities {
303 bidirectional: true,
304 hooks: true,
305 permissions: true,
306 interrupts: true,
307 },
308 }
309 }
310
311 pub fn handle_init_response(&self, response: InitResponse) -> Result<()> {
313 if response.protocol_version != "1.0" {
315 return Err(ClaudeError::protocol_error(format!(
316 "Unsupported protocol version: {}",
317 response.protocol_version
318 )));
319 }
320
321 self.initialized.store(true, Ordering::SeqCst);
322 Ok(())
323 }
324
325 pub async fn send_request(
327 &self,
328 request: ControlRequest,
329 ) -> Result<oneshot::Receiver<ControlResponse>> {
330 if !self.is_initialized() {
331 return Err(ClaudeError::protocol_error(
332 "Protocol not initialized - call init first",
333 ));
334 }
335
336 let id = self.get_request_id(&request);
337 let (response_tx, response_rx) = oneshot::channel();
338
339 let pending = PendingRequest { response_tx };
340
341 {
342 let mut pending_requests = self.pending_requests.lock().await;
343 pending_requests.insert(id, pending);
344 }
345
346 Ok(response_rx)
347 }
348
349 fn get_request_id(&self, request: &ControlRequest) -> RequestId {
351 match request {
352 ControlRequest::Interrupt { id } => id.clone(),
353 ControlRequest::SendMessage { id, .. } => id.clone(),
354 ControlRequest::HookResponse { id, .. } => id.clone(),
355 ControlRequest::PermissionResponse { id, .. } => id.clone(),
356 }
357 }
358
359 pub async fn handle_response(&self, response: ControlResponse) -> Result<()> {
361 match &response {
362 ControlResponse::Success { id, .. } | ControlResponse::Error { id, .. } => {
363 let mut pending_requests = self.pending_requests.lock().await;
364 if let Some(pending) = pending_requests.remove(id) {
365 let _ = pending.response_tx.send(response);
366 }
367 Ok(())
368 }
369 ControlResponse::Hook { id, event } => {
370 if let Some(ref tx) = self.hook_tx {
371 tx.send((id.clone(), *event))
372 .map_err(|_| ClaudeError::protocol_error("Hook channel closed"))?;
373 }
374 Ok(())
375 }
376 ControlResponse::Permission { id, request } => {
377 if let Some(ref tx) = self.permission_tx {
378 tx.send((id.clone(), request.clone()))
379 .map_err(|_| ClaudeError::protocol_error("Permission channel closed"))?;
380 }
381 Ok(())
382 }
383 }
384 }
385
386 pub fn create_interrupt_request(&self) -> ControlRequest {
388 ControlRequest::Interrupt {
389 id: self.next_id(),
390 }
391 }
392
393 pub fn create_send_message_request(&self, content: String) -> ControlRequest {
395 ControlRequest::SendMessage {
396 id: self.next_id(),
397 content,
398 }
399 }
400
401 pub fn create_hook_response(
403 &self,
404 hook_id: String,
405 response: serde_json::Value,
406 ) -> ControlRequest {
407 ControlRequest::HookResponse {
408 id: self.next_id(),
409 hook_id,
410 response,
411 }
412 }
413
414 pub fn create_permission_response(
416 &self,
417 request_id: RequestId,
418 result: PermissionResult,
419 ) -> ControlRequest {
420 ControlRequest::PermissionResponse {
421 id: self.next_id(),
422 request_id,
423 result,
424 }
425 }
426
427 pub fn serialize_message(&self, message: &ControlMessage) -> Result<String> {
429 serde_json::to_string(message)
430 .map(|s| format!("{s}\n"))
431 .map_err(|e| ClaudeError::json_encode(format!("Failed to serialize message: {e}")))
432 }
433
434 pub fn deserialize_message(&self, json: &str) -> Result<ControlMessage> {
436 serde_json::from_str(json)
437 .map_err(|e| ClaudeError::json_decode(format!("Failed to deserialize message: {e}")))
438 }
439}
440
441impl Default for ProtocolHandler {
442 fn default() -> Self {
443 Self::new()
444 }
445}
446
447#[cfg(test)]
448mod tests {
449 use super::*;
450 use crate::types::ToolName;
451
452 #[test]
453 fn test_request_id_generation() {
454 let handler = ProtocolHandler::new();
455 let id1 = handler.next_id();
456 let id2 = handler.next_id();
457 assert_ne!(id1, id2);
458 }
459
460 #[test]
461 fn test_init_request_creation() {
462 let handler = ProtocolHandler::new();
463 let init_req = handler.create_init_request();
464 assert_eq!(init_req.protocol_version, "1.0");
465 assert!(init_req.capabilities.bidirectional);
466 }
467
468 #[test]
469 fn test_serialize_deserialize() {
470 let handler = ProtocolHandler::new();
471 let request = handler.create_interrupt_request();
472 let message = ControlMessage::Request(request);
473
474 let serialized = handler.serialize_message(&message).unwrap();
475 let deserialized = handler.deserialize_message(serialized.trim()).unwrap();
476
477 match deserialized {
478 ControlMessage::Request(ControlRequest::Interrupt { .. }) => {}
479 _ => panic!("Wrong message type"),
480 }
481 }
482
483 #[test]
484 fn test_deserialize_invalid_json() {
485 let handler = ProtocolHandler::new();
486 let result = handler.deserialize_message("not valid json");
487 assert!(result.is_err());
488 }
489
490 #[test]
491 fn test_deserialize_invalid_message_structure() {
492 let handler = ProtocolHandler::new();
493 let invalid = r#"{"type":"unknown_type"}"#;
494 let result = handler.deserialize_message(invalid);
495 assert!(result.is_err());
496 }
497
498 #[test]
499 fn test_deserialize_missing_fields() {
500 let handler = ProtocolHandler::new();
501 let missing = r#"{"type":"request"}"#;
502 let result = handler.deserialize_message(missing);
503 assert!(result.is_err());
504 }
505
506 #[tokio::test]
507 async fn test_handle_response_with_missing_pending_request() {
508 let handler = ProtocolHandler::new();
509 handler.set_initialized(true);
510
511 let response = ControlResponse::Success {
513 id: RequestId::new("non-existent-req"),
514 data: None,
515 };
516
517 let result = handler.handle_response(response).await;
519 assert!(result.is_ok());
520 }
521
522 #[tokio::test]
523 async fn test_hook_response_without_channel() {
524 let handler = ProtocolHandler::new();
525
526 let response = ControlResponse::Hook {
528 id: "hook-1".to_string(),
529 event: HookEvent::PreToolUse,
530 };
531
532 let result = handler.handle_response(response).await;
534 assert!(result.is_ok());
535 }
536
537 #[tokio::test]
538 async fn test_permission_response_without_channel() {
539 let handler = ProtocolHandler::new();
540
541 let response = ControlResponse::Permission {
543 id: RequestId::new("perm-1"),
544 request: PermissionRequest {
545 tool_name: ToolName::new("test"),
546 tool_input: serde_json::json!({}),
547 context: crate::types::ToolPermissionContext {
548 suggestions: vec![],
549 },
550 },
551 };
552
553 let result = handler.handle_response(response).await;
555 assert!(result.is_ok());
556 }
557
558 #[test]
559 fn test_init_response_with_wrong_version() {
560 let handler = ProtocolHandler::new();
561
562 let init_response = InitResponse {
563 protocol_version: "999.0".to_string(),
564 cli_version: "1.0.0".to_string(),
565 capabilities: ServerCapabilities {
566 streaming: true,
567 tools: true,
568 mcp: true,
569 },
570 session_id: "test".to_string(),
571 };
572
573 let result = handler.handle_init_response(init_response);
574 assert!(result.is_err());
575 assert!(!handler.is_initialized());
576 }
577
578 #[tokio::test]
579 async fn test_send_request_without_init() {
580 let handler = ProtocolHandler::new();
581 assert!(!handler.is_initialized());
582
583 let request = handler.create_interrupt_request();
584 let result = handler.send_request(request).await;
585 assert!(result.is_err());
586 }
587
588 #[test]
589 fn test_serialize_all_request_types() {
590 let handler = ProtocolHandler::new();
591
592 let req = handler.create_interrupt_request();
594 let msg = ControlMessage::Request(req);
595 assert!(handler.serialize_message(&msg).is_ok());
596
597 let req = handler.create_send_message_request("test".to_string());
599 let msg = ControlMessage::Request(req);
600 assert!(handler.serialize_message(&msg).is_ok());
601
602 let req = handler.create_hook_response("hook-1".to_string(), serde_json::json!({}));
604 let msg = ControlMessage::Request(req);
605 assert!(handler.serialize_message(&msg).is_ok());
606
607 let req = handler.create_permission_response(
609 RequestId::new("req-1"),
610 crate::types::PermissionResult::Allow(crate::types::PermissionResultAllow {
611 updated_input: None,
612 updated_permissions: None,
613 }),
614 );
615 let msg = ControlMessage::Request(req);
616 assert!(handler.serialize_message(&msg).is_ok());
617 }
618
619 #[test]
620 fn test_serialize_all_response_types() {
621 let handler = ProtocolHandler::new();
622
623 let resp = ControlResponse::Success {
625 id: RequestId::new("req-1"),
626 data: Some(serde_json::json!({"result": "ok"})),
627 };
628 let msg = ControlMessage::Response(resp);
629 assert!(handler.serialize_message(&msg).is_ok());
630
631 let resp = ControlResponse::Error {
633 id: RequestId::new("req-1"),
634 message: "test error".to_string(),
635 code: Some("ERR_TEST".to_string()),
636 };
637 let msg = ControlMessage::Response(resp);
638 assert!(handler.serialize_message(&msg).is_ok());
639
640 let resp = ControlResponse::Hook {
642 id: "hook-1".to_string(),
643 event: HookEvent::PreToolUse,
644 };
645 let msg = ControlMessage::Response(resp);
646 assert!(handler.serialize_message(&msg).is_ok());
647
648 let resp = ControlResponse::Permission {
650 id: RequestId::new("perm-1"),
651 request: PermissionRequest {
652 tool_name: ToolName::new("test"),
653 tool_input: serde_json::json!({}),
654 context: crate::types::ToolPermissionContext {
655 suggestions: vec![],
656 },
657 },
658 };
659 let msg = ControlMessage::Response(resp);
660 assert!(handler.serialize_message(&msg).is_ok());
661 }
662
663 #[test]
664 fn test_get_request_id() {
665 let handler = ProtocolHandler::new();
666
667 let interrupt = ControlRequest::Interrupt {
668 id: RequestId::new("id1"),
669 };
670 assert_eq!(handler.get_request_id(&interrupt).as_str(), "id1");
671
672 let send_msg = ControlRequest::SendMessage {
673 id: RequestId::new("id2"),
674 content: "test".to_string(),
675 };
676 assert_eq!(handler.get_request_id(&send_msg).as_str(), "id2");
677
678 let hook_resp = ControlRequest::HookResponse {
679 id: RequestId::new("id3"),
680 hook_id: "hook".to_string(),
681 response: serde_json::json!({}),
682 };
683 assert_eq!(handler.get_request_id(&hook_resp).as_str(), "id3");
684
685 let perm_resp = ControlRequest::PermissionResponse {
686 id: RequestId::new("id4"),
687 request_id: RequestId::new("perm"),
688 result: crate::types::PermissionResult::Allow(
689 crate::types::PermissionResultAllow {
690 updated_input: None,
691 updated_permissions: None,
692 },
693 ),
694 };
695 assert_eq!(handler.get_request_id(&perm_resp).as_str(), "id4");
696 }
697}