diff --git a/Cargo.lock b/Cargo.lock index 2d7f344..c23c2ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -861,7 +861,7 @@ dependencies = [ [[package]] name = "supabase-storage" -version = "0.1.0" +version = "0.2.0" dependencies = [ "async-trait", "derive_more", diff --git a/Cargo.toml b/Cargo.toml index 62a72b1..f133634 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "supabase-storage" authors = ["tthefux@gmail.com"] -version = "0.1.1" +version = "0.2.0" edition = "2021" license = "MIT" readme = "README.md" diff --git a/examples/get_object.rs b/examples/get_object.rs index 64a000b..2c203df 100644 --- a/examples/get_object.rs +++ b/examples/get_object.rs @@ -1,4 +1,5 @@ use dotenv::dotenv; +use reqwest::header::{HeaderMap, HeaderValue}; use supabase_storage::config::SupabaseConfig; use supabase_storage::Storage; @@ -7,12 +8,32 @@ async fn main() { dotenv().ok(); let config = SupabaseConfig::default(); - let storage = Storage::new_with_config(config); + let storage = Storage::new_with_config(config.clone()); + + let mut headers = HeaderMap::new(); + if let Some(api_key) = config.clone().supabase_api_key { + headers.insert( + "Authorization", + HeaderValue::from_str(&format!("Bearer {}", api_key)).expect("header value is invalid"), + ); + headers.insert( + "apiKey", + HeaderValue::from_str(&format!("{}", api_key)).expect("header value is invalid"), + ); + } let bucket_name = "thefux"; let object = "btc.pdf"; - let response = storage + let mut response = storage + .from() + .get_object(bucket_name, object) + .execute() + .await + .unwrap(); + + println!("{:?}", response); + response = storage .from() .get_object(bucket_name, object) .execute() diff --git a/src/build/bucket.rs b/src/build/bucket.rs index 4e7b2f5..64ced97 100644 --- a/src/build/bucket.rs +++ b/src/build/bucket.rs @@ -199,6 +199,8 @@ impl Builder { /// ``` pub fn update_bucket(mut self, bucket_id: &str, body: &str) -> Executor { self.headers + .lock() + .unwrap() .insert("Content-Type", HeaderValue::from_static("application/json")); self.method = Method::PUT; self.url diff --git a/src/build/builder.rs b/src/build/builder.rs index f49922f..84391d3 100644 --- a/src/build/builder.rs +++ b/src/build/builder.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use super::executor::Executor; use reqwest::{ header::{HeaderMap, HeaderValue, IntoHeaderName}, @@ -14,8 +16,8 @@ pub enum BodyType { pub struct Builder { pub url: Url, - pub headers: HeaderMap, - pub client: Client, + pub headers: Arc>, + pub client: Arc>, pub method: Method, pub body: Option, } @@ -35,11 +37,12 @@ impl Builder { /// use reqwest::header::{HeaderMap, HeaderValue}; /// use reqwest::Client; /// use url::Url; + /// use std::sync::{Arc, Mutex}; /// /// let url = Url::parse("http://localhost").unwrap(); - /// let builder = Builder::new(url, HeaderMap::new(), Client::new()); + /// let builder = Builder::new(url, Arc::new(Mutex::new(HeaderMap::new())), Arc::new(Mutex::new(Client::new()))); /// ``` - pub fn new(url: Url, headers: HeaderMap, client: Client) -> Self { + pub fn new(url: Url, headers: Arc>, client: Arc>) -> Self { Self { url, headers, @@ -61,10 +64,14 @@ impl Builder { // .body(self.body.unwrap_or_default()) // } pub fn build(self) -> RequestBuilder { + // let headers = self.headers.lock().unwrap(); + let headers = Arc::try_unwrap(self.headers).unwrap(); let mut request = self .client + .lock() + .unwrap() .request(self.method, self.url.to_string()) - .headers(self.headers); + .headers(headers.into_inner().unwrap()); if let Some(body) = self.body { match body { @@ -94,14 +101,15 @@ impl Builder { /// use reqwest::header::{HeaderMap, HeaderValue}; /// use reqwest::Client; /// use url::Url; + /// use std::sync::{Arc, Mutex}; /// /// let url = Url::parse("http://localhost").unwrap(); /// - /// let _ = Builder::new(url, HeaderMap::new(), Client::new()) + /// let _ = Builder::new(url, Arc::new(Mutex::new(HeaderMap::new())), Arc::new(Mutex::new(Client::new()))) /// .header("Authorization", HeaderValue::from_static("Bearer ")); /// ``` - pub fn header(mut self, key: impl IntoHeaderName, value: HeaderValue) -> Self { - self.headers.insert(key, value); + pub fn header(self, key: impl IntoHeaderName, value: HeaderValue) -> Self { + self.headers.lock().unwrap().insert(key, value); self } @@ -118,6 +126,7 @@ impl Builder { /// use reqwest::header::{HeaderMap, HeaderValue}; /// use reqwest::Client; /// use url::Url; + /// use std::sync::{Arc, Mutex}; /// /// #[tokio::main] /// async fn main() { @@ -125,7 +134,7 @@ impl Builder { /// let mut headers = HeaderMap::new(); /// headers.insert("Authorization", HeaderValue::from_static("Bearer YOUR_ACCESS_TOKEN")); /// - /// let builder = Builder::new(url, headers, Client::new()) + /// let builder = Builder::new(url, Arc::new(Mutex::new(headers)), Arc::new(Mutex::new(Client::new()))) /// .header("Authorization", HeaderValue::from_static("Bearer ")); /// /// // Execute the request and handle the response @@ -161,6 +170,7 @@ mod test { header::{HeaderMap, HeaderValue}, Client, }; + use std::sync::{Arc, Mutex}; use url::Url; use super::Builder; @@ -170,16 +180,24 @@ mod test { let mut headers = HeaderMap::new(); headers.insert("Authorization", HeaderValue::from_static("Bearer test")); let url = Url::parse("http://localhost").unwrap(); - let builder = Builder::new(url, headers, Client::new()); + let builder = Builder::new( + url, + Arc::new(Mutex::new(headers)), + Arc::new(Mutex::new(Client::new())), + ); assert_eq!(builder.url.scheme(), "http"); - assert_eq!(builder.headers.len(), 1); + assert_eq!(builder.headers.lock().unwrap().len(), 1); } #[test] fn test_add_header() { let url = Url::parse("http://localhost").unwrap(); - let builder = Builder::new(url, HeaderMap::new(), Client::new()) - .header("Authorization", HeaderValue::from_static("Bearer test")); - assert_eq!(builder.headers.len(), 1); + let builder = Builder::new( + url, + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), + ) + .header("Authorization", HeaderValue::from_static("Bearer test")); + assert_eq!(builder.headers.lock().unwrap().len(), 1); } } diff --git a/src/build/object.rs b/src/build/object.rs index ab7ae89..c68b9c9 100644 --- a/src/build/object.rs +++ b/src/build/object.rs @@ -102,6 +102,8 @@ impl Builder { /// ``` pub fn delete_objects(mut self, bucket_id: &str, body: &str) -> Executor { self.headers + .lock() + .unwrap() .insert("Content-Type", HeaderValue::from_static("application/json")); self.url .path_segments_mut() @@ -159,6 +161,8 @@ impl Builder { .first_or_octet_stream() .to_string(); self.headers + .lock() + .unwrap() .insert("Content-Type", HeaderValue::from_str(&mime).unwrap()); self.url @@ -295,6 +299,8 @@ impl Builder { /// ``` pub fn download_object(mut self, bucket_id: &str) -> Executor { self.headers + .lock() + .unwrap() .insert("Content-Type", HeaderValue::from_static("application/json")); self.method = Method::POST; self.url @@ -309,6 +315,7 @@ impl Builder { #[cfg(test)] mod test { use reqwest::{header::HeaderMap, Client}; + use std::sync::{Arc, Mutex}; use url::{Host, Origin}; use crate::build::builder::Builder; @@ -317,13 +324,19 @@ mod test { fn test_download_object() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .download_object("test_bucket"); assert_eq!( - executor.builder.headers.get("Content-Type").unwrap(), + executor + .builder + .headers + .lock() + .unwrap() + .get("Content-Type") + .unwrap(), "application/json" ); assert_eq!(executor.builder.url.path(), "/object/test_bucket"); diff --git a/src/build/object/list.rs b/src/build/object/list.rs index 0e6084f..725ac56 100644 --- a/src/build/object/list.rs +++ b/src/build/object/list.rs @@ -49,6 +49,8 @@ impl Builder { /// ``` pub fn list_objects(mut self, bucket_id: &str, body: &str) -> Executor { self.headers + .lock() + .unwrap() .insert("Content-Type", HeaderValue::from_static("application/json")); self.method = Method::POST; self.url @@ -66,6 +68,7 @@ impl Builder { #[cfg(test)] mod test { use reqwest::{header::HeaderMap, Client}; + use std::sync::{Arc, Mutex}; use url::{Host, Origin}; use crate::build::builder::{BodyType, Builder}; @@ -74,13 +77,19 @@ mod test { fn test_list_objects() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .list_objects("test_bucket", r#"{"test": "body"}"#); assert_eq!( - executor.builder.headers.get("Content-Type").unwrap(), + executor + .builder + .headers + .lock() + .unwrap() + .get("Content-Type") + .unwrap(), "application/json" ); assert_eq!(executor.builder.url.path(), "/object/list/test_bucket"); diff --git a/src/build/object/move_copy.rs b/src/build/object/move_copy.rs index 38dbed9..21fc396 100644 --- a/src/build/object/move_copy.rs +++ b/src/build/object/move_copy.rs @@ -23,6 +23,8 @@ impl From for &str { impl Builder { pub(crate) fn action_intern(mut self, move_obj: MoveCopyObject, action: &str) -> Executor { self.headers + .lock() + .unwrap() .insert("Content-Type", HeaderValue::from_static("application/json")); self.method = Method::POST; self.url @@ -221,6 +223,8 @@ impl Builder { #[cfg(test)] mod test { + use std::sync::{Arc, Mutex}; + use reqwest::{header::HeaderMap, Client, Method}; use url::{Host, Origin}; @@ -233,13 +237,19 @@ mod test { fn test_copy_object() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .copy_object("thefux", "from", "to"); assert_eq!( - executor.builder.headers.get("Content-Type").unwrap(), + executor + .builder + .headers + .lock() + .unwrap() + .get("Content-Type") + .unwrap(), "application/json" ); @@ -265,8 +275,8 @@ mod test { fn test_move_object() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .move_object("thefux", "from", "to"); @@ -277,8 +287,8 @@ mod test { fn test_move_object_from() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .move_object_from(MoveCopyObject { bucket_id: "thefux".to_string(), @@ -302,8 +312,8 @@ mod test { fn test_copy_object_from() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .copy_object_from(MoveCopyObject { bucket_id: "thefux".to_string(), diff --git a/src/build/object/public.rs b/src/build/object/public.rs index c56d95a..e439c44 100644 --- a/src/build/object/public.rs +++ b/src/build/object/public.rs @@ -91,6 +91,8 @@ impl Builder { #[cfg(test)] mod test { + use std::sync::{Arc, Mutex}; + use reqwest::{header::HeaderMap, Client, Method}; use url::{Host, Origin}; @@ -100,8 +102,8 @@ mod test { fn test_get_public_object() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .get_public_object("thefux", "test.pdf"); @@ -120,8 +122,8 @@ mod test { fn test_get_public_object_info() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .get_public_object_info("thefux", "test.pdf"); diff --git a/src/build/object/render.rs b/src/build/object/render.rs index 00c5631..a9d45b0 100644 --- a/src/build/object/render.rs +++ b/src/build/object/render.rs @@ -69,6 +69,7 @@ impl Builder { #[cfg(test)] mod test { use reqwest::{header::HeaderMap, Client, Method}; + use std::sync::{Arc, Mutex}; use url::{Host, Origin}; use crate::{ @@ -82,8 +83,8 @@ mod test { fn test_get_object_with_transform() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .get_object_with_transform( "thefux", diff --git a/src/build/object/sign.rs b/src/build/object/sign.rs index 28733fd..e8aacd4 100644 --- a/src/build/object/sign.rs +++ b/src/build/object/sign.rs @@ -50,6 +50,8 @@ impl Builder { /// ``` pub fn create_signed_url(mut self, bucket_name: &str, object: &str, body: &str) -> Executor { self.headers + .lock() + .unwrap() .insert("Content-Type", HeaderValue::from_static("application/json")); self.method = Method::POST; self.url @@ -98,6 +100,8 @@ impl Builder { /// ``` pub fn create_signed_urls(mut self, bucket_name: &str, body: &str) -> Executor { self.headers + .lock() + .unwrap() .insert("Content-Type", HeaderValue::from_static("application/json")); self.method = Method::POST; self.url @@ -169,6 +173,7 @@ impl Builder { #[cfg(test)] mod test { use reqwest::{header::HeaderMap, Client, Method}; + use std::sync::{Arc, Mutex}; use url::{Host, Origin}; use crate::build::builder::{BodyType, Builder}; @@ -177,8 +182,8 @@ mod test { fn test_get_object_with_signed_url() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .get_object_with_pre_assigned_url("thefux", "btc.pdf", "token"); @@ -195,8 +200,8 @@ mod test { fn test_create_signed_url() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .create_signed_url( "thefux", @@ -245,8 +250,8 @@ mod test { fn test_create_signed_urls() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .create_signed_urls("thefux", r#"{"paths":["btc.pdf","test.pdf"]}"#); diff --git a/src/build/object/upload.rs b/src/build/object/upload.rs index dbfcd7b..63f2803 100644 --- a/src/build/object/upload.rs +++ b/src/build/object/upload.rs @@ -113,14 +113,14 @@ impl Builder { self.url(bucket_id, object); if let Some(cache_content) = file_options.cache_control { - self.headers.insert( + self.headers.lock().unwrap().insert( "cache-control", HeaderValue::from_str(&format!("max-age={}", cache_content)).unwrap(), ); } if let Some(content_type) = file_options.content_type { - self.headers.insert( + self.headers.lock().unwrap().insert( "content-type", HeaderValue::from_str(&content_type).unwrap(), ); @@ -181,6 +181,8 @@ impl Builder { .first_or_octet_stream() .to_string(); self.headers + .lock() + .unwrap() .insert("Content-Type", HeaderValue::from_str(&mime).unwrap()); self.method = Method::PUT; @@ -246,14 +248,14 @@ impl Builder { file_options: FileOptions, ) -> Executor { if let Some(cache_content) = file_options.cache_control { - self.headers.insert( + self.headers.lock().unwrap().insert( "cache-control", HeaderValue::from_str(&format!("max-age={}", cache_content)).unwrap(), ); } if let Some(content_type) = file_options.content_type { - self.headers.insert( + self.headers.lock().unwrap().insert( "content-type", HeaderValue::from_str(&content_type).unwrap(), ); @@ -262,11 +264,13 @@ impl Builder { .first_or_octet_stream() .to_string(); self.headers + .lock() + .unwrap() .insert("Content-Type", HeaderValue::from_str(&mime).unwrap()); } if let Some(upsert) = file_options.upsert { - self.headers.insert( + self.headers.lock().unwrap().insert( "x-upsert", HeaderValue::from_str(&upsert.to_string()).unwrap(), ); @@ -287,6 +291,7 @@ impl Builder { #[cfg(test)] mod test { use reqwest::{header::HeaderMap, Client, Method}; + use std::sync::{Arc, Mutex}; use url::{Host, Origin}; use super::*; @@ -295,8 +300,8 @@ mod test { fn test_create_signed_upload_url() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .create_signed_upload_url("thefux", "bitcoin.pdf"); @@ -315,8 +320,8 @@ mod test { async fn test_upload_to_signed_url_async() { let executor = Builder::new( url::Url::parse("http://localhost").unwrap(), - HeaderMap::new(), - Client::new(), + Arc::new(Mutex::new(HeaderMap::new())), + Arc::new(Mutex::new(Client::new())), ) .upload_to_signed_url_async( "thefux", diff --git a/src/lib.rs b/src/lib.rs index 05534f1..275cfe6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use reqwest::{ header::{HeaderMap, HeaderValue}, Client, @@ -68,7 +70,7 @@ impl Storage { ); headers.insert( "apiKey", - HeaderValue::from_str(&format!("{}", api_key)).expect("header value is invalid"), + HeaderValue::from_str(&api_key).expect("header value is invalid"), ); } @@ -89,6 +91,10 @@ impl Storage { /// let builder = storage.from(); /// ``` pub fn from(&self) -> Builder { - Builder::new(self.url.clone(), self.headers.clone(), self.client.clone()) + Builder::new( + self.url.clone(), + Arc::new(Mutex::new(self.headers.clone())), + Arc::new(Mutex::new(self.client.clone())), + ) } }