@@ -9,10 +9,13 @@ use google_drive3::{
9
9
use http_body_util:: BodyExt ;
10
10
use hyper_rustls:: HttpsConnector ;
11
11
use hyper_util:: client:: legacy:: connect:: HttpConnector ;
12
+ use indexmap:: IndexSet ;
12
13
use log:: debug;
13
14
14
15
use crate :: ops:: sdk:: * ;
15
16
17
+ const FOLDER_MIME_TYPE : & ' static str = "application/vnd.google-apps.folder" ;
18
+
16
19
#[ derive( Debug , Deserialize ) ]
17
20
pub struct Spec {
18
21
service_account_credential_path : String ,
@@ -28,7 +31,6 @@ struct Executor {
28
31
29
32
impl Executor {
30
33
async fn new ( spec : Spec ) -> Result < Self > {
31
- // let user_secret = read_authorized_user_secret(spec.service_account_credential_path).await?;
32
34
let service_account_key =
33
35
read_service_account_key ( spec. service_account_credential_path ) . await ?;
34
36
let auth = ServiceAccountAuthenticator :: builder ( service_account_key)
@@ -64,12 +66,18 @@ fn escape_string(s: &str) -> String {
64
66
escaped
65
67
}
66
68
67
- #[ async_trait]
68
- impl SourceExecutor for Executor {
69
- async fn list_keys ( & self ) -> Result < Vec < KeyValue > > {
70
- let query = format ! ( "'{}' in parents" , escape_string( & self . root_folder_id) ) ;
69
+ impl Executor {
70
+ async fn traverse_folder (
71
+ & self ,
72
+ folder_id : & str ,
73
+ visited_folder_ids : & mut IndexSet < String > ,
74
+ result : & mut IndexSet < KeyValue > ,
75
+ ) -> Result < ( ) > {
76
+ if !visited_folder_ids. insert ( folder_id. to_string ( ) ) {
77
+ return Ok ( ( ) ) ;
78
+ }
79
+ let query = format ! ( "'{}' in parents" , escape_string( folder_id) ) ;
71
80
let mut next_page_token: Option < String > = None ;
72
- let mut result = Vec :: new ( ) ;
73
81
loop {
74
82
let mut list_call = self
75
83
. drive_hub
@@ -83,9 +91,12 @@ impl SourceExecutor for Executor {
83
91
let ( _, files) = list_call. doit ( ) . await ?;
84
92
if let Some ( files) = files. files {
85
93
for file in files {
86
- debug ! ( "file: {:?}" , file) ;
87
94
if let Some ( id) = file. id {
88
- result. push ( KeyValue :: Str ( Arc :: from ( id) ) ) ;
95
+ if file. mime_type . as_ref ( ) == Some ( & FOLDER_MIME_TYPE . to_string ( ) ) {
96
+ Box :: pin ( self . traverse_folder ( & id, visited_folder_ids, result) ) . await ?;
97
+ } else {
98
+ result. insert ( KeyValue :: Str ( Arc :: from ( id) ) ) ;
99
+ }
89
100
}
90
101
}
91
102
}
@@ -94,7 +105,17 @@ impl SourceExecutor for Executor {
94
105
break ;
95
106
}
96
107
}
97
- Ok ( result)
108
+ Ok ( ( ) )
109
+ }
110
+ }
111
+
112
+ #[ async_trait]
113
+ impl SourceExecutor for Executor {
114
+ async fn list_keys ( & self ) -> Result < Vec < KeyValue > > {
115
+ let mut result = IndexSet :: new ( ) ;
116
+ self . traverse_folder ( & self . root_folder_id , & mut IndexSet :: new ( ) , & mut result)
117
+ . await ?;
118
+ Ok ( result. into_iter ( ) . collect ( ) )
98
119
}
99
120
100
121
async fn get_value ( & self , key : & KeyValue ) -> Result < Option < FieldValues > > {
0 commit comments