feat: use features to split up api into its respective parts
Edge Storage now has its own client EdgeStorageClient Bunny.net has its own client BunnyClient
This commit is contained in:
parent
53e5238485
commit
914db27a98
12 changed files with 304 additions and 324 deletions
13
src/bunny/api_key.rs
Normal file
13
src/bunny/api_key.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
/// API Key struct returned by list_api_keys()
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ApiKey {
|
||||
/// API Key ID
|
||||
pub id: i32,
|
||||
/// API Key
|
||||
pub key: String,
|
||||
/// ??
|
||||
pub roles: Vec<String>,
|
||||
}
|
23
src/bunny/country.rs
Normal file
23
src/bunny/country.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use serde::Deserialize;
|
||||
use url::Url;
|
||||
|
||||
/// Country struct returned by get_countries() function
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Country {
|
||||
/// Country name
|
||||
pub name: String,
|
||||
/// Country ISO code
|
||||
pub iso_code: String,
|
||||
/// Country is part of the EU
|
||||
#[serde(rename = "IsEU")]
|
||||
pub is_eu: bool,
|
||||
/// Tax rate in percentage
|
||||
pub tax_rate: f32,
|
||||
/// Tax prefix
|
||||
pub tax_prefix: String,
|
||||
/// URL to country flag
|
||||
pub flag_url: Url,
|
||||
/// ??
|
||||
pub pop_list: Vec<String>,
|
||||
}
|
110
src/bunny/mod.rs
110
src/bunny/mod.rs
|
@ -1,82 +1,54 @@
|
|||
//! Contains structs, enums and implementations for the main bunny.net API
|
||||
|
||||
use serde::Deserialize;
|
||||
use url::Url;
|
||||
|
||||
use crate::{Client, error::Error};
|
||||
use crate::error::Error;
|
||||
use reqwest::{
|
||||
Client as RClient,
|
||||
header::{HeaderMap, HeaderValue},
|
||||
};
|
||||
|
||||
/// Country struct returned by get_countries() function
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Country {
|
||||
/// Country name
|
||||
pub name: String,
|
||||
/// Country ISO code
|
||||
pub iso_code: String,
|
||||
/// Country is part of the EU
|
||||
#[serde(rename = "IsEU")]
|
||||
pub is_eu: bool,
|
||||
/// Tax rate in percentage
|
||||
pub tax_rate: f32,
|
||||
/// Tax prefix
|
||||
pub tax_prefix: String,
|
||||
/// URL to country flag
|
||||
pub flag_url: Url,
|
||||
/// ??
|
||||
pub pop_list: Vec<String>,
|
||||
mod api_key;
|
||||
pub use api_key::ApiKey;
|
||||
mod country;
|
||||
pub use country::Country;
|
||||
mod pagination;
|
||||
pub use pagination::Pagination;
|
||||
mod region;
|
||||
pub use region::Region;
|
||||
|
||||
/// API Client for bunny.net
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BunnyClient {
|
||||
reqwest: RClient,
|
||||
}
|
||||
|
||||
/// API Key struct returned by list_api_keys()
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ApiKey {
|
||||
/// API Key ID
|
||||
pub id: i32,
|
||||
/// API Key
|
||||
pub key: String,
|
||||
/// ??
|
||||
pub roles: Vec<String>,
|
||||
}
|
||||
impl BunnyClient {
|
||||
/// Creates a new BunnyClient using the supplied `api_key`
|
||||
///
|
||||
/// ```
|
||||
/// use bunny_api_tokio::{BunnyClient, error::Error};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> Result<(), Error> {
|
||||
/// // Bunny.net api key
|
||||
/// let mut client = BunnyClient::new("api_key").await?;
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub async fn new<T: AsRef<str>>(api_key: T) -> Result<Self, Error> {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.append("AccessKey", HeaderValue::from_str(api_key.as_ref())?);
|
||||
headers.append("accept", HeaderValue::from_str("application/json")?);
|
||||
|
||||
/// Pagination struct used by Bunny.net API
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Pagination<T> {
|
||||
/// Vector of type T
|
||||
pub items: Vec<T>,
|
||||
/// Current page number
|
||||
pub current_page: i32,
|
||||
/// Total amount of type T
|
||||
pub total_items: i32,
|
||||
/// Has more items
|
||||
pub has_more_items: bool,
|
||||
}
|
||||
let reqwest = RClient::builder().default_headers(headers).build()?;
|
||||
|
||||
/// Region struct returned by region_list()
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Region {
|
||||
/// Region ID
|
||||
pub id: i32,
|
||||
/// Name of the region
|
||||
pub name: String,
|
||||
/// Price per gigabyte in region
|
||||
pub price_per_gigabyte: f32,
|
||||
/// Region 2 letter code
|
||||
pub region_code: String,
|
||||
/// Continent 2 letter code
|
||||
pub continent_code: String,
|
||||
/// Country 2 letter code
|
||||
pub country_code: String,
|
||||
/// Region latitude
|
||||
pub latitude: f32,
|
||||
/// Region longitude
|
||||
pub longitude: f32,
|
||||
/// ??
|
||||
pub allow_latency_routing: bool,
|
||||
}
|
||||
Ok(Self {
|
||||
reqwest,
|
||||
})
|
||||
}
|
||||
|
||||
impl Client {
|
||||
// TODO: Following functions could probably use better naming, the names are currently derived from the titles on the API reference
|
||||
|
||||
/// Returns a list of countries and tax rates
|
||||
|
|
15
src/bunny/pagination.rs
Normal file
15
src/bunny/pagination.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
/// Pagination struct used by Bunny.net API
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Pagination<T> {
|
||||
/// Vector of type T
|
||||
pub items: Vec<T>,
|
||||
/// Current page number
|
||||
pub current_page: i32,
|
||||
/// Total amount of type T
|
||||
pub total_items: i32,
|
||||
/// Has more items
|
||||
pub has_more_items: bool,
|
||||
}
|
25
src/bunny/region.rs
Normal file
25
src/bunny/region.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
/// Region struct returned by region_list()
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Region {
|
||||
/// Region ID
|
||||
pub id: i32,
|
||||
/// Name of the region
|
||||
pub name: String,
|
||||
/// Price per gigabyte in region
|
||||
pub price_per_gigabyte: f32,
|
||||
/// Region 2 letter code
|
||||
pub region_code: String,
|
||||
/// Continent 2 letter code
|
||||
pub continent_code: String,
|
||||
/// Country 2 letter code
|
||||
pub country_code: String,
|
||||
/// Region latitude
|
||||
pub latitude: f32,
|
||||
/// Region longitude
|
||||
pub longitude: f32,
|
||||
/// ??
|
||||
pub allow_latency_routing: bool,
|
||||
}
|
46
src/edge_storage/endpoint.rs
Normal file
46
src/edge_storage/endpoint.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
use url::Url;
|
||||
use crate::error::Error;
|
||||
|
||||
/// Endpoints for Edge Storage API
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Endpoint {
|
||||
/// Uses https://storage.bunnycdn.com as endpoint
|
||||
Frankfurt,
|
||||
/// Uses https://uk.storage.bunnycdn.com as endpoint
|
||||
London,
|
||||
/// Uses https://ny.storage.bunnycdn.com as endpoint
|
||||
NewYork,
|
||||
/// Uses https://la.storage.bunnycdn.com as endpoint
|
||||
LosAngeles,
|
||||
/// Uses https://sg.storage.bunnycdn.com as endpoint
|
||||
Singapore,
|
||||
/// Uses https://se.storage.bunnycdn.com as endpoint
|
||||
Stockholm,
|
||||
/// Uses https://br.storage.bunnycdn.com as endpoint
|
||||
SaoPaulo,
|
||||
/// Uses https://jh.storage.bunnycdn.com as endpoint
|
||||
Johannesburg,
|
||||
/// Uses https://syd.storage.bunnycdn.com as endpoint
|
||||
Sydney,
|
||||
/// Lets you input a custom endpoint, in case bunny adds a new one and this crate isnt up-to-date, has to be a valid URL with http(s) in front
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl TryInto<Url> for Endpoint {
|
||||
type Error = Error;
|
||||
|
||||
fn try_into(self) -> Result<Url, Error> {
|
||||
match self {
|
||||
Endpoint::Frankfurt => Ok(Url::parse("https://storage.bunnycdn.com")?),
|
||||
Endpoint::London => Ok(Url::parse("https://uk.storage.bunnycdn.com")?),
|
||||
Endpoint::NewYork => Ok(Url::parse("https://ny.storage.bunnycdn.com")?),
|
||||
Endpoint::LosAngeles => Ok(Url::parse("https://la.storage.bunnycdn.com")?),
|
||||
Endpoint::Singapore => Ok(Url::parse("https://sg.storage.bunnycdn.com")?),
|
||||
Endpoint::Stockholm => Ok(Url::parse("https://se.storage.bunnycdn.com")?),
|
||||
Endpoint::SaoPaulo => Ok(Url::parse("https://br.storage.bunnycdn.com")?),
|
||||
Endpoint::Johannesburg => Ok(Url::parse("https://jh.storage.bunnycdn.com")?),
|
||||
Endpoint::Sydney => Ok(Url::parse("https://syd.storage.bunnycdn.com")?),
|
||||
Endpoint::Custom(url) => Ok(Url::parse(&url)?),
|
||||
}
|
||||
}
|
||||
}
|
37
src/edge_storage/list_file.rs
Normal file
37
src/edge_storage/list_file.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
/// File information returned by list
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ListFile {
|
||||
/// ??
|
||||
pub guid: String,
|
||||
/// Name of the storage zone the object is in
|
||||
pub storage_zone_name: String,
|
||||
/// Path to object
|
||||
pub path: String,
|
||||
/// Object name
|
||||
pub object_name: String,
|
||||
/// Length of the object in bytes
|
||||
pub length: u32,
|
||||
/// When the object was last modified
|
||||
pub last_changed: String,
|
||||
/// ??
|
||||
pub server_id: u32,
|
||||
/// ??
|
||||
pub array_number: u32,
|
||||
/// If the object is a directory
|
||||
pub is_directory: bool,
|
||||
/// ??
|
||||
pub user_id: String,
|
||||
/// Object content type
|
||||
pub content_type: String,
|
||||
/// When the object was created
|
||||
pub date_created: String,
|
||||
/// ID of the storage zone the object is in
|
||||
pub storage_zone_id: u32,
|
||||
/// File checksum on server
|
||||
pub checksum: String,
|
||||
/// Zones the object is replicated to
|
||||
pub replicated_zones: String,
|
||||
}
|
|
@ -2,131 +2,52 @@
|
|||
//!
|
||||
//! Contains enums, structs and functions for the Bunny Edge Storage API
|
||||
|
||||
use crate::Error;
|
||||
use crate::error::Error;
|
||||
use bytes::Bytes;
|
||||
use reqwest::{header::{HeaderMap, HeaderValue}, Client};
|
||||
use serde::Deserialize;
|
||||
use url::Url;
|
||||
|
||||
/// Endpoints for Edge Storage API
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum Endpoint {
|
||||
/// Uses https://storage.bunnycdn.com as endpoint
|
||||
Frankfurt,
|
||||
/// Uses https://uk.storage.bunnycdn.com as endpoint
|
||||
London,
|
||||
/// Uses https://ny.storage.bunnycdn.com as endpoint
|
||||
NewYork,
|
||||
/// Uses https://la.storage.bunnycdn.com as endpoint
|
||||
LosAngeles,
|
||||
/// Uses https://sg.storage.bunnycdn.com as endpoint
|
||||
Singapore,
|
||||
/// Uses https://se.storage.bunnycdn.com as endpoint
|
||||
Stockholm,
|
||||
/// Uses https://br.storage.bunnycdn.com as endpoint
|
||||
SaoPaulo,
|
||||
/// Uses https://jh.storage.bunnycdn.com as endpoint
|
||||
Johannesburg,
|
||||
/// Uses https://syd.storage.bunnycdn.com as endpoint
|
||||
Sydney,
|
||||
/// Lets you input a custom endpoint, in case bunny adds a new one and this crate isnt up-to-date, has to be a valid URL with http(s) in front
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl TryInto<Url> for Endpoint {
|
||||
type Error = Error;
|
||||
|
||||
fn try_into(self) -> Result<Url, Error> {
|
||||
match self {
|
||||
Endpoint::Frankfurt => Ok(Url::parse("https://storage.bunnycdn.com")?),
|
||||
Endpoint::London => Ok(Url::parse("https://uk.storage.bunnycdn.com")?),
|
||||
Endpoint::NewYork => Ok(Url::parse("https://ny.storage.bunnycdn.com")?),
|
||||
Endpoint::LosAngeles => Ok(Url::parse("https://la.storage.bunnycdn.com")?),
|
||||
Endpoint::Singapore => Ok(Url::parse("https://sg.storage.bunnycdn.com")?),
|
||||
Endpoint::Stockholm => Ok(Url::parse("https://se.storage.bunnycdn.com")?),
|
||||
Endpoint::SaoPaulo => Ok(Url::parse("https://br.storage.bunnycdn.com")?),
|
||||
Endpoint::Johannesburg => Ok(Url::parse("https://jh.storage.bunnycdn.com")?),
|
||||
Endpoint::Sydney => Ok(Url::parse("https://syd.storage.bunnycdn.com")?),
|
||||
Endpoint::Custom(url) => Ok(Url::parse(&url)?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// File information returned by list
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ListFile {
|
||||
/// ??
|
||||
pub guid: String,
|
||||
/// Name of the storage zone the object is in
|
||||
pub storage_zone_name: String,
|
||||
/// Path to object
|
||||
pub path: String,
|
||||
/// Object name
|
||||
pub object_name: String,
|
||||
/// Length of the object in bytes
|
||||
pub length: u32,
|
||||
/// When the object was last modified
|
||||
pub last_changed: String,
|
||||
/// ??
|
||||
pub server_id: u32,
|
||||
/// ??
|
||||
pub array_number: u32,
|
||||
/// If the object is a directory
|
||||
pub is_directory: bool,
|
||||
/// ??
|
||||
pub user_id: String,
|
||||
/// Object content type
|
||||
pub content_type: String,
|
||||
/// When the object was created
|
||||
pub date_created: String,
|
||||
/// ID of the storage zone the object is in
|
||||
pub storage_zone_id: u32,
|
||||
/// File checksum on server
|
||||
pub checksum: String,
|
||||
/// Zones the object is replicated to
|
||||
pub replicated_zones: String,
|
||||
}
|
||||
mod endpoint;
|
||||
pub use endpoint::Endpoint;
|
||||
mod list_file;
|
||||
pub use list_file::ListFile;
|
||||
|
||||
/// Edge Storage API for bunny
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Storage {
|
||||
pub struct EdgeStorageClient {
|
||||
pub(crate) url: Url,
|
||||
pub(crate) reqwest: Client,
|
||||
}
|
||||
|
||||
impl<'a> Storage {
|
||||
/// Sets endpoint and storage zone used by Edge Storage API
|
||||
impl<'a> EdgeStorageClient {
|
||||
/// Creates a new EdgeStorageClient using the supplied `api_key`
|
||||
///
|
||||
/// ```
|
||||
/// use bunny_api_tokio::{Client, error::Error, edge_storage::Endpoint};
|
||||
/// use bunny_api_tokio::{EdgeStorageClient, error::Error, edge_storage::Endpoint};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> Result<(), Error> {
|
||||
/// // API key here can be left as "" if you never plan on using anything from the bunny.net api
|
||||
/// let mut client = Client::new("api_key").await?;
|
||||
///
|
||||
/// // Requires own API key to use
|
||||
/// client.storage.init("storage_zone_api_key", Endpoint::Frankfurt, "MyStorageZone").await?;
|
||||
/// let mut client = EdgeStorageClient::new("storage_zone_api_key", Endpoint::Frankfurt, "MyStorageZone").await?;
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub async fn init<T: AsRef<str>, T1: AsRef<str>>(
|
||||
&mut self,
|
||||
api_key: T,
|
||||
endpoint: Endpoint,
|
||||
storage_zone: T1,
|
||||
) -> Result<(), Error> {
|
||||
pub async fn new<T: AsRef<str>, T1: AsRef<str>>(api_key: T, endpoint: Endpoint, storage_zone: T1) -> Result<Self, Error> {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.append("AccessKey", HeaderValue::from_str(api_key.as_ref())?);
|
||||
headers.append("accept", HeaderValue::from_str("application/json")?);
|
||||
|
||||
let reqwest = Client::builder().default_headers(headers).build()?;
|
||||
|
||||
self.reqwest = Client::builder().default_headers(headers).build()?;
|
||||
let endpoint: Url = endpoint.try_into()?;
|
||||
let storage_zone = String::from("/") + storage_zone.as_ref() + "/";
|
||||
|
||||
self.url = endpoint.join(&storage_zone)?;
|
||||
Ok(())
|
||||
let url = endpoint.join(&storage_zone)?;
|
||||
|
||||
Ok(Self {
|
||||
url,
|
||||
reqwest,
|
||||
})
|
||||
}
|
||||
|
||||
/// Uploads a file to the Storage Zone
|
55
src/lib.rs
55
src/lib.rs
|
@ -19,53 +19,12 @@
|
|||
//! ```
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use error::Error;
|
||||
use reqwest::{
|
||||
Client as RClient,
|
||||
header::{HeaderMap, HeaderValue},
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
pub mod bunny;
|
||||
#[cfg(feature = "bunnynet")]
|
||||
mod bunny;
|
||||
#[cfg(feature = "bunnynet")]
|
||||
pub use bunny::BunnyClient;
|
||||
#[cfg(feature = "edge_storage")]
|
||||
pub mod edge_storage;
|
||||
#[cfg(feature = "edge_storage")]
|
||||
pub use edge_storage::EdgeStorageClient;
|
||||
pub mod error;
|
||||
|
||||
/// API Client for bunny
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Client {
|
||||
reqwest: RClient,
|
||||
/// Used to interact with the Edge Storage API
|
||||
pub storage: edge_storage::Storage,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
/// Creates a new Client using the supplied `api_key`
|
||||
///
|
||||
/// ```
|
||||
/// use bunny_api_tokio::{Client, error::Error};
|
||||
///
|
||||
/// #[tokio::main]
|
||||
/// async fn main() -> Result<(), Error> {
|
||||
/// // Bunny.net api key
|
||||
/// let mut client = Client::new("api_key").await?;
|
||||
///
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub async fn new<T: AsRef<str>>(api_key: T) -> Result<Self, Error> {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.append("AccessKey", HeaderValue::from_str(api_key.as_ref())?);
|
||||
headers.append("accept", HeaderValue::from_str("application/json")?);
|
||||
|
||||
let reqwest = RClient::builder().default_headers(headers).build()?;
|
||||
let storage_reqwest = RClient::new();
|
||||
|
||||
Ok(Self {
|
||||
reqwest,
|
||||
storage: edge_storage::Storage {
|
||||
url: Url::parse("https://storage.bunnycdn.com").unwrap(),
|
||||
reqwest: storage_reqwest,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue