1use std::io::{self, Write};
8
9use reqwest::{Body, Response};
10use rkyv::Archive;
11
12use crate::Error;
13
14const REQUIRED_RUSK_VERSION: &str = "0.7.0";
16
17#[derive(Debug)]
18pub struct RuskRequest {
20 topic: String,
21 data: Vec<u8>,
22}
23
24impl RuskRequest {
25 pub fn new(topic: &str, data: Vec<u8>) -> Self {
27 let topic = topic.to_string();
28 Self { data, topic }
29 }
30
31 pub fn to_bytes(&self) -> io::Result<Vec<u8>> {
33 let mut buffer = vec![];
34 buffer.write_all(&(self.topic.len() as u32).to_le_bytes())?;
35 buffer.write_all(self.topic.as_bytes())?;
36 buffer.write_all(&self.data)?;
37
38 Ok(buffer)
39 }
40}
41#[derive(Clone)]
42pub struct RuskHttpClient {
44 uri: String,
45}
46
47impl RuskHttpClient {
48 pub fn new(uri: String) -> Self {
50 Self { uri }
51 }
52
53 pub async fn contract_query<I, const N: usize>(
55 &self,
56 contract: &str,
57 method: &str,
58 value: &I,
59 ) -> Result<Vec<u8>, Error>
60 where
61 I: Archive,
62 I: rkyv::Serialize<rkyv::ser::serializers::AllocSerializer<N>>,
63 {
64 let data = rkyv::to_bytes(value).map_err(|_| Error::Rkyv)?.to_vec();
65 let request = RuskRequest::new(method, data);
66
67 let response = self.call_raw(1, contract, &request, false).await?;
68
69 Ok(response.bytes().await?.to_vec())
70 }
71
72 pub async fn check_connection(&self) -> Result<(), reqwest::Error> {
74 reqwest::Client::new().post(&self.uri).send().await?;
75 Ok(())
76 }
77
78 pub async fn call(
82 &self,
83 target_type: u8,
84 target: &str,
85 request: &RuskRequest,
86 ) -> Result<Vec<u8>, Error> {
87 let response =
88 self.call_raw(target_type, target, request, false).await?;
89 let data = response.bytes().await?;
90 Ok(data.to_vec())
91 }
92 pub async fn call_raw(
94 &self,
95 target_type: u8,
96 target: &str,
97 request: &RuskRequest,
98 feed: bool,
99 ) -> Result<Response, Error> {
100 let uri = &self.uri;
101 let client = reqwest::Client::new();
102 let mut request = client
103 .post(format!("{uri}/{target_type}/{target}"))
104 .body(Body::from(request.to_bytes()?))
105 .header("Content-Type", "application/octet-stream")
106 .header("rusk-version", REQUIRED_RUSK_VERSION);
107
108 if feed {
109 request = request.header("Rusk-Feeder", "1");
110 }
111 let response = request.send().await?;
112
113 let status = response.status();
114 if status.is_client_error() || status.is_server_error() {
115 let error = &response.bytes().await?;
116
117 let error = String::from_utf8(error.to_vec())
118 .unwrap_or("unparsable error".into());
119
120 let msg = format!("{status}: {error}");
121
122 Err(Error::Rusk(msg))
123 } else {
124 Ok(response)
125 }
126 }
127}