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) } }