1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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)
    }
}