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 : Option < String > ,
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 : Some ( String :: 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| {
@@ -100,31 +130,76 @@ impl Commands {
100
130
self . state_machine . set_final_state ( state) ;
101
131
self . state_machine . set_handler ( state, handler. clone ( ) ) ;
102
132
}
133
+ }
134
+
135
+ pub ( crate ) fn help (
136
+ & mut self ,
137
+ cmd : & ' static str ,
138
+ desc : & ' static str ,
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 ,
150
+ ) {
151
+ let base_cmd = & cmd[ 1 ..] ;
152
+ info ! ( "Adding command ?help {}" , & base_cmd) ;
153
+ let mut state = 0 ;
103
154
104
155
self . menu . as_mut ( ) . map ( |menu| {
105
- * menu += command ;
106
- * menu += " \n "
156
+ menu. insert ( cmd , ( desc , guard ) ) ;
157
+ menu
107
158
} ) ;
159
+
160
+ state = add_help_menu ( & mut self . state_machine , base_cmd, state) ;
161
+ self . state_machine . set_final_state ( state) ;
162
+ self . state_machine . set_handler (
163
+ state,
164
+ Arc :: new ( Command {
165
+ guard,
166
+ ptr : Box :: new ( handler) ,
167
+ } ) ,
168
+ ) ;
108
169
}
109
170
110
- pub ( crate ) fn menu ( & mut self ) -> Option < String > {
111
- self . menu . as_mut ( ) . map ( |menu| * menu += "?help\n " ) ;
171
+ pub ( crate ) fn menu ( & mut self ) -> Option < HashMap < & ' static str , ( & ' static str , GuardFn ) > > {
112
172
self . menu . take ( )
113
173
}
114
174
115
175
pub ( crate ) fn execute < ' m > ( & ' m self , cx : Context , msg : Message ) {
116
176
let message = & msg. content ;
117
177
if !msg. is_own ( & cx) && message. starts_with ( PREFIX ) {
118
178
self . state_machine . process ( message) . map ( |matched| {
119
- info ! ( "Executing command {}" , message) ;
179
+ info ! ( "Processing command: {}" , message) ;
120
180
let args = Args {
121
181
http : & self . client ,
122
182
cx : & cx,
123
183
msg : & msg,
124
184
params : matched. params ,
125
185
} ;
126
- if let Err ( e) = ( matched. handler ) ( args) {
127
- 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) ,
128
203
}
129
204
} ) ;
130
205
}
@@ -145,7 +220,7 @@ fn key_value_pair(s: &'static str) -> Option<&'static str> {
145
220
. flatten ( )
146
221
}
147
222
148
- 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 {
149
224
if i > 0 {
150
225
let mut char_set = CharacterSet :: from_char ( ' ' ) ;
151
226
char_set. insert ( '\n' ) ;
@@ -156,8 +231,24 @@ fn add_space(state_machine: &mut StateMachine, mut state: usize, i: usize) -> us
156
231
state
157
232
}
158
233
159
- fn add_dynamic_segment (
160
- state_machine : & mut StateMachine ,
234
+ fn add_help_menu < T > (
235
+ mut state_machine : & mut StateMachine < T > ,
236
+ cmd : & ' static str ,
237
+ mut state : usize ,
238
+ ) -> usize {
239
+ "?help" . chars ( ) . for_each ( |ch| {
240
+ state = state_machine. add ( state, CharacterSet :: from_char ( ch) ) ;
241
+ } ) ;
242
+ state = add_space ( & mut state_machine, state, 1 ) ;
243
+ cmd. chars ( ) . for_each ( |ch| {
244
+ state = state_machine. add ( state, CharacterSet :: from_char ( ch) ) ;
245
+ } ) ;
246
+
247
+ state
248
+ }
249
+
250
+ fn add_dynamic_segment < T > (
251
+ state_machine : & mut StateMachine < T > ,
161
252
name : & ' static str ,
162
253
mut state : usize ,
163
254
) -> usize {
@@ -171,8 +262,8 @@ fn add_dynamic_segment(
171
262
state
172
263
}
173
264
174
- fn add_remaining_segment (
175
- state_machine : & mut StateMachine ,
265
+ fn add_remaining_segment < T > (
266
+ state_machine : & mut StateMachine < T > ,
176
267
name : & ' static str ,
177
268
mut state : usize ,
178
269
) -> usize {
@@ -185,8 +276,8 @@ fn add_remaining_segment(
185
276
state
186
277
}
187
278
188
- fn add_code_segment_multi_line (
189
- state_machine : & mut StateMachine ,
279
+ fn add_code_segment_multi_line < T > (
280
+ state_machine : & mut StateMachine < T > ,
190
281
name : & ' static str ,
191
282
mut state : usize ,
192
283
) -> usize {
@@ -219,8 +310,8 @@ fn add_code_segment_multi_line(
219
310
state
220
311
}
221
312
222
- fn add_code_segment_single_line (
223
- state_machine : & mut StateMachine ,
313
+ fn add_code_segment_single_line < T > (
314
+ state_machine : & mut StateMachine < T > ,
224
315
name : & ' static str ,
225
316
mut state : usize ,
226
317
n_backticks : usize ,
@@ -239,7 +330,11 @@ fn add_code_segment_single_line(
239
330
state
240
331
}
241
332
242
- 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 {
243
338
name. chars ( ) . for_each ( |c| {
244
339
state = state_machine. add ( state, CharacterSet :: from_char ( c) ) ;
245
340
} ) ;
0 commit comments