package org.rakam.presto.analysis;
import io.airlift.http.client.HttpClient;
import io.airlift.http.client.JsonBodyGenerator;
import io.airlift.http.client.Request;
import io.airlift.http.client.StringResponseHandler;
import io.airlift.json.JsonCodec;
import io.airlift.log.Logger;
import org.rakam.aws.kinesis.AWSKinesisModule;
import org.rakam.aws.kinesis.ForStreamer;
import org.rakam.aws.kinesis.StreamQuery;
import org.rakam.plugin.stream.CollectionStreamQuery;
import org.rakam.plugin.stream.EventStream;
import org.rakam.plugin.stream.StreamResponse;
import javax.inject.Inject;
import javax.ws.rs.core.UriBuilder;
import java.net.URI;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static com.google.common.net.MediaType.JSON_UTF_8;
import static io.airlift.http.client.Request.Builder.*;
import static javax.ws.rs.core.HttpHeaders.CONTENT_TYPE;
public class PrestoEventStream
implements EventStream
{
private final static Logger LOGGER = Logger.get(PrestoEventStream.class);
private final HttpClient httpClient;
private final int streamingPort;
private final URI prestoAddress;
private final JsonCodec<StreamQuery> queryCodec;
@Inject
public PrestoEventStream(@ForStreamer HttpClient httpClient, AWSKinesisModule.PrestoStreamConfig config, PrestoConfig prestoConfig)
{
this.httpClient = httpClient;
this.streamingPort = config.getPort();
this.prestoAddress = prestoConfig.getAddress();
this.queryCodec = JsonCodec.jsonCodec(StreamQuery.class);
}
@Override
public EventStreamer subscribe(String project, List<CollectionStreamQuery> collections, List<String> columns, StreamResponse response)
{
StreamQuery query = new StreamQuery(project, collections);
URI uri = UriBuilder.fromUri(prestoAddress)
.port(streamingPort)
.path("connector/streamer")
.build();
Request request = preparePost()
.setUri(uri)
.setHeader(CONTENT_TYPE, JSON_UTF_8.toString())
.setBodyGenerator(JsonBodyGenerator.jsonBodyGenerator(queryCodec, query))
.build();
String ticket = httpClient.execute(request, StringResponseHandler.createStringResponseHandler()).getBody();
return new EventStreamer()
{
private AtomicInteger failed = new AtomicInteger();
@Override
public synchronized void sync()
{
try {
URI uri = UriBuilder.fromUri(prestoAddress)
.port(streamingPort)
.path("connector/streamer")
.queryParam("ticket", ticket)
.build();
Request request = prepareGet().setUri(uri).build();
String data = httpClient.execute(request, StringResponseHandler.createStringResponseHandler()).getBody();
response.send("data", data);
}
catch (Exception e) {
if (failed.incrementAndGet() > 5) {
LOGGER.error(e, "Error while streaming records to client");
shutdown();
}
}
}
@Override
public void shutdown()
{
URI uri = UriBuilder.fromUri(prestoAddress)
.port(streamingPort)
.path("connector/streamer")
.queryParam("ticket", ticket)
.build();
Request request = prepareDelete().setUri(uri).build();
httpClient.execute(request, StringResponseHandler.createStringResponseHandler());
}
};
}
}