Files
LuaScript/src/main/java/org/openautonomousconnection/luascript/events/LuaEventDispatcher.java
2026-01-16 21:47:04 +01:00

101 lines
3.6 KiB
Java

package org.openautonomousconnection.luascript.events;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaFunction;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.openautonomousconnection.luascript.security.LuaExecutionPolicy;
import org.openautonomousconnection.luascript.security.LuaSecurityManager;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* Stores bindings (elementId,eventName -> handlerPath) and dispatches events into Lua.
*/
public final class LuaEventDispatcher {
private final Globals globals;
private final LuaSecurityManager securityManager;
private final LuaExecutionPolicy policy;
private final ConcurrentHashMap<String, String> bindings = new ConcurrentHashMap<>();
public LuaEventDispatcher(Globals globals, LuaSecurityManager securityManager, LuaExecutionPolicy policy) {
this.globals = Objects.requireNonNull(globals, "globals");
this.securityManager = Objects.requireNonNull(securityManager, "securityManager");
this.policy = Objects.requireNonNull(policy, "policy");
}
public void bind(String elementId, String eventName, String handlerPath) {
Objects.requireNonNull(elementId, "elementId");
Objects.requireNonNull(eventName, "eventName");
Objects.requireNonNull(handlerPath, "handlerPath");
String k = key(elementId, UiEventRegistry.normalize(eventName));
bindings.put(k, handlerPath);
}
public void unbind(String elementId, String eventName) {
Objects.requireNonNull(elementId, "elementId");
Objects.requireNonNull(eventName, "eventName");
bindings.remove(key(elementId, UiEventRegistry.normalize(eventName)));
}
public boolean hasBinding(String elementId, String eventName) {
return bindings.containsKey(key(elementId, UiEventRegistry.normalize(eventName)));
}
public boolean dispatch(UiEvent event) {
Objects.requireNonNull(event, "event");
String k = key(event.targetId(), UiEventRegistry.normalize(event.type()));
String handlerPath = bindings.get(k);
if (handlerPath == null) return false;
LuaValue fn = resolvePath(handlerPath);
if (fn.isnil() || !fn.isfunction()) {
throw new LuaError("Handler is not a function: " + handlerPath);
}
LuaValue eventTable = toLuaEvent(event);
Varargs args = LuaValue.varargsOf(new LuaValue[]{eventTable});
securityManager.callGuarded(globals, (LuaFunction) fn, args, policy);
return true;
}
private LuaValue resolvePath(String path) {
String[] parts = path.split("\\.");
LuaValue cur = globals;
for (String p : parts) {
String key = p.trim();
if (key.isEmpty()) throw new LuaError("Invalid handler path: " + path);
cur = cur.get(key);
if (cur.isnil()) return LuaValue.NIL;
}
return cur;
}
private LuaValue toLuaEvent(UiEvent event) {
LuaTable t = new LuaTable();
t.set("target", LuaValue.valueOf(event.targetId()));
t.set("type", LuaValue.valueOf(event.type()));
LuaTable d = new LuaTable();
for (Map.Entry<String, Object> e : event.data().entrySet()) {
String k = e.getKey();
if (k == null) continue;
d.set(k, JavaToLua.coerce(e.getValue()));
}
t.set("data", d);
return t;
}
private static String key(String elementId, String event) {
return elementId + "\n" + event;
}
}