package org.webpieces.http2client.impl;
import java.util.concurrent.CompletableFuture;
import org.webpieces.data.api.DataWrapper;
import org.webpieces.data.api.DataWrapperGenerator;
import org.webpieces.data.api.DataWrapperGeneratorFactory;
import org.webpieces.http2client.api.dto.Http2Response;
import org.webpieces.http2client.api.exception.ServerRstStreamException;
import com.webpieces.hpack.api.dto.Http2Headers;
import com.webpieces.http2engine.api.client.Http2ResponseListener;
import com.webpieces.http2engine.api.client.PushPromiseListener;
import com.webpieces.http2parser.api.dto.DataFrame;
import com.webpieces.http2parser.api.dto.RstStreamFrame;
import com.webpieces.http2parser.api.dto.lib.PartialStream;
public class SingleResponseListener implements Http2ResponseListener {
private static final DataWrapperGenerator dataGen = DataWrapperGeneratorFactory.createDataWrapperGenerator();
private CompletableFuture<Http2Response> responseFuture = new CompletableFuture<Http2Response>();
private Http2Headers headers;
private DataWrapper fullData = dataGen.emptyWrapper();
@Override
public CompletableFuture<Void> incomingPartialResponse(PartialStream response) {
if(headers == null) {
incomingResponse((Http2Headers) response);
} else if(response instanceof DataFrame) {
incomingData((DataFrame) response);
} else if(response instanceof RstStreamFrame) {
serverCancelledRequest((RstStreamFrame) response);
} else if(response instanceof Http2Headers) {
incomingEndHeaders((Http2Headers) response);
} else
throw new UnsupportedOperationException("missing use case. type="+response.getClass()+" msg="+response);
//complete immediately because client is in control of single request/response
//and can just send less requests if he wants to back off
return CompletableFuture.completedFuture(null);
}
public void incomingResponse(Http2Headers headers) {
this.headers = headers;
if(headers.isEndOfStream())
responseFuture.complete(new Http2Response(headers, fullData, null));
}
public void incomingData(DataFrame data) {
fullData = dataGen.chainDataWrappers(fullData, data.getData());
if(data.isEndOfStream())
responseFuture.complete(new Http2Response(headers, fullData, null));
}
public void incomingEndHeaders(Http2Headers trailingHeaders) {
if(!trailingHeaders.isEndOfStream()) {
responseFuture.completeExceptionally(new IllegalArgumentException("An assumption we made was wrong. isComplete should be true here"));
throw new IllegalArgumentException("An assumption we made was wrong. isComplete should be true here");
}
Http2Response response = new Http2Response(headers, fullData, trailingHeaders);
responseFuture.complete(response);
}
public void serverCancelledRequest(RstStreamFrame response) {
responseFuture.completeExceptionally(new ServerRstStreamException("Server cancelled this stream. code="+response.getErrorCode()));
}
public CompletableFuture<Http2Response> fetchResponseFuture() {
return responseFuture;
}
@Override
public PushPromiseListener newIncomingPush(int streamId) {
throw new UnsupportedOperationException("you should either turn push promise setting off or not use single request/response since the server is sending a push_promise");
}
}