1use errors::TxLogErrors;
6use hex;
7use serde::{Deserialize, Serialize};
8
9mod errors;
10
11#[derive(Clone)]
12pub struct TxlogClient {
13 pub url: String,
14 secret: String,
15}
16
17#[derive(Serialize, Deserialize)]
18pub struct SubmitResponse {
19 pub success: bool,
20}
21
22#[derive(Serialize, Deserialize)]
23pub struct TxResponse {
24 pub txid: String,
25 pub status: u32,
26 pub created: String,
27 pub updated: String,
28}
29
30pub fn new(url: String, secret: String) -> TxlogClient {
32 return TxlogClient { url, secret };
34}
35
36pub struct SubmitMetadata {
37 pub metadata: Option<String>,
38 pub merchant: Option<String>,
39 pub network: Option<String>,
40}
41
42impl TxlogClient {
43 pub async fn rawtx(&self, txid: &String) -> Result<Vec<u8>, TxLogErrors> {
45 let client = reqwest::Client::new();
46 let url = format!("{}/tx/{}/raw", &self.url, txid);
47 let response = client
48 .get(&url)
49 .header("Authorization", format!("Bearer {}", self.secret))
50 .send()
51 .await?;
52
53 let body = match response.text().await {
54 Err(e) => return Err(TxLogErrors::BodyDecodeError(e)),
55 Ok(v) => v,
56 };
57
58 let decoded = match hex::decode(&body) {
59 Ok(v) => v,
60 Err(e) => return Err(TxLogErrors::HexDecode(e)),
61 };
62
63 return Ok(decoded);
64 }
65
66 pub async fn tx(&self, txid: &String) -> Result<TxResponse, TxLogErrors> {
68 let client = reqwest::Client::new();
69 let url = format!("{}/tx/{}", &self.url, txid);
70 let response = client
71 .get(&url)
72 .header("Authorization", format!("Bearer {}", self.secret))
73 .send()
74 .await?;
75
76 let res = match response.json::<TxResponse>().await {
77 Ok(v) => v,
78 Err(e) => return Err(TxLogErrors::BodyDecodeError(e)),
79 };
80
81 Ok(res)
82 }
83
84 pub async fn submit(
86 &self,
87 rawtx: Vec<u8>,
88 params: Option<SubmitMetadata>,
89 ) -> Result<SubmitResponse, TxLogErrors> {
90 let client = reqwest::Client::new();
91 let url = format!("{}/tx", &self.url);
92 let mut query_params: Vec<(String, String)> = vec![];
93
94 match params {
95 Some(p) => {
96 match p.metadata {
97 Some(v) => query_params.push(("metadata".to_string(), v)),
98 None => (),
99 };
100 match p.merchant {
101 Some(v) => query_params.push(("merchant".to_string(), v)),
102 None => (),
103 };
104 match p.network {
105 Some(v) => query_params.push(("network".to_string(), v)),
106 None => (),
107 };
108 }
109 None => (),
110 }
111
112 let response = client
113 .post(&url)
114 .query(&query_params)
115 .header("Authorization", format!("Bearer {}", self.secret))
116 .header("Content-Type", "application/octet-stream")
117 .body(rawtx)
118 .send()
119 .await?;
120
121 let res = match response.json::<SubmitResponse>().await {
122 Ok(v) => v,
123 Err(e) => return Err(TxLogErrors::BodyDecodeError(e)),
124 };
125
126 if !res.success {
127 return Err(TxLogErrors::SubmitResponseFailed);
128 }
129
130 Ok(res)
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 macro_rules! aw {
137 ($e:expr) => {
138 tokio_test::block_on($e)
139 };
140 }
141
142 #[test]
143 fn test_rawtx() {
144 let secret = dotenv::var("TXLOG_SECRET").unwrap();
146 let url = dotenv::var("TXLOG_URL").unwrap();
147 let rawtx = dotenv::var("RAWTX").unwrap();
148 let txid = dotenv::var("TXID").unwrap();
149
150 let client = crate::new(url, secret);
151
152 let response = aw!(client.rawtx(&txid)).unwrap();
153
154 assert_eq!(response, hex::decode(&rawtx).unwrap());
155 }
156
157 #[test]
158 fn test_submit() {
159 let secret = dotenv::var("TXLOG_SECRET").unwrap();
161 let url = dotenv::var("TXLOG_URL").unwrap();
162 let rawtx = dotenv::var("RAWTX").unwrap();
163
164 let client = crate::new(url, secret);
165
166 let response = aw!(client.submit(hex::decode(&rawtx).unwrap(), None)).unwrap();
167
168 assert_eq!(response.success, true);
169 }
170
171 #[test]
172 fn test_tx() {
173 let secret = dotenv::var("TXLOG_SECRET").unwrap();
175 let url = dotenv::var("TXLOG_URL").unwrap();
176 let txid = dotenv::var("TXID").unwrap();
177
178 let client = crate::new(url, secret);
179
180 let response = aw!(client.tx(&txid)).unwrap();
181
182 assert_eq!(response.txid, txid);
183 }
184}