1use std::fmt;
5
6use borsh::{BorshDeserialize, BorshSerialize};
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9
10use crate::RexValue;
11
12type HeadersInnerType = std::collections::BTreeMap<String, RexValue>;
13
14#[derive(
16 Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default, BorshSerialize, BorshDeserialize,
17)]
18pub struct Headers(HeadersInnerType);
19
20#[derive(Error, Debug)]
21pub enum HeadersError {
22 #[error("Failed to decode {encoding} for parameter '{param}': {reason}")]
23 DecodeError {
24 param: String,
25 encoding: String,
26 reason: String,
27 },
28
29 #[error("JSON parsing error: {reason}")]
30 JsonError { reason: String },
31}
32
33impl Headers {
34 pub fn new(headers: HeadersInnerType) -> Self {
42 Headers(headers)
43 }
44
45 pub fn insert_plain(&mut self, key: String, value: String) {
53 self.0.insert(key, RexValue::Plain(value.into_bytes()));
54 }
55
56 pub fn insert_encrypted(&mut self, key: String, encrypted_value: String) {
66 self.0
67 .insert(key, RexValue::Encrypted(encrypted_value.into_bytes()));
68 }
69
70 #[cfg(feature = "non-pdk")]
80 pub fn insert_encrypted_bytes(&mut self, key: String, ciphertext: Vec<u8>) {
81 use fastcrypto::encoding::{Base64, Encoding};
82 let encoded = Base64::encode(&ciphertext);
84 self.0
85 .insert(key, RexValue::Encrypted(encoded.into_bytes()));
86 }
87
88 pub fn into_inner(self) -> HeadersInnerType {
94 self.0
95 }
96
97 #[cfg(feature = "non-pdk")]
109 pub fn parse_b64(headers_b64: &str) -> Result<Self, HeadersError> {
110 use fastcrypto::{encoding, encoding::Encoding};
111 let headers_bytes =
112 encoding::Base64::decode(headers_b64).map_err(|err| HeadersError::DecodeError {
113 param: "headers".to_string(),
114 encoding: "base64".to_string(),
115 reason: err.to_string(),
116 })?;
117
118 let headers_str =
119 std::str::from_utf8(&headers_bytes).map_err(|err| HeadersError::DecodeError {
120 param: "headers".to_string(),
121 encoding: "utf-8".to_string(),
122 reason: err.to_string(),
123 })?;
124
125 let parsed_headers: Headers =
126 serde_json::from_str(headers_str).map_err(|error| HeadersError::JsonError {
127 reason: format!("Invalid headers JSON: {error}"),
128 })?;
129
130 Ok(parsed_headers)
131 }
132}
133
134impl std::str::FromStr for Headers {
135 type Err = String;
136
137 fn from_str(s: &str) -> Result<Self, Self::Err> {
138 let headers: HeadersInnerType = serde_json::from_str(s).map_err(|e| e.to_string())?;
139 Ok(Headers(headers))
140 }
141}
142
143impl fmt::Display for Headers {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 write!(f, "{}", serde_json::to_string(&self.0).unwrap())
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use std::str::FromStr;
152
153 use super::*;
154
155 #[test]
156 fn test_headers_from_str_json() {
157 let json = r#"{"A": {"Plain":[66]}}"#;
158 let headers = Headers::from_str(json).unwrap();
159 let got = headers.0.into_iter().collect::<Vec<(_, RexValue)>>();
160 let expected = vec![("A".to_string(), RexValue::plain_string("B"))];
161 assert_eq!(got, expected);
162 }
163
164 #[test]
165 fn test_headers_from_str_with_string_values() {
166 let json = r#"{"Mynonce": {"Plain":"abc123"}}"#;
167 let headers = Headers::from_str(json).unwrap();
168 let got = headers.0.into_iter().collect::<Vec<(_, RexValue)>>();
169 let expected = vec![("Mynonce".to_string(), RexValue::plain_string("abc123"))];
170 assert_eq!(got, expected);
171 }
172}