/*******************************************************************************
* Copyright (c) 2016 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package com.openshift.internal.restclient.capability.resources;
import com.openshift.internal.restclient.DefaultClient;
import com.openshift.internal.restclient.URLBuilder;
import com.openshift.internal.restclient.okhttp.ResponseCodeInterceptor;
import com.openshift.internal.restclient.okhttp.WebSocketAdapter;
import com.openshift.restclient.IApiTypeMapper;
import com.openshift.restclient.IClient;
import com.openshift.restclient.UnsupportedEndpointException;
import com.openshift.restclient.capability.IStoppable;
import com.openshift.restclient.capability.resources.IPodLogRetrievalAsync;
import com.openshift.restclient.http.IHttpConstants;
import com.openshift.restclient.model.IPod;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okhttp3.ws.WebSocket;
import okhttp3.ws.WebSocketCall;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Impl of Pod log retrieval using websocket
* @author jeff.cantrill
*
*/
public class PodLogRetrievalAsync implements IPodLogRetrievalAsync{
private static final Logger LOG = LoggerFactory.getLogger(PodLogRetrievalAsync.class);
private static final String CAPABILITY = "log";
private final IPod pod;
private final DefaultClient client;
private final IApiTypeMapper mapper;
public PodLogRetrievalAsync(IPod pod, IClient client) {
this.pod = pod;
this.client = client.adapt(DefaultClient.class);
this.mapper = client.adapt(IApiTypeMapper.class);
}
@Override
public boolean isSupported() {
if(client != null && mapper != null) {
try {
return mapper.getEndpointFor(pod.getApiVersion(), pod.getKind()).isSupported(CAPABILITY);
}catch(UnsupportedEndpointException e) {
//endpoint not found for version/kind
}
}
return false;
}
@Override
public String getName() {
return PodLogRetrievalAsync.class.getSimpleName();
}
@Override
public IStoppable start(IPodLogListener listener) {
return start(listener, null);
}
@Override
public IStoppable start(IPodLogListener listener, Options options) {
Map<String,String> parameters = options != null ? options.getMap() : new HashMap<>();
PodLogListenerAdapter adapter = new PodLogListenerAdapter(listener);
OkHttpClient okClient = client.adapt(OkHttpClient.class);
final String endpoint = new URLBuilder(client.getBaseURL(), mapper)
.kind(pod.getKind())
.namespace(pod.getNamespace())
.name(pod.getName())
.subresource(CAPABILITY)
.addParameters(parameters)
.websocket();
Request request = client.newRequestBuilderTo(endpoint)
.tag( new ResponseCodeInterceptor.Ignore(){} )
.build();
WebSocketCall call = WebSocketCall.create(okClient, request);
call.enqueue(adapter);
return adapter;
}
static class PodLogListenerAdapter extends WebSocketAdapter implements IStoppable{
private final IPodLogListener listener;
private WebSocket wsClient;
private AtomicBoolean open = new AtomicBoolean(false);
public PodLogListenerAdapter(IPodLogListener listener) {
this.listener = listener;
}
@Override
public void stop() {
try {
if(open.get()) {
wsClient.close(IHttpConstants.STATUS_NORMAL_STOP, "Client asking to stop.");
}
} catch (Exception e) {
LOG.debug("Unable to stop the watch client",e);
}finally {
wsClient = null;
}
}
@Override
public void onOpen(WebSocket webSocket, Response response) {
if(open.compareAndSet(false, true)) {
wsClient = webSocket;
listener.onOpen();
}
}
@Override
public void onClose(int code, String reason) {
if(open.compareAndSet(true, false)) {
listener.onClose(code, reason);
}
}
@Override
public void onMessage(ResponseBody message) throws IOException {
listener.onMessage(message.string());
}
@Override
public void onFailure(IOException e, Response response) {
listener.onFailure(e);
}
}
}