1use anyhow::Result;
2use google_auth::TokenManager;
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone)]
6pub struct Client {
7 token_manager: TokenManager,
8}
9pub struct Bucket {
10 client: Client,
11 name: String,
12}
13
14impl Client {
15 pub async fn new() -> Result<Client> {
16 let tm = TokenManager::new(&[]).await?;
17 Ok(Client { token_manager: tm })
18 }
19 pub fn bucket(&self, name: &str) -> Bucket {
20 Bucket {
21 name: name.to_string(),
22 client: self.clone(),
23 }
24 }
25}
26
27impl Bucket {
28 pub async fn list(&mut self, prefix: &str) -> Result<Response> {
29 let url = format!(
30 "https://storage.googleapis.com/storage/v1/b/{}/o?prefix={}",
31 self.name, prefix
32 );
33 let access_token = self.client.token_manager.token().await?;
34 let client = reqwest::Client::new();
35 let res = client
36 .get(&url)
37 .header(reqwest::header::AUTHORIZATION, access_token)
38 .header(reqwest::header::ACCEPT, "application/json")
39 .send()
40 .await?;
41 let res: Response = res.json().await?;
42 Ok(res)
43 }
44
45 pub async fn insert(&mut self, data: Vec<u8>, file_name: &str) -> Result<Object> {
46 let url = format!(
47 "https://storage.googleapis.com/upload/storage/v1/b/{}/o?uploadType=media&name={}",
48 self.name, file_name
49 );
50 let access_token = self.client.token_manager.token().await?;
51 let client = reqwest::Client::new();
52 let len = data.len();
53 let res = client
54 .post(&url)
55 .body(data)
56 .header(reqwest::header::AUTHORIZATION, access_token)
57 .header(reqwest::header::CONTENT_LENGTH, len)
58 .header(
59 reqwest::header::CONTENT_TYPE,
60 "application/json;charset=UTF-8",
61 )
62 .send()
63 .await?;
64 let object: Object = res.json().await?;
65 Ok(object)
66 }
67}
68
69#[derive(Deserialize, Serialize, Debug)]
70pub struct Error {
71 error: ErrorPayload,
72}
73
74#[derive(Deserialize, Serialize, Debug)]
75pub struct ErrorPayload {
76 code: u32,
77 message: String,
78}
79
80#[derive(Deserialize, Serialize, Debug)]
81#[serde(untagged)]
82pub enum Response {
83 Error(Error),
84 Objects(Objects),
85}
86
87#[derive(Deserialize, Serialize, Debug)]
88pub struct Objects {
89 kind: String,
90 pub items: Vec<Object>,
91}
92
93#[derive(Deserialize, Serialize, Debug, Clone)]
94#[serde(rename_all = "camelCase")]
95pub struct Object {
96 kind: String,
97 id: String,
98 self_link: String,
99 media_link: String,
100 name: String,
101 bucket: String,
102 generation: String,
103 metageneration: String,
104 content_type: Option<String>,
105 storage_class: String,
106 size: String,
107 md5_hash: String,
108 crc32c: String,
109 etag: String,
110 time_created: String,
111 updated: String,
112 time_storage_class_updated: String,
113}
114
115impl Object {
116 pub async fn download(&self, mut client: Client) -> Result<String> {
117 let http_client = reqwest::Client::new();
118 let resp = http_client
119 .get(&self.media_link)
120 .header(
121 reqwest::header::AUTHORIZATION,
122 client.token_manager.token().await?,
123 )
124 .header(
125 reqwest::header::AUTHORIZATION,
126 client.token_manager.token().await?,
127 )
128 .send()
129 .await?;
130 let body = resp.text().await?;
131 Ok(body)
132 }
133}