11#![ allow( clippy:: await_holding_refcell_ref) ]
2+
23use super :: dev:: * ;
4+ use dv_api:: process:: ScriptExecutor ;
35use dv_wrap:: User ;
4- use mlua:: { Table , Value } ;
6+ use dv_wrap:: ops;
7+ use mlua:: { FromLua , LuaSerdeExt , Table , Value } ;
8+ use tracing:: debug;
9+
10+ pub struct UserWrapper {
11+ ctx : ContextWrapper ,
12+ uid : String ,
13+ }
14+
15+ impl UserWrapper {
16+ pub fn new ( ctx : ContextWrapper , uid : String ) -> Self {
17+ Self { ctx, uid }
18+ }
19+ }
20+
21+ #[ derive( serde:: Deserialize ) ]
22+ struct ExecOptions {
23+ reply : bool ,
24+ etor : Option < ScriptExecutor > ,
25+ }
26+
27+ impl FromLua for ExecOptions {
28+ fn from_lua ( value : Value , lua : & mlua:: Lua ) -> mlua:: Result < Self > {
29+ if let Some ( b) = value. as_boolean ( ) {
30+ return Ok ( ExecOptions {
31+ reply : b,
32+ etor : None ,
33+ } ) ;
34+ }
35+ lua. from_value ( value)
36+ }
37+ }
38+ impl UserData for UserWrapper {
39+ fn add_methods < M : UserDataMethods < Self > > ( methods : & mut M ) {
40+ methods. add_async_method (
41+ "exec" ,
42+ |_, this, ( commands, opt) : ( String , ExecOptions ) | async move {
43+ let ctx = this. ctx . ctx ( ) ;
44+ external_error ( ops:: exec ( & ctx, & this. uid , & commands, opt. reply , opt. etor ) ) . await
45+ } ,
46+ ) ;
47+ methods. add_async_method (
48+ "write" ,
49+ |_, this, ( path, content) : ( String , String ) | async move {
50+ let ctx = this. ctx . ctx ( ) ;
51+ external_error ( ops:: write ( & ctx, & this. uid , & path, & content) ) . await
52+ } ,
53+ ) ;
54+ methods. add_async_method ( "read" , |_, this, path : String | async move {
55+ let ctx = this. ctx . ctx ( ) ;
56+ external_error ( ops:: read ( & ctx, & this. uid , & path) ) . await
57+ } ) ;
58+ methods. add_meta_method ( mlua:: MetaMethod :: Index , |_, this, key : String | {
59+ let ctx = this. ctx . ctx ( ) ;
60+ let user = ctx. get_user ( & this. uid ) . expect ( "User must exist" ) ;
61+ if let Some ( value) = user. vars . get ( & key) {
62+ return Ok ( Some ( value. clone ( ) ) ) ;
63+ }
64+ Ok ( None )
65+ } ) ;
66+ }
67+ }
568
669pub struct UserManager {
770 ctx : ContextWrapper ,
871}
72+
973impl UserManager {
1074 pub fn new ( ctx : ContextWrapper ) -> Self {
1175 Self { ctx }
1276 }
1377}
1478
79+ impl std:: ops:: Deref for UserManager {
80+ type Target = ContextWrapper ;
81+ fn deref ( & self ) -> & Self :: Target {
82+ & self . ctx
83+ }
84+ }
85+
86+ impl std:: ops:: DerefMut for UserManager {
87+ fn deref_mut ( & mut self ) -> & mut Self :: Target {
88+ & mut self . ctx
89+ }
90+ }
91+
1592impl UserData for UserManager {
1693 fn add_methods < M : UserDataMethods < Self > > ( methods : & mut M ) {
1794 fn add_user_prepare ( obj : Table ) -> mlua:: Result < dv_api:: multi:: Config > {
@@ -33,7 +110,7 @@ impl UserData for UserManager {
33110 methods. add_async_method_mut ( "add_cur" , |_, this, obj : Table | async move {
34111 let mut cfg = add_user_prepare ( obj) ?;
35112 external_error ( async {
36- let mut ctx = this. ctx . ctx_mut ( ) ;
113+ let mut ctx = this. ctx_mut ( ) ;
37114 if ctx. contains_user ( "cur" ) {
38115 dv_api:: whatever!( "user cur already exists" ) ;
39116 }
@@ -48,7 +125,7 @@ impl UserData for UserManager {
48125 |_, this, ( uid, obj) : ( String , Table ) | async move {
49126 let mut cfg = add_user_prepare ( obj) ?;
50127 external_error ( async {
51- let mut ctx = this. ctx . ctx_mut ( ) ;
128+ let mut ctx = this. ctx_mut ( ) ;
52129 if ctx. contains_user ( & uid) {
53130 dv_api:: whatever!( "user {uid} already exists" ) ;
54131 }
@@ -58,5 +135,47 @@ impl UserData for UserManager {
58135 . await
59136 } ,
60137 ) ;
138+
139+ methods. add_meta_method (
140+ mlua:: MetaMethod :: Index ,
141+ |_, this, key : String | -> mlua:: Result < Option < UserWrapper > > {
142+ debug ! ( "Accessing user: {}" , key) ;
143+ if !this. ctx ( ) . contains_user ( & key) {
144+ return Ok ( None ) ;
145+ }
146+ Ok ( Some ( UserWrapper :: new ( this. ctx . clone ( ) , key) ) )
147+ } ,
148+ ) ;
149+ }
150+ }
151+
152+ #[ cfg( test) ]
153+ mod tests {
154+ use super :: ExecOptions ;
155+ use dv_api:: process:: ScriptExecutor ;
156+ use mlua:: FromLua ;
157+
158+ fn exec_options_des_suc_f ( s : & str ) -> ExecOptions {
159+ let lua = mlua:: Lua :: new ( ) ;
160+ let val = lua. load ( s) . eval :: < mlua:: Value > ( ) . expect ( "Failed to load" ) ;
161+ ExecOptions :: from_lua ( val, & lua) . expect ( "Failed to deserialize" )
162+ }
163+ #[ test]
164+ fn exec_options_serde ( ) {
165+ let opt = exec_options_des_suc_f ( "true" ) ;
166+ assert ! ( opt. reply) ;
167+ assert ! ( opt. etor. is_none( ) ) ;
168+
169+ let opt = exec_options_des_suc_f ( "{reply = false}" ) ;
170+ assert ! ( !opt. reply) ;
171+ assert ! ( opt. etor. is_none( ) ) ;
172+
173+ let opt = exec_options_des_suc_f ( "{reply = true, etor = 'sh'}" ) ;
174+ assert ! ( opt. reply) ;
175+ assert_eq ! ( opt. etor, Some ( ScriptExecutor :: Sh ) ) ;
176+
177+ let opt = exec_options_des_suc_f ( "{reply = false, etor = 'bash'}" ) ;
178+ assert ! ( !opt. reply) ;
179+ assert_eq ! ( opt. etor, Some ( ScriptExecutor :: Bash ) ) ;
61180 }
62181}
0 commit comments