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

com.faunadb.client.streaming.BodyValueFlowProcessor Maven / Gradle / Ivy

The newest version!
package com.faunadb.client.streaming;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.faunadb.client.HttpResponses;
import com.faunadb.client.errors.StreamingException;
import com.faunadb.client.types.Field;
import com.faunadb.client.types.Value;
import com.faunadb.common.Connection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.Flow;
import java.util.concurrent.SubmissionPublisher;
import java.util.stream.Collectors;

public class BodyValueFlowProcessor extends SubmissionPublisher implements Flow.Processor, Value> {

    public BodyValueFlowProcessor(ObjectMapper json, Connection connection) {
        this.json = json;
        this.connection = connection;
    }

    private static Value ErrorValue = new Value.StringV("error");
    private static Field TxnField = Field.at("txn").to(Long.class);

    private final Logger log = LoggerFactory.getLogger(getClass());
    private ObjectMapper json;
    private Connection connection;
    private Flow.Subscription subscription = null;
    private Flow.Subscriber subscriber = null;

    private void requestOne() {
        subscription.request(1);
    }

    @Override
    public void subscribe(Flow.Subscriber subscriber) {
        if (this.subscriber == null) {
            this.subscriber = subscriber;
            super.subscribe(subscriber);
            requestOne();
        } else
            throw new IllegalStateException("BodyValueFlowProcessor can have only one subscriber");
    }

    @Override
    public void onSubscribe(Flow.Subscription subscription) {
        this.subscription = subscription;
    }

    @Override
    public void onNext(List items) {
        String text = items.stream()
            .map(b -> StandardCharsets.UTF_8.decode(b).toString())
            .collect(Collectors.joining());

        try {
            JsonNode jsonNode = json.readTree(text);
            Value value = json.treeToValue(jsonNode, Value.class);
            // update connection last txn time
            value.getOptional(TxnField).ifPresent(ts -> connection.syncLastTxnTime(ts));

            Boolean errorEventType = value.at("type")
                .getOptional()
                .map(v -> v.equals(ErrorValue))
                .orElse(false);

            if (errorEventType) {
                HttpResponses.QueryError queryError = json.treeToValue(jsonNode.get("event"), HttpResponses.QueryError.class);
                Exception ex = new StreamingException(queryError.code() + ": " + queryError.description());
                subscriber.onError(ex); // notify subscriber stream
                subscription.cancel(); // cancel subscription on the request body
            } else {
                submit(value);
            }
        } catch (Exception ex){
            log.error("could not parse event " + text, ex);
            subscriber.onError(ex); // notify subscriber stream
            subscription.cancel(); // cancel subscription on the request body
        }

        requestOne();
    }

    @Override
    public void onError(Throwable throwable) {
        log.error("unrecoverable error encountered by subscription", throwable);
        subscriber.onError(throwable);
    }

    @Override
    public void onComplete() {
        log.debug("subscription completed");
        subscriber.onComplete();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy