diff --git a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ProxyWasm.java b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ProxyWasm.java
index 087a65e..630c1b9 100644
--- a/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ProxyWasm.java
+++ b/proxy-wasm-java-host/src/main/java/io/roastedroot/proxywasm/ProxyWasm.java
@@ -59,7 +59,7 @@ private ProxyWasm(Builder other) throws StartException {
public void start() throws StartException {
if (pluginContext != null) {
- throw new IllegalStateException("already started");
+ return;
}
this.pluginContext = new PluginContext(this, pluginHandler);
diff --git a/proxy-wasm-jaxrs/pom.xml b/proxy-wasm-jaxrs/pom.xml
index 610f38d..0c8a4c0 100644
--- a/proxy-wasm-jaxrs/pom.xml
+++ b/proxy-wasm-jaxrs/pom.xml
@@ -114,10 +114,8 @@
- build
generate-code
generate-code-tests
- native-image-agent
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/HttpHandler.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/HttpHandler.java
index 6af101c..69542b1 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/HttpHandler.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/HttpHandler.java
@@ -50,7 +50,7 @@
import io.roastedroot.proxywasm.StreamType;
import io.roastedroot.proxywasm.WasmException;
import io.roastedroot.proxywasm.WasmResult;
-import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServerRequest;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.core.Response;
@@ -64,10 +64,10 @@
class HttpHandler extends ChainedHandler {
private final PluginHandler next;
- private final HttpServer httpServer;
+ private final HttpServerRequest httpServer;
private final long startedAt;
- HttpHandler(PluginHandler pluginHandler, HttpServer httpServer) {
+ HttpHandler(PluginHandler pluginHandler, HttpServerRequest httpServer) {
this.next = pluginHandler;
this.httpServer = httpServer;
this.startedAt = System.currentTimeMillis();
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/PluginHandler.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/PluginHandler.java
index 3d80f14..0e76cb7 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/PluginHandler.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/PluginHandler.java
@@ -23,6 +23,7 @@ class PluginHandler extends ChainedHandler {
// Filter Chain Methods
// //////////////////////////////////////////////////////////////////////
private Handler next;
+ WasmPlugin plugin;
PluginHandler() {
this(new Handler() {});
@@ -37,6 +38,16 @@ protected Handler next() {
return next;
}
+ // //////////////////////////////////////////////////////////////////////
+ // Cleanup
+ // //////////////////////////////////////////////////////////////////////
+ public void close() {
+ if (cancelTick != null) {
+ cancelTick.run();
+ cancelTick = null;
+ }
+ }
+
// //////////////////////////////////////////////////////////////////////
// Properties
// //////////////////////////////////////////////////////////////////////
@@ -103,7 +114,9 @@ public LogLevel getLogLevel() throws WasmException {
// Timers
// //////////////////////////////////////////////////////////////////////
+ int minTickPeriodMilliseconds;
private int tickPeriodMilliseconds;
+ private Runnable cancelTick;
public int getTickPeriodMilliseconds() {
return tickPeriodMilliseconds;
@@ -111,7 +124,36 @@ public int getTickPeriodMilliseconds() {
@Override
public WasmResult setTickPeriodMilliseconds(int tickPeriodMilliseconds) {
+
+ // check for no change
+ if (tickPeriodMilliseconds == this.tickPeriodMilliseconds) {
+ return WasmResult.OK;
+ }
+
+ // cancel the current tick, if any
+ if (cancelTick != null) {
+ cancelTick.run();
+ cancelTick = null;
+ }
+
+ // set the new tick period, if any
this.tickPeriodMilliseconds = tickPeriodMilliseconds;
+ if (this.tickPeriodMilliseconds == 0) {
+ return WasmResult.OK;
+ }
+
+ // schedule the new tick
+ this.cancelTick =
+ this.plugin.httpServer.scheduleTick(
+ Math.max(minTickPeriodMilliseconds, this.tickPeriodMilliseconds),
+ () -> {
+ this.plugin.lock();
+ try {
+ this.plugin.wasm.tick();
+ } finally {
+ this.plugin.unlock();
+ }
+ });
return WasmResult.OK;
}
@@ -132,6 +174,10 @@ public WasmResult setFuncCallData(byte[] data) {
return WasmResult.OK;
}
+ public void setPlugin(WasmPlugin plugin) {
+ this.plugin = plugin;
+ }
+
// //////////////////////////////////////////////////////////////////////
// HTTP calls
// //////////////////////////////////////////////////////////////////////
@@ -296,6 +342,9 @@ public WasmResult removeMetric(int metricId) {
@Override
public ForeignFunction getForeignFunction(String name) {
- return super.getForeignFunction(name);
+ if (foreignFunctions == null) {
+ return null;
+ }
+ return foreignFunctions.get(name);
}
}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/ProxyWasmFilter.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/ProxyWasmFilter.java
index 82eb319..6c548f9 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/ProxyWasmFilter.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/ProxyWasmFilter.java
@@ -3,15 +3,13 @@
import io.roastedroot.proxywasm.Action;
import io.roastedroot.proxywasm.HttpContext;
import io.roastedroot.proxywasm.StartException;
-import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServerRequest;
import jakarta.enterprise.inject.Instance;
-import jakarta.inject.Inject;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.container.ContainerRequestContext;
import jakarta.ws.rs.container.ContainerRequestFilter;
import jakarta.ws.rs.container.ContainerResponseContext;
import jakarta.ws.rs.container.ContainerResponseFilter;
-import jakarta.ws.rs.container.PreMatching;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ReaderInterceptor;
import jakarta.ws.rs.ext.ReaderInterceptorContext;
@@ -20,7 +18,6 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-@PreMatching
public class ProxyWasmFilter
implements ContainerRequestFilter,
ReaderInterceptor,
@@ -30,14 +27,17 @@ public class ProxyWasmFilter
private final WasmPluginPool pluginPool;
- Instance httpServer;
+ Instance httpServer;
- @Inject
- public ProxyWasmFilter(WasmPluginPool pluginPool, Instance httpServer) {
+ public ProxyWasmFilter(WasmPluginPool pluginPool, Instance httpServer) {
this.pluginPool = pluginPool;
this.httpServer = httpServer;
}
+ String name() {
+ return pluginPool.name();
+ }
+
// TODO: the HttpContext and ProxyWasm object's should be closed once the request is done.
// is there an easy way to hook up cleanup code for this?
static class WasmHttpFilterContext {
@@ -46,22 +46,27 @@ static class WasmHttpFilterContext {
final HttpHandler httpHandler;
final HttpContext httpContext;
- public WasmHttpFilterContext(WasmPlugin plugin, HttpServer httpServer) {
+ public WasmHttpFilterContext(WasmPlugin plugin, HttpServerRequest httpServer) {
this.plugin = plugin;
- this.pluginHandler = plugin.pluginHandler();
- this.httpHandler = new HttpHandler(plugin.pluginHandler(), httpServer);
- this.httpContext = plugin.proxyWasm().createHttpContext(this.httpHandler);
+ this.pluginHandler = plugin.handler;
+ this.httpHandler = new HttpHandler(plugin.handler, httpServer);
+ this.httpContext = plugin.wasm.createHttpContext(this.httpHandler);
}
}
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
- WasmPlugin plugin = null;
+ WasmPlugin plugin;
try {
plugin = pluginPool.borrow();
- plugin.lock();
+ } catch (StartException e) {
+ requestContext.abortWith(interalServerError());
+ return;
+ }
+ plugin.lock();
+ try {
var ctx = new WasmHttpFilterContext(plugin, this.httpServer.get());
requestContext.setProperty(FILTER_CONTEXT_PROPERTY_NAME, ctx);
@@ -81,15 +86,15 @@ public void filter(ContainerRequestContext requestContext) throws IOException {
requestContext.abortWith(sendResponse.toResponse());
}
}
-
- } catch (StartException e) {
- requestContext.abortWith(
- Response.status(Response.Status.INTERNAL_SERVER_ERROR).build());
} finally {
plugin.unlock(); // allow another request to use the plugin.
}
}
+ private static Response interalServerError() {
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+ }
+
@Override
public Object aroundReadFrom(ReaderInterceptorContext ctx)
throws IOException, WebApplicationException {
@@ -97,8 +102,7 @@ public Object aroundReadFrom(ReaderInterceptorContext ctx)
var wasmHttpFilterContext =
(WasmHttpFilterContext) ctx.getProperty(FILTER_CONTEXT_PROPERTY_NAME);
if (wasmHttpFilterContext == null) {
- throw new WebApplicationException(
- Response.status(Response.Status.INTERNAL_SERVER_ERROR).build());
+ throw new WebApplicationException(interalServerError());
}
// the plugin may not be interested in the request body.
@@ -147,8 +151,7 @@ public void filter(
var wasmHttpFilterContext =
(WasmHttpFilterContext) requestContext.getProperty(FILTER_CONTEXT_PROPERTY_NAME);
if (wasmHttpFilterContext == null) {
- throw new WebApplicationException(
- Response.status(Response.Status.INTERNAL_SERVER_ERROR).build());
+ throw new WebApplicationException(interalServerError());
}
// the plugin may not be interested in the request headers.
@@ -182,8 +185,7 @@ public void aroundWriteTo(WriterInterceptorContext ctx)
var wasmHttpFilterContext =
(WasmHttpFilterContext) ctx.getProperty(FILTER_CONTEXT_PROPERTY_NAME);
if (wasmHttpFilterContext == null) {
- throw new WebApplicationException(
- Response.status(Response.Status.INTERNAL_SERVER_ERROR).build());
+ throw new WebApplicationException(interalServerError());
}
try {
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPlugin.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPlugin.java
index 5de5bcc..cad5ed8 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPlugin.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPlugin.java
@@ -6,6 +6,7 @@
import io.roastedroot.proxywasm.ForeignFunction;
import io.roastedroot.proxywasm.ProxyWasm;
import io.roastedroot.proxywasm.StartException;
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -13,30 +14,24 @@
public class WasmPlugin {
- private final ProxyWasm proxyWasm;
- private final PluginHandler handler;
+ final PluginHandler handler;
private final ReentrantLock lock;
+ final ProxyWasm wasm;
+ HttpServer httpServer;
private WasmPlugin(ProxyWasm proxyWasm, PluginHandler handler, boolean shared) {
Objects.requireNonNull(proxyWasm);
Objects.requireNonNull(handler);
- this.proxyWasm = proxyWasm;
+ this.wasm = proxyWasm;
this.handler = handler;
this.lock = shared ? new ReentrantLock() : null;
+ this.handler.setPlugin(this);
}
public String name() {
return handler.getName();
}
- ProxyWasm proxyWasm() {
- return proxyWasm;
- }
-
- PluginHandler pluginHandler() {
- return handler;
- }
-
public static WasmPlugin.Builder builder() {
return new WasmPlugin.Builder();
}
@@ -59,10 +54,25 @@ public boolean isShared() {
return lock != null;
}
+ public void setHttpServer(HttpServer httpServer) {
+ this.httpServer = httpServer;
+ }
+
+ public void close() {
+ lock();
+ try {
+ wasm.close();
+ handler.close();
+ } finally {
+ unlock();
+ }
+ }
+
public static class Builder implements Cloneable {
private PluginHandler handler = new PluginHandler();
- private ProxyWasm.Builder proxyWasmBuilder = ProxyWasm.builder().withPluginHandler(handler);
+ private ProxyWasm.Builder proxyWasmBuilder =
+ ProxyWasm.builder().withPluginHandler(handler).withStart(false);
private boolean shared = true;
public WasmPlugin.Builder withName(String name) {
@@ -75,6 +85,11 @@ public Builder withForeignFunctions(Map functions) {
return this;
}
+ public Builder withMinTickPeriodMilliseconds(int minTickPeriodMilliseconds) {
+ this.handler.minTickPeriodMilliseconds = minTickPeriodMilliseconds;
+ return this;
+ }
+
public Builder withLogger(Logger logger) {
this.handler.logger = logger;
return this;
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginFeature.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginFeature.java
index 6204d43..579cb54 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginFeature.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginFeature.java
@@ -2,6 +2,8 @@
import io.roastedroot.proxywasm.StartException;
import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServerRequest;
+import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Any;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
@@ -9,31 +11,44 @@
import jakarta.ws.rs.container.ResourceInfo;
import jakarta.ws.rs.core.FeatureContext;
import jakarta.ws.rs.ext.Provider;
+import java.util.Collection;
import java.util.HashMap;
@Provider
+@ApplicationScoped
public class WasmPluginFeature implements DynamicFeature {
- private HashMap plugins = new HashMap<>();
+ private final HashMap pluginPools = new HashMap<>();
- @Inject @Any Instance requestAdaptor;
+ @Inject @Any Instance httpServerRequest;
@Inject
- public WasmPluginFeature(@Any Instance factories) throws StartException {
+ public WasmPluginFeature(Instance factories, @Any HttpServer httpServer)
+ throws StartException {
for (var factory : factories) {
- var plugin = factory.create();
+ WasmPlugin plugin = null;
+ plugin = factory.create();
+ plugin.setHttpServer(httpServer);
String name = plugin.name();
- if (this.plugins.containsKey(name)) {
+ if (this.pluginPools.containsKey(name)) {
throw new IllegalArgumentException("Duplicate wasm plugin name: " + name);
}
WasmPluginPool pool =
plugin.isShared()
? new WasmPluginPool.AppScoped(plugin)
: new WasmPluginPool.RequestScoped(factory, plugin);
- this.plugins.put(name, pool);
+ this.pluginPools.put(name, pool);
}
}
+ public Collection getPluginPools() {
+ return pluginPools.values();
+ }
+
+ WasmPluginPool pool(String name) {
+ return pluginPools.get(name);
+ }
+
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
@@ -47,9 +62,9 @@ public void configure(ResourceInfo resourceInfo, FeatureContext context) {
resourceInfo.getResourceClass().getAnnotation(NamedWasmPlugin.class);
}
if (pluignNameAnnotation != null) {
- WasmPluginPool factory = plugins.get(pluignNameAnnotation.value());
+ WasmPluginPool factory = pluginPools.get(pluignNameAnnotation.value());
if (factory != null) {
- context.register(new ProxyWasmFilter(factory, requestAdaptor));
+ context.register(new ProxyWasmFilter(factory, httpServerRequest));
}
}
}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginPool.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginPool.java
index a32b86a..7f60bd1 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginPool.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/WasmPluginPool.java
@@ -1,20 +1,39 @@
package io.roastedroot.proxywasm.jaxrs;
import io.roastedroot.proxywasm.StartException;
+import jakarta.annotation.PreDestroy;
+import java.util.Collection;
+import java.util.List;
-public interface WasmPluginPool {
+interface WasmPluginPool {
WasmPlugin borrow() throws StartException;
+ String name();
+
void release(WasmPlugin plugin);
class AppScoped implements WasmPluginPool {
private final WasmPlugin plugin;
- public AppScoped(WasmPlugin plugin) {
+ public AppScoped(WasmPlugin plugin) throws StartException {
this.plugin = plugin;
}
+ @PreDestroy
+ public void close() {
+ plugin.wasm.close();
+ }
+
+ public Collection getPluginPools() {
+ return List.of(plugin);
+ }
+
+ @Override
+ public String name() {
+ return plugin.name();
+ }
+
@Override
public void release(WasmPlugin plugin) {
if (plugin != this.plugin) {
@@ -24,6 +43,7 @@ public void release(WasmPlugin plugin) {
@Override
public WasmPlugin borrow() throws StartException {
+ plugin.wasm.start();
return plugin;
}
}
@@ -31,15 +51,24 @@ public WasmPlugin borrow() throws StartException {
class RequestScoped implements WasmPluginPool {
final WasmPluginFactory factory;
+ private final String name;
public RequestScoped(WasmPluginFactory factory, WasmPlugin plugin) {
this.factory = factory;
+ this.name = plugin.name();
release(plugin);
}
+ @Override
+ public String name() {
+ return this.name;
+ }
+
@Override
public WasmPlugin borrow() throws StartException {
- return factory.create();
+ WasmPlugin plugin = factory.create();
+ plugin.wasm.start();
+ return plugin;
}
// Return the plugin to the pool
@@ -47,7 +76,7 @@ public WasmPlugin borrow() throws StartException {
public void release(WasmPlugin plugin) {
// TODO: maybe implementing pooling in the future to reduce GC pressure
// but for now, we just close the plugin
- plugin.proxyWasm().close();
+ plugin.close();
}
}
}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/servlet/ServletHttpServer.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/servlet/ServletHttpServer.java
index 9b62c43..6c363b2 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/servlet/ServletHttpServer.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/servlet/ServletHttpServer.java
@@ -2,38 +2,25 @@
import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
import jakarta.annotation.Priority;
+import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Alternative;
-import jakarta.enterprise.inject.Instance;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.ws.rs.core.Context;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
@Alternative
@Priority(100)
+@ApplicationScoped
public class ServletHttpServer implements HttpServer {
- private final HttpServletRequest request;
-
- public ServletHttpServer(@Context Instance request) {
- this.request = request.get();
- }
-
- @Override
- public String remoteAddress() {
- return request.getRemoteAddr();
- }
-
- @Override
- public String remotePort() {
- return "" + request.getRemotePort();
- }
-
- @Override
- public String localAddress() {
- return request.getLocalAddr();
- }
+ ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
@Override
- public String localPort() {
- return "" + request.getLocalPort();
+ public Runnable scheduleTick(long delay, Runnable task) {
+ var f = executorService.scheduleAtFixedRate(task, delay, delay, TimeUnit.MILLISECONDS);
+ return () -> {
+ ;
+ f.cancel(false);
+ };
}
}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/servlet/ServletHttpServerRequest.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/servlet/ServletHttpServerRequest.java
new file mode 100644
index 0000000..6d56106
--- /dev/null
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/servlet/ServletHttpServerRequest.java
@@ -0,0 +1,42 @@
+package io.roastedroot.proxywasm.jaxrs.servlet;
+
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServerRequest;
+import jakarta.annotation.Priority;
+import jakarta.enterprise.inject.Alternative;
+import jakarta.enterprise.inject.Instance;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.ws.rs.core.Context;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+@Alternative
+@Priority(100)
+public class ServletHttpServerRequest implements HttpServerRequest {
+
+ private final HttpServletRequest request;
+ ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
+
+ public ServletHttpServerRequest(@Context Instance request) {
+ this.request = request.get();
+ }
+
+ @Override
+ public String remoteAddress() {
+ return request.getRemoteAddr();
+ }
+
+ @Override
+ public String remotePort() {
+ return "" + request.getRemotePort();
+ }
+
+ @Override
+ public String localAddress() {
+ return request.getLocalAddr();
+ }
+
+ @Override
+ public String localPort() {
+ return "" + request.getLocalPort();
+ }
+}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/spi/HttpServer.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/spi/HttpServer.java
index 720f74e..5d34bb5 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/spi/HttpServer.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/spi/HttpServer.java
@@ -5,11 +5,5 @@
*/
public interface HttpServer {
- String remoteAddress();
-
- String remotePort();
-
- String localAddress();
-
- String localPort();
+ Runnable scheduleTick(long delay, Runnable task);
}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/spi/HttpServerRequest.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/spi/HttpServerRequest.java
new file mode 100644
index 0000000..65c1ff7
--- /dev/null
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/spi/HttpServerRequest.java
@@ -0,0 +1,15 @@
+package io.roastedroot.proxywasm.jaxrs.spi;
+
+/**
+ * This interface will help us deal with differences in the http server impl.
+ */
+public interface HttpServerRequest {
+
+ String remoteAddress();
+
+ String remotePort();
+
+ String localAddress();
+
+ String localPort();
+}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/vertx/VertxHttpServer.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/vertx/VertxHttpServer.java
index 97d3b5a..f5e610b 100644
--- a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/vertx/VertxHttpServer.java
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/vertx/VertxHttpServer.java
@@ -1,41 +1,24 @@
package io.roastedroot.proxywasm.jaxrs.vertx;
import io.roastedroot.proxywasm.jaxrs.spi.HttpServer;
-import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.Vertx;
import jakarta.annotation.Priority;
-import jakarta.enterprise.context.RequestScoped;
+import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Alternative;
-import jakarta.enterprise.inject.Instance;
-import jakarta.ws.rs.core.Context;
+import jakarta.inject.Inject;
@Alternative
@Priority(200)
-@RequestScoped
+@ApplicationScoped
public class VertxHttpServer implements HttpServer {
- private final HttpServerRequest request;
-
- public VertxHttpServer(@Context Instance request) {
- this.request = request.get();
- }
-
- @Override
- public String remoteAddress() {
- return request.remoteAddress().hostAddress();
- }
-
- @Override
- public String remotePort() {
- return "" + request.remoteAddress().port();
- }
-
- @Override
- public String localAddress() {
- return request.localAddress().hostAddress();
- }
+ @Inject Vertx vertx;
@Override
- public String localPort() {
- return "" + request.localAddress().port();
+ public Runnable scheduleTick(long delay, Runnable task) {
+ var id = vertx.setPeriodic(delay, x -> task.run());
+ return () -> {
+ vertx.cancelTimer(id);
+ };
}
}
diff --git a/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/vertx/VertxHttpServerRequest.java b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/vertx/VertxHttpServerRequest.java
new file mode 100644
index 0000000..3ca426e
--- /dev/null
+++ b/proxy-wasm-jaxrs/src/main/java/io/roastedroot/proxywasm/jaxrs/vertx/VertxHttpServerRequest.java
@@ -0,0 +1,42 @@
+package io.roastedroot.proxywasm.jaxrs.vertx;
+
+import io.roastedroot.proxywasm.jaxrs.spi.HttpServerRequest;
+import jakarta.annotation.Priority;
+import jakarta.enterprise.context.RequestScoped;
+import jakarta.enterprise.inject.Alternative;
+import jakarta.enterprise.inject.Instance;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.core.Context;
+
+@Alternative
+@Priority(200)
+@RequestScoped
+public class VertxHttpServerRequest implements HttpServerRequest {
+
+ private final io.vertx.core.http.HttpServerRequest request;
+
+ @Inject
+ public VertxHttpServerRequest(@Context Instance request) {
+ this.request = request.get();
+ }
+
+ @Override
+ public String remoteAddress() {
+ return request.remoteAddress().hostAddress();
+ }
+
+ @Override
+ public String remotePort() {
+ return "" + request.remoteAddress().port();
+ }
+
+ @Override
+ public String localAddress() {
+ return request.localAddress().hostAddress();
+ }
+
+ @Override
+ public String localPort() {
+ return "" + request.localAddress().port();
+ }
+}
diff --git a/proxy-wasm-jaxrs/src/test/java/io/roastedroot/proxywasm/jaxrs/ForeignCallOnTickTest.java b/proxy-wasm-jaxrs/src/test/java/io/roastedroot/proxywasm/jaxrs/ForeignCallOnTickTest.java
new file mode 100644
index 0000000..3962461
--- /dev/null
+++ b/proxy-wasm-jaxrs/src/test/java/io/roastedroot/proxywasm/jaxrs/ForeignCallOnTickTest.java
@@ -0,0 +1,46 @@
+package io.roastedroot.proxywasm.jaxrs;
+
+import static io.roastedroot.proxywasm.jaxrs.TestHelpers.parseTestModule;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.roastedroot.proxywasm.StartException;
+import jakarta.enterprise.inject.Produces;
+import jakarta.inject.Inject;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+
+@QuarkusTest
+public class ForeignCallOnTickTest {
+
+ @Produces
+ public WasmPluginFactory create() throws StartException {
+ return () ->
+ WasmPlugin.builder()
+ .withName("foreignCallOnTickTest")
+ .withLogger(new MockLogger())
+ .withMinTickPeriodMilliseconds(
+ 100) // plugin wants a tick every 1 ms, that's too often
+ .withForeignFunctions(Map.of("compress", data -> data))
+ .build(parseTestModule("/go-examples/foreign_call_on_tick/main.wasm"));
+ }
+
+ @Inject WasmPluginFeature feature;
+
+ @Test
+ public void testRequest() throws InterruptedException, StartException {
+ WasmPlugin plugin = feature.pool("foreignCallOnTickTest").borrow();
+ assertNotNull(plugin);
+ assertEquals(1, plugin.handler.getTickPeriodMilliseconds());
+
+ var logger = (MockLogger) plugin.handler.logger;
+ Thread.sleep(200);
+ logger.assertLogsContain(
+ String.format(
+ "foreign function (compress) called: %d, result: %s",
+ 1, "68656c6c6f20776f726c6421"));
+ plugin.handler.logger = null;
+ plugin.close(); // so that the ticks don't keep running in the background.
+ }
+}