Skip to main content

ord_reqwest/
ord_client.rs

1use bitcoin::OutPoint;
2use ordinals::RuneId;
3use reqwest::{Error, Response};
4use serde::{Deserialize, Serialize};
5use crate::data::rune_entry::RuneResponse;
6use crate::models::address::AddressResponse;
7use crate::models::ordinals::OutputResponse;
8
9pub struct OrdClient {
10    client: reqwest::Client,
11    base_api_url: String,
12    pub base_public_url: String,
13}
14
15#[derive(Serialize, Deserialize, Debug, Clone)]
16pub struct InscriptionResponse {
17    pub address: String,
18    pub id: String,
19}
20impl OrdClient {
21    pub fn new() -> Self {
22        let ord_base_url =
23            std::env::var("ORD_BASE_URL").unwrap_or("http://192.168.1.105:4000".to_string());
24        let ord_public_url =
25            std::env::var("ORD_PUBLIC_URL").unwrap_or("https://ordinals.com".to_string());
26        let client = reqwest::Client::builder().timeout(std::time::Duration::from_secs(10)).build().unwrap();
27        OrdClient {
28            client,
29            base_api_url: ord_base_url,
30            base_public_url: ord_public_url,
31        }
32    }
33
34    async fn do_api_call(&self, url: &str) -> Result<Response, Error> {
35        // loop until we get a response from the api
36        loop {
37            let response = self
38                .client
39                .get(url)
40                .header("accept", "application/json")
41                .send()
42                .await;
43            if response.is_ok() {
44                return response;
45            }
46        }
47    }
48
49    pub async fn fetch_rune_details(&self, rune_id: RuneId) -> RuneResponse {
50        // fetch rune details from ord api using ord base url /rune/{rune_id}
51        let rune_url = format!("{}/rune/{}", self.base_api_url, rune_id);
52        // get the response and parse it using serde
53        let api_response = self.do_api_call(&rune_url).await;
54        // get the spaced rune from the response serde json it to RuneResponse and get the spaced rune use serdejson
55        let rune_response =
56            serde_json::from_str::<RuneResponse>(&api_response.unwrap().text().await.unwrap())
57                .unwrap();
58        rune_response
59    }
60
61    pub async fn fetch_latest_block_height(&self) -> u64 {
62        // fetch latest block height from ord api using ord base url /block_height
63        let block_height_url = format!("{}/blockheight", self.base_api_url);
64        // get the response and parse it using serde
65        let api_response = self.do_api_call(&block_height_url).await;
66        // get the block height from the response serde json it to u128 and get the block height use serdejson
67        let block_height =
68            serde_json::from_str::<u64>(&api_response.unwrap().text().await.unwrap()).unwrap();
69        return block_height;
70    }
71    pub async fn fetch_output(&self, out_point: OutPoint) -> OutputResponse {
72        // fetch output details from ord api using ord base url /output/{tx_id}:{vout}
73        let output_url = format!("{}/output/{}:{}", self.base_api_url, out_point.txid, out_point.vout);
74        // get the response and parse it using serde
75        let api_response = self.do_api_call(&output_url).await;
76        // get the output details from the response serde json it to OutputResponse and get the output details use serdejson
77        let output_response =
78            serde_json::from_str::<OutputResponse>(&api_response.unwrap().text().await.unwrap())
79                .unwrap();
80        return output_response;
81    }
82    pub async fn get_address(&self, address: &str) -> AddressResponse {
83        // fetch address details from ord api using ord base url /address/{address}
84        let address_url = format!("{}/address/{}", self.base_api_url, address);
85        // get the response and parse it using serde
86        let api_response = self.do_api_call(&address_url).await;
87        // get the address details from the response serde json it to AddressResponse and get the address details use serdejson
88        let address_response = api_response.unwrap().text().await.unwrap();
89        let address_response: AddressResponse = serde_json::from_str(&address_response).unwrap();
90        address_response
91    }
92
93    pub async fn get_inscription(&self, inscription_id: &str) -> InscriptionResponse {
94        // fetch inscription details from ord api using ord base url /inscription/{inscription_id}
95        let inscription_url = format!("{}/inscription/{}", self.base_api_url, inscription_id);
96        // get the response and parse it using serde
97        let api_response = self.do_api_call(&inscription_url).await.unwrap();
98        // parse the JSON response to InscriptionResponse
99        let inscription_text = api_response.text().await.unwrap();
100        let inscription_response: InscriptionResponse = serde_json::from_str(&inscription_text).unwrap();
101        inscription_response
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use std::str::FromStr;
108
109    use bitcoin::{OutPoint, Txid};
110    use crate::models::address::AddressResponse;
111    use super::*;
112
113    #[tokio::test]
114    #[ignore]
115    async fn fetch_output() {
116        let client = OrdClient::new();
117        let out_point = OutPoint {
118            txid: Txid::from_str("3de0c436d136abfb5f1ec1996d755331f25bf8e424743b1c21e2952fea8ef002").unwrap(),
119            vout: 1
120        };
121        let output_response = client.fetch_output(out_point).await;
122        assert_eq!(output_response.value, 546);
123        assert_eq!(output_response.address, "bc1p90zah9c3hyywydpgnw0gcuk2pwwywj8u7hd0rhhr8kg0x3wl778s4d8h9t");
124    }
125
126    #[tokio::test]
127    #[ignore]
128    async fn fetch_address_details() {
129        let client = OrdClient::new();
130        let address = "bc1pk244ecgfnyurjdj43qh9ha95laff32aa5w7fmscjtt93fkresymqpf8rgz";
131        let address_response: AddressResponse = client.get_address(address).await;
132        assert!(address_response.inscriptions.len() > 0);
133    }
134
135    #[tokio::test]
136    #[ignore]
137    async fn fetch_latest_block_height() {
138        let client = OrdClient::new();
139        let block_height = client.fetch_latest_block_height().await;
140        assert!(block_height > 0);
141    }
142
143    #[tokio::test]
144    #[ignore]
145    async fn fetch_inscription_details() {
146        let client = OrdClient::new();
147        let inscription_id = "0dc34a21a53600106e9c91d7c8d4b84a62a14dbd4b58cad66272dc3bbc8dbdd7i0";
148        let inscription_details = client.get_inscription(inscription_id).await;
149        let details = inscription_details;
150        assert_eq!(details.id, inscription_id);
151    }
152}