From d7a97c76f12a9398d4508b417e073d4f5124f217 Mon Sep 17 00:00:00 2001 From: Hiram Chirino Date: Sat, 29 Mar 2025 09:18:07 -0400 Subject: [PATCH 1/2] Split the Handler interface out into interfaces grouped by function. Signed-off-by: Hiram Chirino --- .../java/io/roastedroot/proxywasm/ABI.java | 2 +- .../roastedroot/proxywasm/ContextHandler.java | 23 + .../roastedroot/proxywasm/CustomHandler.java | 40 ++ .../io/roastedroot/proxywasm/FFIHandler.java | 26 ++ .../proxywasm/GRPCContextHandler.java | 60 +++ .../io/roastedroot/proxywasm/Handler.java | 420 +----------------- .../proxywasm/HttpCallHandler.java | 47 ++ .../proxywasm/HttpContextHandler.java | 59 +++ .../io/roastedroot/proxywasm/LogHandler.java | 10 + .../roastedroot/proxywasm/MetricsHandler.java | 24 + .../roastedroot/proxywasm/PluginHandler.java | 44 ++ .../proxywasm/PropertiesHandler.java | 14 + .../io/roastedroot/proxywasm/SharedData.java | 11 + .../proxywasm/SharedDataHandler.java | 12 + .../proxywasm/SharedQueueHandler.java | 20 + .../proxywasm/StreamContextHandler.java | 69 +++ .../roastedroot/proxywasm/plugin/Plugin.java | 40 ++ .../proxywasm/examples/MockSharedHandler.java | 1 + 18 files changed, 514 insertions(+), 408 deletions(-) create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ContextHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/CustomHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/FFIHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/GRPCContextHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpCallHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpContextHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PluginHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PropertiesHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/StreamContextHandler.java diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java index c2b663e..be620fd 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java @@ -1592,7 +1592,7 @@ int proxyGetSharedData( String key = string(readMemory(keyDataPtr, keySize)); // Get shared data value using handler - Handler.SharedData value = handler.getSharedData(key); + SharedData value = handler.getSharedData(key); if (value == null) { return WasmResult.NOT_FOUND.getValue(); } diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ContextHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ContextHandler.java new file mode 100644 index 0000000..5af83c5 --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ContextHandler.java @@ -0,0 +1,23 @@ +package io.roastedroot.proxywasm; + +public interface ContextHandler { + + /** + * Set the effective context ID. + * + * @param contextID The context ID + * @return The result of the operation + */ + default WasmResult setEffectiveContextID(int contextID) { + return WasmResult.UNIMPLEMENTED; + } + + /** + * Indicates to the host that the plugin is done processing active context. + * + * @return The result of the operation + */ + default WasmResult done() { + return WasmResult.NOT_FOUND; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/CustomHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/CustomHandler.java new file mode 100644 index 0000000..8ced4ba --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/CustomHandler.java @@ -0,0 +1,40 @@ +package io.roastedroot.proxywasm; + +public interface CustomHandler { + + /** + * Get a custom buffer. + * + * @param bufferType The buffer type + * @return The custom buffer as a byte[], or null if not available + */ + default byte[] getCustomBuffer(int bufferType) { + return null; + } + + /** + * Set a custom buffer. + * + * @param bufferType The buffer type + * @param buffer The custom buffer as a byte[] + * @return WasmResult indicating success or failure + */ + default WasmResult setCustomBuffer(int bufferType, byte[] buffer) { + return WasmResult.UNIMPLEMENTED; + } + + default ProxyMap getCustomHeaders(int mapType) { + return null; + } + + /** + * Set a custom header map. + * + * @param mapType The type of map to set + * @param map The header map to set + * @return WasmResult indicating success or failure + */ + default WasmResult setCustomHeaders(int mapType, ProxyMap map) { + return WasmResult.UNIMPLEMENTED; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/FFIHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/FFIHandler.java new file mode 100644 index 0000000..76c58e4 --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/FFIHandler.java @@ -0,0 +1,26 @@ +package io.roastedroot.proxywasm; + +public interface FFIHandler { + /** + * Get the function call data. + * + * @return The function call data as a byte[], or null if not available + */ + default byte[] getFuncCallData() { + return null; + } + + /** + * Set the function call data. + * + * @param data The function call data as a byte[] + * @return WasmResult indicating success or failure + */ + default WasmResult setFuncCallData(byte[] data) { + return WasmResult.UNIMPLEMENTED; + } + + default ForeignFunction getForeignFunction(String name) { + return null; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/GRPCContextHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/GRPCContextHandler.java new file mode 100644 index 0000000..08ca2dc --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/GRPCContextHandler.java @@ -0,0 +1,60 @@ +package io.roastedroot.proxywasm; + +public interface GRPCContextHandler extends StreamContextHandler { + + default ProxyMap getGrpcReceiveInitialMetaData() { + return null; + } + + default ProxyMap getGrpcReceiveTrailerMetaData() { + return null; + } + + /** + * Get the gRPC receive buffer. + * + * @return The gRPC receive buffer as a byte[], or null if not available + */ + default byte[] getGrpcReceiveBuffer() { + return null; + } + + /** + * Set the gRPC receive buffer. + * + * @param buffer The gRPC receive buffer as a byte[] + * @return WasmResult indicating success or failure + */ + default WasmResult setGrpcReceiveBuffer(byte[] buffer) { + return WasmResult.UNIMPLEMENTED; + } + + default int grpcCall( + String upstreamName, + String serviceName, + String methodName, + ProxyMap initialMetadata, + byte[] message, + int timeout) + throws WasmException { + throw new WasmException(WasmResult.UNIMPLEMENTED); + } + + default int grpcStream( + String upstreamName, String serviceName, String methodName, ProxyMap initialMetadata) + throws WasmException { + throw new WasmException(WasmResult.UNIMPLEMENTED); + } + + default WasmResult grpcSend(int streamId, byte[] message, int endStream) { + return WasmResult.UNIMPLEMENTED; + } + + default WasmResult grpcCancel(int callOrstreamId) { + return WasmResult.UNIMPLEMENTED; + } + + default WasmResult grpcClose(int callOrstreamId) { + return WasmResult.UNIMPLEMENTED; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Handler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Handler.java index 7d7c333..c8b8179 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Handler.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/Handler.java @@ -1,415 +1,21 @@ package io.roastedroot.proxywasm; -import java.util.List; +public interface Handler + extends ContextHandler, + LogHandler, + PluginHandler, + PropertiesHandler, + HttpContextHandler, + HttpCallHandler, + SharedDataHandler, + SharedQueueHandler, + FFIHandler, + GRPCContextHandler, + MetricsHandler, + CustomHandler { -public interface Handler { /** * The default handler. It holds no state. */ Handler DEFAULT = new Handler() {}; - - default void log(LogLevel level, String message) throws WasmException {} - - default LogLevel getLogLevel() throws WasmException { - return LogLevel.TRACE; - } - - // TODO: use a better type than Map so that we can support repeated headers - default ProxyMap getHttpRequestHeaders() { - return null; - } - - default ProxyMap getHttpRequestTrailers() { - return null; - } - - default ProxyMap getHttpResponseHeaders() { - return null; - } - - default ProxyMap getHttpResponseTrailers() { - return null; - } - - default ProxyMap getHttpCallResponseHeaders() { - return null; - } - - default ProxyMap getHttpCallResponseTrailers() { - return null; - } - - default ProxyMap getGrpcReceiveInitialMetaData() { - return null; - } - - default ProxyMap getGrpcReceiveTrailerMetaData() { - return null; - } - - default ProxyMap getCustomHeaders(int mapType) { - return null; - } - - default byte[] getProperty(List key) throws WasmException { - return null; - } - - default WasmResult setProperty(List path, byte[] value) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Get the HTTP request body. - * - * @return The HTTP request body as a byte[], or null if not available - */ - default byte[] getHttpRequestBody() { - return null; - } - - /** - * Get the HTTP response body. - * - * @return The HTTP response body as a byte[], or null if not available - */ - default byte[] getHttpResponseBody() { - return null; - } - - /** - * Get the downstream data. - * - * @return The downstream data as a byte[], or null if not available - */ - default byte[] getDownStreamData() { - return null; - } - - /** - * Get the upstream data. - * - * @return The upstream data as a byte[], or null if not available - */ - default byte[] getUpstreamData() { - return null; - } - - /** - * Get the HTTP call response body. - * - * @return The HTTP call response body as a byte[], or null if not available - */ - default byte[] getHttpCallResponseBody() { - return null; - } - - /** - * Get the gRPC receive buffer. - * - * @return The gRPC receive buffer as a byte[], or null if not available - */ - default byte[] getGrpcReceiveBuffer() { - return null; - } - - /** - * Get the plugin configuration. - * - * @return The plugin configuration as a byte[], or null if not available - */ - default byte[] getPluginConfig() { - return null; - } - - /** - * Get the VM configuration. - * - * @return The VM configuration as a byte[], or null if not available - */ - default byte[] getVmConfig() { - return null; - } - - /** - * Get the function call data. - * - * @return The function call data as a byte[], or null if not available - */ - default byte[] getFuncCallData() { - return null; - } - - /** - * Get a custom buffer. - * - * @param bufferType The buffer type - * @return The custom buffer as a byte[], or null if not available - */ - default byte[] getCustomBuffer(int bufferType) { - return null; - } - - /** - * Set the effective context ID. - * - * @param contextID The context ID - * @return The result of the operation - */ - default WasmResult setEffectiveContextID(int contextID) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Indicates to the host that the plugin is done processing active context. - * - * @return The result of the operation - */ - default WasmResult done() { - return WasmResult.NOT_FOUND; - } - - /** - * Sets a low-resolution timer period (tick_period). - * - * When set, the host will call proxy_on_tick every tickPeriodMilliseconds milliseconds. Setting tickPeriodMilliseconds to 0 disables the timer. - * - * @return The current time in nanoseconds - */ - default WasmResult setTickPeriodMilliseconds(int tickPeriodMilliseconds) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Retrieves current time or the approximation of it. - * - * Note Hosts might return approximate time (e.g. frozen at the context creation) to improve performance and/or prevent various attacks. - * - * @return The current time in nanoseconds - */ - default int getCurrentTimeNanoseconds() throws WasmException { - return (int) System.currentTimeMillis() * 1000000; - } - - /** - * Send an HTTP response. - * - * @param responseCode The HTTP response code - * @param responseCodeDetails The response code details - * @param responseBody The response body - * @param additionalHeaders Additional headers to include - * @param grpcStatus The gRPC status code (-1 for non-gRPC responses) - * @return The result of sending the response - */ - default WasmResult sendHttpResponse( - int responseCode, - byte[] responseCodeDetails, - byte[] responseBody, - ProxyMap additionalHeaders, - int grpcStatus) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Set the HTTP request body. - * - * @param body The HTTP request body as a byte[] - * @return WasmResult indicating success or failure - */ - default WasmResult setHttpRequestBody(byte[] body) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Set the HTTP response body. - * - * @param body The HTTP response body as a byte[] - * @return WasmResult indicating success or failure - */ - default WasmResult setHttpResponseBody(byte[] body) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Set the downstream data. - * - * @param data The downstream data as a byte[] - * @return WasmResult indicating success or failure - */ - default WasmResult setDownStreamData(byte[] data) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Set the upstream data. - * - * @param data The upstream data as a byte[] - * @return WasmResult indicating success or failure - */ - default WasmResult setUpstreamData(byte[] data) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Set the HTTP call response body. - * - * @param body The HTTP call response body as a byte[] - * @return WasmResult indicating success or failure - */ - default WasmResult setHttpCallResponseBody(byte[] body) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Set the gRPC receive buffer. - * - * @param buffer The gRPC receive buffer as a byte[] - * @return WasmResult indicating success or failure - */ - default WasmResult setGrpcReceiveBuffer(byte[] buffer) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Set the function call data. - * - * @param data The function call data as a byte[] - * @return WasmResult indicating success or failure - */ - default WasmResult setFuncCallData(byte[] data) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Set a custom buffer. - * - * @param bufferType The buffer type - * @param buffer The custom buffer as a byte[] - * @return WasmResult indicating success or failure - */ - default WasmResult setCustomBuffer(int bufferType, byte[] buffer) { - return WasmResult.UNIMPLEMENTED; - } - - /** - * Set a custom header map. - * - * @param mapType The type of map to set - * @param map The header map to set - * @return WasmResult indicating success or failure - */ - default WasmResult setCustomHeaders(int mapType, ProxyMap map) { - return WasmResult.UNIMPLEMENTED; - } - - default WasmResult setAction(StreamType streamType, Action action) { - return WasmResult.UNIMPLEMENTED; - } - - default WasmResult clearRouteCache() { - return WasmResult.UNIMPLEMENTED; - } - - default int httpCall( - String uri, ProxyMap headers, byte[] body, ProxyMap trailers, int timeoutMilliseconds) - throws WasmException { - throw new WasmException(WasmResult.UNIMPLEMENTED); - } - - default int dispatchHttpCall( - String upstreamName, - ProxyMap headers, - byte[] body, - ProxyMap trailers, - int timeoutMilliseconds) - throws WasmException { - throw new WasmException(WasmResult.UNIMPLEMENTED); - } - - default ForeignFunction getForeignFunction(String name) { - return null; - } - - default int defineMetric(MetricType metricType, String name) throws WasmException { - throw new WasmException(WasmResult.UNIMPLEMENTED); - } - - default WasmResult removeMetric(int metricId) { - return WasmResult.UNIMPLEMENTED; - } - - default WasmResult recordMetric(int metricId, long value) { - return WasmResult.UNIMPLEMENTED; - } - - default WasmResult incrementMetric(int metricId, long value) { - return WasmResult.UNIMPLEMENTED; - } - - default long getMetric(int metricId) throws WasmException { - throw new WasmException(WasmResult.UNIMPLEMENTED); - } - - default int grpcCall( - String upstreamName, - String serviceName, - String methodName, - ProxyMap initialMetadata, - byte[] message, - int timeout) - throws WasmException { - throw new WasmException(WasmResult.UNIMPLEMENTED); - } - - default int grpcStream( - String upstreamName, String serviceName, String methodName, ProxyMap initialMetadata) - throws WasmException { - throw new WasmException(WasmResult.UNIMPLEMENTED); - } - - default WasmResult grpcSend(int streamId, byte[] message, int endStream) { - return WasmResult.UNIMPLEMENTED; - } - - default WasmResult grpcCancel(int callOrstreamId) { - return WasmResult.UNIMPLEMENTED; - } - - default WasmResult grpcClose(int callOrstreamId) { - return WasmResult.UNIMPLEMENTED; - } - - class SharedData { - public byte[] data; - public int cas; - - public SharedData(byte[] data, int cas) { - this.data = data; - this.cas = cas; - } - } - - default SharedData getSharedData(String key) throws WasmException { - throw new WasmException(WasmResult.UNIMPLEMENTED); - } - - default WasmResult setSharedData(String key, byte[] value, int cas) { - return WasmResult.UNIMPLEMENTED; - } - - default int registerSharedQueue(QueueName name) throws WasmException { - throw new WasmException(WasmResult.UNIMPLEMENTED); - } - - default int resolveSharedQueue(QueueName name) throws WasmException { - throw new WasmException(WasmResult.UNIMPLEMENTED); - } - - default byte[] dequeueSharedQueue(int queueId) throws WasmException { - throw new WasmException(WasmResult.UNIMPLEMENTED); - } - - default WasmResult enqueueSharedQueue(int queueId, byte[] value) { - return WasmResult.UNIMPLEMENTED; - } } diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpCallHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpCallHandler.java new file mode 100644 index 0000000..3bbd8e3 --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpCallHandler.java @@ -0,0 +1,47 @@ +package io.roastedroot.proxywasm; + +public interface HttpCallHandler { + + default int httpCall( + String uri, ProxyMap headers, byte[] body, ProxyMap trailers, int timeoutMilliseconds) + throws WasmException { + throw new WasmException(WasmResult.UNIMPLEMENTED); + } + + default int dispatchHttpCall( + String upstreamName, + ProxyMap headers, + byte[] body, + ProxyMap trailers, + int timeoutMilliseconds) + throws WasmException { + throw new WasmException(WasmResult.UNIMPLEMENTED); + } + + /** + * Set the HTTP call response body. + * + * @param body The HTTP call response body as a byte[] + * @return WasmResult indicating success or failure + */ + default WasmResult setHttpCallResponseBody(byte[] body) { + return WasmResult.UNIMPLEMENTED; + } + + default ProxyMap getHttpCallResponseHeaders() { + return null; + } + + default ProxyMap getHttpCallResponseTrailers() { + return null; + } + + /** + * Get the HTTP call response body. + * + * @return The HTTP call response body as a byte[], or null if not available + */ + default byte[] getHttpCallResponseBody() { + return null; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpContextHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpContextHandler.java new file mode 100644 index 0000000..e07b52d --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/HttpContextHandler.java @@ -0,0 +1,59 @@ +package io.roastedroot.proxywasm; + +public interface HttpContextHandler extends StreamContextHandler { + + // TODO: use a better type than Map so that we can support repeated headers + default ProxyMap getHttpRequestHeaders() { + return null; + } + + default ProxyMap getHttpRequestTrailers() { + return null; + } + + default ProxyMap getHttpResponseHeaders() { + return null; + } + + default ProxyMap getHttpResponseTrailers() { + return null; + } + + /** + * Get the HTTP request body. + * + * @return The HTTP request body as a byte[], or null if not available + */ + default byte[] getHttpRequestBody() { + return null; + } + + /** + * Get the HTTP response body. + * + * @return The HTTP response body as a byte[], or null if not available + */ + default byte[] getHttpResponseBody() { + return null; + } + + /** + * Set the HTTP request body. + * + * @param body The HTTP request body as a byte[] + * @return WasmResult indicating success or failure + */ + default WasmResult setHttpRequestBody(byte[] body) { + return WasmResult.UNIMPLEMENTED; + } + + /** + * Set the HTTP response body. + * + * @param body The HTTP response body as a byte[] + * @return WasmResult indicating success or failure + */ + default WasmResult setHttpResponseBody(byte[] body) { + return WasmResult.UNIMPLEMENTED; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogHandler.java new file mode 100644 index 0000000..1424605 --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogHandler.java @@ -0,0 +1,10 @@ +package io.roastedroot.proxywasm; + +public interface LogHandler { + + default void log(LogLevel level, String message) throws WasmException {} + + default LogLevel getLogLevel() throws WasmException { + return LogLevel.TRACE; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java new file mode 100644 index 0000000..8a9a8b8 --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java @@ -0,0 +1,24 @@ +package io.roastedroot.proxywasm; + +public interface MetricsHandler { + + default int defineMetric(MetricType metricType, String name) throws WasmException { + throw new WasmException(WasmResult.UNIMPLEMENTED); + } + + default WasmResult removeMetric(int metricId) { + return WasmResult.UNIMPLEMENTED; + } + + default WasmResult recordMetric(int metricId, long value) { + return WasmResult.UNIMPLEMENTED; + } + + default WasmResult incrementMetric(int metricId, long value) { + return WasmResult.UNIMPLEMENTED; + } + + default long getMetric(int metricId) throws WasmException { + throw new WasmException(WasmResult.UNIMPLEMENTED); + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PluginHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PluginHandler.java new file mode 100644 index 0000000..969a17c --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PluginHandler.java @@ -0,0 +1,44 @@ +package io.roastedroot.proxywasm; + +public interface PluginHandler { + + /** + * Get the plugin configuration. + * + * @return The plugin configuration as a byte[], or null if not available + */ + default byte[] getPluginConfig() { + return null; + } + + /** + * Get the VM configuration. + * + * @return The VM configuration as a byte[], or null if not available + */ + default byte[] getVmConfig() { + return null; + } + + /** + * Sets a low-resolution timer period (tick_period). + * + * When set, the host will call proxy_on_tick every tickPeriodMilliseconds milliseconds. Setting tickPeriodMilliseconds to 0 disables the timer. + * + * @return The current time in nanoseconds + */ + default WasmResult setTickPeriodMilliseconds(int tickPeriodMilliseconds) { + return WasmResult.UNIMPLEMENTED; + } + + /** + * Retrieves current time or the approximation of it. + * + * Note Hosts might return approximate time (e.g. frozen at the context creation) to improve performance and/or prevent various attacks. + * + * @return The current time in nanoseconds + */ + default int getCurrentTimeNanoseconds() throws WasmException { + return (int) System.currentTimeMillis() * 1000000; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PropertiesHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PropertiesHandler.java new file mode 100644 index 0000000..afd5e6f --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/PropertiesHandler.java @@ -0,0 +1,14 @@ +package io.roastedroot.proxywasm; + +import java.util.List; + +public interface PropertiesHandler { + + default byte[] getProperty(List key) throws WasmException { + return null; + } + + default WasmResult setProperty(List path, byte[] value) { + return WasmResult.UNIMPLEMENTED; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java new file mode 100644 index 0000000..690461a --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java @@ -0,0 +1,11 @@ +package io.roastedroot.proxywasm; + +public class SharedData { + public byte[] data; + public int cas; + + public SharedData(byte[] data, int cas) { + this.data = data; + this.cas = cas; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java new file mode 100644 index 0000000..dff9210 --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java @@ -0,0 +1,12 @@ +package io.roastedroot.proxywasm; + +public interface SharedDataHandler { + + default SharedData getSharedData(String key) throws WasmException { + throw new WasmException(WasmResult.UNIMPLEMENTED); + } + + default WasmResult setSharedData(String key, byte[] value, int cas) { + return WasmResult.UNIMPLEMENTED; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java new file mode 100644 index 0000000..cf64685 --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java @@ -0,0 +1,20 @@ +package io.roastedroot.proxywasm; + +public interface SharedQueueHandler { + + default int registerSharedQueue(QueueName name) throws WasmException { + throw new WasmException(WasmResult.UNIMPLEMENTED); + } + + default int resolveSharedQueue(QueueName name) throws WasmException { + throw new WasmException(WasmResult.UNIMPLEMENTED); + } + + default byte[] dequeueSharedQueue(int queueId) throws WasmException { + throw new WasmException(WasmResult.UNIMPLEMENTED); + } + + default WasmResult enqueueSharedQueue(int queueId, byte[] value) { + return WasmResult.UNIMPLEMENTED; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/StreamContextHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/StreamContextHandler.java new file mode 100644 index 0000000..40c02bb --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/StreamContextHandler.java @@ -0,0 +1,69 @@ +package io.roastedroot.proxywasm; + +public interface StreamContextHandler { + + /** + * Send an HTTP response. + * + * @param responseCode The HTTP response code + * @param responseCodeDetails The response code details + * @param responseBody The response body + * @param additionalHeaders Additional headers to include + * @param grpcStatus The gRPC status code (-1 for non-gRPC responses) + * @return The result of sending the response + */ + default WasmResult sendHttpResponse( + int responseCode, + byte[] responseCodeDetails, + byte[] responseBody, + ProxyMap additionalHeaders, + int grpcStatus) { + return WasmResult.UNIMPLEMENTED; + } + + default WasmResult setAction(StreamType streamType, Action action) { + return WasmResult.UNIMPLEMENTED; + } + + default WasmResult clearRouteCache() { + return WasmResult.UNIMPLEMENTED; + } + + /** + * Get the downstream data. + * + * @return The downstream data as a byte[], or null if not available + */ + default byte[] getDownStreamData() { + return null; + } + + /** + * Set the downstream data. + * + * @param data The downstream data as a byte[] + * @return WasmResult indicating success or failure + */ + default WasmResult setDownStreamData(byte[] data) { + return WasmResult.UNIMPLEMENTED; + } + + /** + * Get the upstream data. + * + * @return The upstream data as a byte[], or null if not available + */ + default byte[] getUpstreamData() { + return null; + } + + /** + * Set the upstream data. + * + * @param data The upstream data as a byte[] + * @return WasmResult indicating success or failure + */ + default WasmResult setUpstreamData(byte[] data) { + return WasmResult.UNIMPLEMENTED; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Plugin.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Plugin.java index 15ddcfa..1109bda 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Plugin.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Plugin.java @@ -19,6 +19,8 @@ import io.roastedroot.proxywasm.MetricType; import io.roastedroot.proxywasm.ProxyMap; import io.roastedroot.proxywasm.ProxyWasm; +import io.roastedroot.proxywasm.QueueName; +import io.roastedroot.proxywasm.SharedData; import io.roastedroot.proxywasm.StartException; import io.roastedroot.proxywasm.WasmException; import io.roastedroot.proxywasm.WasmResult; @@ -530,5 +532,43 @@ public ForeignFunction getForeignFunction(String name) { } return foreignFunctions.get(name); } + + // ////////////////////////////////////////////////////////////////////// + // Shared Data + // ////////////////////////////////////////////////////////////////////// + + @Override + public SharedData getSharedData(String key) throws WasmException { + return next().getSharedData(key); + } + + @Override + public WasmResult setSharedData(String key, byte[] value, int cas) { + return next().setSharedData(key, value, cas); + } + + // ////////////////////////////////////////////////////////////////////// + // Shared Queue + // ////////////////////////////////////////////////////////////////////// + + @Override + public int registerSharedQueue(QueueName queueName) throws WasmException { + return next().registerSharedQueue(queueName); + } + + @Override + public int resolveSharedQueue(QueueName queueName) throws WasmException { + return next().resolveSharedQueue(queueName); + } + + @Override + public byte[] dequeueSharedQueue(int queueId) throws WasmException { + return next().dequeueSharedQueue(queueId); + } + + @Override + public WasmResult enqueueSharedQueue(int queueId, byte[] value) { + return next().enqueueSharedQueue(queueId, value); + } } } diff --git a/proxy-wasm-java-host/src/test/java/io/roastedroot/proxywasm/examples/MockSharedHandler.java b/proxy-wasm-java-host/src/test/java/io/roastedroot/proxywasm/examples/MockSharedHandler.java index 03b77db..98b6b51 100644 --- a/proxy-wasm-java-host/src/test/java/io/roastedroot/proxywasm/examples/MockSharedHandler.java +++ b/proxy-wasm-java-host/src/test/java/io/roastedroot/proxywasm/examples/MockSharedHandler.java @@ -2,6 +2,7 @@ import io.roastedroot.proxywasm.Handler; import io.roastedroot.proxywasm.QueueName; +import io.roastedroot.proxywasm.SharedData; import io.roastedroot.proxywasm.WasmException; import io.roastedroot.proxywasm.WasmResult; import java.util.HashMap; From 03763ef06d8fa4568689f72537fb77fbe2ea22b0 Mon Sep 17 00:00:00 2001 From: Hiram Chirino Date: Sat, 29 Mar 2025 09:56:23 -0400 Subject: [PATCH 2/2] Support configuring metric, shared data, and shared queue handlers on the plugin. Signed-off-by: Hiram Chirino --- .../java/io/roastedroot/proxywasm/ABI.java | 10 +- .../io/roastedroot/proxywasm/LogHandler.java | 2 + .../roastedroot/proxywasm/MetricsHandler.java | 2 + .../io/roastedroot/proxywasm/SharedData.java | 12 +- .../proxywasm/SharedDataHandler.java | 2 + .../proxywasm/SharedQueueHandler.java | 2 + .../roastedroot/proxywasm/plugin/Logger.java | 10 -- .../roastedroot/proxywasm/plugin/Metric.java | 33 ----- .../roastedroot/proxywasm/plugin/Plugin.java | 119 ++++++++---------- .../plugin/SimpleMetricsHandler.java | 97 ++++++++++++++ .../plugin/SimpleSharedDataHandler.java | 37 ++++++ .../plugin/SimpleSharedQueueHandler.java | 77 ++++++++++++ .../proxywasm/examples/MockSharedHandler.java | 4 +- .../proxywasm/jaxrs/example/MockLogger.java | 4 +- .../proxywasm/jaxrs/example/MockLogger.java | 4 +- 15 files changed, 291 insertions(+), 124 deletions(-) delete mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Logger.java delete mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Metric.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleMetricsHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleSharedDataHandler.java create mode 100644 proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleSharedQueueHandler.java diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java index be620fd..5a76d3e 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ABI.java @@ -1598,18 +1598,18 @@ int proxyGetSharedData( } try { - if (value.data.length != 0) { - int addr = malloc(value.data.length); - putMemory(addr, value.data); + if (value.data().length != 0) { + int addr = malloc(value.data().length); + putMemory(addr, value.data()); putUint32(returnValueData, addr); } else { putUint32(returnValueData, 0); } - putUint32(returnValueSize, value.data.length); + putUint32(returnValueSize, value.data().length); } catch (WasmException e) { throw new WasmException(WasmResult.INVALID_MEMORY_ACCESS); } - putUint32(returnCas, value.cas); + putUint32(returnCas, value.cas()); return WasmResult.OK.getValue(); } catch (WasmException e) { diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogHandler.java index 1424605..511ae55 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogHandler.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/LogHandler.java @@ -2,6 +2,8 @@ public interface LogHandler { + LogHandler DEFAULT = new LogHandler() {}; + default void log(LogLevel level, String message) throws WasmException {} default LogLevel getLogLevel() throws WasmException { diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java index 8a9a8b8..cb2ef98 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/MetricsHandler.java @@ -2,6 +2,8 @@ public interface MetricsHandler { + MetricsHandler DEFAULT = new MetricsHandler() {}; + default int defineMetric(MetricType metricType, String name) throws WasmException { throw new WasmException(WasmResult.UNIMPLEMENTED); } diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java index 690461a..791b623 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedData.java @@ -1,11 +1,19 @@ package io.roastedroot.proxywasm; public class SharedData { - public byte[] data; - public int cas; + private final byte[] data; + private final int cas; public SharedData(byte[] data, int cas) { this.data = data; this.cas = cas; } + + public byte[] data() { + return data; + } + + public int cas() { + return cas; + } } diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java index dff9210..1079813 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedDataHandler.java @@ -2,6 +2,8 @@ public interface SharedDataHandler { + SharedDataHandler DEFAULT = new SharedDataHandler() {}; + default SharedData getSharedData(String key) throws WasmException { throw new WasmException(WasmResult.UNIMPLEMENTED); } diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java index cf64685..e94c32c 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/SharedQueueHandler.java @@ -2,6 +2,8 @@ public interface SharedQueueHandler { + SharedQueueHandler DEFAULT = new SharedQueueHandler() {}; + default int registerSharedQueue(QueueName name) throws WasmException { throw new WasmException(WasmResult.UNIMPLEMENTED); } diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Logger.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Logger.java deleted file mode 100644 index c9226e4..0000000 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Logger.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.roastedroot.proxywasm.plugin; - -import io.roastedroot.proxywasm.LogLevel; - -public interface Logger { - - void log(LogLevel level, String message); - - LogLevel getLogLevel(); -} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Metric.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Metric.java deleted file mode 100644 index 62e4191..0000000 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Metric.java +++ /dev/null @@ -1,33 +0,0 @@ -package io.roastedroot.proxywasm.plugin; - -import io.roastedroot.proxywasm.MetricType; - -public class Metric { - - final int id; - final MetricType type; - final String name; - long value; - - public Metric(int id, MetricType type, String name) { - this.id = id; - this.type = type; - this.name = name; - } - - public int id() { - return id; - } - - public MetricType type() { - return type; - } - - public String name() { - return name; - } - - public long value() { - return value; - } -} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Plugin.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Plugin.java index 1109bda..a493dbd 100644 --- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Plugin.java +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/Plugin.java @@ -15,12 +15,16 @@ import io.roastedroot.proxywasm.ChainedHandler; import io.roastedroot.proxywasm.ForeignFunction; import io.roastedroot.proxywasm.Handler; +import io.roastedroot.proxywasm.LogHandler; import io.roastedroot.proxywasm.LogLevel; import io.roastedroot.proxywasm.MetricType; +import io.roastedroot.proxywasm.MetricsHandler; import io.roastedroot.proxywasm.ProxyMap; import io.roastedroot.proxywasm.ProxyWasm; import io.roastedroot.proxywasm.QueueName; import io.roastedroot.proxywasm.SharedData; +import io.roastedroot.proxywasm.SharedDataHandler; +import io.roastedroot.proxywasm.SharedQueueHandler; import io.roastedroot.proxywasm.StartException; import io.roastedroot.proxywasm.WasmException; import io.roastedroot.proxywasm.WasmResult; @@ -41,6 +45,10 @@ public final class Plugin { private final boolean shared; private final String name; + private final MetricsHandler metricsHandler; + private final SharedQueueHandler sharedQueueHandler; + private final SharedDataHandler sharedDataHandler; + private Plugin(Builder builder, ProxyWasm proxyWasm) throws StartException { Objects.requireNonNull(proxyWasm); this.name = Objects.requireNonNullElse(builder.name, "default"); @@ -49,9 +57,16 @@ private Plugin(Builder builder, ProxyWasm proxyWasm) throws StartException { this.upstreams = builder.upstreams; this.strictUpstreams = builder.strictUpstreams; this.minTickPeriodMilliseconds = builder.minTickPeriodMilliseconds; - this.logger = builder.logger; this.vmConfig = builder.vmConfig; this.pluginConfig = builder.pluginConfig; + this.logger = Objects.requireNonNullElse(builder.logger, LogHandler.DEFAULT); + ; + this.metricsHandler = + Objects.requireNonNullElse(builder.metricsHandler, MetricsHandler.DEFAULT); + this.sharedQueueHandler = + Objects.requireNonNullElse(builder.sharedQueueHandler, SharedQueueHandler.DEFAULT); + this.sharedDataHandler = + Objects.requireNonNullElse(builder.sharedDataHandler, SharedDataHandler.DEFAULT); this.wasm = proxyWasm; this.wasm.setPluginHandler(new HandlerImpl()); @@ -86,7 +101,7 @@ public void setServerAdaptor(ServerAdaptor serverAdaptor) { this.serverAdaptor = serverAdaptor; } - public Logger logger() { + public LogHandler logger() { return logger; } @@ -121,9 +136,12 @@ public static class Builder implements Cloneable { private HashMap upstreams; private boolean strictUpstreams; private int minTickPeriodMilliseconds; - private Logger logger; + private LogHandler logger; private byte[] vmConfig; private byte[] pluginConfig; + private MetricsHandler metricsHandler; + private SharedQueueHandler sharedQueueHandler; + private SharedDataHandler sharedDataHandler; public Plugin.Builder withName(String name) { this.name = name; @@ -150,11 +168,26 @@ public Builder withMinTickPeriodMilliseconds(int minTickPeriodMilliseconds) { return this; } - public Builder withLogger(Logger logger) { + public Builder withLogger(LogHandler logger) { this.logger = logger; return this; } + public Builder withMetricsHandler(MetricsHandler metricsHandler) { + this.metricsHandler = metricsHandler; + return this; + } + + public Builder withSharedQueueHandler(SharedQueueHandler sharedQueueHandler) { + this.sharedQueueHandler = sharedQueueHandler; + return this; + } + + public Builder withSharedDataHandler(SharedDataHandler sharedDataHandler) { + this.sharedDataHandler = sharedDataHandler; + return this; + } + public Plugin.Builder withShared(boolean shared) { this.shared = shared; return this; @@ -202,7 +235,7 @@ public Plugin build(ProxyWasm proxyWasm) throws StartException { } } - public Logger logger; + public LogHandler logger; static final boolean DEBUG = "true".equals(System.getenv("DEBUG")); byte[] vmConfig; byte[] pluginConfig; @@ -214,26 +247,9 @@ public Plugin build(ProxyWasm proxyWasm) throws StartException { private int tickPeriodMilliseconds; private Runnable cancelTick; HashMap foreignFunctions; - private final AtomicInteger lastMetricId = new AtomicInteger(0); - private HashMap metrics = new HashMap<>(); - private HashMap metricsByName = new HashMap<>(); private byte[] funcCallData = new byte[0]; private final HashMap, byte[]> properties = new HashMap<>(); - public static class Metric { - - public final int id; - public final MetricType type; - public final String name; - public long value; - - public Metric(int id, MetricType type, String name) { - this.id = id; - this.type = type; - this.name = name; - } - } - class HandlerImpl extends ChainedHandler { @Override @@ -282,21 +298,12 @@ public WasmResult setProperty(List path, byte[] value) { @Override public void log(LogLevel level, String message) throws WasmException { - Logger l = logger; - if (l == null) { - super.log(level, message); - return; - } - l.log(level, message); + logger.log(level, message); } @Override public LogLevel getLogLevel() throws WasmException { - Logger l = logger; - if (l == null) { - return super.getLogLevel(); - } - return l.getLogLevel(); + return logger.getLogLevel(); } // ////////////////////////////////////////////////////////////////////// @@ -474,51 +481,27 @@ public int dispatchHttpCall( @Override public int defineMetric(MetricType type, String name) throws WasmException { - var id = lastMetricId.incrementAndGet(); - io.roastedroot.proxywasm.plugin.Metric value = - new io.roastedroot.proxywasm.plugin.Metric(id, type, name); - metrics.put(id, value); - metricsByName.put(name, value); - return id; + return metricsHandler.defineMetric(type, name); } @Override public long getMetric(int metricId) throws WasmException { - var metric = metrics.get(metricId); - if (metric == null) { - throw new WasmException(WasmResult.NOT_FOUND); - } - return metric.value; + return metricsHandler.getMetric(metricId); } @Override public WasmResult incrementMetric(int metricId, long value) { - var metric = metrics.get(metricId); - if (metric == null) { - return WasmResult.NOT_FOUND; - } - metric.value += value; - return WasmResult.OK; + return metricsHandler.incrementMetric(metricId, value); } @Override public WasmResult recordMetric(int metricId, long value) { - var metric = metrics.get(metricId); - if (metric == null) { - return WasmResult.NOT_FOUND; - } - metric.value = value; - return WasmResult.OK; + return metricsHandler.recordMetric(metricId, value); } @Override public WasmResult removeMetric(int metricId) { - io.roastedroot.proxywasm.plugin.Metric metric = metrics.remove(metricId); - if (metric == null) { - return WasmResult.NOT_FOUND; - } - metricsByName.remove(metric.name); - return WasmResult.OK; + return metricsHandler.removeMetric(metricId); } // ////////////////////////////////////////////////////////////////////// @@ -539,12 +522,12 @@ public ForeignFunction getForeignFunction(String name) { @Override public SharedData getSharedData(String key) throws WasmException { - return next().getSharedData(key); + return sharedDataHandler.getSharedData(key); } @Override public WasmResult setSharedData(String key, byte[] value, int cas) { - return next().setSharedData(key, value, cas); + return sharedDataHandler.setSharedData(key, value, cas); } // ////////////////////////////////////////////////////////////////////// @@ -553,22 +536,22 @@ public WasmResult setSharedData(String key, byte[] value, int cas) { @Override public int registerSharedQueue(QueueName queueName) throws WasmException { - return next().registerSharedQueue(queueName); + return sharedQueueHandler.registerSharedQueue(queueName); } @Override public int resolveSharedQueue(QueueName queueName) throws WasmException { - return next().resolveSharedQueue(queueName); + return sharedQueueHandler.resolveSharedQueue(queueName); } @Override public byte[] dequeueSharedQueue(int queueId) throws WasmException { - return next().dequeueSharedQueue(queueId); + return sharedQueueHandler.dequeueSharedQueue(queueId); } @Override public WasmResult enqueueSharedQueue(int queueId, byte[] value) { - return next().enqueueSharedQueue(queueId, value); + return sharedQueueHandler.enqueueSharedQueue(queueId, value); } } } diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleMetricsHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleMetricsHandler.java new file mode 100644 index 0000000..6e9970e --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleMetricsHandler.java @@ -0,0 +1,97 @@ +package io.roastedroot.proxywasm.plugin; + +import io.roastedroot.proxywasm.MetricType; +import io.roastedroot.proxywasm.MetricsHandler; +import io.roastedroot.proxywasm.WasmException; +import io.roastedroot.proxywasm.WasmResult; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicInteger; + +public class SimpleMetricsHandler implements MetricsHandler { + + public static class Metric { + + private final int id; + private final MetricType type; + private final String name; + private long value; + + public Metric(int id, MetricType type, String name) { + this.id = id; + this.type = type; + this.name = name; + } + + public int id() { + return id; + } + + public MetricType type() { + return type; + } + + public String name() { + return name; + } + + public long getValue() { + return value; + } + + public void setValue(long value) { + this.value = value; + } + } + + private final AtomicInteger lastMetricId = new AtomicInteger(0); + private HashMap metrics = new HashMap<>(); + private HashMap metricsByName = new HashMap<>(); + + @Override + public synchronized int defineMetric(MetricType type, String name) throws WasmException { + var id = lastMetricId.incrementAndGet(); + Metric value = new Metric(id, type, name); + metrics.put(id, value); + metricsByName.put(name, value); + return id; + } + + @Override + public synchronized long getMetric(int metricId) throws WasmException { + var metric = metrics.get(metricId); + if (metric == null) { + throw new WasmException(WasmResult.NOT_FOUND); + } + return metric.getValue(); + } + + @Override + public synchronized WasmResult incrementMetric(int metricId, long value) { + var metric = metrics.get(metricId); + if (metric == null) { + return WasmResult.NOT_FOUND; + } + metric.setValue(metric.getValue() + value); + return WasmResult.OK; + } + + @Override + public synchronized WasmResult recordMetric(int metricId, long value) { + var metric = metrics.get(metricId); + if (metric == null) { + return WasmResult.NOT_FOUND; + } + metric.setValue(value); + return WasmResult.OK; + } + + @Override + public synchronized WasmResult removeMetric(int metricId) { + Metric metric = metrics.remove(metricId); + if (metric == null) { + return WasmResult.NOT_FOUND; + } + metricsByName.remove(metric.name()); + return WasmResult.OK; + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleSharedDataHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleSharedDataHandler.java new file mode 100644 index 0000000..65c5081 --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleSharedDataHandler.java @@ -0,0 +1,37 @@ +package io.roastedroot.proxywasm.plugin; + +import io.roastedroot.proxywasm.SharedData; +import io.roastedroot.proxywasm.SharedDataHandler; +import io.roastedroot.proxywasm.WasmException; +import io.roastedroot.proxywasm.WasmResult; +import java.util.HashMap; + +public class SimpleSharedDataHandler implements SharedDataHandler { + + private final HashMap sharedData = new HashMap<>(); + + @Override + public synchronized SharedData getSharedData(String key) throws WasmException { + return sharedData.get(key); + } + + @Override + public synchronized WasmResult setSharedData(String key, byte[] value, int cas) { + SharedData prev = sharedData.get(key); + if (prev == null) { + if (cas == 0) { + sharedData.put(key, new SharedData(value, 0)); + return WasmResult.OK; + } else { + return WasmResult.CAS_MISMATCH; + } + } else { + if (cas == 0 || prev.cas() == cas) { + sharedData.put(key, new SharedData(value, prev.cas() + 1)); + return WasmResult.OK; + } else { + return WasmResult.CAS_MISMATCH; + } + } + } +} diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleSharedQueueHandler.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleSharedQueueHandler.java new file mode 100644 index 0000000..34e7501 --- /dev/null +++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/plugin/SimpleSharedQueueHandler.java @@ -0,0 +1,77 @@ +package io.roastedroot.proxywasm.plugin; + +import io.roastedroot.proxywasm.QueueName; +import io.roastedroot.proxywasm.SharedQueueHandler; +import io.roastedroot.proxywasm.WasmException; +import io.roastedroot.proxywasm.WasmResult; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicInteger; + +public class SimpleSharedQueueHandler implements SharedQueueHandler { + + public static class SharedQueue { + public final QueueName queueName; + public final LinkedList data = new LinkedList<>(); + public final int id; + + public SharedQueue(QueueName queueName, int id) { + this.queueName = queueName; + this.id = id; + } + } + + private final AtomicInteger lastSharedQueueId = new AtomicInteger(0); + private final HashMap sharedQueues = new HashMap<>(); + + public synchronized SharedQueue getSharedQueue(int queueId) { + return sharedQueues.get(queueId); + } + + @Override + public synchronized WasmResult enqueueSharedQueue(int queueId, byte[] value) { + SharedQueue queue = sharedQueues.get(queueId); + if (queue == null) { + return WasmResult.NOT_FOUND; + } + queue.data.add(value); + return WasmResult.OK; + } + + @Override + public synchronized byte[] dequeueSharedQueue(int queueId) throws WasmException { + SharedQueue queue = sharedQueues.get(queueId); + if (queue == null) { + throw new WasmException(WasmResult.NOT_FOUND); + } + return queue.data.poll(); + } + + @Override + public synchronized int resolveSharedQueue(QueueName queueName) throws WasmException { + var existing = + sharedQueues.values().stream() + .filter(x -> x.queueName.equals(queueName)) + .findFirst(); + if (existing.isPresent()) { + return existing.get().id; + } else { + throw new WasmException(WasmResult.NOT_FOUND); + } + } + + @Override + public synchronized int registerSharedQueue(QueueName queueName) throws WasmException { + var existing = + sharedQueues.values().stream() + .filter(x -> x.queueName.equals(queueName)) + .findFirst(); + if (existing.isPresent()) { + return existing.get().id; + } else { + int id = lastSharedQueueId.incrementAndGet(); + sharedQueues.put(id, new SharedQueue(queueName, id)); + return id; + } + } +} diff --git a/proxy-wasm-java-host/src/test/java/io/roastedroot/proxywasm/examples/MockSharedHandler.java b/proxy-wasm-java-host/src/test/java/io/roastedroot/proxywasm/examples/MockSharedHandler.java index 98b6b51..16d7f24 100644 --- a/proxy-wasm-java-host/src/test/java/io/roastedroot/proxywasm/examples/MockSharedHandler.java +++ b/proxy-wasm-java-host/src/test/java/io/roastedroot/proxywasm/examples/MockSharedHandler.java @@ -29,8 +29,8 @@ public WasmResult setSharedData(String key, byte[] value, int cas) { return WasmResult.CAS_MISMATCH; } } else { - if (cas == 0 || prev.cas == cas) { - sharedData.put(key, new SharedData(value, prev.cas + 1)); + if (cas == 0 || prev.cas() == cas) { + sharedData.put(key, new SharedData(value, prev.cas() + 1)); return WasmResult.OK; } else { return WasmResult.CAS_MISMATCH; diff --git a/proxy-wasm-jaxrs-jersey/src/test/java/io/roastedroot/proxywasm/jaxrs/example/MockLogger.java b/proxy-wasm-jaxrs-jersey/src/test/java/io/roastedroot/proxywasm/jaxrs/example/MockLogger.java index 33799f8..964c5f8 100644 --- a/proxy-wasm-jaxrs-jersey/src/test/java/io/roastedroot/proxywasm/jaxrs/example/MockLogger.java +++ b/proxy-wasm-jaxrs-jersey/src/test/java/io/roastedroot/proxywasm/jaxrs/example/MockLogger.java @@ -1,10 +1,10 @@ package io.roastedroot.proxywasm.jaxrs.example; +import io.roastedroot.proxywasm.LogHandler; import io.roastedroot.proxywasm.LogLevel; -import io.roastedroot.proxywasm.plugin.Logger; import java.util.ArrayList; -public class MockLogger implements Logger { +public class MockLogger implements LogHandler { static final boolean DEBUG = "true".equals(System.getenv("DEBUG")); diff --git a/proxy-wasm-jaxrs-quarkus/src/test/java/io/roastedroot/proxywasm/jaxrs/example/MockLogger.java b/proxy-wasm-jaxrs-quarkus/src/test/java/io/roastedroot/proxywasm/jaxrs/example/MockLogger.java index 33799f8..964c5f8 100644 --- a/proxy-wasm-jaxrs-quarkus/src/test/java/io/roastedroot/proxywasm/jaxrs/example/MockLogger.java +++ b/proxy-wasm-jaxrs-quarkus/src/test/java/io/roastedroot/proxywasm/jaxrs/example/MockLogger.java @@ -1,10 +1,10 @@ package io.roastedroot.proxywasm.jaxrs.example; +import io.roastedroot.proxywasm.LogHandler; import io.roastedroot.proxywasm.LogLevel; -import io.roastedroot.proxywasm.plugin.Logger; import java.util.ArrayList; -public class MockLogger implements Logger { +public class MockLogger implements LogHandler { static final boolean DEBUG = "true".equals(System.getenv("DEBUG"));