16
16
*
17
17
*/
18
18
19
- use std:: collections:: HashSet ;
19
+ use std:: collections:: { HashMap , HashSet } ;
20
20
21
21
use actix_web:: { http:: header:: ContentType , Error } ;
22
22
use chrono:: Utc ;
23
23
use datafusion:: error:: DataFusionError ;
24
24
use http:: StatusCode ;
25
25
use itertools:: Itertools ;
26
26
use once_cell:: sync:: Lazy ;
27
+ use relative_path:: RelativePathBuf ;
27
28
use serde:: { Deserialize , Serialize } ;
28
29
use serde_json:: Error as SerdeError ;
29
30
use tokio:: sync:: RwLock ;
30
- use tracing:: { error, trace , warn } ;
31
+ use tracing:: error;
31
32
32
33
use crate :: {
33
- handlers:: http:: rbac:: RBACError ,
34
+ handlers:: http:: {
35
+ rbac:: RBACError ,
36
+ users:: { CORRELATION_DIR , USERS_ROOT_DIR } ,
37
+ } ,
34
38
option:: CONFIG ,
35
39
query:: QUERY_SESSION ,
36
40
rbac:: { map:: SessionKey , Users } ,
@@ -39,167 +43,208 @@ use crate::{
39
43
utils:: { get_hash, user_auth_for_query} ,
40
44
} ;
41
45
42
- pub static CORRELATIONS : Lazy < Correlation > = Lazy :: new ( Correlation :: default) ;
46
+ pub static CORRELATIONS : Lazy < Correlations > = Lazy :: new ( Correlations :: default) ;
43
47
44
- #[ derive( Debug , Default ) ]
45
- pub struct Correlation ( RwLock < Vec < CorrelationConfig > > ) ;
48
+ type CorrelationMap = HashMap < CorrelationId , CorrelationConfig > ;
46
49
47
- impl Correlation {
48
- //load correlations from storage
50
+ #[ derive( Debug , Default , derive_more:: Deref ) ]
51
+ pub struct Correlations ( RwLock < CorrelationMap > ) ;
52
+
53
+ impl Correlations {
54
+ // Load correlations from storage
49
55
pub async fn load ( & self ) -> anyhow:: Result < ( ) > {
50
56
let store = CONFIG . storage ( ) . get_object_store ( ) ;
51
57
let all_correlations = store. get_all_correlations ( ) . await . unwrap_or_default ( ) ;
52
58
53
- let correlations: Vec < CorrelationConfig > = all_correlations
54
- . into_iter ( )
55
- . flat_map ( |( _, correlations_bytes) | correlations_bytes)
56
- . filter_map ( |correlation| {
57
- serde_json:: from_slice ( & correlation)
58
- . inspect_err ( |e| {
59
- error ! ( "Unable to load correlation: {e}" ) ;
60
- } )
61
- . ok ( )
62
- } )
63
- . collect ( ) ;
59
+ for correlations_bytes in all_correlations. values ( ) . flatten ( ) {
60
+ let correlation = match serde_json:: from_slice :: < CorrelationConfig > ( correlations_bytes)
61
+ {
62
+ Ok ( c) => c,
63
+ Err ( e) => {
64
+ error ! ( "Unable to load correlation file : {e}" ) ;
65
+ continue ;
66
+ }
67
+ } ;
68
+
69
+ self . write ( )
70
+ . await
71
+ . insert ( correlation. id . to_owned ( ) , correlation) ;
72
+ }
64
73
65
- let mut s = self . 0 . write ( ) . await ;
66
- s. extend ( correlations) ;
67
74
Ok ( ( ) )
68
75
}
69
76
70
- pub async fn list_correlations_for_user (
77
+ pub async fn list_correlations (
71
78
& self ,
72
79
session_key : & SessionKey ,
73
- user_id : & str ,
74
80
) -> Result < Vec < CorrelationConfig > , CorrelationError > {
75
- let correlations = self . 0 . read ( ) . await . iter ( ) . cloned ( ) . collect_vec ( ) ;
76
-
77
81
let mut user_correlations = vec ! [ ] ;
78
82
let permissions = Users . get_permissions ( session_key) ;
79
83
80
- for c in correlations {
81
- let tables = & c
84
+ for correlation in self . read ( ) . await . values ( ) {
85
+ let tables = & correlation
82
86
. table_configs
83
87
. iter ( )
84
88
. map ( |t| t. table_name . clone ( ) )
85
89
. collect_vec ( ) ;
86
- if user_auth_for_query ( & permissions, tables) . is_ok ( ) && c . user_id == user_id {
87
- user_correlations. push ( c ) ;
90
+ if user_auth_for_query ( & permissions, tables) . is_ok ( ) {
91
+ user_correlations. push ( correlation . clone ( ) ) ;
88
92
}
89
93
}
94
+
90
95
Ok ( user_correlations)
91
96
}
92
97
93
98
pub async fn get_correlation (
94
99
& self ,
95
100
correlation_id : & str ,
96
- user_id : & str ,
97
101
) -> Result < CorrelationConfig , CorrelationError > {
98
- let read = self . 0 . read ( ) . await ;
99
- let correlation = read
100
- . iter ( )
101
- . find ( |c| c. id == correlation_id && c. user_id == user_id)
102
- . cloned ( ) ;
103
-
104
- correlation. ok_or_else ( || {
105
- CorrelationError :: AnyhowError ( anyhow:: Error :: msg ( format ! (
106
- "Unable to find correlation with ID- {correlation_id}"
107
- ) ) )
108
- } )
102
+ self . read ( )
103
+ . await
104
+ . get ( correlation_id)
105
+ . cloned ( )
106
+ . ok_or_else ( || {
107
+ CorrelationError :: AnyhowError ( anyhow:: Error :: msg ( format ! (
108
+ "Unable to find correlation with ID- {correlation_id}"
109
+ ) ) )
110
+ } )
109
111
}
110
112
111
- pub async fn update ( & self , correlation : & CorrelationConfig ) -> Result < ( ) , CorrelationError > {
112
- // save to memory
113
- let mut s = self . 0 . write ( ) . await ;
114
- s. retain ( |c| c. id != correlation. id ) ;
115
- s. push ( correlation. clone ( ) ) ;
116
- Ok ( ( ) )
113
+ /// Create correlation associated with the user
114
+ pub async fn create (
115
+ & self ,
116
+ mut correlation : CorrelationConfig ,
117
+ session_key : & SessionKey ,
118
+ ) -> Result < CorrelationConfig , CorrelationError > {
119
+ correlation. id = get_hash ( Utc :: now ( ) . timestamp_micros ( ) . to_string ( ) . as_str ( ) ) ;
120
+ correlation. validate ( session_key) . await ?;
121
+
122
+ // Update in storage
123
+ let correlation_bytes = serde_json:: to_vec ( & correlation) ?. into ( ) ;
124
+ let path = correlation. path ( ) ;
125
+ CONFIG
126
+ . storage ( )
127
+ . get_object_store ( )
128
+ . put_object ( & path, correlation_bytes)
129
+ . await ?;
130
+
131
+ // Update in memory
132
+ self . write ( ) . await . insert (
133
+ correlation. id . to_owned ( ) ,
134
+ correlation. clone ( ) ,
135
+ ) ;
136
+
137
+ Ok ( correlation)
117
138
}
118
139
119
- pub async fn delete ( & self , correlation_id : & str ) -> Result < ( ) , CorrelationError > {
120
- // now delete from memory
121
- let read_access = self . 0 . read ( ) . await ;
140
+ /// Update existing correlation for the user and with the same ID
141
+ pub async fn update (
142
+ & self ,
143
+ mut updated_correlation : CorrelationConfig ,
144
+ session_key : & SessionKey ,
145
+ ) -> Result < CorrelationConfig , CorrelationError > {
146
+ // validate whether user has access to this correlation object or not
147
+ let correlation = self . get_correlation ( & updated_correlation. id ) . await ?;
148
+ if correlation. user_id != updated_correlation. user_id {
149
+ return Err ( CorrelationError :: AnyhowError ( anyhow:: Error :: msg ( format ! (
150
+ r#"User "{}" isn't authorized to update correlation with ID - {}"# ,
151
+ updated_correlation. user_id, correlation. id
152
+ ) ) ) ) ;
153
+ }
122
154
123
- let index = read_access
124
- . iter ( )
125
- . enumerate ( )
126
- . find ( |( _, c) | c. id == correlation_id)
127
- . to_owned ( ) ;
128
-
129
- if let Some ( ( index, _) ) = index {
130
- // drop the read access in order to get exclusive write access
131
- drop ( read_access) ;
132
- self . 0 . write ( ) . await . remove ( index) ;
133
- trace ! ( "removed correlation from memory" ) ;
134
- } else {
135
- warn ! ( "Correlation ID- {correlation_id} not found in memory!" ) ;
155
+ correlation. validate ( session_key) . await ?;
156
+ updated_correlation. update ( correlation) ;
157
+
158
+ // Update in storage
159
+ let correlation_bytes = serde_json:: to_vec ( & updated_correlation) ?. into ( ) ;
160
+ let path = updated_correlation. path ( ) ;
161
+ CONFIG
162
+ . storage ( )
163
+ . get_object_store ( )
164
+ . put_object ( & path, correlation_bytes)
165
+ . await ?;
166
+
167
+ // Update in memory
168
+ self . write ( ) . await . insert (
169
+ updated_correlation. id . to_owned ( ) ,
170
+ updated_correlation. clone ( ) ,
171
+ ) ;
172
+
173
+ Ok ( updated_correlation)
174
+ }
175
+
176
+ /// Delete correlation from memory and storage
177
+ pub async fn delete (
178
+ & self ,
179
+ correlation_id : & str ,
180
+ user_id : & str ,
181
+ ) -> Result < ( ) , CorrelationError > {
182
+ let correlation = CORRELATIONS . get_correlation ( correlation_id) . await ?;
183
+ if correlation. user_id != user_id {
184
+ return Err ( CorrelationError :: AnyhowError ( anyhow:: Error :: msg ( format ! (
185
+ r#"User "{user_id}" isn't authorized to delete correlation with ID - {correlation_id}"#
186
+ ) ) ) ) ;
136
187
}
188
+
189
+ // Delete from memory
190
+ self . write ( ) . await . remove ( & correlation. id ) ;
191
+
192
+ // Delete from storage
193
+ let path = correlation. path ( ) ;
194
+ CONFIG
195
+ . storage ( )
196
+ . get_object_store ( )
197
+ . delete_object ( & path)
198
+ . await ?;
199
+
137
200
Ok ( ( ) )
138
201
}
139
202
}
140
203
141
- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
204
+ #[ derive( Debug , Clone , Default , Serialize , Deserialize ) ]
142
205
#[ serde( rename_all = "camelCase" ) ]
143
206
pub enum CorrelationVersion {
207
+ #[ default]
144
208
V1 ,
145
209
}
146
210
211
+ type CorrelationId = String ;
212
+ type UserId = String ;
213
+
147
214
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
148
215
#[ serde( rename_all = "camelCase" ) ]
149
216
pub struct CorrelationConfig {
217
+ #[ serde( default ) ]
150
218
pub version : CorrelationVersion ,
151
219
pub title : String ,
152
- pub id : String ,
153
- pub user_id : String ,
220
+ #[ serde( default ) ]
221
+ pub id : CorrelationId ,
222
+ #[ serde( default ) ]
223
+ pub user_id : UserId ,
154
224
pub table_configs : Vec < TableConfig > ,
155
225
pub join_config : JoinConfig ,
156
226
pub filter : Option < FilterQuery > ,
157
227
pub start_time : Option < String > ,
158
228
pub end_time : Option < String > ,
159
229
}
160
230
161
- impl CorrelationConfig { }
162
-
163
- #[ derive( Debug , Clone , Serialize , Deserialize ) ]
164
- #[ serde( rename_all = "camelCase" ) ]
165
- pub struct CorrelationRequest {
166
- pub title : String ,
167
- pub table_configs : Vec < TableConfig > ,
168
- pub join_config : JoinConfig ,
169
- pub filter : Option < FilterQuery > ,
170
- pub start_time : Option < String > ,
171
- pub end_time : Option < String > ,
172
- }
173
-
174
- impl From < CorrelationRequest > for CorrelationConfig {
175
- fn from ( val : CorrelationRequest ) -> Self {
176
- Self {
177
- version : CorrelationVersion :: V1 ,
178
- title : val. title ,
179
- id : get_hash ( Utc :: now ( ) . timestamp_micros ( ) . to_string ( ) . as_str ( ) ) ,
180
- user_id : String :: default ( ) ,
181
- table_configs : val. table_configs ,
182
- join_config : val. join_config ,
183
- filter : val. filter ,
184
- start_time : val. start_time ,
185
- end_time : val. end_time ,
186
- }
231
+ impl CorrelationConfig {
232
+ pub fn path ( & self ) -> RelativePathBuf {
233
+ RelativePathBuf :: from_iter ( [
234
+ USERS_ROOT_DIR ,
235
+ & self . user_id ,
236
+ CORRELATION_DIR ,
237
+ & format ! ( "{}.json" , self . id) ,
238
+ ] )
187
239
}
188
- }
189
240
190
- impl CorrelationRequest {
191
- pub fn generate_correlation_config ( self , id : String , user_id : String ) -> CorrelationConfig {
192
- CorrelationConfig {
193
- version : CorrelationVersion :: V1 ,
194
- title : self . title ,
195
- id,
196
- user_id,
197
- table_configs : self . table_configs ,
198
- join_config : self . join_config ,
199
- filter : self . filter ,
200
- start_time : self . start_time ,
201
- end_time : self . end_time ,
202
- }
241
+ pub fn update ( & mut self , update : Self ) {
242
+ self . title = update. title ;
243
+ self . table_configs = update. table_configs ;
244
+ self . join_config = update. join_config ;
245
+ self . filter = update. filter ;
246
+ self . start_time = update. start_time ;
247
+ self . end_time = update. end_time ;
203
248
}
204
249
205
250
/// This function will validate the TableConfigs, JoinConfig, and user auth
0 commit comments