1
- use crate :: state_machine:: { CharacterSet , StateMachine } ;
1
+ use crate :: {
2
+ api,
3
+ state_machine:: { CharacterSet , StateMachine } ,
4
+ } ;
2
5
use reqwest:: blocking:: Client as HttpClient ;
3
6
use serenity:: { model:: channel:: Message , prelude:: Context } ;
4
7
use std:: { collections:: HashMap , sync:: Arc } ;
5
8
6
9
const PREFIX : & ' static str = "?" ;
7
10
pub ( crate ) type Result < T > = std:: result:: Result < T , Box < dyn std:: error:: Error > > ;
8
- pub ( crate ) type CmdPtr = Arc < dyn for < ' m > Fn ( Args < ' m > ) -> Result < ( ) > + Send + Sync > ;
11
+ pub ( crate ) type GuardFn = fn ( & Args ) -> Result < bool > ;
12
+
13
+ struct Command {
14
+ guard : GuardFn ,
15
+ ptr : Box < dyn for < ' m > Fn ( Args < ' m > ) -> Result < ( ) > + Send + Sync > ,
16
+ }
17
+
18
+ impl Command {
19
+ fn authorize ( & self , args : & Args ) -> Result < bool > {
20
+ ( self . guard ) ( & args)
21
+ }
22
+
23
+ fn call ( & self , args : Args ) -> Result < ( ) > {
24
+ ( self . ptr ) ( args)
25
+ }
26
+ }
9
27
10
28
pub struct Args < ' m > {
11
29
pub http : & ' m HttpClient ,
@@ -15,24 +33,33 @@ pub struct Args<'m> {
15
33
}
16
34
17
35
pub ( crate ) struct Commands {
18
- state_machine : StateMachine ,
36
+ state_machine : StateMachine < Arc < Command > > ,
19
37
client : HttpClient ,
20
- menu : HashMap < & ' static str , & ' static str > ,
38
+ menu : Option < HashMap < & ' static str , ( & ' static str , GuardFn ) > > ,
21
39
}
22
40
23
41
impl Commands {
24
42
pub ( crate ) fn new ( ) -> Self {
25
43
Self {
26
44
state_machine : StateMachine :: new ( ) ,
27
45
client : HttpClient :: new ( ) ,
28
- menu : HashMap :: new ( ) ,
46
+ menu : Some ( HashMap :: new ( ) ) ,
29
47
}
30
48
}
31
49
32
50
pub ( crate ) fn add (
33
51
& mut self ,
34
52
command : & ' static str ,
35
53
handler : impl Fn ( Args ) -> Result < ( ) > + Send + Sync + ' static ,
54
+ ) {
55
+ self . add_protected ( command, handler, |_| Ok ( true ) ) ;
56
+ }
57
+
58
+ pub ( crate ) fn add_protected (
59
+ & mut self ,
60
+ command : & ' static str ,
61
+ handler : impl Fn ( Args ) -> Result < ( ) > + Send + Sync + ' static ,
62
+ guard : GuardFn ,
36
63
) {
37
64
info ! ( "Adding command {}" , & command) ;
38
65
let mut state = 0 ;
@@ -89,7 +116,10 @@ impl Commands {
89
116
}
90
117
} ) ;
91
118
92
- let handler = Arc :: new ( handler) ;
119
+ let handler = Arc :: new ( Command {
120
+ guard,
121
+ ptr : Box :: new ( handler) ,
122
+ } ) ;
93
123
94
124
if opt_lambda_state. is_some ( ) {
95
125
opt_final_states. iter ( ) . for_each ( |state| {
@@ -107,35 +137,69 @@ impl Commands {
107
137
cmd : & ' static str ,
108
138
desc : & ' static str ,
109
139
handler : impl Fn ( Args ) -> Result < ( ) > + Send + Sync + ' static ,
140
+ ) {
141
+ self . help_protected ( cmd, desc, handler, |_| Ok ( true ) ) ;
142
+ }
143
+
144
+ pub ( crate ) fn help_protected (
145
+ & mut self ,
146
+ cmd : & ' static str ,
147
+ desc : & ' static str ,
148
+ handler : impl Fn ( Args ) -> Result < ( ) > + Send + Sync + ' static ,
149
+ guard : GuardFn ,
110
150
) {
111
151
let base_cmd = & cmd[ 1 ..] ;
112
152
info ! ( "Adding command ?help {}" , & base_cmd) ;
113
153
let mut state = 0 ;
114
154
115
- self . menu . insert ( cmd, desc) ;
116
- state = add_help_menu ( & mut self . state_machine , base_cmd, state) ;
155
+ self . menu . as_mut ( ) . map ( |menu| {
156
+ menu. insert ( cmd, ( desc, guard) ) ;
157
+ menu
158
+ } ) ;
117
159
160
+ state = add_help_menu ( & mut self . state_machine , base_cmd, state) ;
118
161
self . state_machine . set_final_state ( state) ;
119
- self . state_machine . set_handler ( state, Arc :: new ( handler) ) ;
162
+ self . state_machine . set_handler (
163
+ state,
164
+ Arc :: new ( Command {
165
+ guard,
166
+ ptr : Box :: new ( handler) ,
167
+ } ) ,
168
+ ) ;
120
169
}
121
170
122
- pub ( crate ) fn menu ( & mut self ) -> & HashMap < & ' static str , & ' static str > {
123
- & self . menu
171
+ pub ( crate ) fn menu ( & mut self ) -> Option < HashMap < & ' static str , ( & ' static str , GuardFn ) > > {
172
+ self . menu . take ( )
124
173
}
125
174
126
175
pub ( crate ) fn execute < ' m > ( & ' m self , cx : Context , msg : Message ) {
127
176
let message = & msg. content ;
128
177
if !msg. is_own ( & cx) && message. starts_with ( PREFIX ) {
129
178
self . state_machine . process ( message) . map ( |matched| {
130
- info ! ( "Executing command {}" , message) ;
179
+ info ! ( "Processing command: {}" , message) ;
131
180
let args = Args {
132
181
http : & self . client ,
133
182
cx : & cx,
134
183
msg : & msg,
135
184
params : matched. params ,
136
185
} ;
137
- if let Err ( e) = ( matched. handler ) ( args) {
138
- println ! ( "{}" , e) ;
186
+ info ! ( "Checking permissions" ) ;
187
+ match matched. handler . authorize ( & args) {
188
+ Ok ( true ) => {
189
+ info ! ( "Executing command" ) ;
190
+ if let Err ( e) = matched. handler . call ( args) {
191
+ error ! ( "{}" , e) ;
192
+ }
193
+ }
194
+ Ok ( false ) => {
195
+ info ! ( "Not executing command, unauthorized" ) ;
196
+ if let Err ( e) =
197
+ api:: send_reply ( & args, "You do not have permission to run this command" )
198
+ {
199
+ error ! ( "{}" , e) ;
200
+ }
201
+ }
202
+ Err ( e) => error ! ( "{}" , e) ,
139
203
}
140
204
} ) ;
141
205
}
@@ -156,7 +220,7 @@ fn key_value_pair(s: &'static str) -> Option<&'static str> {
156
220
. flatten ( )
157
221
}
158
222
159
- fn add_space ( state_machine : & mut StateMachine , mut state : usize , i : usize ) -> usize {
223
+ fn add_space < T > ( state_machine : & mut StateMachine < T > , mut state : usize , i : usize ) -> usize {
160
224
if i > 0 {
161
225
let mut char_set = CharacterSet :: from_char ( ' ' ) ;
162
226
char_set. insert ( '\n' ) ;
@@ -167,8 +231,8 @@ fn add_space(state_machine: &mut StateMachine, mut state: usize, i: usize) -> us
167
231
state
168
232
}
169
233
170
- fn add_help_menu (
171
- mut state_machine : & mut StateMachine ,
234
+ fn add_help_menu < T > (
235
+ mut state_machine : & mut StateMachine < T > ,
172
236
cmd : & ' static str ,
173
237
mut state : usize ,
174
238
) -> usize {
@@ -183,8 +247,8 @@ fn add_help_menu(
183
247
state
184
248
}
185
249
186
- fn add_dynamic_segment (
187
- state_machine : & mut StateMachine ,
250
+ fn add_dynamic_segment < T > (
251
+ state_machine : & mut StateMachine < T > ,
188
252
name : & ' static str ,
189
253
mut state : usize ,
190
254
) -> usize {
@@ -198,8 +262,8 @@ fn add_dynamic_segment(
198
262
state
199
263
}
200
264
201
- fn add_remaining_segment (
202
- state_machine : & mut StateMachine ,
265
+ fn add_remaining_segment < T > (
266
+ state_machine : & mut StateMachine < T > ,
203
267
name : & ' static str ,
204
268
mut state : usize ,
205
269
) -> usize {
@@ -212,8 +276,8 @@ fn add_remaining_segment(
212
276
state
213
277
}
214
278
215
- fn add_code_segment_multi_line (
216
- state_machine : & mut StateMachine ,
279
+ fn add_code_segment_multi_line < T > (
280
+ state_machine : & mut StateMachine < T > ,
217
281
name : & ' static str ,
218
282
mut state : usize ,
219
283
) -> usize {
@@ -246,8 +310,8 @@ fn add_code_segment_multi_line(
246
310
state
247
311
}
248
312
249
- fn add_code_segment_single_line (
250
- state_machine : & mut StateMachine ,
313
+ fn add_code_segment_single_line < T > (
314
+ state_machine : & mut StateMachine < T > ,
251
315
name : & ' static str ,
252
316
mut state : usize ,
253
317
n_backticks : usize ,
@@ -266,7 +330,11 @@ fn add_code_segment_single_line(
266
330
state
267
331
}
268
332
269
- fn add_key_value ( state_machine : & mut StateMachine , name : & ' static str , mut state : usize ) -> usize {
333
+ fn add_key_value < T > (
334
+ state_machine : & mut StateMachine < T > ,
335
+ name : & ' static str ,
336
+ mut state : usize ,
337
+ ) -> usize {
270
338
name. chars ( ) . for_each ( |c| {
271
339
state = state_machine. add ( state, CharacterSet :: from_char ( c) ) ;
272
340
} ) ;
0 commit comments