use of io.servicetalk.concurrent.api.Publisher in project servicetalk by apple.
the class ProtocolCompatibilityTest method serviceTalkServer.
private static TestServerContext serviceTalkServer(final ErrorMode errorMode, final boolean ssl, final GrpcExecutionStrategy strategy, @Nullable final String compression, @Nullable final Duration timeout, Queue<Throwable> reqStreamError) throws Exception {
final Compat.CompatService compatService = new Compat.CompatService() {
@Override
public Publisher<CompatResponse> bidirectionalStreamingCall(final GrpcServiceContext ctx, final Publisher<CompatRequest> pub) {
reqStreamError.add(SERVER_PROCESSED_TOKEN);
maybeThrowFromRpc(errorMode);
return pub.map(req -> response(req.getId())).beforeFinally(errorConsumer());
}
@Override
public Single<CompatResponse> clientStreamingCall(final GrpcServiceContext ctx, final Publisher<CompatRequest> pub) {
reqStreamError.add(SERVER_PROCESSED_TOKEN);
maybeThrowFromRpc(errorMode);
return pub.collect(() -> 0, (sum, req) -> sum + req.getId()).map(this::response).beforeFinally(errorConsumer());
}
@Override
public Single<CompatResponse> scalarCall(final GrpcServiceContext ctx, final CompatRequest req) {
maybeThrowFromRpc(errorMode);
return succeeded(response(req.getId()));
}
@Override
public Publisher<CompatResponse> serverStreamingCall(final GrpcServiceContext ctx, final CompatRequest req) {
maybeThrowFromRpc(errorMode);
return Publisher.fromIterable(() -> IntStream.range(0, req.getId()).iterator()).map(this::response);
}
private CompatResponse response(final int value) {
if (errorMode == ErrorMode.SIMPLE_IN_RESPONSE) {
throwGrpcStatusException();
} else if (errorMode == ErrorMode.STATUS_IN_RESPONSE) {
throwGrpcStatusExceptionWithStatus();
}
return computeResponse(value);
}
private TerminalSignalConsumer errorConsumer() {
return new TerminalSignalConsumer() {
@Override
public void onComplete() {
}
@Override
public void onError(final Throwable throwable) {
reqStreamError.add(throwable);
}
@Override
public void cancel() {
reqStreamError.add(new IOException("cancelled"));
}
};
}
};
final ServiceFactory serviceFactory = new ServiceFactory.Builder().bufferEncoders(serviceTalkCompressions(compression)).bufferDecoderGroup(serviceTalkDecompression(compression)).bidirectionalStreamingCall(strategy, compatService).clientStreamingCall(strategy, compatService).scalarCall(strategy, compatService).serverStreamingCall(strategy, compatService).build();
final ServerContext serverContext = serviceTalkServerBuilder(errorMode, ssl, timeout, b -> b.executionStrategy(strategy)).listenAndAwait(serviceFactory);
return TestServerContext.fromServiceTalkServerContext(serverContext);
}
use of io.servicetalk.concurrent.api.Publisher in project servicetalk by apple.
the class ProtoBufSerializationProviderBuilder method build0.
@SuppressWarnings("unchecked")
private void build0() {
for (Map.Entry<Class<? extends MessageLite>, Parser<? extends MessageLite>> entry : types.entrySet()) {
Class<MessageLite> messageType = (Class<MessageLite>) entry.getKey();
Parser<MessageLite> parser = (Parser<MessageLite>) entry.getValue();
Map<ContentCodec, HttpSerializer> serializersForType = new HashMap<>();
Map<ContentCodec, HttpDeserializer> deserializersForType = new HashMap<>();
for (ContentCodec codec : supportedCodings) {
DefaultSerializer serializer = new DefaultSerializer(new ProtoBufSerializationProvider<>(messageType, codec, parser));
HttpSerializer<MessageLite> httpSerializer = new ProtoHttpSerializer<>(serializer, codec, messageType);
serializersForType.put(codec, httpSerializer);
deserializersForType.put(codec, new HttpDeserializer<MessageLite>() {
@Override
public MessageLite deserialize(final HttpHeaders headers, final Buffer payload) {
return serializer.deserializeAggregatedSingle(payload, messageType);
}
@Override
public BlockingIterable<MessageLite> deserialize(final HttpHeaders headers, final BlockingIterable<Buffer> payload) {
return serializer.deserialize(payload, messageType);
}
@Override
public Publisher<MessageLite> deserialize(final HttpHeaders headers, final Publisher<Buffer> payload) {
return serializer.deserialize(payload, messageType);
}
});
}
serializers.put(messageType, serializersForType);
deserializers.put(messageType, deserializersForType);
}
}
use of io.servicetalk.concurrent.api.Publisher in project servicetalk by apple.
the class ProtocolCompatibilityTest method grpcJavaClient.
// Wrap grpc client in our client interface to simplify test code
private static CompatClient grpcJavaClient(final SocketAddress address, @Nullable final String compression, final boolean ssl, @Nullable Duration timeout) throws Exception {
final NettyChannelBuilder builder = NettyChannelBuilder.forAddress(address);
if (ssl) {
final SslContext context = GrpcSslContexts.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
builder.sslContext(context);
} else {
builder.usePlaintext();
}
final ManagedChannel channel = builder.build();
// stub is immutable and each builder step returns a new instance.
CompatGrpc.CompatStub stub = CompatGrpc.newStub(channel);
if (compression != null) {
stub = stub.withCompression(compression);
}
if (null != timeout) {
stub = stub.withDeadlineAfter(timeout.toNanos(), NANOSECONDS);
}
final CompatGrpc.CompatStub finalStub = stub;
return new CompatClient() {
@Override
public GrpcExecutionContext executionContext() {
throw new UnsupportedOperationException();
}
@Override
public Publisher<CompatResponse> bidirectionalStreamingCall(final Publisher<CompatRequest> request) {
final PublisherSource.Processor<CompatResponse, CompatResponse> processor = newPublisherProcessor(3);
sendRequest(request, finalStub.bidirectionalStreamingCall(adaptResponse(processor)));
return fromSource(processor);
}
@Override
public Publisher<CompatResponse> bidirectionalStreamingCall(final GrpcClientMetadata metadata, final Publisher<CompatRequest> request) {
return bidirectionalStreamingCall(request);
}
@Deprecated
@Override
public Publisher<CompatResponse> bidirectionalStreamingCall(final BidirectionalStreamingCallMetadata metadata, final Publisher<CompatRequest> request) {
return bidirectionalStreamingCall(request);
}
@SuppressWarnings("unchecked")
@Override
public Single<CompatResponse> clientStreamingCall(final Publisher<CompatRequest> request) {
final Processor<CompatResponse, CompatResponse> processor = newSingleProcessor();
final StreamObserver<CompatRequest> requestObserver = finalStub.clientStreamingCall(adaptResponse(processor));
sendRequest(request, requestObserver);
return (Single<CompatResponse>) processor;
}
@Deprecated
@Override
public Single<CompatResponse> clientStreamingCall(final ClientStreamingCallMetadata metadata, final Publisher<CompatRequest> request) {
return clientStreamingCall(request);
}
@Override
public Single<CompatResponse> clientStreamingCall(final GrpcClientMetadata metadata, final Publisher<CompatRequest> request) {
return clientStreamingCall(request);
}
@SuppressWarnings("unchecked")
@Override
public Single<CompatResponse> scalarCall(final CompatRequest request) {
final Processor<CompatResponse, CompatResponse> processor = newSingleProcessor();
finalStub.scalarCall(request, adaptResponse(processor));
return (Single<CompatResponse>) processor;
}
@Deprecated
@Override
public Single<CompatResponse> scalarCall(final ScalarCallMetadata metadata, final CompatRequest request) {
return scalarCall(request);
}
@Override
public Single<CompatResponse> scalarCall(final GrpcClientMetadata metadata, final CompatRequest request) {
return scalarCall(request);
}
@Override
public Publisher<CompatResponse> serverStreamingCall(final CompatRequest request) {
final PublisherSource.Processor<CompatResponse, CompatResponse> processor = newPublisherProcessor(3);
finalStub.serverStreamingCall(request, adaptResponse(processor));
return fromSource(processor);
}
@Deprecated
@Override
public Publisher<CompatResponse> serverStreamingCall(final ServerStreamingCallMetadata metadata, final CompatRequest request) {
return serverStreamingCall(request);
}
@Override
public Publisher<CompatResponse> serverStreamingCall(final GrpcClientMetadata metadata, final CompatRequest request) {
return serverStreamingCall(request);
}
@Override
public void close() throws Exception {
channel.shutdown().awaitTermination(DEFAULT_TIMEOUT_SECONDS, SECONDS);
}
@Override
public Completable closeAsync() {
throw new UnsupportedOperationException();
}
@Override
public Completable onClose() {
throw new UnsupportedOperationException();
}
@Override
public BlockingCompatClient asBlockingClient() {
throw new UnsupportedOperationException();
}
private void sendRequest(final Publisher<CompatRequest> request, final StreamObserver<CompatRequest> requestObserver) {
request.whenOnComplete(requestObserver::onCompleted).whenOnError(requestObserver::onError).forEach(requestObserver::onNext);
}
private StreamObserver<CompatResponse> adaptResponse(final Processor<CompatResponse, CompatResponse> processor) {
return new StreamObserver<CompatResponse>() {
@Override
public void onNext(final CompatResponse value) {
processor.onSuccess(value);
}
@Override
public void onError(final Throwable t) {
processor.onError(t);
}
@Override
public void onCompleted() {
// ignored
}
};
}
private StreamObserver<CompatResponse> adaptResponse(final PublisherSource.Processor<CompatResponse, CompatResponse> processor) {
return new StreamObserver<CompatResponse>() {
@Override
public void onNext(final CompatResponse value) {
processor.onNext(value);
}
@Override
public void onError(final Throwable t) {
processor.onError(t);
}
@Override
public void onCompleted() {
processor.onComplete();
}
};
}
};
}
use of io.servicetalk.concurrent.api.Publisher in project servicetalk by apple.
the class BlockingStreamingToStreamingService method handle.
@Override
public Single<StreamingHttpResponse> handle(final HttpServiceContext ctx, final StreamingHttpRequest request, final StreamingHttpResponseFactory responseFactory) {
return new Single<StreamingHttpResponse>() {
@Override
protected void handleSubscribe(final Subscriber<? super StreamingHttpResponse> subscriber) {
final ThreadInterruptingCancellable tiCancellable = new ThreadInterruptingCancellable(currentThread());
try {
subscriber.onSubscribe(tiCancellable);
} catch (Throwable cause) {
handleExceptionFromOnSubscribe(subscriber, cause);
return;
}
// This exists to help users with error propagation. If the user closes the payloadWriter and they throw
// (e.g. try-with-resources) this processor is merged with the payloadWriter Publisher so the error will
// still be propagated.
final Processor exceptionProcessor = newCompletableProcessor();
final BufferHttpPayloadWriter payloadWriter = new BufferHttpPayloadWriter(ctx.headersFactory().newTrailers());
DefaultBlockingStreamingHttpServerResponse response = null;
try {
final Consumer<DefaultHttpResponseMetaData> sendMeta = (metaData) -> {
final DefaultStreamingHttpResponse result;
try {
// transfer-encoding takes precedence over content-length.
// > When a message does not have a Transfer-Encoding header field, a
// Content-Length header field can provide the anticipated size.
// https://tools.ietf.org/html/rfc7230#section-3.3.2
final HttpHeaders headers = metaData.headers();
final HttpProtocolVersion version = metaData.version();
boolean addTrailers = version.major() > 1 || isTransferEncodingChunked(headers);
if (!addTrailers && h1TrailersSupported(version) && !hasContentLength(headers) && // breaks our HttpResponseDecoder
!HEAD.equals(request.method())) {
// this is likely not supported in http/1.0 and it is possible that a response has
// neither header and the connection close indicates the end of the response.
// https://tools.ietf.org/html/rfc7230#section-3.3.3
headers.add(TRANSFER_ENCODING, CHUNKED);
addTrailers = true;
}
Publisher<Object> messageBody = fromSource(exceptionProcessor).merge(payloadWriter.connect());
if (addTrailers) {
messageBody = messageBody.concat(succeeded(payloadWriter.trailers()));
}
messageBody = messageBody.beforeSubscription(() -> new Subscription() {
@Override
public void request(final long n) {
}
@Override
public void cancel() {
tiCancellable.cancel();
}
});
result = new DefaultStreamingHttpResponse(metaData.status(), version, headers, metaData.context0(), ctx.executionContext().bufferAllocator(), messageBody, forTransportReceive(false, version, headers), ctx.headersFactory());
} catch (Throwable t) {
subscriber.onError(t);
throw t;
}
subscriber.onSuccess(result);
};
response = new DefaultBlockingStreamingHttpServerResponse(OK, request.version(), ctx.headersFactory().newHeaders(), payloadWriter, ctx.executionContext().bufferAllocator(), sendMeta);
original.handle(ctx, request.toBlockingStreamingRequest(), response);
// The user code has returned successfully, complete the processor so the response stream can
// complete. If the user handles the request asynchronously (e.g. on another thread) they are
// responsible for closing the payloadWriter.
exceptionProcessor.onComplete();
} catch (Throwable cause) {
tiCancellable.setDone(cause);
if (response == null || response.markMetaSent()) {
safeOnError(subscriber, cause);
} else {
try {
exceptionProcessor.onError(cause);
} finally {
safeClose(payloadWriter, cause);
}
}
return;
}
tiCancellable.setDone();
}
};
}
use of io.servicetalk.concurrent.api.Publisher in project servicetalk by apple.
the class AbstractStreamingHttpConnection method request.
@Override
public Single<StreamingHttpResponse> request(final StreamingHttpRequest request) {
return defer(() -> {
Publisher<Object> flatRequest;
// See https://tools.ietf.org/html/rfc7230#section-3.3.3
if (canAddRequestContentLength(request)) {
flatRequest = setRequestContentLength(connectionContext().protocol(), request);
} else {
if (emptyMessageBody(request, request.messageBody())) {
flatRequest = flatEmptyMessage(connectionContext().protocol(), request, request.messageBody());
} else {
// Defer subscribe to the messageBody until transport requests it to allow clients retry failed
// requests with non-replayable messageBody
flatRequest = Single.<Object>succeeded(request).concat(request.messageBody(), true);
if (shouldAppendTrailers(connectionContext().protocol(), request)) {
flatRequest = flatRequest.scanWith(HeaderUtils::appendTrailersMapper);
}
}
addRequestTransferEncodingIfNecessary(request);
}
final HttpExecutionStrategy strategy = requestExecutionStrategy(request, executionContext().executionStrategy());
if (strategy.isSendOffloaded()) {
flatRequest = flatRequest.subscribeOn(connectionContext.executionContext().executor(), IoThreadFactory.IoThread::currentThreadIsIoThread);
}
Single<StreamingHttpResponse> resp = invokeClient(flatRequest, determineFlushStrategyForApi(request));
if (strategy.isMetadataReceiveOffloaded()) {
resp = resp.publishOn(connectionContext.executionContext().executor(), IoThreadFactory.IoThread::currentThreadIsIoThread);
}
if (strategy.isDataReceiveOffloaded()) {
resp = resp.map(response -> response.transformMessageBody(payload -> payload.publishOn(connectionContext.executionContext().executor(), IoThreadFactory.IoThread::currentThreadIsIoThread)));
}
return resp.shareContextOnSubscribe();
});
}
Aggregations