implement streaming requests
This commit is contained in:
parent
fb5f1bf2ba
commit
2d072a6b12
12 changed files with 208 additions and 56 deletions
|
@ -2027,9 +2027,6 @@ private:
|
||||||
kj::strTree(
|
kj::strTree(
|
||||||
sp, " public static final class ", methodName, " {\n",
|
sp, " public static final class ", methodName, " {\n",
|
||||||
sp, " public interface Request extends org.capnproto.Request<", paramBuilder, "> {\n",
|
sp, " public interface Request extends org.capnproto.Request<", paramBuilder, "> {\n",
|
||||||
sp, " default org.capnproto.FromPointerBuilder<", paramBuilder, "> getParamsFactory() {\n",
|
|
||||||
sp, " return ", paramFactory, ";\n",
|
|
||||||
sp, " }\n",
|
|
||||||
sp, " default Response send() {\n",
|
sp, " default Response send() {\n",
|
||||||
sp, " return new Response(this.sendInternal());\n",
|
sp, " return new Response(this.sendInternal());\n",
|
||||||
sp, " }\n",
|
sp, " }\n",
|
||||||
|
@ -2050,7 +2047,7 @@ private:
|
||||||
// client call
|
// client call
|
||||||
kj::strTree(
|
kj::strTree(
|
||||||
sp, "public Methods.", methodName, ".Request ", methodName, "Request() {\n",
|
sp, "public Methods.", methodName, ".Request ", methodName, "Request() {\n",
|
||||||
sp, " var result = newCall(0x", interfaceIdHex, "L, (short)", methodId, ");\n",
|
sp, " var result = newCall(", paramFactory, ", 0x", interfaceIdHex, "L, (short)", methodId, ");\n",
|
||||||
sp, " return () -> result;\n",
|
sp, " return () -> result;\n",
|
||||||
sp, "}\n"
|
sp, "}\n"
|
||||||
),
|
),
|
||||||
|
|
|
@ -1698,9 +1698,9 @@ final class RpcState<VatId> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletionStage<?> sendStreaming() {
|
public CompletableFuture<java.lang.Void> sendStreaming() {
|
||||||
// TODO falling back to regular send for now...
|
// TODO falling back to regular send for now...
|
||||||
return send();
|
return send().thenApply(results -> null);
|
||||||
}
|
}
|
||||||
|
|
||||||
QuestionRef sendInternal(boolean isTailCall) {
|
QuestionRef sendInternal(boolean isTailCall) {
|
||||||
|
|
|
@ -215,8 +215,6 @@ public final class CapabilityTest {
|
||||||
var factory = Test.TestGenerics.newFactory(Test.TestAllTypes.factory, AnyPointer.factory);
|
var factory = Test.TestGenerics.newFactory(Test.TestAllTypes.factory, AnyPointer.factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@org.junit.Test
|
@org.junit.Test
|
||||||
public void thisCap() {
|
public void thisCap() {
|
||||||
var callCount = new Counter();
|
var callCount = new Counter();
|
||||||
|
@ -234,4 +232,16 @@ public final class CapabilityTest {
|
||||||
client2.barRequest().send().join();
|
client2.barRequest().send().join();
|
||||||
Assert.assertEquals(3, callCount.value());
|
Assert.assertEquals(3, callCount.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@org.junit.Test
|
||||||
|
public void testStreamingCallsBlockSubsequentCalls() {
|
||||||
|
var server = new RpcTestUtil.TestStreamingImpl();
|
||||||
|
var cap = new Test.TestStreaming.Client(server);
|
||||||
|
|
||||||
|
{
|
||||||
|
var req = cap.doStreamIRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,6 +230,7 @@ class RpcTestUtil {
|
||||||
public TestTailCalleeImpl(Counter count) {
|
public TestTailCalleeImpl(Counter count) {
|
||||||
this(count, READY_NOW);
|
this(count, READY_NOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestTailCalleeImpl(Counter count, CompletableFuture<java.lang.Void> releaseMe) {
|
public TestTailCalleeImpl(Counter count, CompletableFuture<java.lang.Void> releaseMe) {
|
||||||
this.count = count;
|
this.count = count;
|
||||||
this.releaseMe = releaseMe;
|
this.releaseMe = releaseMe;
|
||||||
|
@ -328,5 +329,40 @@ class RpcTestUtil {
|
||||||
return this.impl.foo(context);
|
return this.impl.foo(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class TestStreamingImpl
|
||||||
|
extends Test.TestStreaming.Server {
|
||||||
|
|
||||||
|
public int iSum = 0;
|
||||||
|
public int jSum = 0;
|
||||||
|
CompletableFuture<java.lang.Void> fulfiller;
|
||||||
|
boolean jShouldThrow = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CompletableFuture<java.lang.Void> doStreamI(StreamingCallContext<Test.TestStreaming.DoStreamIParams.Reader> context) {
|
||||||
|
iSum += context.getParams().getI();
|
||||||
|
fulfiller = new CompletableFuture<>();
|
||||||
|
return fulfiller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CompletableFuture<java.lang.Void> doStreamJ(StreamingCallContext<Test.TestStreaming.DoStreamJParams.Reader> context) {
|
||||||
|
context.allowCancellation();
|
||||||
|
jSum += context.getParams().getJ();
|
||||||
|
if (jShouldThrow) {
|
||||||
|
return CompletableFuture.failedFuture(RpcException.failed("throw requested"));
|
||||||
|
}
|
||||||
|
fulfiller = new CompletableFuture<>();
|
||||||
|
return fulfiller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CompletableFuture<java.lang.Void> finishStream(CallContext<Test.TestStreaming.FinishStreamParams.Reader, Test.TestStreaming.FinishStreamResults.Builder> context) {
|
||||||
|
var results = context.getResults();
|
||||||
|
results.setTotalI(iSum);
|
||||||
|
results.setTotalJ(jSum);
|
||||||
|
return READY_NOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,13 @@ interface TestTailCaller {
|
||||||
foo @0 (i :Int32, callee :TestTailCallee) -> TestTailCallee.TailResult;
|
foo @0 (i :Int32, callee :TestTailCallee) -> TestTailCallee.TailResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface TestStreaming {
|
||||||
|
doStreamI @0 (i: UInt32) -> stream;
|
||||||
|
doStreamJ @1 (j: UInt32) -> stream;
|
||||||
|
finishStream @2 () -> (totalI :UInt32, totalJ: UInt32);
|
||||||
|
# Test streaming. finishStream() returns the totals of the values streamed to the other calls.
|
||||||
|
}
|
||||||
|
|
||||||
interface TestHandle {}
|
interface TestHandle {}
|
||||||
|
|
||||||
interface TestMoreStuff extends(TestCallOrder) {
|
interface TestMoreStuff extends(TestCallOrder) {
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
package org.capnproto;
|
package org.capnproto;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public final class AnyPointer {
|
public final class AnyPointer {
|
||||||
public static final class Factory
|
public static final class Factory
|
||||||
implements PointerFactory<Builder, Reader>,
|
implements PointerFactory<Builder, Reader>,
|
||||||
|
@ -209,6 +211,11 @@ public final class AnyPointer {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public org.capnproto.Request<Builder> getBaseRequest() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RequestHook getHook() {
|
public RequestHook getHook() {
|
||||||
return this.requestHook;
|
return this.requestHook;
|
||||||
|
@ -228,4 +235,44 @@ public final class AnyPointer {
|
||||||
return this.requestHook.send();
|
return this.requestHook.send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final class StreamingRequest
|
||||||
|
implements org.capnproto.StreamingRequest<Builder> {
|
||||||
|
|
||||||
|
private final Builder params;
|
||||||
|
private final RequestHook requestHook;
|
||||||
|
|
||||||
|
StreamingRequest(AnyPointer.Request request) {
|
||||||
|
this(request.params, request.requestHook);
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamingRequest(Builder params, RequestHook requestHook) {
|
||||||
|
this.params = params;
|
||||||
|
this.requestHook = requestHook;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Builder getParams() {
|
||||||
|
return this.params;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public org.capnproto.StreamingRequest<Builder> getTypelessRequest() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestHook getHook() {
|
||||||
|
return this.requestHook;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FromPointerBuilder<Builder> getParamsFactory() {
|
||||||
|
return AnyPointer.factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<java.lang.Void> send() {
|
||||||
|
return this.requestHook.sendStreaming();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,14 +87,40 @@ public final class Capability {
|
||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
default Request<AnyPointer.Builder> newCall(long interfaceId, short methodId) {
|
default <T> Request<T> newCall(FromPointerBuilder<T> paramsFactory, long interfaceId, short methodId) {
|
||||||
return this.getHook().newCall(interfaceId, methodId);
|
var request = this.getHook().newCall(interfaceId, methodId);
|
||||||
|
return new Request<>() {
|
||||||
|
@Override
|
||||||
|
public FromPointerBuilder<T> getParamsFactory() {
|
||||||
|
return paramsFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
default <T> StreamingRequest<T> newStreamingCall(FromPointerBuilder<T> paramsBuilder,
|
@Override
|
||||||
long interfaceId, short methodId) {
|
public Request<AnyPointer.Builder> getTypelessRequest() {
|
||||||
var request = getHook().newCall(interfaceId, methodId);
|
return request;
|
||||||
return new StreamingRequest<> (paramsBuilder, request.getParams(), request.getHook());
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Request<T> getBaseRequest() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
default <T> StreamingRequest<T> newStreamingCall(FromPointerBuilder<T> paramsFactory, long interfaceId, short methodId) {
|
||||||
|
var request = this.getHook().newCall(interfaceId, methodId);
|
||||||
|
var streamingRequest = new AnyPointer.StreamingRequest(request.getParams(), request.getHook());
|
||||||
|
return new StreamingRequest<>() {
|
||||||
|
@Override
|
||||||
|
public FromPointerBuilder<T> getParamsFactory() {
|
||||||
|
return paramsFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StreamingRequest<AnyPointer.Builder> getTypelessRequest() {
|
||||||
|
return streamingRequest;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,10 +403,10 @@ public final class Capability {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<?> sendStreaming() {
|
public CompletableFuture<java.lang.Void> sendStreaming() {
|
||||||
// We don't do any special handling of streaming in RequestHook for local requests, because
|
// We don't do any special handling of streaming in RequestHook for local requests, because
|
||||||
// there is no latency to compensate for between the client and server in this case.
|
// there is no latency to compensate for between the client and server in this case.
|
||||||
return send();
|
return send().thenApply(results -> null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2,23 +2,17 @@ package org.capnproto;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public interface Request<Params> {
|
public interface Request<Params>
|
||||||
|
extends RequestBase<Params> {
|
||||||
|
|
||||||
FromPointerBuilder<Params> getParamsFactory();
|
RequestBase<Params> getBaseRequest();
|
||||||
|
|
||||||
Request<AnyPointer.Builder> getTypelessRequest();
|
default FromPointerBuilder<Params> getParamsFactory() {
|
||||||
|
return getBaseRequest().getParamsFactory();
|
||||||
default Params getParams() {
|
|
||||||
return this.getTypelessRequest().getParams().getAs(this.getParamsFactory());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default RequestHook getHook() {
|
default RequestBase<AnyPointer.Builder> getTypelessRequest() {
|
||||||
return this.getTypelessRequest().getHook();
|
return getBaseRequest().getTypelessRequest();
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
default RemotePromise<AnyPointer.Reader> sendInternal() {
|
|
||||||
return this.getTypelessRequest().sendInternal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static <Params> Request<Params> newBrokenRequest(FromPointerBuilder<Params> paramsFactory,
|
static <Params> Request<Params> newBrokenRequest(FromPointerBuilder<Params> paramsFactory,
|
||||||
|
@ -34,7 +28,7 @@ public interface Request<Params> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<?> sendStreaming() {
|
public CompletableFuture<java.lang.Void> sendStreaming() {
|
||||||
return CompletableFuture.failedFuture(exc);
|
return CompletableFuture.failedFuture(exc);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -46,9 +40,14 @@ public interface Request<Params> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Request<AnyPointer.Builder> getTypelessRequest() {
|
public RequestBase<AnyPointer.Builder> getTypelessRequest() {
|
||||||
return new AnyPointer.Request(message.getRoot(AnyPointer.factory), hook);
|
return new AnyPointer.Request(message.getRoot(AnyPointer.factory), hook);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Request<Params> getBaseRequest() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +64,11 @@ public interface Request<Params> {
|
||||||
public Request<AnyPointer.Builder> getTypelessRequest() {
|
public Request<AnyPointer.Builder> getTypelessRequest() {
|
||||||
return typeless;
|
return typeless;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Request<Params> getBaseRequest() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
runtime/src/main/java/org/capnproto/RequestBase.java
Normal file
20
runtime/src/main/java/org/capnproto/RequestBase.java
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package org.capnproto;
|
||||||
|
|
||||||
|
public interface RequestBase<Params> {
|
||||||
|
|
||||||
|
FromPointerBuilder<Params> getParamsFactory();
|
||||||
|
|
||||||
|
RequestBase<AnyPointer.Builder> getTypelessRequest();
|
||||||
|
|
||||||
|
default Params getParams() {
|
||||||
|
return this.getTypelessRequest().getParams().getAs(this.getParamsFactory());
|
||||||
|
}
|
||||||
|
|
||||||
|
default RequestHook getHook() {
|
||||||
|
return this.getTypelessRequest().getHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
default RemotePromise<AnyPointer.Reader> sendInternal() {
|
||||||
|
return this.getTypelessRequest().sendInternal();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
package org.capnproto;
|
package org.capnproto;
|
||||||
|
|
||||||
import java.util.concurrent.CompletionStage;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public interface RequestHook {
|
public interface RequestHook {
|
||||||
|
|
||||||
RemotePromise<AnyPointer.Reader> send();
|
RemotePromise<AnyPointer.Reader> send();
|
||||||
|
|
||||||
CompletionStage<?> sendStreaming();
|
CompletableFuture<java.lang.Void> sendStreaming();
|
||||||
|
|
||||||
default Object getBrand() {
|
default Object getBrand() {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -2,12 +2,20 @@ package org.capnproto;
|
||||||
|
|
||||||
public class StreamingCallContext<Params> {
|
public class StreamingCallContext<Params> {
|
||||||
|
|
||||||
private final FromPointerReader<Params> params;
|
private final FromPointerReader<Params> paramsFactory;
|
||||||
final CallContextHook hook;
|
private final CallContextHook hook;
|
||||||
|
|
||||||
public StreamingCallContext(FromPointerReader<Params> params,
|
public StreamingCallContext(FromPointerReader<Params> paramsFactory,
|
||||||
CallContextHook hook) {
|
CallContextHook hook) {
|
||||||
this.params = params;
|
this.paramsFactory = paramsFactory;
|
||||||
this.hook = hook;
|
this.hook = hook;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final Params getParams() {
|
||||||
|
return this.hook.getParams().getAs(paramsFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void allowCancellation() {
|
||||||
|
this.hook.allowCancellation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,23 @@
|
||||||
package org.capnproto;
|
package org.capnproto;
|
||||||
|
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CompletionStage;
|
|
||||||
|
|
||||||
public class StreamingRequest<Params> {
|
public interface StreamingRequest<Params> {
|
||||||
|
|
||||||
private final FromPointerBuilder<Params> paramsBuilder;
|
FromPointerBuilder<Params> getParamsFactory();
|
||||||
AnyPointer.Builder params;
|
|
||||||
RequestHook hook;
|
|
||||||
|
|
||||||
StreamingRequest(FromPointerBuilder<Params> paramsBuilder,
|
StreamingRequest<AnyPointer.Builder> getTypelessRequest();
|
||||||
AnyPointer.Builder params, RequestHook hook) {
|
|
||||||
this.paramsBuilder = paramsBuilder;
|
default Params getParams() {
|
||||||
this.params = params;
|
return this.getTypelessRequest().getParams().getAs(this.getParamsFactory());
|
||||||
this.hook = hook;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletionStage<?> send() {
|
default RequestHook getHook() {
|
||||||
var promise = hook.sendStreaming();
|
return this.getTypelessRequest().getHook();
|
||||||
hook = null; // prevent reuse
|
}
|
||||||
return promise;
|
|
||||||
|
default CompletableFuture<java.lang.Void> send() {
|
||||||
|
return this.getHook().sendStreaming();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue