bsv/wallet/serializer/
frame.rs1use super::read_varint;
4use crate::wallet::error::WalletError;
5
6pub struct RequestFrame {
8 pub call: u8,
9 pub originator: String,
10 pub params: Vec<u8>,
11}
12
13pub fn write_request_frame(frame: &RequestFrame) -> Vec<u8> {
15 let originator_bytes = frame.originator.as_bytes();
16 let mut buf = Vec::with_capacity(1 + 1 + originator_bytes.len() + frame.params.len());
17 buf.push(frame.call);
18 buf.push(originator_bytes.len() as u8);
19 buf.extend_from_slice(originator_bytes);
20 buf.extend_from_slice(&frame.params);
21 buf
22}
23
24pub fn read_request_frame(data: &[u8]) -> Result<RequestFrame, WalletError> {
26 if data.len() < 2 {
27 return Err(WalletError::Internal("request frame too short".to_string()));
28 }
29 let call = data[0];
30 let originator_len = data[1] as usize;
31 if data.len() < 2 + originator_len {
32 return Err(WalletError::Internal(
33 "request frame originator truncated".to_string(),
34 ));
35 }
36 let originator = String::from_utf8(data[2..2 + originator_len].to_vec())
37 .map_err(|e| WalletError::Internal(e.to_string()))?;
38 let params = data[2 + originator_len..].to_vec();
39 Ok(RequestFrame {
40 call,
41 originator,
42 params,
43 })
44}
45
46pub fn write_result_frame(result: Option<&[u8]>, error: Option<&WalletError>) -> Vec<u8> {
50 let mut buf = Vec::new();
51 if let Some(err) = error {
52 match err {
53 WalletError::Protocol { code, message } => {
54 buf.push(*code);
55 let msg_bytes = message.as_bytes();
56 buf.extend_from_slice(&super::varint_bytes(msg_bytes.len() as u64));
57 buf.extend_from_slice(msg_bytes);
58 buf.extend_from_slice(&super::varint_bytes(0));
60 }
61 _ => {
62 let msg = err.to_string();
63 buf.push(1); let msg_bytes = msg.as_bytes();
65 buf.extend_from_slice(&super::varint_bytes(msg_bytes.len() as u64));
66 buf.extend_from_slice(msg_bytes);
67 buf.extend_from_slice(&super::varint_bytes(0));
68 }
69 }
70 } else {
71 buf.push(0x00); if let Some(data) = result {
73 buf.extend_from_slice(data);
74 }
75 }
76 buf
77}
78
79pub fn read_result_frame(data: &[u8]) -> Result<Vec<u8>, WalletError> {
81 if data.is_empty() {
82 return Err(WalletError::Internal("empty result frame".to_string()));
83 }
84 let error_byte = data[0];
85 if error_byte == 0 {
86 return Ok(data[1..].to_vec());
88 }
89 let mut cursor = std::io::Cursor::new(&data[1..]);
91 let msg_len = read_varint(&mut cursor)?;
92 let mut msg_buf = vec![0u8; msg_len as usize];
93 std::io::Read::read_exact(&mut cursor, &mut msg_buf)
94 .map_err(|e| WalletError::Internal(e.to_string()))?;
95 let message = String::from_utf8(msg_buf).map_err(|e| WalletError::Internal(e.to_string()))?;
96
97 let stack_len = read_varint(&mut cursor)?;
98 let mut stack_buf = vec![0u8; stack_len as usize];
99 std::io::Read::read_exact(&mut cursor, &mut stack_buf)
100 .map_err(|e| WalletError::Internal(e.to_string()))?;
101
102 Err(WalletError::Protocol {
103 code: error_byte,
104 message,
105 })
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn test_request_frame_roundtrip() {
114 let frame = RequestFrame {
115 call: 11,
116 originator: "test-app".to_string(),
117 params: vec![1, 2, 3, 4],
118 };
119 let wire = write_request_frame(&frame);
120 let parsed = read_request_frame(&wire).unwrap();
121 assert_eq!(parsed.call, 11);
122 assert_eq!(parsed.originator, "test-app");
123 assert_eq!(parsed.params, vec![1, 2, 3, 4]);
124 }
125
126 #[test]
127 fn test_request_frame_empty_originator() {
128 let frame = RequestFrame {
129 call: 1,
130 originator: String::new(),
131 params: vec![5, 6],
132 };
133 let wire = write_request_frame(&frame);
134 assert_eq!(wire[0], 1);
135 assert_eq!(wire[1], 0);
136 assert_eq!(&wire[2..], &[5, 6]);
137 let parsed = read_request_frame(&wire).unwrap();
138 assert_eq!(parsed.call, 1);
139 assert_eq!(parsed.originator, "");
140 assert_eq!(parsed.params, vec![5, 6]);
141 }
142
143 #[test]
144 fn test_result_frame_success() {
145 let wire = write_result_frame(Some(&[1, 2, 3]), None);
146 assert_eq!(wire[0], 0);
147 let data = read_result_frame(&wire).unwrap();
148 assert_eq!(data, vec![1, 2, 3]);
149 }
150
151 #[test]
152 fn test_result_frame_success_empty() {
153 let wire = write_result_frame(None, None);
154 assert_eq!(wire, vec![0]);
155 let data = read_result_frame(&wire).unwrap();
156 assert!(data.is_empty());
157 }
158
159 #[test]
160 fn test_result_frame_error() {
161 let err = WalletError::Protocol {
162 code: 5,
163 message: "test error".to_string(),
164 };
165 let wire = write_result_frame(None, Some(&err));
166 assert_ne!(wire[0], 0);
167 let result = read_result_frame(&wire);
168 assert!(result.is_err());
169 }
170}