gcslib 0.2.1

A library for Google Cloud Storage
Documentation
use anyhow::Result;
use google_auth::TokenManager;
use serde::{Deserialize, Serialize};

#[derive(Clone)]
pub struct Client {
    token_manager: TokenManager,
}
pub struct Bucket {
    client: Client,
    name: String,
}

impl Client {
    pub async fn new() -> Result<Client> {
        let tm = TokenManager::new(&[]).await?;
        Ok(Client { token_manager: tm })
    }
    pub fn bucket(&self, name: &str) -> Bucket {
        Bucket {
            name: name.to_string(),
            client: self.clone(),
        }
    }
}

impl Bucket {
    pub async fn list(&mut self, prefix: &str) -> Result<Response> {
        let url = format!(
            "https://storage.googleapis.com/storage/v1/b/{}/o?prefix={}",
            self.name, prefix
        );
        let access_token = self.client.token_manager.token().await?;
        let client = reqwest::Client::new();
        let res = client
            .get(&url)
            .header(reqwest::header::AUTHORIZATION, access_token)
            .header(reqwest::header::ACCEPT, "application/json")
            .send()
            .await?;
        let res: Response = res.json().await?;
        Ok(res)
    }

    pub async fn insert(&mut self, data: Vec<u8>, file_name: &str) -> Result<Object> {
        let url = format!(
            "https://storage.googleapis.com/upload/storage/v1/b/{}/o?uploadType=media&name={}",
            self.name, file_name
        );
        let access_token = self.client.token_manager.token().await?;
        let client = reqwest::Client::new();
        let len = data.len();
        let res = client
            .post(&url)
            .body(data)
            .header(reqwest::header::AUTHORIZATION, access_token)
            .header(reqwest::header::CONTENT_LENGTH, len)
            .header(
                reqwest::header::CONTENT_TYPE,
                "application/json;charset=UTF-8",
            )
            .send()
            .await?;
        let object: Object = res.json().await?;
        Ok(object)
    }
}

#[derive(Deserialize, Serialize, Debug)]
pub struct Error {
    error: ErrorPayload,
}

#[derive(Deserialize, Serialize, Debug)]
pub struct ErrorPayload {
    code: u32,
    message: String,
}

#[derive(Deserialize, Serialize, Debug)]
#[serde(untagged)]
pub enum Response {
    Error(Error),
    Objects(Objects),
}

#[derive(Deserialize, Serialize, Debug)]
pub struct Objects {
    kind: String,
    pub items: Vec<Object>,
}

#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Object {
    kind: String,
    id: String,
    self_link: String,
    media_link: String,
    name: String,
    bucket: String,
    generation: String,
    metageneration: String,
    content_type: Option<String>,
    storage_class: String,
    size: String,
    md5_hash: String,
    crc32c: String,
    etag: String,
    time_created: String,
    updated: String,
    time_storage_class_updated: String,
}

impl Object {
    pub async fn download(&self, mut client: Client) -> Result<String> {
        let http_client = reqwest::Client::new();
        let resp = http_client
            .get(&self.media_link)
            .header(
                reqwest::header::AUTHORIZATION,
                client.token_manager.token().await?,
            )
            .header(
                reqwest::header::AUTHORIZATION,
                client.token_manager.token().await?,
            )
            .send()
            .await?;
        let body = resp.text().await?;
        Ok(body)
    }
}