more lua api stuff

This commit is contained in:
Luuk van Oijen
2023-11-12 16:29:22 +01:00
parent 8ee6ba16f2
commit a23b5a43c0
5 changed files with 79 additions and 25 deletions

View File

@@ -1,5 +1,31 @@
use super::Backend;
use super::{Backend, ServerBoundPluginEvent};
use std::sync::Arc;
use tokio::sync::mpsc::Sender;
use mlua::prelude::*;
use mlua::{UserData, UserDataMethods};
struct Context {
tx: Arc<Sender<ServerBoundPluginEvent>>,
}
impl Context {
fn new(tx: Arc<Sender<ServerBoundPluginEvent>>) -> Self {
Self {
tx,
}
}
}
impl UserData for Context {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("RegisterEventHandler", |_, me, (event_name, handler_name): (String, String)| {
debug!("Event handler registered: {} (EVENT) = {} (LUA)", event_name, handler_name);
// TODO: Figure out how to handle these errors (?)
let _ = me.tx.blocking_send(ServerBoundPluginEvent::RegisterEventHandler((event_name, handler_name)));
Ok(())
});
}
}
pub struct BackendLua {
lua: Lua,
@@ -21,17 +47,24 @@ impl Backend for BackendLua {
Ok(())
}
fn load_api(&mut self) -> anyhow::Result<()> {
fn load_api(&mut self, tx: Arc<Sender<ServerBoundPluginEvent>>) -> anyhow::Result<()> {
let print_fn = self.lua.create_function(|_lua, (msg,): (String,)| {
info!("[LUA] {}", msg);
Ok(())
})?;
let api = self.lua.create_table()?;
// let register_event_handler_fn = self.lua.create_function(|_lua, (name, handler_name): (String, String)| {
// tx.blocking_send(ServerBoundPluginEvent::RegisterEventHandler((name, handler_name)));
// Ok(())
// })?;
api.set("print", print_fn)?;
// let api = self.lua.create_table()?;
let api = Context::new(tx);
// api.set("", thing)?;
self.lua.globals().set("MP", api)?;
let globals = self.lua.globals();
globals.set("MP", api)?;
globals.set("print", print_fn)?;
Ok(())
}

View File

@@ -1,21 +1,34 @@
pub mod backend_lua;
use std::sync::Arc;
use tokio::runtime::Runtime;
use tokio::sync::Mutex;
use tokio::sync::mpsc::{self, Sender, Receiver};
pub trait Backend {
/// NOTE: Send is required as the backend is constructed on the main thread and sent over.
/// Even if we construct it inside the runtime however, because of tokio, we would
// still have to require Send as the runtime might run on different threads (?)
pub trait Backend: Send {
fn load(&mut self, code: String) -> anyhow::Result<()>;
fn load_api(&mut self) -> anyhow::Result<()> { Ok(()) }
fn load_api(&mut self, tx: Arc<Sender<ServerBoundPluginEvent>>) -> anyhow::Result<()> { Ok(()) }
}
#[derive(Debug)]
pub enum Argument {
Number(f32),
}
#[derive(Debug)]
pub enum PluginBoundPluginEvent {
CallEventHandler((String, Vec<Argument>))
}
#[derive(Debug)]
pub enum ServerBoundPluginEvent {
PluginLoaded,
/// Arguments: (event name, handler function name)
RegisterEventHandler((String, String)),
}
pub struct Plugin {
@@ -25,27 +38,33 @@ pub struct Plugin {
}
impl Plugin {
pub fn new(backend: Box<dyn Backend>) -> Self {
pub fn new(mut backend: Box<dyn Backend>, src: String) -> anyhow::Result<Self> {
let runtime = Runtime::new().expect("Failed to create a tokio Runtime!");
let (pb_tx, mut pb_rx) = mpsc::channel(1_000);
let (sb_tx, sb_rx) = mpsc::channel(1_000);
runtime.spawn(async move {
if sb_tx.send(ServerBoundPluginEvent::PluginLoaded).await.is_err() {
error!("Plugin communication channels somehow already closed!");
return;
let sb_tx = Arc::new(sb_tx);
runtime.spawn_blocking(move || {
if backend.load_api(sb_tx.clone()).is_ok() {
if backend.load(src).is_ok() {
if sb_tx.blocking_send(ServerBoundPluginEvent::PluginLoaded).is_err() {
error!("Plugin communication channels somehow already closed!");
return;
}
}
}
loop {
if let Some(message) = pb_rx.recv().await {
if let Some(message) = pb_rx.blocking_recv() {
debug!("Received message: {:?}", message);
} else {
return;
}
}
});
Self {
Ok(Self {
runtime,
tx: pb_tx,
rx: sb_rx,
}
})
}
}