ckb_script_ipc_common/channel.rs
1use crate::io::{BufReader, BufWriter, Read, Write};
2use crate::{
3 error::{IpcError, ProtocolErrorCode},
4 ipc::Serve,
5 packet::{Packet, RequestPacket, ResponsePacket},
6};
7use alloc::string::String;
8use alloc::vec;
9use serde::{Deserialize, Serialize};
10use serde_json::{from_slice, to_vec};
11
12/// The `Channel` struct facilitates communication between a client and a server.
13/// It handles the transmission of requests from the client to the server and the reception
14/// of responses from the server to the client. Communication is achieved through the use of pipes.
15///
16/// # Fields
17///
18/// * `reader` - Responsible for reading data from the channel.
19/// * `writer` - Responsible for writing data to the channel.
20pub struct Channel<R: Read, W: Write> {
21 reader: BufReader<R>,
22 writer: BufWriter<W>,
23}
24
25impl<R: Read, W: Write> Channel<R, W> {
26 pub fn new(reader: R, writer: W) -> Self {
27 Self {
28 reader: BufReader::new(reader),
29 writer: BufWriter::new(writer),
30 }
31 }
32}
33
34impl<R: Read, W: Write> Channel<R, W> {
35 /// Executes the server loop, processing incoming requests and sending responses.
36 ///
37 /// This function runs an infinite loop, continuously receiving requests from the client,
38 /// processing them using the provided service implementation, and sending back the responses.
39 /// If an error occurs during the processing of a request or the sending of a response, the
40 /// error is logged (if logging is enabled) and the error code is sent back to the client.
41 ///
42 /// # Arguments
43 ///
44 /// * `serve` - A mutable reference to the service implementation that handles the requests and
45 /// generates the responses. The service must implement the `Serve` trait with the appropriate
46 /// request and response types.
47 ///
48 /// # Type Parameters
49 ///
50 /// * `Req` - The type of the request messages. It must implement `Serialize` and `Deserialize`.
51 /// * `Resp` - The type of the response messages. It must implement `Serialize` and `Deserialize`.
52 /// * `S` - The type of the service implementation. It must implement the `Serve` trait with
53 /// `Req` as the request type and `Resp` as the response type.
54 ///
55 /// # Returns
56 ///
57 /// A `Result` indicating the success or failure of the server execution. If the server runs
58 /// successfully, it never returns. If an error occurs, it returns an `IpcError`.
59 pub fn execute<Req, Resp, S>(mut self, serve: &mut S) -> Result<(), IpcError>
60 where
61 Req: Serialize + for<'de> Deserialize<'de>,
62 Resp: Serialize + for<'de> Deserialize<'de>,
63 S: Serve<Req = Req, Resp = Resp>,
64 {
65 loop {
66 let result = self
67 .receive_request()
68 .and_then(|req| serve.serve(req).map_err(Into::into))
69 .and_then(|resp| self.send_response(resp));
70
71 match result {
72 Ok(_) => continue,
73 Err(e) => {
74 #[cfg(feature = "enable-logging")]
75 log::error!("Error in execute loop: {:?}", e);
76 // notify client
77 self.send_error_code(e.clone().into()).unwrap();
78 return Err(e);
79 }
80 }
81 }
82 }
83 ///
84 /// Sends a request to the server and waits for a response.
85 ///
86 /// This function serializes the request, sends it to the server, and then waits for the server's response.
87 /// It returns the deserialized response or an `IpcError` if an error occurs during the process.
88 ///
89 /// # Arguments
90 ///
91 /// * `_method_name` - A static string slice representing the name of the method being called.
92 /// * `req` - The request message to be sent to the server. It must implement `Serialize` and `Deserialize`.
93 ///
94 /// # Type Parameters
95 ///
96 /// * `Req` - The type of the request message. It must implement `Serialize` and `Deserialize`.
97 /// * `Resp` - The type of the response message. It must implement `Serialize` and `Deserialize`.
98 ///
99 /// # Returns
100 ///
101 /// A `Result` containing the deserialized response message if the call is successful, or an `IpcError` if
102 /// an error occurs during the process.
103 /// # Example
104 ///
105 /// ```rust,ignore
106 /// use ckb_script_ipc_common::channel::Channel;
107 /// use serde::{Serialize, Deserialize};
108 ///
109 /// #[derive(Serialize, Deserialize)]
110 /// struct MyRequest {
111 /// // request fields
112 /// }
113 ///
114 /// #[derive(Serialize, Deserialize)]
115 /// struct MyResponse {
116 /// // response fields
117 /// }
118 ///
119 /// let mut channel = Channel::new(reader, writer);
120 /// let request = MyRequest { /* fields */ };
121 /// let response: MyResponse = channel.call("my_method", request).expect("Failed to call method");
122 /// ```
123 pub fn call<Req, Resp>(
124 &mut self,
125 _method_name: &'static str,
126 req: Req,
127 ) -> Result<Resp, IpcError>
128 where
129 Req: Serialize + for<'de> Deserialize<'de>,
130 Resp: Serialize + for<'de> Deserialize<'de>,
131 {
132 let result = self.send_request(req).and_then(|_| self.receive_response());
133 match result {
134 Ok(resp) => Ok(resp),
135 Err(e) => {
136 #[cfg(feature = "enable-logging")]
137 log::error!("Error in call({}): {:?}", _method_name, e);
138 Err(e)
139 }
140 }
141 }
142 pub(crate) fn send_request<Req: Serialize>(&mut self, req: Req) -> Result<(), IpcError> {
143 let serialized_req = to_vec(&req).map_err(|_| IpcError::SerializeError)?;
144 let packet = RequestPacket::new(serialized_req);
145 #[cfg(feature = "enable-logging")]
146 log::info!("send request: {:?}", packet);
147
148 let bytes = packet.serialize();
149 self.writer.write(&bytes)?;
150 self.writer.flush()?;
151 Ok(())
152 }
153
154 /// Sends a raw JSON string request to the server.
155 ///
156 /// This function takes a JSON string and sends it directly as a request packet to the server,
157 /// without performing any serialization. This is useful when working with raw JSON data that
158 /// doesn't need to be converted from Rust types.
159 ///
160 /// # Arguments
161 ///
162 /// * `json` - A string slice containing the JSON request to be sent.
163 ///
164 /// # Returns
165 ///
166 /// A `Result` indicating whether the request was successfully sent, or an `IpcError` if
167 /// writing to the channel fails.
168 pub fn send_json_request(&mut self, json: &str) -> Result<(), IpcError> {
169 let packet = RequestPacket::new(json.as_bytes().to_vec());
170 #[cfg(feature = "enable-logging")]
171 log::info!("send request: {:?}", packet);
172
173 let bytes = packet.serialize();
174 self.writer.write(&bytes)?;
175 self.writer.flush()?;
176 Ok(())
177 }
178 pub(crate) fn send_response<Resp: Serialize>(&mut self, resp: Resp) -> Result<(), IpcError> {
179 let serialized_resp = to_vec(&resp).map_err(|_| IpcError::SerializeError)?;
180 let packet = ResponsePacket::new(0, serialized_resp);
181 #[cfg(feature = "enable-logging")]
182 log::info!("send response: {:?}", packet);
183
184 let bytes = packet.serialize();
185 self.writer.write(&bytes)?;
186 self.writer.flush()?;
187 Ok(())
188 }
189 pub(crate) fn send_error_code(
190 &mut self,
191 error_code: ProtocolErrorCode,
192 ) -> Result<(), IpcError> {
193 let packet = ResponsePacket::new(error_code.clone() as u64, vec![]);
194 #[cfg(feature = "enable-logging")]
195 log::info!("send error code: {:?}", error_code as u64);
196 let bytes = packet.serialize();
197 self.writer.write(&bytes)?;
198 self.writer.flush()?;
199 Ok(())
200 }
201 pub(crate) fn receive_request<Req: for<'de> Deserialize<'de>>(
202 &mut self,
203 ) -> Result<Req, IpcError> {
204 let packet = RequestPacket::read_from(&mut self.reader)?;
205 #[cfg(feature = "enable-logging")]
206 log::info!("receive request: {:?}", packet);
207 let req = from_slice(packet.payload()).map_err(|_| IpcError::DeserializeError)?;
208 Ok(req)
209 }
210 pub(crate) fn receive_response<Resp: for<'de> Deserialize<'de>>(
211 &mut self,
212 ) -> Result<Resp, IpcError> {
213 let packet = ResponsePacket::read_from(&mut self.reader)?;
214
215 #[cfg(feature = "enable-logging")]
216 log::info!("Received response: {:?}", packet);
217
218 let error_code = ProtocolErrorCode::from(packet.error_code());
219 match error_code {
220 ProtocolErrorCode::Ok => {}
221 e => {
222 #[cfg(feature = "enable-logging")]
223 log::error!("Received error code: {:?}", e);
224 return Err(IpcError::ProtocolError(e));
225 }
226 }
227 from_slice(packet.payload()).map_err(|_| IpcError::DeserializeError)
228 }
229
230 /// Receives a JSON string response from the server.
231 ///
232 /// This function reads a response packet from the server and returns its payload as a String,
233 /// without attempting to deserialize it into a specific type. This is useful when working
234 /// with raw JSON responses that don't need to be converted into specific Rust types.
235 ///
236 /// # Returns
237 ///
238 /// * `Ok(String)` - A String containing the JSON response if successful
239 /// * `Err(IpcError)` - An error if:
240 /// - Reading from the channel fails
241 /// - The server returns an error code
242 /// - The response payload contains invalid UTF-8
243 ///
244 pub fn receive_json_response(&mut self) -> Result<String, IpcError> {
245 let packet = ResponsePacket::read_from(&mut self.reader)?;
246
247 #[cfg(feature = "enable-logging")]
248 log::info!("Received response: {:?}", packet);
249
250 let error_code = ProtocolErrorCode::from(packet.error_code());
251 match error_code {
252 ProtocolErrorCode::Ok => {}
253 e => {
254 #[cfg(feature = "enable-logging")]
255 log::error!("Received error code: {:?}", e);
256 return Err(IpcError::ProtocolError(e));
257 }
258 }
259 Ok(String::from_utf8_lossy(packet.payload()).into_owned())
260 }
261}