cloudflare_kv_proxy/
lib.rs1mod types;
2use reqwest::{header, Response};
3use serde::Serialize;
4use std::time::Duration;
5use types::ApiResult;
6pub use types::{Error, NotFoundMapping, Result};
7
8macro_rules! execute {
9 ($send: expr) => {
10 $send
11 .send()
12 .await
13 .and_then(crate::Response::error_for_status)?
14 .json::<crate::ApiResult<_>>()
15 .await?
16 .into()
17 };
18}
19
20#[cfg(feature = "cache")]
21mod cache;
22
23#[derive(Debug)]
25pub struct Client {
26 endpoint: String,
27 client: reqwest::Client,
28
29 #[cfg(feature = "cache")]
30 cache: cache::Cache,
31}
32
33#[derive(thiserror::Error, Debug)]
35pub enum ClientError {
36 #[error("token format error {0}")]
37 Token(#[from] reqwest::header::InvalidHeaderValue),
38 #[error("client build error {0}")]
39 Client(#[from] reqwest::Error),
40}
41
42impl Client {
43 pub fn new<T: Into<String>, E: Into<String>>(
46 endpoint: E,
47 token: T,
48 timeout: Duration,
49 #[cfg(feature = "cache")] cache_size: usize,
50 #[cfg(feature = "cache")] expire_ttl: std::time::Duration,
51 ) -> std::result::Result<Self, ClientError> {
52 let mut endpoint: String = endpoint.into();
54 if !endpoint.ends_with('/') {
55 endpoint.push('/');
56 }
57 let token = token.into();
58 let mut headers = header::HeaderMap::new();
59 headers.insert("Authorization", header::HeaderValue::from_str(&token)?);
60 Ok(Self {
61 endpoint,
62 client: reqwest::Client::builder()
63 .default_headers(headers)
64 .timeout(timeout)
65 .tcp_nodelay(true)
66 .build()?,
67 #[cfg(feature = "cache")]
68 cache: cache::new_cache(cache_size, expire_ttl.into()),
69 })
70 }
71
72 #[cfg(not(feature = "cache"))]
74 pub async fn get<T: serde::de::DeserializeOwned>(&self, key: &str) -> Result<T> {
75 execute!(self.client.get(format!("{}{}", self.endpoint, key)))
76 }
77
78 pub async fn put<T: Serialize + ?Sized>(&self, key: &str, value: &T) -> Result<()> {
80 let r: Result<()> = execute!(self
81 .client
82 .put(format!("{}{}", self.endpoint, key))
83 .json(value));
84 #[cfg(feature = "cache")]
85 if r.is_ok() {
86 self.set_cache(key, value);
87 }
88 r
89 }
90
91 pub async fn put_with_ttl<T: Serialize + ?Sized>(
93 &self,
94 key: &str,
95 value: &T,
96 ttl: Duration,
97 ) -> Result<()> {
98 let r: Result<()> = execute!(self
99 .client
100 .put(format!("{}{}", self.endpoint, key))
101 .header("ttl", ttl.as_secs())
102 .json(value));
103 #[cfg(feature = "cache")]
104 if r.is_ok() {
105 self.set_cache(key, value);
106 }
107 r
108 }
109
110 pub async fn delete(&self, key: &str) -> Result<()> {
112 let r: Result<()> = execute!(self.client.delete(format!("{}{}", self.endpoint, key)));
113 #[cfg(feature = "cache")]
114 if r.is_ok() {
115 self.prune_cached(key);
116 }
117 r
118 }
119}