• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Blightmud / Blightmud / 18404277942

10 Oct 2025 10:48AM UTC coverage: 73.884% (+0.3%) from 73.595%
18404277942

push

github

web-flow
Allows core.exec to receive a table of arguments (#1282)

* Allows core.exec to receive a table of arguments

When receiving a table, the first element is the executable to run, and
remaining elements are passed as arguments to the executable.

Fixes #1280

* Add tests for core.exec

---------

Co-authored-by: ja-cop <>

20 of 27 new or added lines in 3 files covered. (74.07%)

6654 of 9006 relevant lines covered (73.88%)

343.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.5
/src/lua/core.rs
1
use std::sync::mpsc::Sender;
2

3
use libmudtelnet::bytes::Bytes;
4
use log::debug;
5
use mlua::{AnyUserData, Table, UserData, UserDataMethods, Value};
6

7
use crate::event::Event;
8
use crate::io::{exec, exec_args};
9

10
use super::{
11
    constants::{
12
        PROTO_DISABLED_LISTENERS_TABLE, PROTO_ENABLED_LISTENERS_TABLE, PROTO_SUBNEG_LISTENERS_TABLE,
13
    },
14
    exec_response::ExecResponse,
15
};
16

17
#[derive(Debug, Clone)]
18
pub struct Core {
19
    main_writer: Sender<Event>,
20
    next_id: u32,
21
}
22

23
impl Core {
24
    pub fn new(writer: Sender<Event>) -> Self {
179✔
25
        Self {
179✔
26
            main_writer: writer,
179✔
27
            next_id: 0,
179✔
28
        }
179✔
29
    }
179✔
30

31
    fn next_index(&mut self) -> u32 {
2,869✔
32
        self.next_id += 1;
2,869✔
33
        self.next_id
2,869✔
34
    }
2,869✔
35
}
36

37
impl UserData for Core {
38
    fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
179✔
39
        methods.add_function("enable_protocol", |ctx, proto: u8| {
1,076✔
40
            let this_aux = ctx.globals().get::<AnyUserData>("core")?;
1,076✔
41
            let this = this_aux.borrow_mut::<Core>()?;
1,076✔
42
            this.main_writer.send(Event::EnableProto(proto)).unwrap();
1,076✔
43
            Ok(())
1,076✔
44
        });
1,076✔
45
        methods.add_function("disable_protocol", |ctx, proto: u8| {
179✔
46
            let this_aux = ctx.globals().get::<AnyUserData>("core")?;
×
47
            let this = this_aux.borrow_mut::<Core>()?;
×
48
            this.main_writer.send(Event::DisableProto(proto)).unwrap();
×
49
            Ok(())
×
50
        });
×
51
        methods.add_function_mut("on_protocol_enabled", |ctx, cb: mlua::Function| {
1,076✔
52
            let table: Table = ctx.named_registry_value(PROTO_ENABLED_LISTENERS_TABLE)?;
1,076✔
53
            let this_aux = ctx.globals().get::<AnyUserData>("core")?;
1,076✔
54
            let mut this = this_aux.borrow_mut::<Core>()?;
1,076✔
55
            table.set(this.next_index(), cb)?;
1,076✔
56
            ctx.set_named_registry_value(PROTO_ENABLED_LISTENERS_TABLE, table)?;
1,076✔
57
            Ok(())
1,076✔
58
        });
1,076✔
59
        methods.add_function_mut("on_protocol_disabled", |ctx, cb: mlua::Function| {
896✔
60
            let table: Table = ctx.named_registry_value(PROTO_DISABLED_LISTENERS_TABLE)?;
896✔
61
            let this_aux = ctx.globals().get::<AnyUserData>("core")?;
896✔
62
            let mut this = this_aux.borrow_mut::<Core>()?;
896✔
63
            table.set(this.next_index(), cb)?;
896✔
64
            ctx.set_named_registry_value(PROTO_DISABLED_LISTENERS_TABLE, table)?;
896✔
65
            Ok(())
896✔
66
        });
896✔
67
        methods.add_function_mut("subneg_recv", |ctx, cb: mlua::Function| {
897✔
68
            let table: Table = ctx.named_registry_value(PROTO_SUBNEG_LISTENERS_TABLE)?;
897✔
69
            let this_aux = ctx.globals().get::<AnyUserData>("core")?;
897✔
70
            let mut this = this_aux.borrow_mut::<Core>()?;
897✔
71
            table.set(this.next_index(), cb)?;
897✔
72
            ctx.set_named_registry_value(PROTO_SUBNEG_LISTENERS_TABLE, table)?;
897✔
73
            Ok(())
897✔
74
        });
897✔
75
        methods.add_function_mut("subneg_send", |ctx, (proto, bytes): (u8, Table)| {
179✔
76
            let this_aux = ctx.globals().get::<AnyUserData>("core")?;
30✔
77
            let this = this_aux.borrow_mut::<Core>()?;
30✔
78
            let data = bytes
30✔
79
                .pairs::<i32, u8>()
30✔
80
                .filter_map(Result::ok)
30✔
81
                .map(|pair| pair.1)
30✔
82
                .collect::<Bytes>();
30✔
83
            debug!("lua subneg: {}", String::from_utf8_lossy(&data).to_mut());
30✔
84
            this.main_writer
30✔
85
                .send(Event::ProtoSubnegSend(proto, data))
30✔
86
                .unwrap();
30✔
87
            Ok(())
30✔
88
        });
30✔
89
        methods.add_function(
179✔
90
            "exec",
91
            |_, cmd: Value| -> Result<ExecResponse, mlua::Error> {
21✔
92
                match cmd {
21✔
93
                    Value::String(shell) => match exec(&shell.to_str()?) {
7✔
94
                        Ok(output) => Ok(ExecResponse::from(output)),
7✔
NEW
95
                        Err(err) => Err(mlua::Error::RuntimeError(err.to_string())),
×
96
                    },
97
                    Value::Table(strings) => {
14✔
98
                        let args: Vec<_> = strings.sequence_values::<String>().flatten().collect();
14✔
99
                        match exec_args(&args[..]) {
14✔
100
                            Ok(output) => Ok(ExecResponse::from(output)),
14✔
NEW
101
                            Err(err) => Err(mlua::Error::RuntimeError(err.to_string())),
×
102
                        }
103
                    }
NEW
104
                    _ => Err(mlua::Error::RuntimeError(String::from(
×
NEW
105
                        "argument #1 must be either a string or a table",
×
NEW
106
                    ))),
×
107
                }
108
            },
21✔
109
        );
110
        methods.add_function("time", |_, ()| -> Result<i64, mlua::Error> {
179✔
111
            Ok(chrono::Local::now().timestamp_millis())
7✔
112
        });
7✔
113
    }
179✔
114
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc