1use async_trait::async_trait;
2use std::fmt::Display;
3
4use crate::{
5 Message, Notification, Request, Response, message::Direction,
6 processed_message::ProcessedMessage,
7};
8
9#[derive(Debug)]
10pub enum HookError {
11 ProcessingFailed(String),
12}
13
14impl Display for HookError {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 match self {
17 HookError::ProcessingFailed(msg) => write!(f, "Hook processing failed: {}", msg),
18 }
19 }
20}
21
22impl std::error::Error for HookError {}
23
24#[derive(Debug)]
25pub struct HookOutput {
26 pub message: Option<Message>,
27 pub generated_messages: Vec<(Direction, Message)>,
28}
29
30impl HookOutput {
31 pub fn new(message: Message) -> Self {
32 Self {
33 message: Some(message),
34 generated_messages: Vec::new(),
35 }
36 }
37
38 pub fn empty() -> Self {
39 Self {
40 message: None,
41 generated_messages: Vec::new(),
42 }
43 }
44
45 pub fn with_message(mut self, direction: Direction, message: Message) -> Self {
46 self.generated_messages.push((direction, message));
47 self
48 }
49
50 pub fn with_messages(mut self, messages: Vec<(Direction, Message)>) -> Self {
51 self.generated_messages.extend(messages);
52 self
53 }
54
55 pub fn as_processed(self) -> ProcessedMessage {
56 match self.message {
57 Some(message) => {
58 if self.generated_messages.is_empty() {
59 return ProcessedMessage::Forward(message);
60 }
61
62 ProcessedMessage::WithMessages {
63 message,
64 generated_messages: self.generated_messages,
65 }
66 }
67 None => ProcessedMessage::Ignore {
68 generated_messages: self.generated_messages,
69 },
70 }
71 }
72}
73
74pub type HookResult = Result<HookOutput, HookError>;
75
76#[async_trait]
77pub trait Hook: Send + Sync {
78 async fn on_request(&self, request: Request) -> HookResult {
79 Ok(HookOutput::new(Message::Request(request)))
80 }
81
82 async fn on_response(&self, response: Response) -> HookResult {
83 Ok(HookOutput::new(Message::Response(response)))
84 }
85
86 async fn on_notification(&self, notification: Notification) -> HookResult {
87 Ok(HookOutput::new(Message::Notification(notification)))
88 }
89}