All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.servicetalk.grpc.api.GrpcRouteConversions Maven / Gradle / Ivy

There is a newer version: 0.42.47
Show newest version
/*
 * Copyright © 2019 Apple Inc. and the ServiceTalk project authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.servicetalk.grpc.api;

import io.servicetalk.concurrent.CompletableSource;
import io.servicetalk.concurrent.GracefulAutoCloseable;
import io.servicetalk.concurrent.PublisherSource.Subscriber;
import io.servicetalk.concurrent.api.AsyncCloseable;
import io.servicetalk.concurrent.api.AsyncCloseables;
import io.servicetalk.concurrent.api.Completable;
import io.servicetalk.concurrent.api.Publisher;
import io.servicetalk.concurrent.api.Single;
import io.servicetalk.concurrent.api.internal.ConnectablePayloadWriter;
import io.servicetalk.concurrent.internal.ConcurrentTerminalSubscriber;
import io.servicetalk.grpc.api.GrpcRoutes.BlockingRoute;
import io.servicetalk.grpc.api.GrpcRoutes.BlockingStreamingRoute;
import io.servicetalk.grpc.api.GrpcRoutes.RequestStreamingRoute;
import io.servicetalk.grpc.api.GrpcRoutes.ResponseStreamingRoute;
import io.servicetalk.grpc.api.GrpcRoutes.Route;
import io.servicetalk.grpc.api.GrpcRoutes.StreamingRoute;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

import static io.servicetalk.concurrent.Cancellable.IGNORE_CANCEL;
import static io.servicetalk.concurrent.api.Publisher.from;
import static io.servicetalk.concurrent.api.SourceAdapters.toSource;
import static io.servicetalk.concurrent.internal.SubscriberUtils.handleExceptionFromOnSubscribe;
import static io.servicetalk.utils.internal.PlatformDependent.throwException;
import static java.util.Objects.requireNonNull;

final class GrpcRouteConversions {

    private static final Logger LOGGER = LoggerFactory.getLogger(GrpcRouteConversions.class);

    private GrpcRouteConversions() {
        // No instance
    }

    static  Route toRoute(
            final StreamingRoute original) {
        requireNonNull(original);
        return new Route() {
            @Override
            public Single handle(final GrpcServiceContext ctx, final Req request) {
                return original.handle(ctx, from(request)).firstOrError();
            }

            @Override
            public Completable closeAsync() {
                return original.closeAsync();
            }

            @Override
            public Completable closeAsyncGracefully() {
                return original.closeAsyncGracefully();
            }
        };
    }

    static  Route toRoute(
            final BlockingStreamingRoute original) {
        return toRoute(toStreaming(original));
    }

    static  Route toRoute(
            final BlockingRoute original) {
        return toRoute(toStreaming(original));
    }

    static  StreamingRoute toStreaming(
            final Route original) {
        requireNonNull(original);
        return new StreamingRoute() {
            @Override
            public Publisher handle(final GrpcServiceContext ctx, final Publisher request) {
                return request.firstOrError().flatMapPublisher(req -> original.handle(ctx, req).toPublisher());
            }

            @Override
            public Completable closeAsync() {
                return original.closeAsync();
            }

            @Override
            public Completable closeAsyncGracefully() {
                return original.closeAsyncGracefully();
            }
        };
    }

    static  StreamingRoute toStreaming(
            final BlockingStreamingRoute original) {
        requireNonNull(original);
        return new StreamingRoute() {
            private final AsyncCloseable closeable = toAsyncCloseable(original);
            @Override
            public Publisher handle(final GrpcServiceContext ctx, final Publisher request) {
                return new Publisher() {
                    @Override
                    protected void handleSubscribe(final Subscriber subscriber) {
                        final ConnectablePayloadWriter connectablePayloadWriter =
                                new ConnectablePayloadWriter<>();
                        final Publisher pub = connectablePayloadWriter.connect();
                        final ConcurrentTerminalSubscriber concurrentTerminalSubscriber =
                                new ConcurrentTerminalSubscriber<>(subscriber, false);
                        toSource(pub).subscribe(concurrentTerminalSubscriber);
                        final GrpcPayloadWriter grpcPayloadWriter = new GrpcPayloadWriter() {
                            @Override
                            public void write(final Resp resp) throws IOException {
                                connectablePayloadWriter.write(resp);
                            }

                            @Override
                            public void close() throws IOException {
                                connectablePayloadWriter.close();
                            }

                            @Override
                            public void flush() throws IOException {
                                connectablePayloadWriter.flush();
                            }
                        };
                        try {
                            original.handle(ctx, request.toIterable(), grpcPayloadWriter);
                        } catch (Throwable t) {
                            concurrentTerminalSubscriber.onError(t);
                        } finally {
                            try {
                                grpcPayloadWriter.close();
                            } catch (IOException e) {
                                if (!concurrentTerminalSubscriber.processOnError(e)) {
                                    LOGGER.error("Failed to close GrpcPayloadWriter", e);
                                }
                            }
                        }
                    }
                };
            }

            @Override
            public Completable closeAsync() {
                return closeable.closeAsync();
            }

            @Override
            public Completable closeAsyncGracefully() {
                return closeable.closeAsyncGracefully();
            }
        };
    }

    static  StreamingRoute toStreaming(
            final BlockingRoute original) {
        requireNonNull(original);
        return new StreamingRoute() {
            private final AsyncCloseable closeable = toAsyncCloseable(original);
            @Override
            public Publisher handle(final GrpcServiceContext ctx, final Publisher request) {
                return request.firstOrError().map(req -> {
                    try {
                        return original.handle(ctx, req);
                    } catch (Exception e) {
                        return throwException(e);
                    }
                }).toPublisher();
            }

            @Override
            public Completable closeAsync() {
                return closeable.closeAsync();
            }

            @Override
            public Completable closeAsyncGracefully() {
                return closeable.closeAsyncGracefully();
            }
        };
    }

    static  RequestStreamingRoute
    toRequestStreamingRoute(final Route original) {
        requireNonNull(original);
        return new RequestStreamingRoute() {
            @Override
            public Single handle(final GrpcServiceContext ctx, final Publisher request) {
                return request.firstOrError().flatMap(req -> original.handle(ctx, req));
            }

            @Override
            public Completable closeAsync() {
                return original.closeAsync();
            }

            @Override
            public Completable closeAsyncGracefully() {
                return original.closeAsyncGracefully();
            }
        };
    }

    static  RequestStreamingRoute
    toRequestStreamingRoute(final StreamingRoute original) {
        requireNonNull(original);
        return new RequestStreamingRoute() {
            @Override
            public Single handle(final GrpcServiceContext ctx, final Publisher request) {
                return original.handle(ctx, request).firstOrError();
            }

            @Override
            public Completable closeAsync() {
                return original.closeAsync();
            }

            @Override
            public Completable closeAsyncGracefully() {
                return original.closeAsyncGracefully();
            }
        };
    }

    static  RequestStreamingRoute
    toRequestStreamingRoute(final BlockingStreamingRoute original) {
        return toRequestStreamingRoute(toStreaming(original));
    }

    static  RequestStreamingRoute
    toRequestStreamingRoute(final BlockingRoute original) {
        return toRequestStreamingRoute(toStreaming(original));
    }

    static  ResponseStreamingRoute
    toResponseStreamingRoute(final Route original) {
        requireNonNull(original);
        return new ResponseStreamingRoute() {
            @Override
            public Publisher handle(final GrpcServiceContext ctx, final Req request) {
                return original.handle(ctx, request).toPublisher();
            }

            @Override
            public Completable closeAsync() {
                return original.closeAsync();
            }

            @Override
            public Completable closeAsyncGracefully() {
                return original.closeAsyncGracefully();
            }
        };
    }

    static  ResponseStreamingRoute
    toResponseStreamingRoute(final StreamingRoute original) {
        requireNonNull(original);
        return new ResponseStreamingRoute() {
            @Override
            public Publisher handle(final GrpcServiceContext ctx, final Req request) {
                return original.handle(ctx, from(request));
            }

            @Override
            public Completable closeAsync() {
                return original.closeAsync();
            }

            @Override
            public Completable closeAsyncGracefully() {
                return original.closeAsyncGracefully();
            }
        };
    }

    static  ResponseStreamingRoute
    toResponseStreamingRoute(final BlockingStreamingRoute original) {
        return toResponseStreamingRoute(toStreaming(original));
    }

    static  ResponseStreamingRoute
    toResponseStreamingRoute(final BlockingRoute original) {
        return toResponseStreamingRoute(toStreaming(original));
    }

    static AsyncCloseable toAsyncCloseable(final GracefulAutoCloseable original) {
        return AsyncCloseables.toAsyncCloseable(graceful -> new Completable() {
            @Override
            protected void handleSubscribe(final CompletableSource.Subscriber subscriber) {
                try {
                    subscriber.onSubscribe(IGNORE_CANCEL);
                } catch (Throwable cause) {
                    handleExceptionFromOnSubscribe(subscriber, cause);
                    return;
                }

                try {
                    if (graceful) {
                        original.closeGracefully();
                    } else {
                        original.close();
                    }
                    subscriber.onComplete();
                } catch (Throwable t) {
                    subscriber.onError(t);
                }
            }
        });
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy