A decentralized music tracking and discovery platform built on AT Protocol 馃幍
at setup-tracing 166 lines 4.9 kB view raw
1use std::env; 2 3use actix_web::HttpResponse; 4use anyhow::Error; 5use reqwest::Client; 6use serde_json::json; 7 8use crate::types::{ 9 file::{File, FileList}, 10 token::AccessToken, 11}; 12 13pub const BASE_URL: &str = "https://www.googleapis.com/drive/v3"; 14 15pub async fn get_access_token(refresh_token: &str) -> Result<AccessToken, Error> { 16 let client = Client::new(); 17 18 let params = [ 19 ("grant_type", "refresh_token"), 20 ("refresh_token", refresh_token), 21 ("client_id", &env::var("GOOGLE_CLIENT_ID")?), 22 ("client_secret", &env::var("GOOGLE_CLIENT_SECRET")?), 23 ]; 24 25 let body = serde_urlencoded::to_string(&params)?; 26 let res = client 27 .post("https://oauth2.googleapis.com/token") 28 .header("Content-Type", "application/x-www-form-urlencoded") 29 .header("Content-Length", body.len()) 30 .body(body) 31 .send() 32 .await?; 33 34 Ok(res.json::<AccessToken>().await?) 35} 36 37pub struct GoogleDriveClient { 38 pub access_token: String, 39} 40 41impl GoogleDriveClient { 42 pub async fn new(refresh_token: &str) -> Result<Self, Error> { 43 let res = get_access_token(refresh_token).await?; 44 Ok(Self { 45 access_token: res.access_token, 46 }) 47 } 48 49 pub async fn get_files(&self, name: &str) -> Result<FileList, Error> { 50 let client = Client::new(); 51 let url = format!("{}/files", BASE_URL); 52 let res = client 53 .get(&url) 54 .bearer_auth(&self.access_token) 55 .query(&[ 56 ( 57 "q", 58 format!( 59 "name='{}' and mimeType='application/vnd.google-apps.folder'", 60 name 61 ) 62 .as_str(), 63 ), 64 ("fields", "files(id, name, mimeType, parents)"), 65 ("orderBy", "name"), 66 ]) 67 .send() 68 .await?; 69 70 Ok(res.json::<FileList>().await?) 71 } 72 73 pub async fn create_music_directory(&self) -> Result<File, Error> { 74 let client = Client::new(); 75 let url = format!("{}/files", BASE_URL); 76 let res = client 77 .post(&url) 78 .bearer_auth(&self.access_token) 79 .json(&json!({ 80 "name": "Music", 81 "mimeType": "application/vnd.google-apps.folder", 82 })) 83 .send() 84 .await?; 85 86 Ok(res.json::<File>().await?) 87 } 88 89 pub async fn get_music_directory(&self) -> Result<FileList, Error> { 90 let client = Client::new(); 91 let url = format!("{}/files", BASE_URL); 92 let res = client.get(&url) 93 .bearer_auth(&self.access_token) 94 .query(&[ 95 ("q", "name='Music' and mimeType='application/vnd.google-apps.folder' and 'root' in parents"), 96 ("fields", "files(id, name, mimeType, parents)"), 97 ("orderBy", "name"), 98 ]) 99 .send() 100 .await?; 101 102 let files = res.json::<FileList>().await?; 103 104 if files.files.len() == 0 { 105 let music_dir = self.create_music_directory().await?; 106 return Ok(FileList { 107 files: vec![music_dir], 108 next_page_token: None, 109 }); 110 } 111 112 Ok(files) 113 } 114 115 pub async fn get_files_in_parents(&self, parent_id: &str) -> Result<FileList, Error> { 116 let client = Client::new(); 117 let url = format!("{}/files", BASE_URL); 118 let res = client 119 .get(&url) 120 .bearer_auth(&self.access_token) 121 .query(&[ 122 ("q", format!("'{}' in parents", parent_id).as_str()), 123 ("fields", "files(id, name, mimeType, parents)"), 124 ("orderBy", "name"), 125 ]) 126 .send() 127 .await?; 128 Ok(res.json::<FileList>().await?) 129 } 130 131 pub async fn get_file(&self, file_id: &str) -> Result<File, Error> { 132 let client = Client::new(); 133 let url = format!("{}/files/{}", BASE_URL, file_id); 134 let res = client 135 .get(&url) 136 .bearer_auth(&self.access_token) 137 .query(&[("fields", "id, name, mimeType, parents")]) 138 .send() 139 .await?; 140 141 Ok(res.json::<File>().await?) 142 } 143 144 pub async fn download_file(&self, file_id: &str) -> Result<HttpResponse, Error> { 145 let client = Client::new(); 146 let url = format!("{}/files/{}", BASE_URL, file_id); 147 let res = client 148 .get(&url) 149 .bearer_auth(&self.access_token) 150 .query(&[("alt", "media")]) 151 .send() 152 .await?; 153 154 let mut actix_response = HttpResponse::Ok(); 155 156 // Forward headers 157 for (key, value) in res.headers().iter() { 158 actix_response.append_header((key.as_str(), value.to_str().unwrap_or(""))); 159 } 160 161 // Forward body 162 let body = res.bytes_stream(); 163 164 Ok(actix_response.streaming(body)) 165 } 166}