diff --git a/src/main/java/org/openautonomousconnection/luascript/events/JavaToLua.java b/src/main/java/org/openautonomousconnection/luascript/events/JavaToLua.java index dbd0312..a7fafb2 100644 --- a/src/main/java/org/openautonomousconnection/luascript/events/JavaToLua.java +++ b/src/main/java/org/openautonomousconnection/luascript/events/JavaToLua.java @@ -11,7 +11,8 @@ import java.util.Map; */ public final class JavaToLua { - private JavaToLua() { } + private JavaToLua() { + } public static LuaValue coerce(Object v) { if (v == null) return LuaValue.NIL; diff --git a/src/main/java/org/openautonomousconnection/luascript/events/LuaEventDispatcher.java b/src/main/java/org/openautonomousconnection/luascript/events/LuaEventDispatcher.java index 7d49573..ca8b4aa 100644 --- a/src/main/java/org/openautonomousconnection/luascript/events/LuaEventDispatcher.java +++ b/src/main/java/org/openautonomousconnection/luascript/events/LuaEventDispatcher.java @@ -1,11 +1,6 @@ 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.luaj.vm2.*; import org.openautonomousconnection.luascript.security.LuaExecutionPolicy; import org.openautonomousconnection.luascript.security.LuaSecurityManager; @@ -29,6 +24,10 @@ public final class LuaEventDispatcher { this.policy = Objects.requireNonNull(policy, "policy"); } + private static String key(String elementId, String event) { + return elementId + "\n" + event; + } + public void bind(String elementId, String eventName, String handlerPath) { Objects.requireNonNull(elementId, "elementId"); Objects.requireNonNull(eventName, "eventName"); @@ -93,8 +92,4 @@ public final class LuaEventDispatcher { t.set("data", d); return t; } - - private static String key(String elementId, String event) { - return elementId + "\n" + event; - } } diff --git a/src/main/java/org/openautonomousconnection/luascript/events/UiEvent.java b/src/main/java/org/openautonomousconnection/luascript/events/UiEvent.java index 1d889a1..d004912 100644 --- a/src/main/java/org/openautonomousconnection/luascript/events/UiEvent.java +++ b/src/main/java/org/openautonomousconnection/luascript/events/UiEvent.java @@ -7,27 +7,11 @@ import java.util.Objects; /** * Event passed from host into Lua. */ -public final class UiEvent { - - private final String targetId; - private final String type; - private final Map data; +public record UiEvent(String targetId, String type, Map data) { public UiEvent(String targetId, String type, Map data) { this.targetId = Objects.requireNonNull(targetId, "targetId"); this.type = Objects.requireNonNull(type, "type"); this.data = (data == null) ? Collections.emptyMap() : Collections.unmodifiableMap(data); } - - public String targetId() { - return targetId; - } - - public String type() { - return type; - } - - public Map data() { - return data; - } } \ No newline at end of file diff --git a/src/main/java/org/openautonomousconnection/luascript/events/UiEventRegistry.java b/src/main/java/org/openautonomousconnection/luascript/events/UiEventRegistry.java index ac3acaf..115e49d 100644 --- a/src/main/java/org/openautonomousconnection/luascript/events/UiEventRegistry.java +++ b/src/main/java/org/openautonomousconnection/luascript/events/UiEventRegistry.java @@ -7,7 +7,8 @@ import java.util.Locale; */ public final class UiEventRegistry { - private UiEventRegistry() { } + private UiEventRegistry() { + } public static String normalize(String eventName) { if (eventName == null) throw new IllegalArgumentException("eventName is null"); diff --git a/src/main/java/org/openautonomousconnection/luascript/hosts/ConsoleHost.java b/src/main/java/org/openautonomousconnection/luascript/hosts/ConsoleHost.java index 30e9be9..10493b9 100644 --- a/src/main/java/org/openautonomousconnection/luascript/hosts/ConsoleHost.java +++ b/src/main/java/org/openautonomousconnection/luascript/hosts/ConsoleHost.java @@ -4,18 +4,28 @@ package org.openautonomousconnection.luascript.hosts; * Host capability for console logging. */ public interface ConsoleHost { - /** @param message message */ + /** + * @param message message + */ void info(String message); - /** @param message message */ + /** + * @param message message + */ void log(String message); - /** @param message message */ + /** + * @param message message + */ void warn(String message); - /** @param message message */ + /** + * @param message message + */ void error(String message); - /** @param message message */ + /** + * @param message message + */ void exception(String message); } diff --git a/src/main/java/org/openautonomousconnection/luascript/hosts/DomHost.java b/src/main/java/org/openautonomousconnection/luascript/hosts/DomHost.java index 9ecd3e0..72a0034 100644 --- a/src/main/java/org/openautonomousconnection/luascript/hosts/DomHost.java +++ b/src/main/java/org/openautonomousconnection/luascript/hosts/DomHost.java @@ -45,7 +45,7 @@ public interface DomHost { * Sets the text content of an element. * * @param elementId element id - * @param text text + * @param text text */ void setTextContent(String elementId, String text); @@ -53,7 +53,7 @@ public interface DomHost { * Gets a single attribute or null if missing. * * @param elementId element id - * @param name attribute name + * @param name attribute name * @return value or null */ String getAttribute(String elementId, String name); @@ -62,8 +62,8 @@ public interface DomHost { * Sets an attribute (creates it if missing). * * @param elementId element id - * @param name attribute name - * @param value attribute value + * @param name attribute name + * @param value attribute value */ void setAttribute(String elementId, String name, String value); @@ -71,7 +71,7 @@ public interface DomHost { * Removes an attribute. * * @param elementId element id - * @param name attribute name + * @param name attribute name */ void removeAttribute(String elementId, String name); @@ -94,7 +94,7 @@ public interface DomHost { /** * Creates a new element (detached) and returns its id. * - * @param tagName tag name + * @param tagName tag name * @param requestedId optional requested id, may be null/blank for auto id * @return created element id */ @@ -111,15 +111,15 @@ public interface DomHost { * Moves/appends child under parent. * * @param parentId parent id - * @param childId child id + * @param childId child id */ void appendChild(String parentId, String childId); /** * Inserts child before an existing direct child. * - * @param parentId parent id - * @param childId child id + * @param parentId parent id + * @param childId child id * @param beforeChildId existing child id */ void insertBefore(String parentId, String childId, String beforeChildId); diff --git a/src/main/java/org/openautonomousconnection/luascript/hosts/HostServices.java b/src/main/java/org/openautonomousconnection/luascript/hosts/HostServices.java index 1bdb86c..364fc1c 100644 --- a/src/main/java/org/openautonomousconnection/luascript/hosts/HostServices.java +++ b/src/main/java/org/openautonomousconnection/luascript/hosts/HostServices.java @@ -24,6 +24,13 @@ public final class HostServices { this.resources = b.resources; } + /** + * @return builder + */ + public static Builder builder() { + return new Builder(); + } + /** * @return optional DomHost capability */ @@ -45,21 +52,20 @@ public final class HostServices { return Optional.ofNullable(resources); } - /** @return optional console host */ + /** + * @return optional console host + */ public Optional console() { return Optional.ofNullable(console); } - /** @return optional ui host */ + /** + * @return optional ui host + */ public Optional ui() { return Optional.ofNullable(ui); } - /** @return builder */ - public static Builder builder() { - return new Builder(); - } - /** * Builder for HostServices. */ diff --git a/src/main/java/org/openautonomousconnection/luascript/runtime/LuaRuntime.java b/src/main/java/org/openautonomousconnection/luascript/runtime/LuaRuntime.java index a234d66..068444f 100644 --- a/src/main/java/org/openautonomousconnection/luascript/runtime/LuaRuntime.java +++ b/src/main/java/org/openautonomousconnection/luascript/runtime/LuaRuntime.java @@ -5,10 +5,10 @@ import org.openautonomousconnection.luascript.events.LuaEventDispatcher; import org.openautonomousconnection.luascript.hosts.HostServices; import org.openautonomousconnection.luascript.security.LuaExecutionPolicy; import org.openautonomousconnection.luascript.security.LuaSecurityManager; -import org.openautonomousconnection.luascript.tables.console.ConsoleTable; import org.openautonomousconnection.luascript.tables.DomTable; import org.openautonomousconnection.luascript.tables.EventsTable; import org.openautonomousconnection.luascript.tables.UiTable; +import org.openautonomousconnection.luascript.tables.console.ConsoleTable; import java.util.Objects; diff --git a/src/main/java/org/openautonomousconnection/luascript/runtime/LuaScriptBootstrap.java b/src/main/java/org/openautonomousconnection/luascript/runtime/LuaScriptBootstrap.java index b0d615c..7810f91 100644 --- a/src/main/java/org/openautonomousconnection/luascript/runtime/LuaScriptBootstrap.java +++ b/src/main/java/org/openautonomousconnection/luascript/runtime/LuaScriptBootstrap.java @@ -17,7 +17,8 @@ import java.util.Objects; */ public final class LuaScriptBootstrap { - private LuaScriptBootstrap() { } + private LuaScriptBootstrap() { + } public static void bootstrap(Globals globals, HostServices services, LuaEventDispatcher dispatcher) { Objects.requireNonNull(globals, "globals"); diff --git a/src/main/java/org/openautonomousconnection/luascript/runtime/LuaScriptExecutor.java b/src/main/java/org/openautonomousconnection/luascript/runtime/LuaScriptExecutor.java index 61978bb..300672d 100644 --- a/src/main/java/org/openautonomousconnection/luascript/runtime/LuaScriptExecutor.java +++ b/src/main/java/org/openautonomousconnection/luascript/runtime/LuaScriptExecutor.java @@ -11,7 +11,8 @@ import java.util.Objects; */ public final class LuaScriptExecutor { - private LuaScriptExecutor() { } + private LuaScriptExecutor() { + } public static void execute(Globals globals, String source, String chunkName) { Objects.requireNonNull(globals, "globals"); diff --git a/src/main/java/org/openautonomousconnection/luascript/security/LuaExecutionPolicy.java b/src/main/java/org/openautonomousconnection/luascript/security/LuaExecutionPolicy.java index e0f1e8f..7df2b46 100644 --- a/src/main/java/org/openautonomousconnection/luascript/security/LuaExecutionPolicy.java +++ b/src/main/java/org/openautonomousconnection/luascript/security/LuaExecutionPolicy.java @@ -5,9 +5,9 @@ import java.time.Duration; /** * Execution policy for guarded Lua execution. * - * @param timeout max wall-clock time + * @param timeout max wall-clock time * @param instructionLimit max VM instruction budget (approximation via debug hook) - * @param hookStep number of VM instructions between hook ticks + * @param hookStep number of VM instructions between hook ticks */ public record LuaExecutionPolicy(Duration timeout, long instructionLimit, int hookStep) { diff --git a/src/main/java/org/openautonomousconnection/luascript/security/LuaSecurityManager.java b/src/main/java/org/openautonomousconnection/luascript/security/LuaSecurityManager.java index df749c4..fa3abfe 100644 --- a/src/main/java/org/openautonomousconnection/luascript/security/LuaSecurityManager.java +++ b/src/main/java/org/openautonomousconnection/luascript/security/LuaSecurityManager.java @@ -28,39 +28,6 @@ public final class LuaSecurityManager implements AutoCloseable { }); } - /** - * Executes a Lua function guarded by the provided policy. - * - * @param globals globals/environment - * @param function function to execute - * @param args arguments - * @param policy execution policy - * @return results (Lua varargs) - */ - public Varargs callGuarded(Globals globals, LuaFunction function, Varargs args, LuaExecutionPolicy policy) { - Objects.requireNonNull(globals, "globals"); - Objects.requireNonNull(function, "function"); - Objects.requireNonNull(args, "args"); - Objects.requireNonNull(policy, "policy"); - - Future f = executor.submit(() -> callWithHook(globals, function, args, policy)); - - try { - return f.get(policy.timeout().toMillis(), TimeUnit.MILLISECONDS); - } catch (TimeoutException e) { - f.cancel(true); - throw new LuaError("Lua execution timed out after " + policy.timeout().toMillis() + "ms"); - } catch (ExecutionException e) { - Throwable c = e.getCause(); - if (c instanceof LuaError le) throw le; - if (c instanceof RuntimeException re) throw re; - throw new RuntimeException(c); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException("Interrupted while waiting for Lua execution", e); - } - } - private static Varargs callWithHook(Globals globals, LuaFunction function, Varargs args, LuaExecutionPolicy policy) { final LuaValue sethook = resolveAndHideDebugSetHook(globals); @@ -136,6 +103,39 @@ public final class LuaSecurityManager implements AutoCloseable { return sethook; } + /** + * Executes a Lua function guarded by the provided policy. + * + * @param globals globals/environment + * @param function function to execute + * @param args arguments + * @param policy execution policy + * @return results (Lua varargs) + */ + public Varargs callGuarded(Globals globals, LuaFunction function, Varargs args, LuaExecutionPolicy policy) { + Objects.requireNonNull(globals, "globals"); + Objects.requireNonNull(function, "function"); + Objects.requireNonNull(args, "args"); + Objects.requireNonNull(policy, "policy"); + + Future f = executor.submit(() -> callWithHook(globals, function, args, policy)); + + try { + return f.get(policy.timeout().toMillis(), TimeUnit.MILLISECONDS); + } catch (TimeoutException e) { + f.cancel(true); + throw new LuaError("Lua execution timed out after " + policy.timeout().toMillis() + "ms"); + } catch (ExecutionException e) { + Throwable c = e.getCause(); + if (c instanceof LuaError le) throw le; + if (c instanceof RuntimeException re) throw re; + throw new RuntimeException(c); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Interrupted while waiting for Lua execution", e); + } + } + @Override public void close() { executor.shutdownNow(); diff --git a/src/main/java/org/openautonomousconnection/luascript/tables/DomTable.java b/src/main/java/org/openautonomousconnection/luascript/tables/DomTable.java index d07be76..75ab565 100644 --- a/src/main/java/org/openautonomousconnection/luascript/tables/DomTable.java +++ b/src/main/java/org/openautonomousconnection/luascript/tables/DomTable.java @@ -2,10 +2,13 @@ package org.openautonomousconnection.luascript.tables; import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaValue; -import org.luaj.vm2.lib.*; -import org.openautonomousconnection.luascript.utils.ScriptTable; +import org.luaj.vm2.lib.OneArgFunction; +import org.luaj.vm2.lib.ThreeArgFunction; +import org.luaj.vm2.lib.TwoArgFunction; +import org.luaj.vm2.lib.ZeroArgFunction; import org.openautonomousconnection.luascript.hosts.DomHost; import org.openautonomousconnection.luascript.hosts.HostServices; +import org.openautonomousconnection.luascript.utils.ScriptTable; import java.util.List; import java.util.Map; @@ -21,6 +24,17 @@ public final class DomTable extends ScriptTable { super("dom"); } + private static LuaValue toLuaArray(List values) { + LuaTable t = new LuaTable(); + if (values == null || values.isEmpty()) return t; + + int i = 1; + for (String v : values) { + t.set(i++, v == null ? LuaValue.NIL : LuaValue.valueOf(v)); + } + return t; + } + @Override protected void define(HostServices services) { DomHost dom = services.dom().orElseThrow(() -> new IllegalStateException("DomHost not provided")); @@ -165,15 +179,4 @@ public final class DomTable extends ScriptTable { } }); } - - private static LuaValue toLuaArray(List values) { - LuaTable t = new LuaTable(); - if (values == null || values.isEmpty()) return t; - - int i = 1; - for (String v : values) { - t.set(i++, v == null ? LuaValue.NIL : LuaValue.valueOf(v)); - } - return t; - } } diff --git a/src/main/java/org/openautonomousconnection/luascript/tables/EventsTable.java b/src/main/java/org/openautonomousconnection/luascript/tables/EventsTable.java index dc25d86..d75ad1b 100644 --- a/src/main/java/org/openautonomousconnection/luascript/tables/EventsTable.java +++ b/src/main/java/org/openautonomousconnection/luascript/tables/EventsTable.java @@ -3,11 +3,11 @@ package org.openautonomousconnection.luascript.tables; import org.luaj.vm2.LuaValue; import org.luaj.vm2.lib.OneArgFunction; import org.luaj.vm2.lib.TwoArgFunction; -import org.openautonomousconnection.luascript.utils.ScriptTable; import org.openautonomousconnection.luascript.events.LuaEventDispatcher; import org.openautonomousconnection.luascript.events.UiEventRegistry; import org.openautonomousconnection.luascript.hosts.EventHost; import org.openautonomousconnection.luascript.hosts.HostServices; +import org.openautonomousconnection.luascript.utils.ScriptTable; /** * events namespace for manual binding/unbinding. diff --git a/src/main/java/org/openautonomousconnection/luascript/tables/UiTable.java b/src/main/java/org/openautonomousconnection/luascript/tables/UiTable.java index 14756c0..2cc7d85 100644 --- a/src/main/java/org/openautonomousconnection/luascript/tables/UiTable.java +++ b/src/main/java/org/openautonomousconnection/luascript/tables/UiTable.java @@ -3,9 +3,9 @@ package org.openautonomousconnection.luascript.tables; import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaValue; import org.luaj.vm2.lib.OneArgFunction; -import org.openautonomousconnection.luascript.utils.ScriptTable; import org.openautonomousconnection.luascript.hosts.HostServices; import org.openautonomousconnection.luascript.hosts.UiHost; +import org.openautonomousconnection.luascript.utils.ScriptTable; /** * ui namespace for common UI operations. @@ -55,7 +55,8 @@ public final class UiTable extends ScriptTable { }); table().set("getText", new OneArgFunction() { - @Override public LuaValue call(LuaValue id) { + @Override + public LuaValue call(LuaValue id) { String v = ui.getText(id.checkjstring()); return v == null ? LuaValue.NIL : LuaValue.valueOf(v); } diff --git a/src/main/java/org/openautonomousconnection/luascript/tables/console/ConsoleLogTable.java b/src/main/java/org/openautonomousconnection/luascript/tables/console/ConsoleLogTable.java index 4a7063b..017237f 100644 --- a/src/main/java/org/openautonomousconnection/luascript/tables/console/ConsoleLogTable.java +++ b/src/main/java/org/openautonomousconnection/luascript/tables/console/ConsoleLogTable.java @@ -2,8 +2,8 @@ package org.openautonomousconnection.luascript.tables.console; import org.luaj.vm2.LuaValue; import org.luaj.vm2.lib.OneArgFunction; -import org.openautonomousconnection.luascript.utils.ScriptTable; import org.openautonomousconnection.luascript.hosts.HostServices; +import org.openautonomousconnection.luascript.utils.ScriptTable; public class ConsoleLogTable extends ScriptTable { /** diff --git a/src/main/java/org/openautonomousconnection/luascript/utils/LuaGlobalsFactory.java b/src/main/java/org/openautonomousconnection/luascript/utils/LuaGlobalsFactory.java index 0b30a10..cfcca18 100644 --- a/src/main/java/org/openautonomousconnection/luascript/utils/LuaGlobalsFactory.java +++ b/src/main/java/org/openautonomousconnection/luascript/utils/LuaGlobalsFactory.java @@ -22,48 +22,7 @@ import java.util.function.Consumer; */ public final class LuaGlobalsFactory { - private LuaGlobalsFactory() { } - - /** - * Configuration options for creating a {@link Globals} instance. - */ - public static final class Options { - private boolean enableDebug; - private boolean sandbox; - private Consumer hostApiConfigurer; - - /** - * Enables or disables Lua debug library exposure. - * - * @param enableDebug true to enable debug lib, false otherwise - * @return this options instance - */ - public Options enableDebug(boolean enableDebug) { - this.enableDebug = enableDebug; - return this; - } - - /** - * Enables or disables sandbox hardening (disables os/io/debug/luajava/package/require/loadfile/dofile). - * - * @param sandbox true to harden, false otherwise - * @return this options instance - */ - public Options sandbox(boolean sandbox) { - this.sandbox = sandbox; - return this; - } - - /** - * Adds a hook to register host APIs (e.g. {@code host.ui.alert}). - * - * @param hostApiConfigurer configurer callback - * @return this options instance - */ - public Options hostApiConfigurer(Consumer hostApiConfigurer) { - this.hostApiConfigurer = hostApiConfigurer; - return this; - } + private LuaGlobalsFactory() { } /** @@ -134,4 +93,46 @@ public final class LuaGlobalsFactory { g.set("host", host); return host; } + + /** + * Configuration options for creating a {@link Globals} instance. + */ + public static final class Options { + private boolean enableDebug; + private boolean sandbox; + private Consumer hostApiConfigurer; + + /** + * Enables or disables Lua debug library exposure. + * + * @param enableDebug true to enable debug lib, false otherwise + * @return this options instance + */ + public Options enableDebug(boolean enableDebug) { + this.enableDebug = enableDebug; + return this; + } + + /** + * Enables or disables sandbox hardening (disables os/io/debug/luajava/package/require/loadfile/dofile). + * + * @param sandbox true to harden, false otherwise + * @return this options instance + */ + public Options sandbox(boolean sandbox) { + this.sandbox = sandbox; + return this; + } + + /** + * Adds a hook to register host APIs (e.g. {@code host.ui.alert}). + * + * @param hostApiConfigurer configurer callback + * @return this options instance + */ + public Options hostApiConfigurer(Consumer hostApiConfigurer) { + this.hostApiConfigurer = hostApiConfigurer; + return this; + } + } } diff --git a/src/main/java/org/openautonomousconnection/luascript/utils/ScriptTable.java b/src/main/java/org/openautonomousconnection/luascript/utils/ScriptTable.java index 961651d..4cf97e5 100644 --- a/src/main/java/org/openautonomousconnection/luascript/utils/ScriptTable.java +++ b/src/main/java/org/openautonomousconnection/luascript/utils/ScriptTable.java @@ -38,8 +38,8 @@ public abstract class ScriptTable { /** * Injects this table into globals as a global namespace (e.g. "ui", "console", "events"). * - * @param globals globals - * @param services services + * @param globals globals + * @param services services * @param overwriteExisting overwrite existing global */ public final void inject(Globals globals, HostServices services, boolean overwriteExisting) { @@ -58,8 +58,8 @@ public abstract class ScriptTable { /** * Injects a child table as a nested namespace (e.g. ui.modal.*). * - * @param child child table - * @param services host services + * @param child child table + * @param services host services * @param overwriteExisting overwrite if key exists */ public final void injectChild(ScriptTable child, HostServices services, boolean overwriteExisting) {