reactor.netty.NettyOutbound Maven / Gradle / Ivy
Show all versions of reactor-netty-core Show documentation
/*
* Copyright (c) 2011-2023 VMware, Inc. or its affiliates, All Rights Reserved.
*
* 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
*
* https://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 reactor.netty;
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Predicate;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.DefaultFileRegion;
import io.netty.handler.stream.ChunkedNioFile;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import reactor.core.Exceptions;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* An outbound-traffic API delegating to an underlying {@link Channel}.
* Note: With HTTP, chaining multiple send operations is discouraged and will not work as expected
* when send involves scalar or mono publishers. For instance {@code send(flux).send(mono)}
* or {@code send(flux).sendObject(message)} will ignore {@code send(flux)}.
* This is an anticipation of an API simplification moving forward next versions where
* send will not return {@link NettyOutbound} anymore.
*
* @author Stephane Maldini
*/
public interface NettyOutbound extends Publisher {
/**
* Returns the assigned {@link ByteBufAllocator}.
*
* @return the {@link ByteBufAllocator}
*/
ByteBufAllocator alloc();
/**
* Returns a never completing {@link Mono} after this {@link NettyOutbound#then()} has
* completed.
*
* @return a never completing {@link Mono} after this {@link NettyOutbound#then()} has
* completed.
*/
default Mono neverComplete() {
return then(Mono.never()).then();
}
/**
* Sends data to the peer, listens for any error on write and closes on terminal signal
* (complete|error). A new {@link NettyOutbound} type (or the same) for typed send
* sequences.
* Note: Nesting any send* method is not supported.
*
* @param dataStream the dataStream publishing OUT items to write on this channel
*
* @return A new {@link NettyOutbound} to append further send. It will emit a complete
* signal successful sequence write (e.g. after "flush") or any error during write.
*/
default NettyOutbound send(Publisher extends ByteBuf> dataStream) {
return send(dataStream, ReactorNetty.PREDICATE_BB_FLUSH);
}
/**
* Sends data to the peer, listens for any error on write and closes on terminal signal
* (complete|error). A new {@link NettyOutbound} type (or the same) for typed send
* sequences.
* Note: Nesting any send* method is not supported.
*
* @param dataStream the dataStream publishing OUT items to write on this channel
* @param predicate that returns true if explicit flush operation is needed after that buffer
*
* @return A new {@link NettyOutbound} to append further send. It will emit a complete
* signal successful sequence write (e.g. after "flush") or any error during write.
*/
NettyOutbound send(Publisher extends ByteBuf> dataStream, Predicate predicate);
/**
* Sends bytes to the peer, listens for any error on write and closes on terminal
* signal (complete|error). If more than one publisher is attached (multiple calls to
* send()) completion occurs after all publishers complete.
* Note: Nesting any send* method is not supported.
*
* @param dataStream the dataStream publishing Buffer items to write on this channel
*
* @return A Publisher to signal successful sequence write (e.g. after "flush") or any
* error during write
*/
default NettyOutbound sendByteArray(Publisher extends byte[]> dataStream) {
return send(ReactorNetty.publisherOrScalarMap(dataStream, Unpooled::wrappedBuffer));
}
/**
* Sends content from given {@link Path} using
* {@link java.nio.channels.FileChannel#transferTo(long, long, WritableByteChannel)}
* support. If the system supports it and the path resolves to a local file
* system {@link File} then transfer will use zero-byte copy
* to the peer.
* It will
* listen for any error on
* write and close
* on terminal signal (complete|error). If more than one publisher is attached
* (multiple calls to send()) completion occurs after all publishers complete.
*
* Note: this will emit {@link io.netty.channel.FileRegion} in the outbound
* {@link io.netty.channel.ChannelPipeline}
* Note: Nesting any send* method is not supported.
*
* @param file the file Path
*
* @return A Publisher to signal successful sequence write (e.g. after "flush") or any
* error during write
*/
default NettyOutbound sendFile(Path file) {
try {
return sendFile(file, 0L, Files.size(file));
}
catch (IOException e) {
return then(Mono.error(e));
}
}
/**
* Sends content from the given {@link Path} using
* {@link java.nio.channels.FileChannel#transferTo(long, long, WritableByteChannel)}
* support, if the system supports it, the path resolves to a local file
* system {@link File}, compression and SSL/TLS is not enabled, then transfer will
* use zero-byte copy to the peer., otherwise chunked read/write will be used.
*
It will listens for any error on write and closes
* on terminal signal (complete|error). If more than one publisher is attached
* (multiple calls to send()) completion occurs after all publishers complete.
* Note: Nesting any send* method is not supported.
*
* @param file the file Path
* @param position where to start
* @param count how much to transfer
*
* @return A Publisher to signal successful sequence write (e.g. after "flush") or any
* error during write
*/
default NettyOutbound sendFile(Path file, long position, long count) {
Objects.requireNonNull(file, "filepath");
return sendUsing(() -> FileChannel.open(file, StandardOpenOption.READ),
(c, fc) -> {
if (ReactorNetty.mustChunkFileTransfer(c, file)) {
ReactorNetty.addChunkedWriter(c);
try {
return new ChunkedNioFile(fc, position, count, 1024);
}
catch (Exception ioe) {
throw Exceptions.propagate(ioe);
}
}
return new DefaultFileRegion(fc, position, count);
},
ReactorNetty.fileCloser);
}
/**
* Sends content from given {@link Path} using chunked read/write. It will listen
* for any error on write and close on terminal signal (complete|error). If more than
* one publisher is attached (multiple calls to send()) completion occurs after all
* publishers complete.
* Note: Nesting any send* method is not supported.
*
* @param file the file Path
* @param position where to start
* @param count how much to transfer
*
* @return A Publisher to signal successful sequence write (e.g. after "flush") or any
* error during write
*/
default NettyOutbound sendFileChunked(Path file, long position, long count) {
Objects.requireNonNull(file, "filepath");
return sendUsing(() -> FileChannel.open(file, StandardOpenOption.READ),
(c, fc) -> {
ReactorNetty.addChunkedWriter(c);
try {
return new ChunkedNioFile(fc, position, count, 1024);
}
catch (Exception e) {
throw Exceptions.propagate(e);
}
},
ReactorNetty.fileCloser);
}
/**
* Sends data to the peer, listens for any error on write and closes on terminal signal
* (complete|error). Each individual {@link Publisher} completion will flush
* the underlying IO runtime.
* Note: Nesting any send* method is not supported.
*
* @param dataStreams the dataStream publishing OUT items to write on this channel
*
* @return A {@link Mono} to signal successful sequence write (e.g. after "flush") or
* any error during write
*/
default NettyOutbound sendGroups(Publisher extends Publisher extends ByteBuf>> dataStreams) {
return send(
Flux.from(dataStreams)
.concatMap(p -> Flux.from(p)
.concatWith(Mono.just(ReactorNetty.BOUNDARY)), 32),
ReactorNetty.PREDICATE_GROUP_FLUSH);
}
/**
* Sends an object through Netty pipeline. If type of {@link Publisher}, sends all signals,
* flushing on complete by default. Write occur in FIFO sequence.
* Note: Nesting any send* method is not supported.
*
* @param dataStream the dataStream publishing items to write on this channel
* or a simple pojo supported by configured Netty handlers
*
* @return A Publisher to signal successful sequence write (e.g. after "flush") or any
* error during write
*/
default NettyOutbound sendObject(Publisher> dataStream) {
return sendObject(dataStream, ReactorNetty.PREDICATE_FLUSH);
}
/**
* Sends an object through Netty pipeline. If type of {@link Publisher}, sends all signals,
* flushing on complete by default. Write occur in FIFO sequence.
* Note: Nesting any send* method is not supported.
*
* @param dataStream the dataStream publishing items to write on this channel
* or a simple pojo supported by configured Netty handlers
* @param predicate that returns true if explicit flush operation is needed after that object
*
* @return A Publisher to signal successful sequence write (e.g. after "flush") or any
* error during write
*/
NettyOutbound sendObject(Publisher> dataStream, Predicate