cull_gmail/
gmail_client.rs1use std::collections::BTreeMap;
2
3use google_gmail1::{
4 Gmail,
5 hyper_rustls::{HttpsConnector, HttpsConnectorBuilder},
6 hyper_util::{
7 client::legacy::{Client, connect::HttpConnector},
8 rt::TokioExecutor,
9 },
10 yup_oauth2::{InstalledFlowAuthenticator, InstalledFlowReturnMethod},
11};
12
13mod message_summary;
14
15pub(crate) use message_summary::MessageSummary;
16
17use crate::{ClientConfig, Error, Result, rules::EolRule};
18
19pub const DEFAULT_MAX_RESULTS: &str = "200";
21
22#[derive(Clone)]
24pub struct GmailClient {
25 hub: Gmail<HttpsConnector<HttpConnector>>,
26 label_map: BTreeMap<String, String>,
27 pub(crate) max_results: u32,
28 pub(crate) label_ids: Vec<String>,
29 pub(crate) query: String,
30 pub(crate) messages: Vec<MessageSummary>,
31 pub(crate) rule: Option<EolRule>,
32 pub(crate) execute: bool,
33}
34
35impl std::fmt::Debug for GmailClient {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 f.debug_struct("Labels")
38 .field("label_map", &self.label_map)
39 .finish()
40 }
41}
42
43impl GmailClient {
44 pub async fn new_with_config(config: ClientConfig) -> Result<Self> {
66 let executor = TokioExecutor::new();
67 let connector = HttpsConnectorBuilder::new()
68 .with_native_roots()
69 .unwrap()
70 .https_or_http()
71 .enable_http1()
72 .build();
73
74 let client = Client::builder(executor.clone()).build(connector.clone());
75 log::trace!("file to persist tokens to `{}`", config.persist_path());
76
77 let auth = InstalledFlowAuthenticator::with_client(
78 config.secret().clone(),
79 InstalledFlowReturnMethod::HTTPRedirect,
80 Client::builder(executor).build(connector),
81 )
82 .persist_tokens_to_disk(config.persist_path())
83 .build()
84 .await
85 .unwrap();
86
87 let hub = Gmail::new(client, auth);
88 let label_map = GmailClient::get_label_map(&hub).await?;
89
90 Ok(GmailClient {
91 hub,
92 label_map,
93 max_results: DEFAULT_MAX_RESULTS.parse::<u32>().unwrap(),
94 label_ids: Vec::new(),
95 query: String::new(),
96 messages: Vec::new(),
97 rule: None,
98 execute: false,
99 })
100 }
101
102 async fn get_label_map(
104 hub: &Gmail<HttpsConnector<HttpConnector>>,
105 ) -> Result<BTreeMap<String, String>> {
106 let call = hub.users().labels_list("me");
107 let (_response, list) = call
108 .add_scope("https://mail.google.com/")
109 .doit()
110 .await
111 .map_err(Box::new)?;
112
113 let Some(label_list) = list.labels else {
114 return Err(Error::NoLabelsFound);
115 };
116
117 let mut label_map = BTreeMap::new();
118 for label in &label_list {
119 if label.id.is_some() && label.name.is_some() {
120 let name = label.name.clone().unwrap();
121 let id = label.id.clone().unwrap();
122 label_map.insert(name, id);
123 }
124 }
125
126 Ok(label_map)
127 }
128
129 pub fn get_label_id(&self, name: &str) -> Option<String> {
132 self.label_map.get(name).cloned()
133 }
134
135 pub fn show_label(&self) {
137 for (name, id) in self.label_map.iter() {
138 log::info!("{name}: {id}")
139 }
140 }
141
142 pub(crate) fn hub(&self) -> Gmail<HttpsConnector<HttpConnector>> {
144 self.hub.clone()
145 }
146}