use of io.micronaut.core.async.subscriber.TypedSubscriber in project micronaut-core by micronaut-projects.
the class MultipartBodyArgumentBinder method bind.
@Override
public BindingResult<MultipartBody> bind(ArgumentConversionContext<MultipartBody> context, HttpRequest<?> source) {
if (source instanceof NettyHttpRequest) {
NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) source;
io.netty.handler.codec.http.HttpRequest nativeRequest = nettyHttpRequest.getNativeRequest();
if (nativeRequest instanceof StreamedHttpRequest) {
HttpContentProcessor<?> processor = beanLocator.findBean(HttpContentSubscriberFactory.class, new ConsumesMediaTypeQualifier<>(MediaType.MULTIPART_FORM_DATA_TYPE)).map(factory -> factory.build(nettyHttpRequest)).orElse(new DefaultHttpContentProcessor(nettyHttpRequest, httpServerConfiguration.get()));
// noinspection unchecked
return () -> Optional.of(subscriber -> processor.subscribe(new TypedSubscriber<Object>((Argument) context.getArgument()) {
Subscription s;
AtomicLong partsRequested = new AtomicLong(0);
@Override
protected void doOnSubscribe(Subscription subscription) {
this.s = subscription;
subscriber.onSubscribe(new Subscription() {
@Override
public void request(long n) {
if (partsRequested.getAndUpdate(prev -> prev + n) == 0) {
s.request(n);
}
}
@Override
public void cancel() {
subscription.cancel();
}
});
}
@Override
protected void doOnNext(Object message) {
if (LOG.isTraceEnabled()) {
LOG.trace("Server received streaming message for argument [{}]: {}", context.getArgument(), message);
}
if (message instanceof ByteBufHolder && ((ByteBufHolder) message).content() instanceof EmptyByteBuf) {
return;
}
if (message instanceof HttpData) {
HttpData data = (HttpData) message;
if (data.isCompleted()) {
partsRequested.decrementAndGet();
if (data instanceof FileUpload) {
subscriber.onNext(new NettyCompletedFileUpload((FileUpload) data, false));
} else if (data instanceof Attribute) {
subscriber.onNext(new NettyCompletedAttribute((Attribute) data, false));
}
// If the user didn't release the data, we should
if (data.refCnt() > 0) {
data.release();
}
}
}
if (partsRequested.get() > 0) {
s.request(1);
}
}
@Override
protected void doOnError(Throwable t) {
if (LOG.isTraceEnabled()) {
LOG.trace("Server received error for argument [" + context.getArgument() + "]: " + t.getMessage(), t);
}
try {
subscriber.onError(t);
} finally {
s.cancel();
}
}
@Override
protected void doOnComplete() {
if (LOG.isTraceEnabled()) {
LOG.trace("Done receiving messages for argument: {}", context.getArgument());
}
subscriber.onComplete();
}
}));
}
}
return BindingResult.EMPTY;
}
use of io.micronaut.core.async.subscriber.TypedSubscriber in project micronaut-core by micronaut-projects.
the class PublisherBodyBinder method bind.
@Override
public BindingResult<Publisher> bind(ArgumentConversionContext<Publisher> context, HttpRequest<?> source) {
if (source instanceof NettyHttpRequest) {
NettyHttpRequest nettyHttpRequest = (NettyHttpRequest) source;
io.netty.handler.codec.http.HttpRequest nativeRequest = nettyHttpRequest.getNativeRequest();
if (nativeRequest instanceof StreamedHttpRequest) {
Argument<?> targetType = context.getFirstTypeVariable().orElse(Argument.OBJECT_ARGUMENT);
HttpContentProcessor<?> processor = httpContentProcessorResolver.resolve(nettyHttpRequest, targetType);
// noinspection unchecked
return () -> Optional.of(subscriber -> processor.subscribe(new TypedSubscriber<Object>((Argument) context.getArgument()) {
Subscription s;
@Override
protected void doOnSubscribe(Subscription subscription) {
this.s = subscription;
subscriber.onSubscribe(subscription);
}
@Override
protected void doOnNext(Object message) {
if (LOG.isTraceEnabled()) {
LOG.trace("Server received streaming message for argument [{}]: {}", context.getArgument(), message);
}
if (message instanceof ByteBufHolder) {
message = ((ByteBufHolder) message).content();
if (message instanceof EmptyByteBuf) {
return;
}
}
ArgumentConversionContext<?> conversionContext = context.with(targetType);
Optional<?> converted = conversionService.convert(message, conversionContext);
if (converted.isPresent()) {
subscriber.onNext(converted.get());
} else {
try {
Optional<ConversionError> lastError = conversionContext.getLastError();
if (lastError.isPresent()) {
if (LOG.isDebugEnabled()) {
LOG.debug("Cannot convert message for argument [" + context.getArgument() + "] and value: " + message, lastError.get());
}
subscriber.onError(new ConversionErrorException(context.getArgument(), lastError.get()));
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Cannot convert message for argument [{}] and value: {}", context.getArgument(), message);
}
subscriber.onError(UnsatisfiedRouteException.create(context.getArgument()));
}
} finally {
s.cancel();
}
}
if (message instanceof ReferenceCounted) {
((ReferenceCounted) message).release();
}
}
@Override
protected void doOnError(Throwable t) {
if (LOG.isTraceEnabled()) {
LOG.trace("Server received error for argument [" + context.getArgument() + "]: " + t.getMessage(), t);
}
try {
subscriber.onError(t);
} finally {
s.cancel();
}
}
@Override
protected void doOnComplete() {
if (LOG.isTraceEnabled()) {
LOG.trace("Done receiving messages for argument: {}", context.getArgument());
}
subscriber.onComplete();
}
}));
}
}
return BindingResult.EMPTY;
}
use of io.micronaut.core.async.subscriber.TypedSubscriber in project micronaut-core by micronaut-projects.
the class JsonContentProcessor method doOnSubscribe.
@Override
protected void doOnSubscribe(Subscription subscription, Subscriber<? super JsonNode> subscriber) {
if (parentSubscription == null) {
return;
}
boolean streamArray = false;
boolean isJsonStream = nettyHttpRequest.getContentType().map(mediaType -> mediaType.equals(MediaType.APPLICATION_JSON_STREAM_TYPE)).orElse(false);
if (subscriber instanceof TypedSubscriber) {
TypedSubscriber typedSubscriber = (TypedSubscriber) subscriber;
Argument typeArgument = typedSubscriber.getTypeArgument();
Class targetType = typeArgument.getType();
if (Publishers.isConvertibleToPublisher(targetType) && !Publishers.isSingle(targetType)) {
Optional<Argument<?>> genericArgument = typeArgument.getFirstTypeVariable();
if (genericArgument.isPresent() && !Iterable.class.isAssignableFrom(genericArgument.get().getType()) && !isJsonStream) {
// if the generic argument is not a iterable type them stream the array into the publisher
streamArray = true;
}
}
}
this.jacksonProcessor = jsonMapper.createReactiveParser(p -> {
}, streamArray);
this.jacksonProcessor.subscribe(new CompletionAwareSubscriber<JsonNode>() {
@Override
protected void doOnSubscribe(Subscription jsonSubscription) {
Subscription childSubscription = new Subscription() {
boolean first = true;
@Override
public synchronized void request(long n) {
// find a better way in the future
if (first) {
jsonSubscription.request(n < Long.MAX_VALUE ? n + 1 : n);
parentSubscription.request(n < Long.MAX_VALUE ? n + 1 : n);
} else {
jsonSubscription.request(n);
parentSubscription.request(n);
}
}
@Override
public synchronized void cancel() {
jsonSubscription.cancel();
parentSubscription.cancel();
}
};
subscriber.onSubscribe(childSubscription);
}
@Override
protected void doOnNext(JsonNode message) {
subscriber.onNext(message);
}
@Override
protected void doOnError(Throwable t) {
subscriber.onError(t);
}
@Override
protected void doOnComplete() {
subscriber.onComplete();
}
});
jacksonProcessor.onSubscribe(subscription);
}
Aggregations